Browse Source

win32 font fix. Tidied up warnings in plugin host. More drawable refactoring. TabbedComponent fix.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
7478c7f9ab
27 changed files with 1770 additions and 1451 deletions
  1. +2
    -2
      extras/audio plugin host/Source/GraphEditorPanel.cpp
  2. +1
    -1
      extras/audio plugin host/Source/MainHostWindow.cpp
  3. +637
    -528
      juce_amalgamated.cpp
  4. +384
    -338
      juce_amalgamated.h
  5. +1
    -1
      src/core/juce_StandardHeader.h
  6. +4
    -4
      src/gui/components/layout/juce_ComponentBuilder.cpp
  7. +63
    -93
      src/gui/components/layout/juce_TabbedComponent.cpp
  8. +6
    -5
      src/gui/components/layout/juce_TabbedComponent.h
  9. +6
    -0
      src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp
  10. +3
    -2
      src/gui/components/positioning/juce_RelativeCoordinatePositioner.h
  11. +12
    -0
      src/gui/components/positioning/juce_RelativeParallelogram.cpp
  12. +2
    -0
      src/gui/components/positioning/juce_RelativeParallelogram.h
  13. +22
    -0
      src/gui/graphics/drawables/juce_Drawable.h
  14. +34
    -34
      src/gui/graphics/drawables/juce_DrawableComposite.cpp
  15. +6
    -5
      src/gui/graphics/drawables/juce_DrawableComposite.h
  16. +37
    -18
      src/gui/graphics/drawables/juce_DrawableImage.cpp
  17. +3
    -1
      src/gui/graphics/drawables/juce_DrawableImage.h
  18. +39
    -67
      src/gui/graphics/drawables/juce_DrawablePath.cpp
  19. +11
    -13
      src/gui/graphics/drawables/juce_DrawablePath.h
  20. +58
    -45
      src/gui/graphics/drawables/juce_DrawableRectangle.cpp
  21. +8
    -8
      src/gui/graphics/drawables/juce_DrawableRectangle.h
  22. +259
    -176
      src/gui/graphics/drawables/juce_DrawableShape.cpp
  23. +56
    -40
      src/gui/graphics/drawables/juce_DrawableShape.h
  24. +83
    -40
      src/gui/graphics/drawables/juce_DrawableText.cpp
  25. +6
    -1
      src/gui/graphics/drawables/juce_DrawableText.h
  26. +3
    -4
      src/gui/graphics/fonts/juce_Font.cpp
  27. +24
    -25
      src/native/mac/juce_mac_CoreGraphicsContext.mm

+ 2
- 2
extras/audio plugin host/Source/GraphEditorPanel.cpp View File

@@ -231,7 +231,7 @@ public:
void mouseDown (const MouseEvent& e)
{
originalPos = relativePositionToGlobal (Point<int>());
originalPos = localPointToGlobal (Point<int>());
toFront (true);
@@ -277,7 +277,7 @@ public:
Point<int> pos (originalPos + Point<int> (e.getDistanceFromDragStartX(), e.getDistanceFromDragStartY()));
if (getParentComponent() != 0)
pos = getParentComponent()->globalPositionToRelative (pos);
pos = getParentComponent()->getLocalPoint (0, pos);
graph.setNodePosition (filterID,
(pos.getX() + getWidth() / 2) / (double) getParentWidth(),


+ 1
- 1
extras/audio plugin host/Source/MainHostWindow.cpp View File

@@ -498,7 +498,7 @@ void MainHostWindow::filesDropped (const StringArray& files, int x, int y)
Point<int> pos (x, y);
if (graphEditor != 0)
pos = relativePositionToOtherComponent (graphEditor, pos);
pos = graphEditor->getLocalPoint (this, pos);
for (int i = 0; i < jmin (5, typesFound.size()); ++i)
createPlugin (typesFound.getUnchecked(i), pos.getX(), pos.getY());


+ 637
- 528
juce_amalgamated.cpp
File diff suppressed because it is too large
View File


+ 384
- 338
juce_amalgamated.h View File

@@ -73,7 +73,7 @@ namespace JuceDummyNamespace {}
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
#define JUCE_BUILDNUMBER 6
#define JUCE_BUILDNUMBER 7

/** Current Juce version number.

@@ -45451,6 +45451,273 @@ private:
/*** End of inlined file: juce_RelativeCoordinate.h ***/


/*** Start of inlined file: juce_RelativeCoordinatePositioner.h ***/
#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
#define __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__


/*** Start of inlined file: juce_RelativePoint.h ***/
#ifndef __JUCE_RELATIVEPOINT_JUCEHEADER__
#define __JUCE_RELATIVEPOINT_JUCEHEADER__

/**
An X-Y position stored as a pair of RelativeCoordinate values.

@see RelativeCoordinate, RelativeRectangle
*/
class JUCE_API RelativePoint
{
public:
/** Creates a point at the origin. */
RelativePoint();

/** Creates an absolute point, relative to the origin. */
RelativePoint (const Point<float>& absolutePoint);

/** Creates an absolute point, relative to the origin. */
RelativePoint (float absoluteX, float absoluteY);

/** Creates an absolute point from two coordinates. */
RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y);

/** Creates a point from a stringified representation.
The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate
strings is explained in the RelativeCoordinate class.
@see toString
*/
RelativePoint (const String& stringVersion);

bool operator== (const RelativePoint& other) const throw();
bool operator!= (const RelativePoint& other) const throw();

/** Calculates the absolute position of this point.

You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
be needed to calculate the result.
*/
const Point<float> resolve (const Expression::EvaluationContext* evaluationContext) const;

/** Changes the values of this point's coordinates to make it resolve to the specified position.

Calling this will leave any anchor points unchanged, but will set any absolute
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
void moveToAbsolute (const Point<float>& newPos, const Expression::EvaluationContext* evaluationContext);

/** Returns a string which represents this point.
This returns a comma-separated pair of coordinates. For details of the string syntax used by the
coordinates, see the RelativeCoordinate constructor notes.
The string that is returned can be passed to the RelativePoint constructor to recreate the point.
*/
const String toString() const;

/** Renames a symbol if it is used by any of the coordinates.
This calls RelativeCoordinate::renameAnchorIfUsed() on its X and Y coordinates.
*/
void renameSymbolIfUsed (const String& oldName, const String& newName);

/** Returns true if this point depends on any other coordinates for its position. */
bool isDynamic() const;

// The actual X and Y coords...
RelativeCoordinate x, y;
};

#endif // __JUCE_RELATIVEPOINT_JUCEHEADER__
/*** End of inlined file: juce_RelativePoint.h ***/


/*** Start of inlined file: juce_MarkerList.h ***/
#ifndef __JUCE_MARKERLIST_JUCEHEADER__
#define __JUCE_MARKERLIST_JUCEHEADER__

/**
Holds a set of named marker points along a one-dimensional axis.

This class is used to store sets of X and Y marker points in components.
@see Component::getMarkers().
*/
class JUCE_API MarkerList
{
public:

/** Creates an empty marker list. */
MarkerList();
/** Creates a copy of another marker list. */
MarkerList (const MarkerList& other);
/** Copies another marker list to this one. */
MarkerList& operator= (const MarkerList& other);
/** Destructor. */
~MarkerList();

/** Represents a marker in a MarkerList. */
class JUCE_API Marker
{
public:
/** Creates a copy of another Marker. */
Marker (const Marker& other);
/** Creates a Marker with a given name and position. */
Marker (const String& name, const RelativeCoordinate& position);

/** The marker's name. */
String name;

/** The marker's position. */
RelativeCoordinate position;

/** Returns true if both the names and positions of these two markers match. */
bool operator== (const Marker&) const throw();
/** Returns true if either the name or position of these two markers differ. */
bool operator!= (const Marker&) const throw();
};

/** Returns the number of markers in the list. */
int getNumMarkers() const throw();

/** Returns one of the markers in the list, by its index. */
const Marker* getMarker (int index) const throw();

/** Returns a named marker, or 0 if no such name is found.
Note that name comparisons are case-sensitive.
*/
const Marker* getMarker (const String& name) const throw();

/** Sets the position of a marker.

If the name already exists, then the existing marker is moved; if it doesn't exist, then a
new marker is added.
*/
void setMarker (const String& name, const RelativeCoordinate& position);

/** Deletes the marker at the given list index. */
void removeMarker (int index);

/** Deletes the marker with the given name. */
void removeMarker (const String& name);

/** Returns true if all the markers in these two lists match exactly. */
bool operator== (const MarkerList& other) const throw();
/** Returns true if not all the markers in these two lists match exactly. */
bool operator!= (const MarkerList& other) const throw();

/**
A class for receiving events when changes are made to a MarkerList.

You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener()
method, and it will be called when markers are moved, added, or deleted.

@see MarkerList::addListener, MarkerList::removeListener
*/
class JUCE_API Listener
{
public:
/** Destructor. */
virtual ~Listener() {}

/** Called when something in the given marker list changes. */
virtual void markersChanged (MarkerList* markerList) = 0;

/** Called when the given marker list is being deleted. */
virtual void markerListBeingDeleted (MarkerList* markerList);
};

/** Registers a listener that will be called when the markers are changed. */
void addListener (Listener* listener);

/** Deregisters a previously-registered listener. */
void removeListener (Listener* listener);

/** Synchronously calls markersChanged() on all the registered listeners. */
void markersHaveChanged();

/** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */
class ValueTreeWrapper
{
public:
ValueTreeWrapper (const ValueTree& state);

ValueTree& getState() throw() { return state; }
int getNumMarkers() const;
const ValueTree getMarkerState (int index) const;
const ValueTree getMarkerState (const String& name) const;
bool containsMarker (const ValueTree& state) const;
const MarkerList::Marker getMarker (const ValueTree& state) const;
void setMarker (const MarkerList::Marker& marker, UndoManager* undoManager);
void removeMarker (const ValueTree& state, UndoManager* undoManager);

void applyTo (MarkerList& markerList);
void readFrom (const MarkerList& markerList, UndoManager* undoManager);

static const Identifier markerTag, nameProperty, posProperty;

private:
ValueTree state;
};

private:

OwnedArray<Marker> markers;
ListenerList <Listener> listeners;

JUCE_LEAK_DETECTOR (MarkerList);
};

#endif // __JUCE_MARKERLIST_JUCEHEADER__
/*** End of inlined file: juce_MarkerList.h ***/

/**
Base class for Component::Positioners that are based upon relative coordinates.
*/
class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner,
public ComponentListener,
public MarkerList::Listener,
public Expression::EvaluationContext
{
public:
RelativeCoordinatePositionerBase (Component& component_);
~RelativeCoordinatePositionerBase();

const Expression getSymbolValue (const String& objectName, const String& member) const;

void componentMovedOrResized (Component&, bool, bool);
void componentParentHierarchyChanged (Component&);
void componentBeingDeleted (Component& component);
void markersChanged (MarkerList*);
void markerListBeingDeleted (MarkerList* markerList);

void apply();

bool addCoordinate (const RelativeCoordinate& coord);
bool addPoint (const RelativePoint& point);

protected:
virtual bool registerCoordinates() = 0;
virtual void applyToComponentBounds() = 0;

private:
Array <Component*> sourceComponents;
Array <MarkerList*> sourceMarkerLists;
bool registeredOk;

bool registerListeners (const Expression& e);
bool registerComponent (const String& componentID);
bool registerMarker (const String markerName);
void registerComponentListener (Component* const comp);
void registerMarkerListListener (MarkerList* const list);
void unregisterListeners();
Component* findComponent (const String& componentID) const;
Component* getSourceComponent (const String& objectName) const;
const Expression xToExpression (const Component* const source, const int x) const;
const Expression yToExpression (const Component* const source, const int y) const;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeCoordinatePositionerBase);
};

#endif // __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
/*** End of inlined file: juce_RelativeCoordinatePositioner.h ***/


/*** Start of inlined file: juce_ComponentBuilder.h ***/
#ifndef __JUCE_COMPONENTBUILDER_JUCEHEADER__
#define __JUCE_COMPONENTBUILDER_JUCEHEADER__
@@ -45841,6 +46108,27 @@ protected:

Point<int> originRelativeToComponent;

#ifndef DOXYGEN
/** Internal utility class used by Drawables. */
template <class DrawableType>
class Positioner : public RelativeCoordinatePositionerBase
{
public:
Positioner (DrawableType& component_)
: RelativeCoordinatePositionerBase (component_),
owner (component_)
{}

bool registerCoordinates() { return owner.registerCoordinates (*this); }
void applyToComponentBounds() { owner.recalculateCoordinates (this); }

private:
DrawableType& owner;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner);
};
#endif

private:
void nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform);

@@ -54179,8 +54467,6 @@ public:

protected:

ScopedPointer<TabbedButtonBar> tabs;

/** This creates one of the tab buttons.

If you need to use custom tab components, you can override this method and
@@ -54188,15 +54474,18 @@ protected:
*/
virtual TabBarButton* createTabButton (const String& tabName, int tabIndex);

/** @internal */
ScopedPointer<TabbedButtonBar> tabs;

private:

OwnedArray <WeakReference<Component> > contentComponents;
Array <WeakReference<Component> > contentComponents;
WeakReference<Component> panelComponent;
int tabDepth;
int outlineThickness, edgeIndent;
static const Identifier deleteComponentId;

friend class TabCompButtonBar;
class ButtonBar;
friend class ButtonBar;
void changeCallback (int newCurrentTabIndex, const String& newTabName);

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabbedComponent);
@@ -57419,206 +57708,12 @@ private:
#endif
#ifndef __JUCE_MARKERLIST_JUCEHEADER__

