| @@ -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(), | |||
| @@ -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()); | |||
| @@ -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); | |||
| @@ -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. | |||
| @@ -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); | |||
| } | |||
| @@ -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 | |||
| @@ -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); | |||
| @@ -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; | |||
| @@ -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; | |||
| @@ -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 | |||
| @@ -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; | |||
| @@ -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); | |||
| @@ -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 | |||
| @@ -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&); | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| @@ -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; | |||
| } | |||
| @@ -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); | |||
| @@ -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 | |||
| @@ -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); | |||
| @@ -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 | |||
| @@ -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&); | |||
| }; | |||
| @@ -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); | |||
| @@ -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); | |||
| @@ -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; | |||
| } | |||
| @@ -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. | |||