/*** Start of inlined file: juce_MarkerList.h ***/
#ifndef __JUCE_MARKERLIST_JUCEHEADER__
#define __JUCE_MARKERLIST_JUCEHEADER__

/**
Holds a set of named marker points along a one-dimensional axis.

This class is used to store sets of X and Y marker points in components.
@see Component::getMarkers().
*/
class JUCE_API MarkerList
{
public:

/** Creates an empty marker list. */
MarkerList();
/** Creates a copy of another marker list. */
MarkerList (const MarkerList& other);
/** Copies another marker list to this one. */
MarkerList& operator= (const MarkerList& other);
/** Destructor. */
~MarkerList();

/** Represents a marker in a MarkerList. */
class JUCE_API Marker
{
public:
/** Creates a copy of another Marker. */
Marker (const Marker& other);
/** Creates a Marker with a given name and position. */
Marker (const String& name, const RelativeCoordinate& position);

/** The marker's name. */
String name;

/** The marker's position. */
RelativeCoordinate position;

/** Returns true if both the names and positions of these two markers match. */
bool operator== (const Marker&) const throw();
/** Returns true if either the name or position of these two markers differ. */
bool operator!= (const Marker&) const throw();
};

/** Returns the number of markers in the list. */
int getNumMarkers() const throw();

/** Returns one of the markers in the list, by its index. */
const Marker* getMarker (int index) const throw();

/** Returns a named marker, or 0 if no such name is found.
Note that name comparisons are case-sensitive.
*/
const Marker* getMarker (const String& name) const throw();

/** Sets the position of a marker.

If the name already exists, then the existing marker is moved; if it doesn't exist, then a
new marker is added.
*/
void setMarker (const String& name, const RelativeCoordinate& position);

/** Deletes the marker at the given list index. */
void removeMarker (int index);

/** Deletes the marker with the given name. */
void removeMarker (const String& name);

/** Returns true if all the markers in these two lists match exactly. */
bool operator== (const MarkerList& other) const throw();
/** Returns true if not all the markers in these two lists match exactly. */
bool operator!= (const MarkerList& other) const throw();

/**
A class for receiving events when changes are made to a MarkerList.

You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener()
method, and it will be called when markers are moved, added, or deleted.

@see MarkerList::addListener, MarkerList::removeListener
*/
class JUCE_API Listener
{
public:
/** Destructor. */
virtual ~Listener() {}

/** Called when something in the given marker list changes. */
virtual void markersChanged (MarkerList* markerList) = 0;

/** Called when the given marker list is being deleted. */
virtual void markerListBeingDeleted (MarkerList* markerList);
};

/** Registers a listener that will be called when the markers are changed. */
void addListener (Listener* listener);

/** Deregisters a previously-registered listener. */
void removeListener (Listener* listener);

/** Synchronously calls markersChanged() on all the registered listeners. */
void markersHaveChanged();

/** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */
class ValueTreeWrapper
{
public:
ValueTreeWrapper (const ValueTree& state);

ValueTree& getState() throw() { return state; }
int getNumMarkers() const;
const ValueTree getMarkerState (int index) const;
const ValueTree getMarkerState (const String& name) const;
bool containsMarker (const ValueTree& state) const;
const MarkerList::Marker getMarker (const ValueTree& state) const;
void setMarker (const MarkerList::Marker& marker, UndoManager* undoManager);
void removeMarker (const ValueTree& state, UndoManager* undoManager);

void applyTo (MarkerList& markerList);
void readFrom (const MarkerList& markerList, UndoManager* undoManager);

static const Identifier markerTag, nameProperty, posProperty;

private:
ValueTree state;
};

private:

OwnedArray<Marker> markers;
ListenerList <Listener> listeners;

JUCE_LEAK_DETECTOR (MarkerList);
};

#endif // __JUCE_MARKERLIST_JUCEHEADER__
/*** End of inlined file: juce_MarkerList.h ***/


#endif
#ifndef __JUCE_RELATIVECOORDINATE_JUCEHEADER__

#endif
#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__

/*** Start of inlined file: juce_RelativeCoordinatePositioner.h ***/
#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
#define __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__

/**
Base class for Component::Positioners that are based upon relative coordinates.
*/
class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner,
public ComponentListener,
public MarkerList::Listener,
public Expression::EvaluationContext
{
public:
RelativeCoordinatePositionerBase (Component& component_);
~RelativeCoordinatePositionerBase();

const Expression getSymbolValue (const String& objectName, const String& member) const;

void componentMovedOrResized (Component&, bool, bool);
void componentParentHierarchyChanged (Component&);
void componentBeingDeleted (Component& component);
void markersChanged (MarkerList*);
void markerListBeingDeleted (MarkerList* markerList);

void apply();

protected:
bool addCoordinate (const RelativeCoordinate& coord);

virtual bool registerCoordinates() = 0;
virtual void applyToComponentBounds() = 0;

private:
Array <Component*> sourceComponents;
Array <MarkerList*> sourceMarkerLists;
bool registeredOk;

bool registerListeners (const Expression& e);
bool registerComponent (const String& componentID);
bool registerMarker (const String markerName);
void registerComponentListener (Component* const comp);
void registerMarkerListListener (MarkerList* const list);
void unregisterListeners();
Component* findComponent (const String& componentID) const;
Component* getSourceComponent (const String& objectName) const;
const Expression xToExpression (const Component* const source, const int x) const;
const Expression yToExpression (const Component* const source, const int y) const;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeCoordinatePositionerBase);
};

#endif // __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
/*** End of inlined file: juce_RelativeCoordinatePositioner.h ***/


#endif
#ifndef __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__

@@ -57626,78 +57721,6 @@ private:
#ifndef __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__
#define __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__


/*** Start of inlined file: juce_RelativePoint.h ***/
#ifndef __JUCE_RELATIVEPOINT_JUCEHEADER__
#define __JUCE_RELATIVEPOINT_JUCEHEADER__

/**
An X-Y position stored as a pair of RelativeCoordinate values.

@see RelativeCoordinate, RelativeRectangle
*/
class JUCE_API RelativePoint
{
public:
/** Creates a point at the origin. */
RelativePoint();

/** Creates an absolute point, relative to the origin. */
RelativePoint (const Point<float>& absolutePoint);

/** Creates an absolute point, relative to the origin. */
RelativePoint (float absoluteX, float absoluteY);

/** Creates an absolute point from two coordinates. */
RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y);

/** Creates a point from a stringified representation.
The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate
strings is explained in the RelativeCoordinate class.
@see toString
*/
RelativePoint (const String& stringVersion);

bool operator== (const RelativePoint& other) const throw();
bool operator!= (const RelativePoint& other) const throw();

/** Calculates the absolute position of this point.

You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
be needed to calculate the result.
*/
const Point<float> resolve (const Expression::EvaluationContext* evaluationContext) const;

/** Changes the values of this point's coordinates to make it resolve to the specified position.

Calling this will leave any anchor points unchanged, but will set any absolute
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
void moveToAbsolute (const Point<float>& newPos, const Expression::EvaluationContext* evaluationContext);

/** Returns a string which represents this point.
This returns a comma-separated pair of coordinates. For details of the string syntax used by the
coordinates, see the RelativeCoordinate constructor notes.
The string that is returned can be passed to the RelativePoint constructor to recreate the point.
*/
const String toString() const;

/** Renames a symbol if it is used by any of the coordinates.
This calls RelativeCoordinate::renameAnchorIfUsed() on its X and Y coordinates.
*/
void renameSymbolIfUsed (const String& oldName, const String& newName);

/** Returns true if this point depends on any other coordinates for its position. */
bool isDynamic() const;

// The actual X and Y coords...
RelativeCoordinate x, y;
};

#endif // __JUCE_RELATIVEPOINT_JUCEHEADER__
/*** End of inlined file: juce_RelativePoint.h ***/

/**
A parallelogram defined by three RelativePoint positions.

@@ -57718,12 +57741,14 @@ public:
const Rectangle<float> getBounds (Expression::EvaluationContext* coordFinder) const;
void getPath (Path& path, Expression::EvaluationContext* coordFinder) const;
const AffineTransform resetToPerpendicular (Expression::EvaluationContext* coordFinder);
bool isDynamic() const;

bool operator== (const RelativeParallelogram& other) const throw();
bool operator!= (const RelativeParallelogram& other) const throw();

static const Point<float> getInternalCoordForPoint (const Point<float>* parallelogramCorners, Point<float> point) throw();
static const Point<float> getPointForInternalCoord (const Point<float>* parallelogramCorners, const Point<float>& internalPoint) throw();
static const Rectangle<float> getBoundingBox (const Point<float>* parallelogramCorners) throw();

RelativePoint topLeft, topRight, bottomLeft;
};
@@ -61744,8 +61769,8 @@ protected:

@see Drawable
*/
class JUCE_API DrawableComposite : public Drawable,
public Expression::EvaluationContext
class JUCE_API DrawableComposite : public Drawable//,
// public Expression::EvaluationContext
{
public:

@@ -61810,8 +61835,6 @@ public:
/** @internal */
static const Identifier valueTreeType;
/** @internal */
const Expression getSymbolValue (const String& symbol, const String& member) const;
/** @internal */
const Rectangle<float> getDrawableBounds() const;
/** @internal */
void childBoundsChanged (Component*);
@@ -61853,7 +61876,10 @@ private:
MarkerList markersX, markersY;
bool updateBoundsReentrant;

void refreshTransformFromBounds();
friend class Drawable::Positioner<DrawableComposite>;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);

void updateBoundsToFitChildren();

DrawableComposite& operator= (const DrawableComposite&);
@@ -61967,7 +61993,9 @@ private:
Colour overlayColour;
RelativeParallelogram bounds;

void refreshTransformFromBounds();
friend class Drawable::Positioner<DrawableImage>;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);

DrawableImage& operator= (const DrawableImage&);
JUCE_LEAK_DETECTOR (DrawableImage);
@@ -62006,6 +62034,29 @@ public:
/** Destructor. */
~DrawableShape();

/** A FillType wrapper that allows the gradient coordinates to be implemented using RelativePoint.
*/
class RelativeFillType
{
public:
RelativeFillType();
RelativeFillType (const FillType& fill);
RelativeFillType (const RelativeFillType&);
RelativeFillType& operator= (const RelativeFillType&);

bool operator== (const RelativeFillType&) const;
bool operator!= (const RelativeFillType&) const;

bool isDynamic() const;
bool recalculateCoords (Expression::EvaluationContext* context);

void writeTo (ValueTree& v, ComponentBuilder::ImageProvider*, UndoManager*) const;
bool readFrom (const ValueTree& v, ComponentBuilder::ImageProvider*);

FillType fill;
RelativePoint gradientPoint1, gradientPoint2, gradientPoint3;
};

/** Sets a fill type for the path.
This colour is used to fill the path - if you don't want the path to be
filled (e.g. if you're just drawing an outline), set this to a transparent
@@ -62015,20 +62066,34 @@ public:
*/
void setFill (const FillType& newFill);

/** Sets a fill type for the path.
This colour is used to fill the path - if you don't want the path to be
filled (e.g. if you're just drawing an outline), set this to a transparent
colour.

@see setPath, setStrokeFill
*/
void setFill (const RelativeFillType& newFill);

/** Returns the current fill type.
@see setFill
*/
const FillType& getFill() const throw() { return mainFill; }
const RelativeFillType& getFill() const throw() { return mainFill; }

/** Sets the fill type with which the outline will be drawn.
@see setFill
*/
void setStrokeFill (const FillType& newStrokeFill);

/** Sets the fill type with which the outline will be drawn.
@see setFill
*/
void setStrokeFill (const RelativeFillType& newStrokeFill);

/** Returns the current stroke fill.
@see setStrokeFill
*/
const FillType& getStrokeFill() const throw() { return strokeFill; }
const RelativeFillType& getStrokeFill() const throw() { return strokeFill; }

/** Changes the properties of the outline that will be drawn around the path.
If the stroke has 0 thickness, no stroke will be drawn.
@@ -62042,7 +62107,7 @@ public:
void setStrokeThickness (float newThickness);

/** Returns the current outline style. */
const PathStrokeType& getStrokeType() const throw() { return strokeType; }
const PathStrokeType& getStrokeType() const throw() { return strokeType; }

/** @internal */
class FillAndStrokeState : public Drawable::ValueTreeWrapperBase
@@ -62050,32 +62115,13 @@ public:
public:
FillAndStrokeState (const ValueTree& state);

const FillType getMainFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const;
ValueTree getMainFillState();
void setMainFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3,
ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager);

const FillType getStrokeFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const;
ValueTree getStrokeFillState();
void setStrokeFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3,
ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager);
ValueTree getFillState (const Identifier& fillOrStrokeType);
const RelativeFillType getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider*) const;
void setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill,
ComponentBuilder::ImageProvider*, UndoManager*);

const PathStrokeType getStrokeType() const;
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager);

static const FillType readFillType (const ValueTree& v, RelativePoint* gradientPoint1,
RelativePoint* gradientPoint2, RelativePoint* gradientPoint3,
Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider);

static void writeFillType (ValueTree& v, const FillType& fillType,
const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
const RelativePoint* gradientPoint3, ComponentBuilder::ImageProvider* imageProvider,
UndoManager* undoManager);
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager*);

static const Identifier type, colour, colours, fill, stroke, path, jointStyle, capStyle, strokeWidth,
gradientPoint1, gradientPoint2, gradientPoint3, radial, imageId, imageOpacity;
@@ -62094,26 +62140,23 @@ protected:
void pathChanged();
/** Called when the cached stroke should be updated. */
void strokeChanged();

/** Implemented by subclasses to regenerate the path. */
virtual bool rebuildPath (Path& path) const = 0;

/** True if there's a stroke with a non-zero thickness and non-transparent colour. */
bool isStrokeVisible() const throw();

/** Updates the details from a FillAndStrokeState object, returning true if something changed. */
bool refreshFillTypes (const FillAndStrokeState& newState,
Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider);

void refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider*);
/** Writes the stroke and fill details to a FillAndStrokeState object. */
void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const;
void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider*, UndoManager*) const;

PathStrokeType strokeType;
Path path, strokePath;

private:
FillType mainFill, strokeFill;
class RelativePositioner;
RelativeFillType mainFill, strokeFill;
ScopedPointer<RelativeCoordinatePositionerBase> mainFillPositioner, strokeFillPositioner;

void setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill,
ScopedPointer<RelativeCoordinatePositionerBase>& positioner);

DrawableShape& operator= (const DrawableShape&);
};
@@ -62184,24 +62227,24 @@ public:
int getNumControlPoints() const throw();

const RelativePoint getControlPoint (int index) const;
Value getControlPointValue (int index, UndoManager* undoManager) const;
Value getControlPointValue (int index, UndoManager*) const;
const RelativePoint getStartPoint() const;
const RelativePoint getEndPoint() const;
void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager);
float getLength (Expression::EvaluationContext* nameFinder) const;
void setControlPoint (int index, const RelativePoint& point, UndoManager*);
float getLength (Expression::EvaluationContext*) const;

ValueTreeWrapper getParent() const;
Element getPreviousElement() const;

const String getModeOfEndPoint() const;
void setModeOfEndPoint (const String& newMode, UndoManager* undoManager);
void setModeOfEndPoint (const String& newMode, UndoManager*);

void convertToLine (UndoManager* undoManager);
void convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager);
void convertToLine (UndoManager*);
void convertToCubic (Expression::EvaluationContext*, UndoManager*);
void convertToPathBreak (UndoManager* undoManager);
ValueTree insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager);
ValueTree insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext*, UndoManager*);
void removePoint (UndoManager* undoManager);
float findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder) const;
float findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext*) const;

static const Identifier mode, startSubPathElement, closeSubPathElement,
lineToElement, quadraticToElement, cubicToElement;
@@ -62220,15 +62263,13 @@ public:
static const Identifier nonZeroWinding, point1, point2, point3;
};

protected:
bool rebuildPath (Path& path) const;

private:

ScopedPointer<RelativePointPath> relativePath;

class RelativePositioner;
friend class RelativePositioner;
void applyRelativePath (const RelativePointPath& newPath);
const RelativePointPath* getRelativePath() const;
void applyRelativePath (const RelativePointPath&, Expression::EvaluationContext*);

DrawablePath& operator= (const DrawablePath&);
JUCE_LEAK_DETECTOR (DrawablePath);
@@ -62290,24 +62331,24 @@ public:
ValueTreeWrapper (const ValueTree& state);

const RelativeParallelogram getRectangle() const;
void setRectangle (const RelativeParallelogram& newBounds, UndoManager* undoManager);
void setRectangle (const RelativeParallelogram& newBounds, UndoManager*);

void setCornerSize (const RelativePoint& cornerSize, UndoManager* undoManager);
void setCornerSize (const RelativePoint& cornerSize, UndoManager*);
const RelativePoint getCornerSize() const;
Value getCornerSizeValue (UndoManager* undoManager) const;
Value getCornerSizeValue (UndoManager*) const;

static const Identifier topLeft, topRight, bottomLeft, cornerSize;
};

protected:
/** @internal */
bool rebuildPath (Path& path) const;

private:
friend class Drawable::Positioner<DrawableRectangle>;

RelativeParallelogram bounds;
RelativePoint cornerSize;

const AffineTransform calculateTransform() const;
void rebuildPath();
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);

DrawableRectangle& operator= (const DrawableRectangle&);
JUCE_LEAK_DETECTOR (DrawableRectangle);
@@ -62425,12 +62466,17 @@ private:

RelativeParallelogram bounds;
RelativePoint fontSizeControlPoint;
Font font;
Point<float> resolvedPoints[3];
Font font, scaledFont;
String text;
Colour colour;
Justification justification;

friend class Drawable::Positioner<DrawableText>;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);
void refreshBounds();
const AffineTransform getArrangementAndTransform (GlyphArrangement& glyphs) const;

DrawableText& operator= (const DrawableText&);
JUCE_LEAK_DETECTOR (DrawableText);


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

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
#define JUCE_BUILDNUMBER 6
#define JUCE_BUILDNUMBER 7
/** Current Juce version number.


+ 4
- 4
src/gui/components/layout/juce_ComponentBuilder.cpp View File

@@ -86,8 +86,9 @@ namespace ComponentBuilderHelpers
if (topLevelComp != 0)
{
ComponentBuilder::TypeHandler* const type = builder.getHandlerForState (state);
const String uid (getStateId (state));
if (type == 0)
if (type == 0 || uid.isEmpty())
{
// ..handle the case where a child of the actual state node has changed.
if (state.getParent().isValid())
@@ -95,21 +96,20 @@ namespace ComponentBuilderHelpers
}
else
{
Component* const changedComp = findComponentWithID (topLevelComp, getStateId (state));
Component* const changedComp = findComponentWithID (topLevelComp, uid);
if (changedComp != 0)
type->updateComponentFromState (changedComp, state);
}
}
}
}
//=============================================================================
const Identifier ComponentBuilder::idProperty ("id");
ComponentBuilder::ComponentBuilder (const ValueTree& state_)
: state (state_)
: state (state_), imageProvider (0)
{
state.addListener (this);
}


+ 63
- 93
src/gui/components/layout/juce_TabbedComponent.cpp View File

@@ -32,17 +32,39 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
class TabCompButtonBar : public TabbedButtonBar
namespace TabbedComponentHelpers
{
public:
TabCompButtonBar (TabbedComponent& owner_,
const TabbedButtonBar::Orientation orientation_)
: TabbedButtonBar (orientation_),
owner (owner_)
const Identifier deleteComponentId ("deleteByTabComp_");
void deleteIfNecessary (Component* const comp)
{
if (comp != 0 && (bool) comp->getProperties() [deleteComponentId])
delete comp;
}
~TabCompButtonBar()
const Rectangle<int> getTabArea (Rectangle<int>& content, BorderSize& outline,
const TabbedButtonBar::Orientation orientation, const int tabDepth)
{
switch (orientation)
{
case TabbedButtonBar::TabsAtTop: outline.setTop (0); return content.removeFromTop (tabDepth);
case TabbedButtonBar::TabsAtBottom: outline.setBottom (0); return content.removeFromBottom (tabDepth);
case TabbedButtonBar::TabsAtLeft: outline.setLeft (0); return content.removeFromLeft (tabDepth);
case TabbedButtonBar::TabsAtRight: outline.setRight (0); return content.removeFromRight (tabDepth);
default: jassertfalse; break;
}
return Rectangle<int>();
}
}
//==============================================================================
class TabbedComponent::ButtonBar : public TabbedButtonBar
{
public:
ButtonBar (TabbedComponent& owner_, const TabbedButtonBar::Orientation orientation_)
: TabbedButtonBar (orientation_),
owner (owner_)
{
}
@@ -69,16 +91,17 @@ public:
private:
TabbedComponent& owner;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabCompButtonBar);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonBar);
};
//==============================================================================
TabbedComponent::TabbedComponent (const TabbedButtonBar::Orientation orientation)
: tabDepth (30),
outlineThickness (1),
edgeIndent (0)
{
addAndMakeVisible (tabs = new TabCompButtonBar (*this, orientation));
addAndMakeVisible (tabs = new ButtonBar (*this, orientation));
}
TabbedComponent::~TabbedComponent()
@@ -114,8 +137,6 @@ TabBarButton* TabbedComponent::createTabButton (const String& tabName, const int
}
//==============================================================================
const Identifier TabbedComponent::deleteComponentId ("deleteByTabComp_");
void TabbedComponent::clearTabs()
{
if (panelComponent != 0)
@@ -128,12 +149,7 @@ void TabbedComponent::clearTabs()
tabs->clearTabs();
for (int i = contentComponents.size(); --i >= 0;)
{
WeakReference<Component>& c = *contentComponents.getUnchecked (i);
if (c != 0 && (bool) c->getProperties() [deleteComponentId])
delete c.get();
}
TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (i));
contentComponents.clear();
}
@@ -144,10 +160,10 @@ void TabbedComponent::addTab (const String& tabName,
const bool deleteComponentWhenNotNeeded,
const int insertIndex)
{
contentComponents.insert (insertIndex, new WeakReference<Component> (contentComponent));
contentComponents.insert (insertIndex, WeakReference<Component> (contentComponent));
if (contentComponent != 0)
contentComponent->getProperties().set (deleteComponentId, deleteComponentWhenNotNeeded);
if (deleteComponentWhenNotNeeded && contentComponent != 0)
contentComponent->getProperties().set (TabbedComponentHelpers::deleteComponentId, true);
tabs->addTab (tabName, tabBackgroundColour, insertIndex);
}
@@ -159,13 +175,9 @@ void TabbedComponent::setTabName (const int tabIndex, const String& newName)
void TabbedComponent::removeTab (const int tabIndex)
{
WeakReference<Component>* c = contentComponents [tabIndex];
if (c != 0)
if (isPositiveAndBelow (tabIndex, contentComponents.size()))
{
if ((bool) ((*c)->getProperties() [deleteComponentId]))
delete c->get();
TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (tabIndex));
contentComponents.remove (tabIndex);
tabs->removeTab (tabIndex);
}
@@ -183,8 +195,7 @@ const StringArray TabbedComponent::getTabNames() const
Component* TabbedComponent::getTabContentComponent (const int tabIndex) const throw()
{
WeakReference<Component>* const c = contentComponents [tabIndex];
return c != 0 ? *c : 0;
return contentComponents [tabIndex];
}
const Colour TabbedComponent::getTabBackgroundColour (const int tabIndex) const throw()
@@ -215,99 +226,62 @@ const String TabbedComponent::getCurrentTabName() const
return tabs->getCurrentTabName();
}
void TabbedComponent::setOutline (int thickness)
void TabbedComponent::setOutline (const int thickness)
{
outlineThickness = thickness;
resized();
repaint();
}
void TabbedComponent::setIndent (const int indentThickness)
{
edgeIndent = indentThickness;
resized();
repaint();
}
void TabbedComponent::paint (Graphics& g)
{
g.fillAll (findColour (backgroundColourId));
const TabbedButtonBar::Orientation o = getOrientation();
int x = 0;
int y = 0;
int r = getWidth();
int b = getHeight();
Rectangle<int> content (getLocalBounds());
BorderSize outline (outlineThickness);
TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth);
if (o == TabbedButtonBar::TabsAtTop)
y += tabDepth;
else if (o == TabbedButtonBar::TabsAtBottom)
b -= tabDepth;
else if (o == TabbedButtonBar::TabsAtLeft)
x += tabDepth;
else if (o == TabbedButtonBar::TabsAtRight)
r -= tabDepth;
g.reduceClipRegion (x, y, r - x, b - y);
g.reduceClipRegion (content);
g.fillAll (tabs->getTabBackgroundColour (getCurrentTabIndex()));
if (outlineThickness > 0)
{
if (o == TabbedButtonBar::TabsAtTop)
--y;
else if (o == TabbedButtonBar::TabsAtBottom)
++b;
else if (o == TabbedButtonBar::TabsAtLeft)
--x;
else if (o == TabbedButtonBar::TabsAtRight)
++r;
g.setColour (findColour (outlineColourId));
g.drawRect (x, y, r - x, b - y, outlineThickness);
RectangleList rl (content);
rl.subtract (outline.subtractedFrom (content));
g.reduceClipRegion (rl);
g.fillAll (findColour (outlineColourId));
}
}
void TabbedComponent::resized()
{
const TabbedButtonBar::Orientation o = getOrientation();
const int indent = edgeIndent + outlineThickness;
BorderSize indents (indent);
Rectangle<int> content (getLocalBounds());
BorderSize outline (outlineThickness);
if (o == TabbedButtonBar::TabsAtTop)
{
tabs->setBounds (0, 0, getWidth(), tabDepth);
indents.setTop (tabDepth + edgeIndent);
}
else if (o == TabbedButtonBar::TabsAtBottom)
{
tabs->setBounds (0, getHeight() - tabDepth, getWidth(), tabDepth);
indents.setBottom (tabDepth + edgeIndent);
}
else if (o == TabbedButtonBar::TabsAtLeft)
{
tabs->setBounds (0, 0, tabDepth, getHeight());
indents.setLeft (tabDepth + edgeIndent);
}
else if (o == TabbedButtonBar::TabsAtRight)
{
tabs->setBounds (getWidth() - tabDepth, 0, tabDepth, getHeight());
indents.setRight (tabDepth + edgeIndent);
}
const Rectangle<int> bounds (indents.subtractedFrom (getLocalBounds()));
tabs->setBounds (TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth));
content = BorderSize (edgeIndent).subtractedFrom (outline.subtractedFrom (content));
for (int i = contentComponents.size(); --i >= 0;)
if (*contentComponents.getUnchecked (i) != 0)
(*contentComponents.getUnchecked (i))->setBounds (bounds);
if (contentComponents.getReference (i) != 0)
contentComponents.getReference (i)->setBounds (content);
}
void TabbedComponent::lookAndFeelChanged()
{
for (int i = contentComponents.size(); --i >= 0;)
if (*contentComponents.getUnchecked (i) != 0)
(*contentComponents.getUnchecked (i))->lookAndFeelChanged();
if (contentComponents.getReference (i) != 0)
contentComponents.getReference (i)->lookAndFeelChanged();
}
void TabbedComponent::changeCallback (const int newCurrentTabIndex,
const String& newTabName)
void TabbedComponent::changeCallback (const int newCurrentTabIndex, const String& newTabName)
{
if (panelComponent != 0)
{
@@ -337,12 +311,8 @@ void TabbedComponent::changeCallback (const int newCurrentTabIndex,
currentTabChanged (newCurrentTabIndex, newTabName);
}
void TabbedComponent::currentTabChanged (const int, const String&)
{
}
void TabbedComponent::currentTabChanged (const int, const String&) {}
void TabbedComponent::popupMenuClickOnTab (const int, const String&) {}
void TabbedComponent::popupMenuClickOnTab (const int, const String&)
{
}
END_JUCE_NAMESPACE

+ 6
- 5
src/gui/components/layout/juce_TabbedComponent.h View File

@@ -214,8 +214,6 @@ public:
protected:
//==============================================================================
ScopedPointer<TabbedButtonBar> tabs;
/** This creates one of the tab buttons.
If you need to use custom tab components, you can override this method and
@@ -223,15 +221,18 @@ protected:
*/
virtual TabBarButton* createTabButton (const String& tabName, int tabIndex);
/** @internal */
ScopedPointer<TabbedButtonBar> tabs;
private:
//==============================================================================
OwnedArray <WeakReference<Component> > contentComponents;
Array <WeakReference<Component> > contentComponents;
WeakReference<Component> panelComponent;
int tabDepth;
int outlineThickness, edgeIndent;
static const Identifier deleteComponentId;
friend class TabCompButtonBar;
class ButtonBar;
friend class ButtonBar;
void changeCallback (int newCurrentTabIndex, const String& newTabName);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabbedComponent);


+ 6
- 0
src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp View File

@@ -121,6 +121,12 @@ bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate&
return registerListeners (coord.getExpression());
}
bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
{
const bool ok = addCoordinate (point.x);
return addCoordinate (point.y) && ok;
}
bool RelativeCoordinatePositionerBase::registerListeners (const Expression& e)
{
bool ok = true;


+ 3
- 2
src/gui/components/positioning/juce_RelativeCoordinatePositioner.h View File

@@ -26,7 +26,7 @@
#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
#define __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
#include "juce_RelativeCoordinate.h"
#include "juce_RelativePoint.h"
#include "juce_MarkerList.h"
#include "../juce_Component.h"
@@ -54,9 +54,10 @@ public:
void apply();
protected:
bool addCoordinate (const RelativeCoordinate& coord);
bool addPoint (const RelativePoint& point);
protected:
virtual bool registerCoordinates() = 0;
virtual void applyToComponentBounds() = 0;


+ 12
- 0
src/gui/components/positioning/juce_RelativeParallelogram.cpp View File

@@ -103,6 +103,11 @@ const AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::E
corners[2].getX(), corners[2].getY(), newBottomLeft.getX(), newBottomLeft.getY());
}
bool RelativeParallelogram::isDynamic() const
{
return topLeft.isDynamic() || topRight.isDynamic() || bottomLeft.isDynamic();
}
bool RelativeParallelogram::operator== (const RelativeParallelogram& other) const throw()
{
return topLeft == other.topLeft && topRight == other.topRight && bottomLeft == other.bottomLeft;
@@ -130,4 +135,11 @@ const Point<float> RelativeParallelogram::getPointForInternalCoord (const Point<
+ Line<float> (Point<float>(), corners[2] - corners[0]).getPointAlongLine (point.getY());
}
const Rectangle<float> RelativeParallelogram::getBoundingBox (const Point<float>* const p) throw()
{
const Point<float> points[] = { p[0], p[1], p[2], p[1] + (p[2] - p[0]) };
return Rectangle<float>::findAreaContainingPoints (points, 4);
}
END_JUCE_NAMESPACE

+ 2
- 0
src/gui/components/positioning/juce_RelativeParallelogram.h View File

@@ -51,12 +51,14 @@ public:
const Rectangle<float> getBounds (Expression::EvaluationContext* coordFinder) const;
void getPath (Path& path, Expression::EvaluationContext* coordFinder) const;
const AffineTransform resetToPerpendicular (Expression::EvaluationContext* coordFinder);
bool isDynamic() const;
bool operator== (const RelativeParallelogram& other) const throw();
bool operator!= (const RelativeParallelogram& other) const throw();
static const Point<float> getInternalCoordForPoint (const Point<float>* parallelogramCorners, Point<float> point) throw();
static const Point<float> getPointForInternalCoord (const Point<float>* parallelogramCorners, const Point<float>& internalPoint) throw();
static const Rectangle<float> getBoundingBox (const Point<float>* parallelogramCorners) throw();
//==============================================================================
RelativePoint topLeft, topRight, bottomLeft;


+ 22
- 0
src/gui/graphics/drawables/juce_Drawable.h View File

@@ -28,6 +28,7 @@
#include "../../components/juce_Component.h"
#include "../../components/positioning/juce_RelativeCoordinate.h"
#include "../../components/positioning/juce_RelativeCoordinatePositioner.h"
#include "../../../containers/juce_ValueTree.h"
#include "../../components/layout/juce_ComponentBuilder.h"
class DrawableComposite;
@@ -215,6 +216,27 @@ protected:
Point<int> originRelativeToComponent;
#ifndef DOXYGEN
/** Internal utility class used by Drawables. */
template <class DrawableType>
class Positioner : public RelativeCoordinatePositionerBase
{
public:
Positioner (DrawableType& component_)
: RelativeCoordinatePositionerBase (component_),
owner (component_)
{}
bool registerCoordinates() { return owner.registerCoordinates (*this); }
void applyToComponentBounds() { owner.recalculateCoordinates (this); }
private:
DrawableType& owner;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner);
};
#endif
private:
void nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform);


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

@@ -61,6 +61,11 @@ DrawableComposite::~DrawableComposite()
deleteAllChildren();
}
Drawable* DrawableComposite::createCopy() const
{
return new DrawableComposite (*this);
}
//==============================================================================
const Rectangle<float> DrawableComposite::getDrawableBounds() const
{
@@ -98,13 +103,26 @@ void DrawableComposite::setContentArea (const RelativeRectangle& newArea)
markersX.setMarker (contentRightMarkerName, newArea.right);
markersY.setMarker (contentTopMarkerName, newArea.top);
markersY.setMarker (contentBottomMarkerName, newArea.bottom);
refreshTransformFromBounds();
}
void DrawableComposite::setBoundingBox (const RelativeParallelogram& newBoundingBox)
void DrawableComposite::setBoundingBox (const RelativeParallelogram& newBounds)
{
bounds = newBoundingBox;
refreshTransformFromBounds();
if (bounds != newBounds)
{
bounds = newBounds;
if (bounds.isDynamic())
{
Drawable::Positioner<DrawableComposite>* const p = new Drawable::Positioner<DrawableComposite> (*this);
setPositioner (p);
p->apply();
}
else
{
setPositioner (0);
recalculateCoordinates (0);
}
}
}
void DrawableComposite::resetBoundingBoxToContentArea()
@@ -127,12 +145,19 @@ void DrawableComposite::resetContentAreaAndBoundingBoxToFitChildren()
resetBoundingBoxToContentArea();
}
void DrawableComposite::refreshTransformFromBounds()
bool DrawableComposite::registerCoordinates (RelativeCoordinatePositionerBase& positioner)
{
bool ok = positioner.addPoint (bounds.topLeft);
ok = positioner.addPoint (bounds.topRight) && ok;
return positioner.addPoint (bounds.bottomLeft) && ok;
}
void DrawableComposite::recalculateCoordinates (Expression::EvaluationContext* context)
{
Point<float> resolved[3];
bounds.resolveThreePoints (resolved, getParent());
bounds.resolveThreePoints (resolved, context);
const Rectangle<float> content (getContentArea().resolve (getParent()));
const Rectangle<float> content (getContentArea().resolve (context));
AffineTransform t (AffineTransform::fromTargetPoints (content.getX(), content.getY(), resolved[0].getX(), resolved[0].getY(),
content.getRight(), content.getY(), resolved[1].getX(), resolved[1].getY(),
@@ -212,27 +237,6 @@ const char* const DrawableComposite::contentRightMarkerName = "right";
const char* const DrawableComposite::contentTopMarkerName = "top";
const char* const DrawableComposite::contentBottomMarkerName = "bottom";
//==============================================================================
const Expression DrawableComposite::getSymbolValue (const String& symbol, const String& member) const
{
jassert (member.isEmpty()) // the only symbols available in a Drawable are markers.
const MarkerList::Marker* m = markersX.getMarker (symbol);
if (m == 0)
m = markersY.getMarker (symbol);
if (m != 0)
return m->position.getExpression();
throw Expression::EvaluationError (symbol, member);
}
Drawable* DrawableComposite::createCopy() const
{
return new DrawableComposite (*this);
}
//==============================================================================
const Identifier DrawableComposite::valueTreeType ("Group");
@@ -321,16 +325,12 @@ void DrawableComposite::refreshFromValueTree (const ValueTree& tree, ComponentBu
const ValueTreeWrapper wrapper (tree);
setComponentID (wrapper.getID());
const RelativeParallelogram newBounds (wrapper.getBoundingBox());
if (bounds != newBounds)
bounds = newBounds;
wrapper.getMarkerList (true).applyTo (markersX);
wrapper.getMarkerList (false).applyTo (markersY);
builder.updateChildComponents (*this, wrapper.getChildList());
setBoundingBox (wrapper.getBoundingBox());
refreshTransformFromBounds();
builder.updateChildComponents (*this, wrapper.getChildList());
}
const ValueTree DrawableComposite::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const


+ 6
- 5
src/gui/graphics/drawables/juce_DrawableComposite.h View File

@@ -38,8 +38,8 @@
@see Drawable
*/
class JUCE_API DrawableComposite : public Drawable,
public Expression::EvaluationContext
class JUCE_API DrawableComposite : public Drawable//,
// public Expression::EvaluationContext
{
public:
//==============================================================================
@@ -107,8 +107,6 @@ public:
/** @internal */
static const Identifier valueTreeType;
/** @internal */
const Expression getSymbolValue (const String& symbol, const String& member) const;
/** @internal */
const Rectangle<float> getDrawableBounds() const;
/** @internal */
void childBoundsChanged (Component*);
@@ -151,7 +149,10 @@ private:
MarkerList markersX, markersY;
bool updateBoundsReentrant;
void refreshTransformFromBounds();
friend class Drawable::Positioner<DrawableComposite>;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);
void updateBoundsToFitChildren();
DrawableComposite& operator= (const DrawableComposite&);


+ 37
- 18
src/gui/graphics/drawables/juce_DrawableImage.cpp View File

@@ -58,17 +58,14 @@ DrawableImage::~DrawableImage()
void DrawableImage::setImage (const Image& imageToUse)
{
image = imageToUse;
setBounds (imageToUse.getBounds());
if (image.isValid())
{
bounds.topLeft = RelativePoint (Point<float> (0.0f, 0.0f));
bounds.topRight = RelativePoint (Point<float> ((float) image.getWidth(), 0.0f));
bounds.bottomLeft = RelativePoint (Point<float> (0.0f, (float) image.getHeight()));
}
bounds.topLeft = RelativePoint (Point<float> (0.0f, 0.0f));
bounds.topRight = RelativePoint (Point<float> ((float) image.getWidth(), 0.0f));
bounds.bottomLeft = RelativePoint (Point<float> (0.0f, (float) image.getHeight()));
recalculateCoordinates (0);
refreshTransformFromBounds();
repaint();
}
void DrawableImage::setOpacity (const float newOpacity)
@@ -83,17 +80,38 @@ void DrawableImage::setOverlayColour (const Colour& newOverlayColour)
void DrawableImage::setBoundingBox (const RelativeParallelogram& newBounds)
{
bounds = newBounds;
refreshTransformFromBounds();
if (bounds != newBounds)
{
bounds = newBounds;
if (bounds.isDynamic())
{
Drawable::Positioner<DrawableImage>* const p = new Drawable::Positioner<DrawableImage> (*this);
setPositioner (p);
p->apply();
}
else
{
setPositioner (0);
recalculateCoordinates (0);
}
}
}
//==============================================================================
void DrawableImage::refreshTransformFromBounds()
bool DrawableImage::registerCoordinates (RelativeCoordinatePositionerBase& positioner)
{
bool ok = positioner.addPoint (bounds.topLeft);
ok = positioner.addPoint (bounds.topRight) && ok;
return positioner.addPoint (bounds.bottomLeft) && ok;
}
void DrawableImage::recalculateCoordinates (Expression::EvaluationContext* context)
{
if (! image.isNull())
if (image.isValid())
{
Point<float> resolved[3];
bounds.resolveThreePoints (resolved, getParent());
bounds.resolveThreePoints (resolved, context);
const Point<float> tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth());
const Point<float> bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight());
@@ -102,8 +120,10 @@ void DrawableImage::refreshTransformFromBounds()
tr.getX(), tr.getY(),
bl.getX(), bl.getY()));
if (! t.isSingularity())
setTransform (t);
if (t.isSingularity())
t = AffineTransform::identity;
setTransform (t);
}
}
@@ -251,12 +271,11 @@ void DrawableImage::refreshFromValueTree (const ValueTree& tree, ComponentBuilde
repaint();
opacity = newOpacity;
overlayColour = newOverlayColour;
bounds = newBounds;
if (image != newImage)
setImage (newImage);
else
refreshTransformFromBounds();
setBoundingBox (newBounds);
}
}


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

@@ -131,7 +131,9 @@ private:
Colour overlayColour;
RelativeParallelogram bounds;
void refreshTransformFromBounds();
friend class Drawable::Positioner<DrawableImage>;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);
DrawableImage& operator= (const DrawableImage&);
JUCE_LEAK_DETECTOR (DrawableImage);


+ 39
- 67
src/gui/graphics/drawables/juce_DrawablePath.cpp View File

@@ -40,10 +40,8 @@ DrawablePath::DrawablePath()
DrawablePath::DrawablePath (const DrawablePath& other)
: DrawableShape (other)
{
const RelativePointPath* const relativePath = other.getRelativePath();
if (relativePath != 0)
setPath (*relativePath);
if (other.relativePath != 0)
setPath (*other.relativePath);
else
setPath (other.path);
}
@@ -74,15 +72,10 @@ const Path& DrawablePath::getStrokePath() const
return strokePath;
}
bool DrawablePath::rebuildPath (Path&) const
{
return false;
}
void DrawablePath::applyRelativePath (const RelativePointPath& relativePath)
void DrawablePath::applyRelativePath (const RelativePointPath& newRelativePath, Expression::EvaluationContext* context)
{
Path newPath;
relativePath.createPath (newPath, 0);
newRelativePath.createPath (newPath, context);
if (path != newPath)
{
@@ -95,9 +88,8 @@ void DrawablePath::applyRelativePath (const RelativePointPath& relativePath)
class DrawablePath::RelativePositioner : public RelativeCoordinatePositionerBase
{
public:
RelativePositioner (DrawablePath& component_, const RelativePointPath& path_)
RelativePositioner (DrawablePath& component_)
: RelativeCoordinatePositionerBase (component_),
path (path_),
owner (component_)
{
}
@@ -106,6 +98,9 @@ public:
{
bool ok = true;
jassert (owner.relativePath != 0);
const RelativePointPath& path = *owner.relativePath;
for (int i = 0; i < path.elements.size(); ++i)
{
RelativePointPath::ElementBase* const e = path.elements.getUnchecked(i);
@@ -114,10 +109,7 @@ public:
RelativePoint* const points = e->getControlPoints (numPoints);
for (int j = numPoints; --j >= 0;)
{
ok = addCoordinate (points[j].x) && ok;
ok = addCoordinate (points[j].y) && ok;
}
ok = addPoint (points[j]) && ok;
}
return ok;
@@ -125,39 +117,33 @@ public:
void applyToComponentBounds()
{
owner.applyRelativePath (path);
jassert (owner.relativePath != 0);
owner.applyRelativePath (*owner.relativePath, this);
}
const RelativePointPath path;
private:
DrawablePath& owner;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativePositioner);
};
const RelativePointPath* DrawablePath::getRelativePath() const
{
RelativePositioner* current = dynamic_cast <RelativePositioner*> (getPositioner());
return current != 0 ? &(current->path) : 0;
}
void DrawablePath::setPath (const RelativePointPath& newRelativePath)
{
if (newRelativePath.containsAnyDynamicPoints())
{
const RelativePointPath* current = getRelativePath();
if (current == 0 || newRelativePath != *current)
if (relativePath == 0 || newRelativePath != *relativePath)
{
RelativePositioner* const p = new RelativePositioner (*this, newRelativePath);
relativePath = new RelativePointPath (newRelativePath);
RelativePositioner* const p = new RelativePositioner (*this);
setPositioner (p);
p->apply();
}
}
else
{
applyRelativePath (newRelativePath);
relativePath = 0;
applyRelativePath (newRelativePath, 0);
}
}
@@ -313,26 +299,26 @@ const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const
return RelativePoint();
}
float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::EvaluationContext* nameFinder) const
float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::EvaluationContext* context) const
{
const Identifier i (state.getType());
if (i == lineToElement || i == closeSubPathElement)
return getEndPoint().resolve (nameFinder).getDistanceFrom (getStartPoint().resolve (nameFinder));
return getEndPoint().resolve (context).getDistanceFrom (getStartPoint().resolve (context));
if (i == cubicToElement)
{
Path p;
p.startNewSubPath (getStartPoint().resolve (nameFinder));
p.cubicTo (getControlPoint (0).resolve (nameFinder), getControlPoint (1).resolve (nameFinder), getControlPoint (2).resolve (nameFinder));
p.startNewSubPath (getStartPoint().resolve (context));
p.cubicTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context), getControlPoint (2).resolve (context));
return p.getLength();
}
if (i == quadraticToElement)
{
Path p;
p.startNewSubPath (getStartPoint().resolve (nameFinder));
p.quadraticTo (getControlPoint (0).resolve (nameFinder), getControlPoint (1).resolve (nameFinder));
p.startNewSubPath (getStartPoint().resolve (context));
p.quadraticTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context));
return p.getLength();
}
@@ -364,7 +350,7 @@ void DrawablePath::ValueTreeWrapper::Element::convertToLine (UndoManager* undoMa
}
}
void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager)
void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::EvaluationContext* context, UndoManager* undoManager)
{
const Identifier i (state.getType());
@@ -375,8 +361,8 @@ void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::Evalua
const RelativePoint start (getStartPoint());
const RelativePoint end (getEndPoint());
const Point<float> startResolved (start.resolve (nameFinder));
const Point<float> endResolved (end.resolve (nameFinder));
const Point<float> startResolved (start.resolve (context));
const Point<float> endResolved (end.resolve (context));
e.setControlPoint (0, startResolved + (endResolved - startResolved) * 0.3f, undoManager);
e.setControlPoint (1, startResolved + (endResolved - startResolved) * 0.7f, undoManager);
e.setControlPoint (2, end, undoManager);
@@ -421,7 +407,7 @@ namespace DrawablePathHelpers
}
}
float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder) const
float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext* context) const
{
using namespace DrawablePathHelpers;
const Identifier type (state.getType());
@@ -431,7 +417,7 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po
{
RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint());
const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) };
const Point<float> points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) };
float bestDistance = std::numeric_limits<float>::max();
@@ -451,7 +437,7 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po
else if (type == quadraticToElement)
{
RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint());
const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) };
const Point<float> points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context) };
float bestDistance = std::numeric_limits<float>::max();
@@ -471,24 +457,24 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po
else if (type == lineToElement)
{
RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint());
const Line<float> line (rp1.resolve (nameFinder), rp2.resolve (nameFinder));
const Line<float> line (rp1.resolve (context), rp2.resolve (context));
bestProp = line.findNearestProportionalPositionTo (targetPoint);
}
return bestProp;
}
ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager)
ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext* context, UndoManager* undoManager)
{
ValueTree newTree;
const Identifier type (state.getType());
if (type == cubicToElement)
{
float bestProp = findProportionAlongLine (targetPoint, nameFinder);
float bestProp = findProportionAlongLine (targetPoint, context);
RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint());
const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) };
const Point<float> points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) };
const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * bestProp),
@@ -513,10 +499,10 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa
}
else if (type == quadraticToElement)
{
float bestProp = findProportionAlongLine (targetPoint, nameFinder);
float bestProp = findProportionAlongLine (targetPoint, context);
RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint());
const Point<float> points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) };
const Point<float> points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context) };
const Point<float> mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * bestProp);
@@ -536,7 +522,7 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<floa
else if (type == lineToElement)
{
RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint());
const Line<float> line (rp1.resolve (nameFinder), rp2.resolve (nameFinder));
const Line<float> line (rp1.resolve (context), rp2.resolve (context));
const Point<float> newPoint (line.findNearestPointTo (targetPoint));
setControlPoint (0, newPoint, undoManager);
@@ -564,15 +550,8 @@ void DrawablePath::refreshFromValueTree (const ValueTree& tree, ComponentBuilder
ValueTreeWrapper v (tree);
setComponentID (v.getID());
if (refreshFillTypes (v, getParent(), builder.getImageProvider()))
repaint();
const PathStrokeType newStroke (v.getStrokeType());
if (strokeType != newStroke)
{
strokeType = newStroke;
strokeChanged();
}
refreshFillTypes (v, builder.getImageProvider());
setStrokeType (v.getStrokeType());
RelativePointPath newRelativePath;
v.writeTo (newRelativePath);
@@ -587,17 +566,10 @@ const ValueTree DrawablePath::createValueTree (ComponentBuilder::ImageProvider*
v.setID (getComponentID());
writeTo (v, imageProvider, 0);
const RelativePointPath* const relativePath = getRelativePath();
if (relativePath != 0)
{
v.readFrom (*relativePath, 0);
}
else
{
RelativePointPath rp (path);
v.readFrom (rp, 0);
}
v.readFrom (RelativePointPath (path), 0);
return tree;
}


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

@@ -97,24 +97,24 @@ public:
int getNumControlPoints() const throw();
const RelativePoint getControlPoint (int index) const;
Value getControlPointValue (int index, UndoManager* undoManager) const;
Value getControlPointValue (int index, UndoManager*) const;
const RelativePoint getStartPoint() const;
const RelativePoint getEndPoint() const;
void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager);
float getLength (Expression::EvaluationContext* nameFinder) const;
void setControlPoint (int index, const RelativePoint& point, UndoManager*);
float getLength (Expression::EvaluationContext*) const;
ValueTreeWrapper getParent() const;
Element getPreviousElement() const;
const String getModeOfEndPoint() const;
void setModeOfEndPoint (const String& newMode, UndoManager* undoManager);
void setModeOfEndPoint (const String& newMode, UndoManager*);
void convertToLine (UndoManager* undoManager);
void convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager);
void convertToLine (UndoManager*);
void convertToCubic (Expression::EvaluationContext*, UndoManager*);
void convertToPathBreak (UndoManager* undoManager);
ValueTree insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager);
ValueTree insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext*, UndoManager*);
void removePoint (UndoManager* undoManager);
float findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder) const;
float findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext*) const;
static const Identifier mode, startSubPathElement, closeSubPathElement,
lineToElement, quadraticToElement, cubicToElement;
@@ -133,15 +133,13 @@ public:
static const Identifier nonZeroWinding, point1, point2, point3;
};
protected:
bool rebuildPath (Path& path) const;
private:
//==============================================================================
ScopedPointer<RelativePointPath> relativePath;
class RelativePositioner;
friend class RelativePositioner;
void applyRelativePath (const RelativePointPath& newPath);
const RelativePointPath* getRelativePath() const;
void applyRelativePath (const RelativePointPath&, Expression::EvaluationContext*);
DrawablePath& operator= (const DrawablePath&);
JUCE_LEAK_DETECTOR (DrawablePath);


+ 58
- 45
src/gui/graphics/drawables/juce_DrawableRectangle.cpp View File

@@ -29,6 +29,8 @@ BEGIN_JUCE_NAMESPACE
#include "juce_DrawableRectangle.h"
#include "juce_DrawableComposite.h"
#include "../../components/positioning/juce_RelativeCoordinatePositioner.h"
//==============================================================================
DrawableRectangle::DrawableRectangle()
@@ -36,7 +38,9 @@ DrawableRectangle::DrawableRectangle()
}
DrawableRectangle::DrawableRectangle (const DrawableRectangle& other)
: DrawableShape (other)
: DrawableShape (other),
bounds (other.bounds),
cornerSize (other.cornerSize)
{
}
@@ -52,51 +56,72 @@ Drawable* DrawableRectangle::createCopy() const
//==============================================================================
void DrawableRectangle::setRectangle (const RelativeParallelogram& newBounds)
{
bounds = newBounds;
pathChanged();
strokeChanged();
if (bounds != newBounds)
{
bounds = newBounds;
rebuildPath();
}
}
void DrawableRectangle::setCornerSize (const RelativePoint& newSize)
{
cornerSize = newSize;
pathChanged();
strokeChanged();
if (cornerSize != newSize)
{
cornerSize = newSize;
rebuildPath();
}
}
//==============================================================================
bool DrawableRectangle::rebuildPath (Path& path) const
void DrawableRectangle::rebuildPath()
{
if (bounds.isDynamic() || cornerSize.isDynamic())
{
Drawable::Positioner<DrawableRectangle>* const p = new Drawable::Positioner<DrawableRectangle> (*this);
setPositioner (p);
p->apply();
}
else
{
setPositioner (0);
recalculateCoordinates (0);
}
}
bool DrawableRectangle::registerCoordinates (RelativeCoordinatePositionerBase& positioner)
{
bool ok = positioner.addPoint (bounds.topLeft);
ok = positioner.addPoint (bounds.topRight) && ok;
ok = positioner.addPoint (bounds.bottomLeft) && ok;
return positioner.addPoint (cornerSize) && ok;
}
void DrawableRectangle::recalculateCoordinates (Expression::EvaluationContext* context)
{
Point<float> points[3];
bounds.resolveThreePoints (points, getParent());
bounds.resolveThreePoints (points, context);
const float cornerSizeX = (float) cornerSize.x.resolve (context);
const float cornerSizeY = (float) cornerSize.y.resolve (context);
const float w = Line<float> (points[0], points[1]).getLength();
const float h = Line<float> (points[0], points[2]).getLength();
const float cornerSizeX = (float) cornerSize.x.resolve (getParent());
const float cornerSizeY = (float) cornerSize.y.resolve (getParent());
path.clear();
Path newPath;
if (cornerSizeX > 0 && cornerSizeY > 0)
path.addRoundedRectangle (0, 0, w, h, cornerSizeX, cornerSizeY);
newPath.addRoundedRectangle (0, 0, w, h, cornerSizeX, cornerSizeY);
else
path.addRectangle (0, 0, w, h);
path.applyTransform (AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(),
w, 0, points[1].getX(), points[1].getY(),
0, h, points[2].getX(), points[2].getY()));
return true;
}
newPath.addRectangle (0, 0, w, h);
const AffineTransform DrawableRectangle::calculateTransform() const
{
Point<float> resolved[3];
bounds.resolveThreePoints (resolved, getParent());
newPath.applyTransform (AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(),
w, 0, points[1].getX(), points[1].getY(),
0, h, points[2].getX(), points[2].getY()));
return AffineTransform::fromTargetPoints (resolved[0].getX(), resolved[0].getY(),
resolved[1].getX(), resolved[1].getY(),
resolved[2].getX(), resolved[2].getY());
if (path != newPath)
{
path.swapWithPath (newPath);
pathChanged();
}
}
//==============================================================================
@@ -148,22 +173,10 @@ void DrawableRectangle::refreshFromValueTree (const ValueTree& tree, ComponentBu
ValueTreeWrapper v (tree);
setComponentID (v.getID());
if (refreshFillTypes (v, getParent(), builder.getImageProvider()))
repaint();
RelativeParallelogram newBounds (v.getRectangle());
const PathStrokeType newStroke (v.getStrokeType());
const RelativePoint newCornerSize (v.getCornerSize());
if (strokeType != newStroke || newBounds != bounds || newCornerSize != cornerSize)
{
repaint();
bounds = newBounds;
strokeType = newStroke;
cornerSize = newCornerSize;
pathChanged();
}
refreshFillTypes (v, builder.getImageProvider());
setStrokeType (v.getStrokeType());
setRectangle (v.getRectangle());
setCornerSize (v.getCornerSize());
}
const ValueTree DrawableRectangle::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const


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

@@ -79,25 +79,25 @@ public:
ValueTreeWrapper (const ValueTree& state);
const RelativeParallelogram getRectangle() const;
void setRectangle (const RelativeParallelogram& newBounds, UndoManager* undoManager);
void setRectangle (const RelativeParallelogram& newBounds, UndoManager*);
void setCornerSize (const RelativePoint& cornerSize, UndoManager* undoManager);
void setCornerSize (const RelativePoint& cornerSize, UndoManager*);
const RelativePoint getCornerSize() const;
Value getCornerSizeValue (UndoManager* undoManager) const;
Value getCornerSizeValue (UndoManager*) const;
static const Identifier topLeft, topRight, bottomLeft, cornerSize;
};
protected:
/** @internal */
bool rebuildPath (Path& path) const;
private:
friend class Drawable::Positioner<DrawableRectangle>;
RelativeParallelogram bounds;
RelativePoint cornerSize;
const AffineTransform calculateTransform() const;
void rebuildPath();
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);
DrawableRectangle& operator= (const DrawableRectangle&);
JUCE_LEAK_DETECTOR (DrawableRectangle);


+ 259
- 176
src/gui/graphics/drawables/juce_DrawableShape.cpp View File

@@ -50,65 +50,111 @@ DrawableShape::~DrawableShape()
{
}
//==============================================================================
class DrawableShape::RelativePositioner : public RelativeCoordinatePositionerBase
{
public:
RelativePositioner (DrawableShape& component_, const DrawableShape::RelativeFillType& fill_, bool isMainFill_)
: RelativeCoordinatePositionerBase (component_),
owner (component_),
fill (fill_),
isMainFill (isMainFill_)
{
}
bool registerCoordinates()
{
bool ok = addPoint (fill.gradientPoint1);
ok = addPoint (fill.gradientPoint2) && ok;
return addPoint (fill.gradientPoint3) && ok;
}
void applyToComponentBounds()
{
if (isMainFill ? owner.mainFill.recalculateCoords (this)
: owner.strokeFill.recalculateCoords (this))
owner.repaint();
}
private:
DrawableShape& owner;
const DrawableShape::RelativeFillType fill;
const bool isMainFill;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativePositioner);
};
void DrawableShape::setFill (const FillType& newFill)
{
mainFill = newFill;
setFill (RelativeFillType (newFill));
}
void DrawableShape::setStrokeFill (const FillType& newFill)
{
strokeFill = newFill;
setStrokeFill (RelativeFillType (newFill));
}
void DrawableShape::setStrokeType (const PathStrokeType& newStrokeType)
void DrawableShape::setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill,
ScopedPointer<RelativeCoordinatePositionerBase>& positioner)
{
strokeType = newStrokeType;
strokeChanged();
if (fill != newFill)
{
fill = newFill;
positioner = 0;
if (fill.isDynamic())
{
positioner = new RelativePositioner (*this, fill, true);
positioner->apply();
}
else
{
fill.recalculateCoords (0);
}
repaint();
}
}
void DrawableShape::setStrokeThickness (const float newThickness)
void DrawableShape::setFill (const RelativeFillType& newFill)
{
setStrokeType (PathStrokeType (newThickness, strokeType.getJointStyle(), strokeType.getEndStyle()));
setFillInternal (mainFill, newFill, mainFillPositioner);
}
bool DrawableShape::isStrokeVisible() const throw()
void DrawableShape::setStrokeFill (const RelativeFillType& newFill)
{
return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.isInvisible();
setFillInternal (strokeFill, newFill, strokeFillPositioner);
}
bool DrawableShape::refreshFillTypes (const FillAndStrokeState& newState,
Expression::EvaluationContext* /*nameFinder*/,
ComponentBuilder::ImageProvider* imageProvider)
void DrawableShape::setStrokeType (const PathStrokeType& newStrokeType)
{
bool hasChanged = false;
if (strokeType != newStrokeType)
{
const FillType f (newState.getMainFill (getParent(), imageProvider));
if (mainFill != f)
{
hasChanged = true;
mainFill = f;
}
strokeType = newStrokeType;
strokeChanged();
}
}
{
const FillType f (newState.getStrokeFill (getParent(), imageProvider));
void DrawableShape::setStrokeThickness (const float newThickness)
{
setStrokeType (PathStrokeType (newThickness, strokeType.getJointStyle(), strokeType.getEndStyle()));
}
if (strokeFill != f)
{
hasChanged = true;
strokeFill = f;
}
}
bool DrawableShape::isStrokeVisible() const throw()
{
return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.fill.isInvisible();
}
return hasChanged;
void DrawableShape::refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider* imageProvider)
{
setFill (newState.getFill (FillAndStrokeState::fill, imageProvider));
setStrokeFill (newState.getFill (FillAndStrokeState::stroke, imageProvider));
}
void DrawableShape::writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const
{
state.setMainFill (mainFill, 0, 0, 0, imageProvider, undoManager);
state.setStrokeFill (strokeFill, 0, 0, 0, imageProvider, undoManager);
state.setFill (FillAndStrokeState::fill, mainFill, imageProvider, undoManager);
state.setFill (FillAndStrokeState::stroke, strokeFill, imageProvider, undoManager);
state.setStrokeType (strokeType, undoManager);
}
@@ -117,19 +163,18 @@ void DrawableShape::paint (Graphics& g)
{
transformContextToCorrectOrigin (g);
g.setFillType (mainFill);
g.setFillType (mainFill.fill);
g.fillPath (path);
if (isStrokeVisible())
{
g.setFillType (strokeFill);
g.setFillType (strokeFill.fill);
g.fillPath (strokePath);
}
}
void DrawableShape::pathChanged()
{
rebuildPath (path);
strokeChanged();
}
@@ -160,211 +205,249 @@ bool DrawableShape::hitTest (int x, int y) const
}
//==============================================================================
const Identifier DrawableShape::FillAndStrokeState::type ("type");
const Identifier DrawableShape::FillAndStrokeState::colour ("colour");
const Identifier DrawableShape::FillAndStrokeState::colours ("colours");
const Identifier DrawableShape::FillAndStrokeState::fill ("Fill");
const Identifier DrawableShape::FillAndStrokeState::stroke ("Stroke");
const Identifier DrawableShape::FillAndStrokeState::path ("Path");
const Identifier DrawableShape::FillAndStrokeState::jointStyle ("jointStyle");
const Identifier DrawableShape::FillAndStrokeState::capStyle ("capStyle");
const Identifier DrawableShape::FillAndStrokeState::strokeWidth ("strokeWidth");
const Identifier DrawableShape::FillAndStrokeState::gradientPoint1 ("point1");
const Identifier DrawableShape::FillAndStrokeState::gradientPoint2 ("point2");
const Identifier DrawableShape::FillAndStrokeState::gradientPoint3 ("point3");
const Identifier DrawableShape::FillAndStrokeState::radial ("radial");
const Identifier DrawableShape::FillAndStrokeState::imageId ("imageId");
const Identifier DrawableShape::FillAndStrokeState::imageOpacity ("imageOpacity");
DrawableShape::FillAndStrokeState::FillAndStrokeState (const ValueTree& state_)
: Drawable::ValueTreeWrapperBase (state_)
DrawableShape::RelativeFillType::RelativeFillType()
{
}
const FillType DrawableShape::FillAndStrokeState::getMainFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const
DrawableShape::RelativeFillType::RelativeFillType (const FillType& fill_)
: fill (fill_)
{
return readFillType (state.getChildWithName (fill), 0, 0, 0, nameFinder, imageProvider);
if (fill.isGradient())
{
const ColourGradient& g = *fill.gradient;
gradientPoint1 = g.point1.transformedBy (fill.transform);
gradientPoint2 = g.point2.transformedBy (fill.transform);
gradientPoint3 = Point<float> (g.point1.getX() + g.point2.getY() - g.point1.getY(),
g.point1.getY() + g.point1.getX() - g.point2.getX())
.transformedBy (fill.transform);
fill.transform = AffineTransform::identity;
}
}
ValueTree DrawableShape::FillAndStrokeState::getMainFillState()
DrawableShape::RelativeFillType::RelativeFillType (const RelativeFillType& other)
: fill (other.fill),
gradientPoint1 (other.gradientPoint1),
gradientPoint2 (other.gradientPoint2),
gradientPoint3 (other.gradientPoint3)
{
ValueTree v (state.getChildWithName (fill));
if (v.isValid())
return v;
}
setMainFill (Colours::black, 0, 0, 0, 0, 0);
return getMainFillState();
DrawableShape::RelativeFillType& DrawableShape::RelativeFillType::operator= (const RelativeFillType& other)
{
fill = other.fill;
gradientPoint1 = other.gradientPoint1;
gradientPoint2 = other.gradientPoint2;
gradientPoint3 = other.gradientPoint3;
return *this;
}
void DrawableShape::FillAndStrokeState::setMainFill (const FillType& newFill, const RelativePoint* gp1, const RelativePoint* gp2,
const RelativePoint* gp3, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager)
bool DrawableShape::RelativeFillType::operator== (const RelativeFillType& other) const
{
ValueTree v (state.getOrCreateChildWithName (fill, undoManager));
writeFillType (v, newFill, gp1, gp2, gp3, imageProvider, undoManager);
return fill == other.fill
&& ((! fill.isGradient())
|| (gradientPoint1 == other.gradientPoint1
&& gradientPoint2 == other.gradientPoint2
&& gradientPoint3 == other.gradientPoint3));
}
const FillType DrawableShape::FillAndStrokeState::getStrokeFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const
bool DrawableShape::RelativeFillType::operator!= (const RelativeFillType& other) const
{
return readFillType (state.getChildWithName (stroke), 0, 0, 0, nameFinder, imageProvider);
return ! operator== (other);
}
ValueTree DrawableShape::FillAndStrokeState::getStrokeFillState()
bool DrawableShape::RelativeFillType::recalculateCoords (Expression::EvaluationContext* context)
{
ValueTree v (state.getChildWithName (stroke));
if (v.isValid())
return v;
if (fill.isGradient())
{
const Point<float> g1 (gradientPoint1.resolve (context));
const Point<float> g2 (gradientPoint2.resolve (context));
AffineTransform t;
ColourGradient& g = *fill.gradient;
if (g.isRadial)
{
const Point<float> g3 (gradientPoint3.resolve (context));
const Point<float> g3Source (g1.getX() + g2.getY() - g1.getY(),
g1.getY() + g1.getX() - g2.getX());
t = AffineTransform::fromTargetPoints (g1.getX(), g1.getY(), g1.getX(), g1.getY(),
g2.getX(), g2.getY(), g2.getX(), g2.getY(),
g3Source.getX(), g3Source.getY(), g3.getX(), g3.getY());
}
setStrokeFill (Colours::black, 0, 0, 0, 0, 0);
return getStrokeFillState();
if (g.point1 != g1 || g.point2 != g2 || fill.transform != t)
{
g.point1 = g1;
g.point2 = g2;
fill.transform = t;
return true;
}
}
return false;
}
void DrawableShape::FillAndStrokeState::setStrokeFill (const FillType& newFill, const RelativePoint* gp1, const RelativePoint* gp2,
const RelativePoint* gp3, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager)
bool DrawableShape::RelativeFillType::isDynamic() const
{
ValueTree v (state.getOrCreateChildWithName (stroke, undoManager));
writeFillType (v, newFill, gp1, gp2, gp3, imageProvider, undoManager);
return gradientPoint1.isDynamic() || gradientPoint2.isDynamic() || gradientPoint3.isDynamic();
}
const PathStrokeType DrawableShape::FillAndStrokeState::getStrokeType() const
void DrawableShape::RelativeFillType::writeTo (ValueTree& v, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const
{
const String jointStyleString (state [jointStyle].toString());
const String capStyleString (state [capStyle].toString());
if (fill.isColour())
{
v.setProperty (FillAndStrokeState::type, "solid", undoManager);
v.setProperty (FillAndStrokeState::colour, String::toHexString ((int) fill.colour.getARGB()), undoManager);
}
else if (fill.isGradient())
{
v.setProperty (FillAndStrokeState::type, "gradient", undoManager);
v.setProperty (FillAndStrokeState::gradientPoint1, gradientPoint1.toString(), undoManager);
v.setProperty (FillAndStrokeState::gradientPoint2, gradientPoint2.toString(), undoManager);
v.setProperty (FillAndStrokeState::gradientPoint3, gradientPoint3.toString(), undoManager);
return PathStrokeType (state [strokeWidth],
jointStyleString == "curved" ? PathStrokeType::curved
: (jointStyleString == "bevel" ? PathStrokeType::beveled
: PathStrokeType::mitered),
capStyleString == "square" ? PathStrokeType::square
: (capStyleString == "round" ? PathStrokeType::rounded
: PathStrokeType::butt));
}
const ColourGradient& cg = *fill.gradient;
v.setProperty (FillAndStrokeState::radial, cg.isRadial, undoManager);
void DrawableShape::FillAndStrokeState::setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager)
{
state.setProperty (strokeWidth, (double) newStrokeType.getStrokeThickness(), undoManager);
state.setProperty (jointStyle, newStrokeType.getJointStyle() == PathStrokeType::mitered
? "miter" : (newStrokeType.getJointStyle() == PathStrokeType::curved ? "curved" : "bevel"), undoManager);
state.setProperty (capStyle, newStrokeType.getEndStyle() == PathStrokeType::butt
? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager);
String s;
for (int i = 0; i < cg.getNumColours(); ++i)
s << ' ' << cg.getColourPosition (i)
<< ' ' << String::toHexString ((int) cg.getColour(i).getARGB());
v.setProperty (FillAndStrokeState::colours, s.trimStart(), undoManager);
}
else if (fill.isTiledImage())
{
v.setProperty (FillAndStrokeState::type, "image", undoManager);
if (imageProvider != 0)
v.setProperty (FillAndStrokeState::imageId, imageProvider->getIdentifierForImage (fill.image), undoManager);
if (fill.getOpacity() < 1.0f)
v.setProperty (FillAndStrokeState::imageOpacity, fill.getOpacity(), undoManager);
else
v.removeProperty (FillAndStrokeState::imageOpacity, undoManager);
}
else
{
jassertfalse;
}
}
const FillType DrawableShape::FillAndStrokeState::readFillType (const ValueTree& v, RelativePoint* const gp1, RelativePoint* const gp2, RelativePoint* const gp3,
Expression::EvaluationContext* const nameFinder, ComponentBuilder::ImageProvider* imageProvider)
bool DrawableShape::RelativeFillType::readFrom (const ValueTree& v, ComponentBuilder::ImageProvider* imageProvider)
{
const String newType (v[type].toString());
const String newType (v [FillAndStrokeState::type].toString());
if (newType == "solid")
{
const String colourString (v [colour].toString());
return FillType (Colour (colourString.isEmpty() ? (uint32) 0xff000000
: (uint32) colourString.getHexValue32()));
const String colourString (v [FillAndStrokeState::colour].toString());
fill.setColour (Colour (colourString.isEmpty() ? (uint32) 0xff000000
: (uint32) colourString.getHexValue32()));
return true;
}
else if (newType == "gradient")
{
RelativePoint p1 (v [gradientPoint1]), p2 (v [gradientPoint2]), p3 (v [gradientPoint3]);
ColourGradient g;
if (gp1 != 0) *gp1 = p1;
if (gp2 != 0) *gp2 = p2;
if (gp3 != 0) *gp3 = p3;
g.point1 = p1.resolve (nameFinder);
g.point2 = p2.resolve (nameFinder);
g.isRadial = v[radial];
g.isRadial = v [FillAndStrokeState::radial];
StringArray colourSteps;
colourSteps.addTokens (v[colours].toString(), false);
colourSteps.addTokens (v [FillAndStrokeState::colours].toString(), false);
for (int i = 0; i < colourSteps.size() / 2; ++i)
g.addColour (colourSteps[i * 2].getDoubleValue(),
Colour ((uint32) colourSteps[i * 2 + 1].getHexValue32()));
FillType fillType (g);
if (g.isRadial)
{
const Point<float> point3 (p3.resolve (nameFinder));
const Point<float> point3Source (g.point1.getX() + g.point2.getY() - g.point1.getY(),
g.point1.getY() + g.point1.getX() - g.point2.getX());
fillType.transform = AffineTransform::fromTargetPoints (g.point1.getX(), g.point1.getY(), g.point1.getX(), g.point1.getY(),
g.point2.getX(), g.point2.getY(), g.point2.getX(), g.point2.getY(),
point3Source.getX(), point3Source.getY(), point3.getX(), point3.getY());
}
fill.setGradient (g);
return fillType;
gradientPoint1 = RelativePoint (v [FillAndStrokeState::gradientPoint1]);
gradientPoint2 = RelativePoint (v [FillAndStrokeState::gradientPoint2]);
gradientPoint3 = RelativePoint (v [FillAndStrokeState::gradientPoint3]);
return true;
}
else if (newType == "image")
{
Image im;
if (imageProvider != 0)
im = imageProvider->getImageForIdentifier (v[imageId]);
im = imageProvider->getImageForIdentifier (v [FillAndStrokeState::imageId]);
FillType f (im, AffineTransform::identity);
f.setOpacity ((float) v.getProperty (imageOpacity, 1.0f));
return f;
fill.setTiledImage (im, AffineTransform::identity);
fill.setOpacity ((float) v.getProperty (FillAndStrokeState::imageOpacity, 1.0f));
return true;
}
jassert (! v.isValid());
return FillType();
jassertfalse;
return false;
}
namespace DrawableShapeHelpers
//==============================================================================
const Identifier DrawableShape::FillAndStrokeState::type ("type");
const Identifier DrawableShape::FillAndStrokeState::colour ("colour");
const Identifier DrawableShape::FillAndStrokeState::colours ("colours");
const Identifier DrawableShape::FillAndStrokeState::fill ("Fill");
const Identifier DrawableShape::FillAndStrokeState::stroke ("Stroke");
const Identifier DrawableShape::FillAndStrokeState::path ("Path");
const Identifier DrawableShape::FillAndStrokeState::jointStyle ("jointStyle");
const Identifier DrawableShape::FillAndStrokeState::capStyle ("capStyle");
const Identifier DrawableShape::FillAndStrokeState::strokeWidth ("strokeWidth");
const Identifier DrawableShape::FillAndStrokeState::gradientPoint1 ("point1");
const Identifier DrawableShape::FillAndStrokeState::gradientPoint2 ("point2");
const Identifier DrawableShape::FillAndStrokeState::gradientPoint3 ("point3");
const Identifier DrawableShape::FillAndStrokeState::radial ("radial");
const Identifier DrawableShape::FillAndStrokeState::imageId ("imageId");
const Identifier DrawableShape::FillAndStrokeState::imageOpacity ("imageOpacity");
DrawableShape::FillAndStrokeState::FillAndStrokeState (const ValueTree& state_)
: Drawable::ValueTreeWrapperBase (state_)
{
const Point<float> calcThirdGradientPoint (const FillType& fillType)
{
const ColourGradient& g = *fillType.gradient;
const Point<float> point3Source (g.point1.getX() + g.point2.getY() - g.point1.getY(),
g.point1.getY() + g.point1.getX() - g.point2.getX());
}
return point3Source.transformedBy (fillType.transform);
}
const DrawableShape::RelativeFillType DrawableShape::FillAndStrokeState::getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider* imageProvider) const
{
DrawableShape::RelativeFillType f;
f.readFrom (state.getChildWithName (fillOrStrokeType), imageProvider);
return f;
}
void DrawableShape::FillAndStrokeState::writeFillType (ValueTree& v, const FillType& fillType,
const RelativePoint* const gp1, const RelativePoint* const gp2, const RelativePoint* gp3,
ComponentBuilder::ImageProvider* imageProvider, UndoManager* const undoManager)
ValueTree DrawableShape::FillAndStrokeState::getFillState (const Identifier& fillOrStrokeType)
{
if (fillType.isColour())
{
v.setProperty (type, "solid", undoManager);
v.setProperty (colour, String::toHexString ((int) fillType.colour.getARGB()), undoManager);
}
else if (fillType.isGradient())
{
v.setProperty (type, "gradient", undoManager);
v.setProperty (gradientPoint1, gp1 != 0 ? gp1->toString() : fillType.gradient->point1.toString(), undoManager);
v.setProperty (gradientPoint2, gp2 != 0 ? gp2->toString() : fillType.gradient->point2.toString(), undoManager);
v.setProperty (gradientPoint3, gp3 != 0 ? gp3->toString() : DrawableShapeHelpers::calcThirdGradientPoint (fillType).toString(), undoManager);
ValueTree v (state.getChildWithName (fillOrStrokeType));
if (v.isValid())
return v;
v.setProperty (radial, fillType.gradient->isRadial, undoManager);
setFill (fillOrStrokeType, FillType (Colours::black), 0, 0);
return getFillState (fillOrStrokeType);
}
String s;
for (int i = 0; i < fillType.gradient->getNumColours(); ++i)
s << ' ' << fillType.gradient->getColourPosition (i)
<< ' ' << String::toHexString ((int) fillType.gradient->getColour(i).getARGB());
void DrawableShape::FillAndStrokeState::setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill,
ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager)
{
ValueTree v (state.getOrCreateChildWithName (fillOrStrokeType, undoManager));
newFill.writeTo (v, imageProvider, undoManager);
}
v.setProperty (colours, s.trimStart(), undoManager);
}
else if (fillType.isTiledImage())
{
v.setProperty (type, "image", undoManager);
const PathStrokeType DrawableShape::FillAndStrokeState::getStrokeType() const
{
const String jointStyleString (state [jointStyle].toString());
const String capStyleString (state [capStyle].toString());
if (imageProvider != 0)
v.setProperty (imageId, imageProvider->getIdentifierForImage (fillType.image), undoManager);
return PathStrokeType (state [strokeWidth],
jointStyleString == "curved" ? PathStrokeType::curved
: (jointStyleString == "bevel" ? PathStrokeType::beveled
: PathStrokeType::mitered),
capStyleString == "square" ? PathStrokeType::square
: (capStyleString == "round" ? PathStrokeType::rounded
: PathStrokeType::butt));
}
if (fillType.getOpacity() < 1.0f)
v.setProperty (imageOpacity, fillType.getOpacity(), undoManager);
else
v.removeProperty (imageOpacity, undoManager);
}
else
{
jassertfalse;
}
void DrawableShape::FillAndStrokeState::setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager)
{
state.setProperty (strokeWidth, (double) newStrokeType.getStrokeThickness(), undoManager);
state.setProperty (jointStyle, newStrokeType.getJointStyle() == PathStrokeType::mitered
? "miter" : (newStrokeType.getJointStyle() == PathStrokeType::curved ? "curved" : "bevel"), undoManager);
state.setProperty (capStyle, newStrokeType.getEndStyle() == PathStrokeType::butt
? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager);
}
END_JUCE_NAMESPACE

+ 56
- 40
src/gui/graphics/drawables/juce_DrawableShape.h View File

@@ -29,7 +29,7 @@
#include "juce_Drawable.h"
#include "../contexts/juce_FillType.h"
#include "../colour/juce_ColourGradient.h"
#include "../../components/positioning/juce_RelativePoint.h"
#include "../../components/positioning/juce_RelativeCoordinatePositioner.h"
//==============================================================================
@@ -50,6 +50,31 @@ public:
/** Destructor. */
~DrawableShape();
//==============================================================================
/** A FillType wrapper that allows the gradient coordinates to be implemented using RelativePoint.
*/
class RelativeFillType
{
public:
RelativeFillType();
RelativeFillType (const FillType& fill);
RelativeFillType (const RelativeFillType&);
RelativeFillType& operator= (const RelativeFillType&);
bool operator== (const RelativeFillType&) const;
bool operator!= (const RelativeFillType&) const;
bool isDynamic() const;
bool recalculateCoords (Expression::EvaluationContext* context);
void writeTo (ValueTree& v, ComponentBuilder::ImageProvider*, UndoManager*) const;
bool readFrom (const ValueTree& v, ComponentBuilder::ImageProvider*);
//==============================================================================
FillType fill;
RelativePoint gradientPoint1, gradientPoint2, gradientPoint3;
};
//==============================================================================
/** Sets a fill type for the path.
This colour is used to fill the path - if you don't want the path to be
@@ -60,20 +85,34 @@ public:
*/
void setFill (const FillType& newFill);
/** Sets a fill type for the path.
This colour is used to fill the path - if you don't want the path to be
filled (e.g. if you're just drawing an outline), set this to a transparent
colour.
@see setPath, setStrokeFill
*/
void setFill (const RelativeFillType& newFill);
/** Returns the current fill type.
@see setFill
*/
const FillType& getFill() const throw() { return mainFill; }
const RelativeFillType& getFill() const throw() { return mainFill; }
/** Sets the fill type with which the outline will be drawn.
@see setFill
*/
void setStrokeFill (const FillType& newStrokeFill);
/** Sets the fill type with which the outline will be drawn.
@see setFill
*/
void setStrokeFill (const RelativeFillType& newStrokeFill);
/** Returns the current stroke fill.
@see setStrokeFill
*/
const FillType& getStrokeFill() const throw() { return strokeFill; }
const RelativeFillType& getStrokeFill() const throw() { return strokeFill; }
/** Changes the properties of the outline that will be drawn around the path.
If the stroke has 0 thickness, no stroke will be drawn.
@@ -87,7 +126,7 @@ public:
void setStrokeThickness (float newThickness);
/** Returns the current outline style. */
const PathStrokeType& getStrokeType() const throw() { return strokeType; }
const PathStrokeType& getStrokeType() const throw() { return strokeType; }
//==============================================================================
/** @internal */
@@ -96,32 +135,13 @@ public:
public:
FillAndStrokeState (const ValueTree& state);
const FillType getMainFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const;
ValueTree getMainFillState();
void setMainFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3,
ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager);
const FillType getStrokeFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const;
ValueTree getStrokeFillState();
void setStrokeFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3,
ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager);
ValueTree getFillState (const Identifier& fillOrStrokeType);
const RelativeFillType getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider*) const;
void setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill,
ComponentBuilder::ImageProvider*, UndoManager*);
const PathStrokeType getStrokeType() const;
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager);
static const FillType readFillType (const ValueTree& v, RelativePoint* gradientPoint1,
RelativePoint* gradientPoint2, RelativePoint* gradientPoint3,
Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider);
static void writeFillType (ValueTree& v, const FillType& fillType,
const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
const RelativePoint* gradientPoint3, ComponentBuilder::ImageProvider* imageProvider,
UndoManager* undoManager);
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager*);
static const Identifier type, colour, colours, fill, stroke, path, jointStyle, capStyle, strokeWidth,
gradientPoint1, gradientPoint2, gradientPoint3, radial, imageId, imageOpacity;
@@ -140,28 +160,24 @@ protected:
void pathChanged();
/** Called when the cached stroke should be updated. */
void strokeChanged();
/** Implemented by subclasses to regenerate the path. */
virtual bool rebuildPath (Path& path) const = 0;
/** True if there's a stroke with a non-zero thickness and non-transparent colour. */
bool isStrokeVisible() const throw();
/** Updates the details from a FillAndStrokeState object, returning true if something changed. */
bool refreshFillTypes (const FillAndStrokeState& newState,
Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider);
void refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider*);
/** Writes the stroke and fill details to a FillAndStrokeState object. */
void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const;
void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider*, UndoManager*) const;
//==============================================================================
PathStrokeType strokeType;
Path path, strokePath;
private:
FillType mainFill, strokeFill;
class RelativePositioner;
RelativeFillType mainFill, strokeFill;
ScopedPointer<RelativeCoordinatePositionerBase> mainFillPositioner, strokeFillPositioner;
void setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill,
ScopedPointer<RelativeCoordinatePositionerBase>& positioner);
DrawableShape& operator= (const DrawableShape&);
};


+ 83
- 40
src/gui/graphics/drawables/juce_DrawableText.cpp View File

@@ -57,38 +57,38 @@ DrawableText::~DrawableText()
}
//==============================================================================
void DrawableText::refreshBounds()
{
setBoundsToEnclose (getDrawableBounds());
repaint();
}
void DrawableText::setText (const String& newText)
{
text = newText;
refreshBounds();
if (text != newText)
{
text = newText;
refreshBounds();
}
}
void DrawableText::setColour (const Colour& newColour)
{
colour = newColour;
repaint();
if (colour != newColour)
{
colour = newColour;
repaint();
}
}
void DrawableText::setFont (const Font& newFont, bool applySizeAndScale)
{
font = newFont;
if (applySizeAndScale)
if (font != newFont)
{
Point<float> corners[3];
bounds.resolveThreePoints (corners, getParent());
font = newFont;
setFontSizeControlPoint (RelativePoint (RelativeParallelogram::getPointForInternalCoord (corners,
Point<float> (font.getHorizontalScale() * font.getHeight(), font.getHeight()))));
}
if (applySizeAndScale)
{
setFontSizeControlPoint (RelativePoint (RelativeParallelogram::getPointForInternalCoord (resolvedPoints,
Point<float> (font.getHorizontalScale() * font.getHeight(), font.getHeight()))));
}
refreshBounds();
refreshBounds();
}
}
void DrawableText::setJustification (const Justification& newJustification)
@@ -99,47 +99,91 @@ void DrawableText::setJustification (const Justification& newJustification)
void DrawableText::setBoundingBox (const RelativeParallelogram& newBounds)
{
bounds = newBounds;
refreshBounds();
if (bounds != newBounds)
{
bounds = newBounds;
refreshBounds();
}
}
void DrawableText::setFontSizeControlPoint (const RelativePoint& newPoint)
{
fontSizeControlPoint = newPoint;
refreshBounds();
if (fontSizeControlPoint != newPoint)
{
fontSizeControlPoint = newPoint;
refreshBounds();
}
}
//==============================================================================
void DrawableText::paint (Graphics& g)
void DrawableText::refreshBounds()
{
transformContextToCorrectOrigin (g);
if (bounds.isDynamic() || fontSizeControlPoint.isDynamic())
{
Drawable::Positioner<DrawableText>* const p = new Drawable::Positioner<DrawableText> (*this);
setPositioner (p);
p->apply();
}
else
{
setPositioner (0);
recalculateCoordinates (0);
}
}
bool DrawableText::registerCoordinates (RelativeCoordinatePositionerBase& positioner)
{
bool ok = positioner.addPoint (bounds.topLeft);
ok = positioner.addPoint (bounds.topRight) && ok;
ok = positioner.addPoint (bounds.bottomLeft) && ok;
return positioner.addPoint (fontSizeControlPoint) && ok;
}
Point<float> points[3];
bounds.resolveThreePoints (points, getParent());
void DrawableText::recalculateCoordinates (Expression::EvaluationContext* context)
{
bounds.resolveThreePoints (resolvedPoints, context);
const float w = Line<float> (points[0], points[1]).getLength();
const float h = Line<float> (points[0], points[2]).getLength();
const float w = Line<float> (resolvedPoints[0], resolvedPoints[1]).getLength();
const float h = Line<float> (resolvedPoints[0], resolvedPoints[2]).getLength();
const Point<float> fontCoords (bounds.getInternalCoordForPoint (points, fontSizeControlPoint.resolve (getParent())));
const Point<float> fontCoords (RelativeParallelogram::getInternalCoordForPoint (resolvedPoints, fontSizeControlPoint.resolve (context)));
const float fontHeight = jlimit (0.01f, jmax (0.01f, h), fontCoords.getY());
const float fontWidth = jlimit (0.01f, jmax (0.01f, w), fontCoords.getX());
Font f (font);
f.setHeight (fontHeight);
f.setHorizontalScale (fontWidth / fontHeight);
scaledFont = font;
scaledFont.setHeight (fontHeight);
scaledFont.setHorizontalScale (fontWidth / fontHeight);
setBoundsToEnclose (getDrawableBounds());
repaint();
}
const AffineTransform DrawableText::getArrangementAndTransform (GlyphArrangement& glyphs) const
{
const float w = Line<float> (resolvedPoints[0], resolvedPoints[1]).getLength();
const float h = Line<float> (resolvedPoints[0], resolvedPoints[2]).getLength();
glyphs.addFittedText (scaledFont, text, 0, 0, w, h, justification, 0x100000);
return AffineTransform::fromTargetPoints (0, 0, resolvedPoints[0].getX(), resolvedPoints[0].getY(),
w, 0, resolvedPoints[1].getX(), resolvedPoints[1].getY(),
0, h, resolvedPoints[2].getX(), resolvedPoints[2].getY());
}
//==============================================================================
void DrawableText::paint (Graphics& g)
{
transformContextToCorrectOrigin (g);
g.setColour (colour);
GlyphArrangement ga;
ga.addFittedText (f, text, 0, 0, w, h, justification, 0x100000);
ga.draw (g, AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(),
w, 0, points[1].getX(), points[1].getY(),
0, h, points[2].getX(), points[2].getY()));
const AffineTransform transform (getArrangementAndTransform (ga));
ga.draw (g, transform);
}
const Rectangle<float> DrawableText::getDrawableBounds() const
{
return bounds.getBounds (getParent());
return RelativeParallelogram::getBoundingBox (resolvedPoints);
}
Drawable* DrawableText::createCopy() const
@@ -254,7 +298,6 @@ void DrawableText::refreshFromValueTree (const ValueTree& tree, ComponentBuilder
if (text != newText || font != newFont || justification != newJustification
|| colour != newColour || bounds != newBounds || newFontPoint != fontSizeControlPoint)
{
repaint();
setBoundingBox (newBounds);
setFontSizeControlPoint (newFontPoint);
setColour (newColour);


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

@@ -134,12 +134,17 @@ private:
//==============================================================================
RelativeParallelogram bounds;
RelativePoint fontSizeControlPoint;
Font font;
Point<float> resolvedPoints[3];
Font font, scaledFont;
String text;
Colour colour;
Justification justification;
friend class Drawable::Positioner<DrawableText>;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);
void refreshBounds();
const AffineTransform getArrangementAndTransform (GlyphArrangement& glyphs) const;
DrawableText& operator= (const DrawableText&);
JUCE_LEAK_DETECTOR (DrawableText);


+ 3
- 4
src/gui/graphics/fonts/juce_Font.cpp View File

@@ -72,10 +72,6 @@ public:
const Typeface::Ptr findTypefaceFor (const Font& font)
{
// (can't initialise defaultFace in the constructor or in getDefaultTypeface() because of recursion).
if (defaultFace == 0)
defaultFace = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (Font());
const int flags = font.getStyleFlags() & (Font::bold | Font::italic);
const String faceName (font.getTypefaceName());
@@ -114,6 +110,9 @@ public:
face.typeface = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (font);
jassert (face.typeface != 0); // the look and feel must return a typeface!
if (defaultFace == 0 && font == Font())
defaultFace = face.typeface;
return face.typeface;
}


+ 24
- 25
src/native/mac/juce_mac_CoreGraphicsContext.mm View File

@@ -90,7 +90,7 @@ public:
}
}
#if JUCE_MAC
#if JUCE_MAC
static NSImage* createNSImage (const Image& image)
{
const ScopedAutoReleasePool pool;
@@ -111,7 +111,7 @@ public:
return im;
}
#endif
#endif
//==============================================================================
CGContextRef context;
@@ -120,11 +120,11 @@ public:
private:
static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format)
{
#if JUCE_BIG_ENDIAN
#if JUCE_BIG_ENDIAN
return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) : kCGBitmapByteOrderDefault;
#else
#else
return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) : kCGBitmapByteOrderDefault;
#endif
#endif
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImage);
@@ -132,11 +132,11 @@ private:
Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage)
{
#if USE_COREGRAPHICS_RENDERING
#if USE_COREGRAPHICS_RENDERING
return new CoreGraphicsImage (format == RGB ? ARGB : format, width, height, clearImage);
#else
#else
return createSoftwareImage (format, width, height, clearImage);
#endif
#endif
}
//==============================================================================
@@ -382,16 +382,16 @@ public:
{
if (replaceExistingContents)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
CGContextClearRect (context, cgRect);
#else
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
#else
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
if (CGContextDrawLinearGradient == 0) // (just a way of checking whether we're running in 10.5 or later)
CGContextClearRect (context, cgRect);
else
#endif
#endif
CGContextSetBlendMode (context, kCGBlendModeCopy);
#endif
#endif
fillCGRect (cgRect, false);
CGContextSetBlendMode (context, kCGBlendModeNormal);
@@ -467,16 +467,16 @@ public:
if (fillEntireClipAsTiles)
{
#if JUCE_IOS
#if JUCE_IOS
CGContextDrawTiledImage (context, imageRect, image);
#else
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
#else
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
// There's a bug in CGContextDrawTiledImage that makes it incredibly slow
// if it's doing a transformation - it's quicker to just draw lots of images manually
if (CGContextDrawTiledImage != 0 && transform.isOnlyTranslation())
CGContextDrawTiledImage (context, imageRect, image);
else
#endif
#endif
{
// Fallback to manually doing a tiled fill on 10.4
CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context));
@@ -496,7 +496,7 @@ public:
y += ih;
}
}
#endif
#endif
}
else
{
@@ -681,8 +681,7 @@ private:
CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient)
{
numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable);
--numGradientLookupEntries;
numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable) - 1;
CGShadingRef result = 0;
CGFunctionRef function = CGFunctionCreate (this, 1, 0, 4, 0, &gradientCallbacks);
@@ -803,7 +802,7 @@ const Image juce_loadWithCoreImage (InputStream& input)
MemoryBlock data;
input.readIntoMemoryBlock (data, -1);
#if JUCE_IOS
#if JUCE_IOS
JUCE_AUTORELEASEPOOL
UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData()
length: data.getSize()
@@ -813,7 +812,7 @@ const Image juce_loadWithCoreImage (InputStream& input)
{
CGImageRef loadedImage = image.CGImage;
#else
#else
CGDataProviderRef provider = CGDataProviderCreateWithData (0, data.getData(), data.getSize(), 0);
CGImageSourceRef imageSource = CGImageSourceCreateWithDataProvider (provider, 0);
CGDataProviderRelease (provider);
@@ -822,7 +821,7 @@ const Image juce_loadWithCoreImage (InputStream& input)
{
CGImageRef loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, 0);
CFRelease (imageSource);
#endif
#endif
if (loadedImage != 0)
{
@@ -841,9 +840,9 @@ const Image juce_loadWithCoreImage (InputStream& input)
CGContextDrawImage (cgImage->context, CGRectMake (0, 0, image.getWidth(), image.getHeight()), loadedImage);
CGContextFlush (cgImage->context);
#if ! JUCE_IOS
#if ! JUCE_IOS
CFRelease (loadedImage);
#endif
#endif
// Because it's impossible to create a truly 24-bit CG image, this flag allows a user
// to find out whether the file they just loaded the image from had an alpha channel or not.


Loading…
Cancel
Save