1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-21 01:24:21 +00:00

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

This commit is contained in:
Julian Storer 2011-01-04 23:04:51 +00:00
parent e5c4ecc670
commit 7478c7f9ab
27 changed files with 1798 additions and 1479 deletions

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -73,7 +73,7 @@ namespace JuceDummyNamespace {}
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
#define JUCE_BUILDNUMBER 6
#define JUCE_BUILDNUMBER 7
/** Current Juce version number.
@ -45451,6 +45451,273 @@ private:
/*** End of inlined file: juce_RelativeCoordinate.h ***/
/*** Start of inlined file: juce_RelativeCoordinatePositioner.h ***/
#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
#define __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
/*** Start of inlined file: juce_RelativePoint.h ***/
#ifndef __JUCE_RELATIVEPOINT_JUCEHEADER__
#define __JUCE_RELATIVEPOINT_JUCEHEADER__
/**
An X-Y position stored as a pair of RelativeCoordinate values.
@see RelativeCoordinate, RelativeRectangle
*/
class JUCE_API RelativePoint
{
public:
/** Creates a point at the origin. */
RelativePoint();
/** Creates an absolute point, relative to the origin. */
RelativePoint (const Point<float>& absolutePoint);
/** Creates an absolute point, relative to the origin. */
RelativePoint (float absoluteX, float absoluteY);
/** Creates an absolute point from two coordinates. */
RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y);
/** Creates a point from a stringified representation.
The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate
strings is explained in the RelativeCoordinate class.
@see toString
*/
RelativePoint (const String& stringVersion);
bool operator== (const RelativePoint& other) const throw();
bool operator!= (const RelativePoint& other) const throw();
/** Calculates the absolute position of this point.
You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
be needed to calculate the result.
*/
const Point<float> resolve (const Expression::EvaluationContext* evaluationContext) const;
/** Changes the values of this point's coordinates to make it resolve to the specified position.
Calling this will leave any anchor points unchanged, but will set any absolute
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
void moveToAbsolute (const Point<float>& newPos, const Expression::EvaluationContext* evaluationContext);
/** Returns a string which represents this point.
This returns a comma-separated pair of coordinates. For details of the string syntax used by the
coordinates, see the RelativeCoordinate constructor notes.
The string that is returned can be passed to the RelativePoint constructor to recreate the point.
*/
const String toString() const;
/** Renames a symbol if it is used by any of the coordinates.
This calls RelativeCoordinate::renameAnchorIfUsed() on its X and Y coordinates.
*/
void renameSymbolIfUsed (const String& oldName, const String& newName);
/** Returns true if this point depends on any other coordinates for its position. */
bool isDynamic() const;
// The actual X and Y coords...
RelativeCoordinate x, y;
};
#endif // __JUCE_RELATIVEPOINT_JUCEHEADER__
/*** End of inlined file: juce_RelativePoint.h ***/
/*** Start of inlined file: juce_MarkerList.h ***/
#ifndef __JUCE_MARKERLIST_JUCEHEADER__
#define __JUCE_MARKERLIST_JUCEHEADER__
/**
Holds a set of named marker points along a one-dimensional axis.
This class is used to store sets of X and Y marker points in components.
@see Component::getMarkers().
*/
class JUCE_API MarkerList
{
public:
/** Creates an empty marker list. */
MarkerList();
/** Creates a copy of another marker list. */
MarkerList (const MarkerList& other);
/** Copies another marker list to this one. */
MarkerList& operator= (const MarkerList& other);
/** Destructor. */
~MarkerList();
/** Represents a marker in a MarkerList. */
class JUCE_API Marker
{
public:
/** Creates a copy of another Marker. */
Marker (const Marker& other);
/** Creates a Marker with a given name and position. */
Marker (const String& name, const RelativeCoordinate& position);
/** The marker's name. */
String name;
/** The marker's position. */
RelativeCoordinate position;
/** Returns true if both the names and positions of these two markers match. */
bool operator== (const Marker&) const throw();
/** Returns true if either the name or position of these two markers differ. */
bool operator!= (const Marker&) const throw();
};
/** Returns the number of markers in the list. */
int getNumMarkers() const throw();
/** Returns one of the markers in the list, by its index. */
const Marker* getMarker (int index) const throw();
/** Returns a named marker, or 0 if no such name is found.
Note that name comparisons are case-sensitive.
*/
const Marker* getMarker (const String& name) const throw();
/** Sets the position of a marker.
If the name already exists, then the existing marker is moved; if it doesn't exist, then a
new marker is added.
*/
void setMarker (const String& name, const RelativeCoordinate& position);
/** Deletes the marker at the given list index. */
void removeMarker (int index);
/** Deletes the marker with the given name. */
void removeMarker (const String& name);
/** Returns true if all the markers in these two lists match exactly. */
bool operator== (const MarkerList& other) const throw();
/** Returns true if not all the markers in these two lists match exactly. */
bool operator!= (const MarkerList& other) const throw();
/**
A class for receiving events when changes are made to a MarkerList.
You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener()
method, and it will be called when markers are moved, added, or deleted.
@see MarkerList::addListener, MarkerList::removeListener
*/
class JUCE_API Listener
{
public:
/** Destructor. */
virtual ~Listener() {}
/** Called when something in the given marker list changes. */
virtual void markersChanged (MarkerList* markerList) = 0;
/** Called when the given marker list is being deleted. */
virtual void markerListBeingDeleted (MarkerList* markerList);
};
/** Registers a listener that will be called when the markers are changed. */
void addListener (Listener* listener);
/** Deregisters a previously-registered listener. */
void removeListener (Listener* listener);
/** Synchronously calls markersChanged() on all the registered listeners. */
void markersHaveChanged();
/** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */
class ValueTreeWrapper
{
public:
ValueTreeWrapper (const ValueTree& state);
ValueTree& getState() throw() { return state; }
int getNumMarkers() const;
const ValueTree getMarkerState (int index) const;
const ValueTree getMarkerState (const String& name) const;
bool containsMarker (const ValueTree& state) const;
const MarkerList::Marker getMarker (const ValueTree& state) const;
void setMarker (const MarkerList::Marker& marker, UndoManager* undoManager);
void removeMarker (const ValueTree& state, UndoManager* undoManager);
void applyTo (MarkerList& markerList);
void readFrom (const MarkerList& markerList, UndoManager* undoManager);
static const Identifier markerTag, nameProperty, posProperty;
private:
ValueTree state;
};
private:
OwnedArray<Marker> markers;
ListenerList <Listener> listeners;
JUCE_LEAK_DETECTOR (MarkerList);
};
#endif // __JUCE_MARKERLIST_JUCEHEADER__
/*** End of inlined file: juce_MarkerList.h ***/
/**
Base class for Component::Positioners that are based upon relative coordinates.
*/
class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner,
public ComponentListener,
public MarkerList::Listener,
public Expression::EvaluationContext
{
public:
RelativeCoordinatePositionerBase (Component& component_);
~RelativeCoordinatePositionerBase();
const Expression getSymbolValue (const String& objectName, const String& member) const;
void componentMovedOrResized (Component&, bool, bool);
void componentParentHierarchyChanged (Component&);
void componentBeingDeleted (Component& component);
void markersChanged (MarkerList*);
void markerListBeingDeleted (MarkerList* markerList);
void apply();
bool addCoordinate (const RelativeCoordinate& coord);
bool addPoint (const RelativePoint& point);
protected:
virtual bool registerCoordinates() = 0;
virtual void applyToComponentBounds() = 0;
private:
Array <Component*> sourceComponents;
Array <MarkerList*> sourceMarkerLists;
bool registeredOk;
bool registerListeners (const Expression& e);
bool registerComponent (const String& componentID);
bool registerMarker (const String markerName);
void registerComponentListener (Component* const comp);
void registerMarkerListListener (MarkerList* const list);
void unregisterListeners();
Component* findComponent (const String& componentID) const;
Component* getSourceComponent (const String& objectName) const;
const Expression xToExpression (const Component* const source, const int x) const;
const Expression yToExpression (const Component* const source, const int y) const;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeCoordinatePositionerBase);
};
#endif // __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
/*** End of inlined file: juce_RelativeCoordinatePositioner.h ***/
/*** Start of inlined file: juce_ComponentBuilder.h ***/
#ifndef __JUCE_COMPONENTBUILDER_JUCEHEADER__
#define __JUCE_COMPONENTBUILDER_JUCEHEADER__
@ -45841,6 +46108,27 @@ protected:
Point<int> originRelativeToComponent;
#ifndef DOXYGEN
/** Internal utility class used by Drawables. */
template <class DrawableType>
class Positioner : public RelativeCoordinatePositionerBase
{
public:
Positioner (DrawableType& component_)
: RelativeCoordinatePositionerBase (component_),
owner (component_)
{}
bool registerCoordinates() { return owner.registerCoordinates (*this); }
void applyToComponentBounds() { owner.recalculateCoordinates (this); }
private:
DrawableType& owner;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner);
};
#endif
private:
void nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform);
@ -54179,8 +54467,6 @@ public:
protected:
ScopedPointer<TabbedButtonBar> tabs;
/** This creates one of the tab buttons.
If you need to use custom tab components, you can override this method and
@ -54188,15 +54474,18 @@ protected:
*/
virtual TabBarButton* createTabButton (const String& tabName, int tabIndex);
/** @internal */
ScopedPointer<TabbedButtonBar> tabs;
private:
OwnedArray <WeakReference<Component> > contentComponents;
Array <WeakReference<Component> > contentComponents;
WeakReference<Component> panelComponent;
int tabDepth;
int outlineThickness, edgeIndent;
static const Identifier deleteComponentId;
friend class TabCompButtonBar;
class ButtonBar;
friend class ButtonBar;
void changeCallback (int newCurrentTabIndex, const String& newTabName);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabbedComponent);
@ -57419,206 +57708,12 @@ private:
#endif
#ifndef __JUCE_MARKERLIST_JUCEHEADER__
/*** Start of inlined file: juce_MarkerList.h ***/
#ifndef __JUCE_MARKERLIST_JUCEHEADER__
#define __JUCE_MARKERLIST_JUCEHEADER__
/**
Holds a set of named marker points along a one-dimensional axis.
This class is used to store sets of X and Y marker points in components.
@see Component::getMarkers().
*/
class JUCE_API MarkerList
{
public:
/** Creates an empty marker list. */
MarkerList();
/** Creates a copy of another marker list. */
MarkerList (const MarkerList& other);
/** Copies another marker list to this one. */
MarkerList& operator= (const MarkerList& other);
/** Destructor. */
~MarkerList();
/** Represents a marker in a MarkerList. */
class JUCE_API Marker
{
public:
/** Creates a copy of another Marker. */
Marker (const Marker& other);
/** Creates a Marker with a given name and position. */
Marker (const String& name, const RelativeCoordinate& position);
/** The marker's name. */
String name;
/** The marker's position. */
RelativeCoordinate position;
/** Returns true if both the names and positions of these two markers match. */
bool operator== (const Marker&) const throw();
/** Returns true if either the name or position of these two markers differ. */
bool operator!= (const Marker&) const throw();
};
/** Returns the number of markers in the list. */
int getNumMarkers() const throw();
/** Returns one of the markers in the list, by its index. */
const Marker* getMarker (int index) const throw();
/** Returns a named marker, or 0 if no such name is found.
Note that name comparisons are case-sensitive.
*/
const Marker* getMarker (const String& name) const throw();
/** Sets the position of a marker.
If the name already exists, then the existing marker is moved; if it doesn't exist, then a
new marker is added.
*/
void setMarker (const String& name, const RelativeCoordinate& position);
/** Deletes the marker at the given list index. */
void removeMarker (int index);
/** Deletes the marker with the given name. */
void removeMarker (const String& name);
/** Returns true if all the markers in these two lists match exactly. */
bool operator== (const MarkerList& other) const throw();
/** Returns true if not all the markers in these two lists match exactly. */
bool operator!= (const MarkerList& other) const throw();
/**
A class for receiving events when changes are made to a MarkerList.
You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener()
method, and it will be called when markers are moved, added, or deleted.
@see MarkerList::addListener, MarkerList::removeListener
*/
class JUCE_API Listener
{
public:
/** Destructor. */
virtual ~Listener() {}
/** Called when something in the given marker list changes. */
virtual void markersChanged (MarkerList* markerList) = 0;
/** Called when the given marker list is being deleted. */
virtual void markerListBeingDeleted (MarkerList* markerList);
};
/** Registers a listener that will be called when the markers are changed. */
void addListener (Listener* listener);
/** Deregisters a previously-registered listener. */
void removeListener (Listener* listener);
/** Synchronously calls markersChanged() on all the registered listeners. */
void markersHaveChanged();
/** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */
class ValueTreeWrapper
{
public:
ValueTreeWrapper (const ValueTree& state);
ValueTree& getState() throw() { return state; }
int getNumMarkers() const;
const ValueTree getMarkerState (int index) const;
const ValueTree getMarkerState (const String& name) const;
bool containsMarker (const ValueTree& state) const;
const MarkerList::Marker getMarker (const ValueTree& state) const;
void setMarker (const MarkerList::Marker& marker, UndoManager* undoManager);
void removeMarker (const ValueTree& state, UndoManager* undoManager);
void applyTo (MarkerList& markerList);
void readFrom (const MarkerList& markerList, UndoManager* undoManager);
static const Identifier markerTag, nameProperty, posProperty;
private:
ValueTree state;
};
private:
OwnedArray<Marker> markers;
ListenerList <Listener> listeners;
JUCE_LEAK_DETECTOR (MarkerList);
};
#endif // __JUCE_MARKERLIST_JUCEHEADER__
/*** End of inlined file: juce_MarkerList.h ***/
#endif
#ifndef __JUCE_RELATIVECOORDINATE_JUCEHEADER__
#endif
#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
/*** Start of inlined file: juce_RelativeCoordinatePositioner.h ***/
#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
#define __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
/**
Base class for Component::Positioners that are based upon relative coordinates.
*/
class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner,
public ComponentListener,
public MarkerList::Listener,
public Expression::EvaluationContext
{
public:
RelativeCoordinatePositionerBase (Component& component_);
~RelativeCoordinatePositionerBase();
const Expression getSymbolValue (const String& objectName, const String& member) const;
void componentMovedOrResized (Component&, bool, bool);
void componentParentHierarchyChanged (Component&);
void componentBeingDeleted (Component& component);
void markersChanged (MarkerList*);
void markerListBeingDeleted (MarkerList* markerList);
void apply();
protected:
bool addCoordinate (const RelativeCoordinate& coord);
virtual bool registerCoordinates() = 0;
virtual void applyToComponentBounds() = 0;
private:
Array <Component*> sourceComponents;
Array <MarkerList*> sourceMarkerLists;
bool registeredOk;
bool registerListeners (const Expression& e);
bool registerComponent (const String& componentID);
bool registerMarker (const String markerName);
void registerComponentListener (Component* const comp);
void registerMarkerListListener (MarkerList* const list);
void unregisterListeners();
Component* findComponent (const String& componentID) const;
Component* getSourceComponent (const String& objectName) const;
const Expression xToExpression (const Component* const source, const int x) const;
const Expression yToExpression (const Component* const source, const int y) const;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeCoordinatePositionerBase);
};
#endif // __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
/*** End of inlined file: juce_RelativeCoordinatePositioner.h ***/
#endif
#ifndef __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__
@ -57626,78 +57721,6 @@ private:
#ifndef __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__
#define __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__
/*** Start of inlined file: juce_RelativePoint.h ***/
#ifndef __JUCE_RELATIVEPOINT_JUCEHEADER__
#define __JUCE_RELATIVEPOINT_JUCEHEADER__
/**
An X-Y position stored as a pair of RelativeCoordinate values.
@see RelativeCoordinate, RelativeRectangle
*/
class JUCE_API RelativePoint
{
public:
/** Creates a point at the origin. */
RelativePoint();
/** Creates an absolute point, relative to the origin. */
RelativePoint (const Point<float>& absolutePoint);
/** Creates an absolute point, relative to the origin. */
RelativePoint (float absoluteX, float absoluteY);
/** Creates an absolute point from two coordinates. */
RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y);
/** Creates a point from a stringified representation.
The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate
strings is explained in the RelativeCoordinate class.
@see toString
*/
RelativePoint (const String& stringVersion);
bool operator== (const RelativePoint& other) const throw();
bool operator!= (const RelativePoint& other) const throw();
/** Calculates the absolute position of this point.
You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
be needed to calculate the result.
*/
const Point<float> resolve (const Expression::EvaluationContext* evaluationContext) const;
/** Changes the values of this point's coordinates to make it resolve to the specified position.
Calling this will leave any anchor points unchanged, but will set any absolute
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
void moveToAbsolute (const Point<float>& newPos, const Expression::EvaluationContext* evaluationContext);
/** Returns a string which represents this point.
This returns a comma-separated pair of coordinates. For details of the string syntax used by the
coordinates, see the RelativeCoordinate constructor notes.
The string that is returned can be passed to the RelativePoint constructor to recreate the point.
*/
const String toString() const;
/** Renames a symbol if it is used by any of the coordinates.
This calls RelativeCoordinate::renameAnchorIfUsed() on its X and Y coordinates.
*/
void renameSymbolIfUsed (const String& oldName, const String& newName);
/** Returns true if this point depends on any other coordinates for its position. */
bool isDynamic() const;
// The actual X and Y coords...
RelativeCoordinate x, y;
};
#endif // __JUCE_RELATIVEPOINT_JUCEHEADER__
/*** End of inlined file: juce_RelativePoint.h ***/
/**
A parallelogram defined by three RelativePoint positions.
@ -57718,12 +57741,14 @@ public:
const Rectangle<float> getBounds (Expression::EvaluationContext* coordFinder) const;
void getPath (Path& path, Expression::EvaluationContext* coordFinder) const;
const AffineTransform resetToPerpendicular (Expression::EvaluationContext* coordFinder);
bool isDynamic() const;
bool operator== (const RelativeParallelogram& other) const throw();
bool operator!= (const RelativeParallelogram& other) const throw();
static const Point<float> getInternalCoordForPoint (const Point<float>* parallelogramCorners, Point<float> point) throw();
static const Point<float> getPointForInternalCoord (const Point<float>* parallelogramCorners, const Point<float>& internalPoint) throw();
static const Rectangle<float> getBoundingBox (const Point<float>* parallelogramCorners) throw();
RelativePoint topLeft, topRight, bottomLeft;
};
@ -61744,8 +61769,8 @@ protected:
@see Drawable
*/
class JUCE_API DrawableComposite : public Drawable,
public Expression::EvaluationContext
class JUCE_API DrawableComposite : public Drawable//,
// public Expression::EvaluationContext
{
public:
@ -61810,8 +61835,6 @@ public:
/** @internal */
static const Identifier valueTreeType;
/** @internal */
const Expression getSymbolValue (const String& symbol, const String& member) const;
/** @internal */
const Rectangle<float> getDrawableBounds() const;
/** @internal */
void childBoundsChanged (Component*);
@ -61853,7 +61876,10 @@ private:
MarkerList markersX, markersY;
bool updateBoundsReentrant;
void refreshTransformFromBounds();
friend class Drawable::Positioner<DrawableComposite>;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);
void updateBoundsToFitChildren();
DrawableComposite& operator= (const DrawableComposite&);
@ -61967,7 +61993,9 @@ private:
Colour overlayColour;
RelativeParallelogram bounds;
void refreshTransformFromBounds();
friend class Drawable::Positioner<DrawableImage>;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);
DrawableImage& operator= (const DrawableImage&);
JUCE_LEAK_DETECTOR (DrawableImage);
@ -62006,6 +62034,29 @@ public:
/** Destructor. */
~DrawableShape();
/** A FillType wrapper that allows the gradient coordinates to be implemented using RelativePoint.
*/
class RelativeFillType
{
public:
RelativeFillType();
RelativeFillType (const FillType& fill);
RelativeFillType (const RelativeFillType&);
RelativeFillType& operator= (const RelativeFillType&);
bool operator== (const RelativeFillType&) const;
bool operator!= (const RelativeFillType&) const;
bool isDynamic() const;
bool recalculateCoords (Expression::EvaluationContext* context);
void writeTo (ValueTree& v, ComponentBuilder::ImageProvider*, UndoManager*) const;
bool readFrom (const ValueTree& v, ComponentBuilder::ImageProvider*);
FillType fill;
RelativePoint gradientPoint1, gradientPoint2, gradientPoint3;
};
/** Sets a fill type for the path.
This colour is used to fill the path - if you don't want the path to be
filled (e.g. if you're just drawing an outline), set this to a transparent
@ -62015,20 +62066,34 @@ public:
*/
void setFill (const FillType& newFill);
/** Sets a fill type for the path.
This colour is used to fill the path - if you don't want the path to be
filled (e.g. if you're just drawing an outline), set this to a transparent
colour.
@see setPath, setStrokeFill
*/
void setFill (const RelativeFillType& newFill);
/** Returns the current fill type.
@see setFill
*/
const FillType& getFill() const throw() { return mainFill; }
const RelativeFillType& getFill() const throw() { return mainFill; }
/** Sets the fill type with which the outline will be drawn.
@see setFill
*/
void setStrokeFill (const FillType& newStrokeFill);
/** Sets the fill type with which the outline will be drawn.
@see setFill
*/
void setStrokeFill (const RelativeFillType& newStrokeFill);
/** Returns the current stroke fill.
@see setStrokeFill
*/
const FillType& getStrokeFill() const throw() { return strokeFill; }
const RelativeFillType& getStrokeFill() const throw() { return strokeFill; }
/** Changes the properties of the outline that will be drawn around the path.
If the stroke has 0 thickness, no stroke will be drawn.
@ -62042,7 +62107,7 @@ public:
void setStrokeThickness (float newThickness);
/** Returns the current outline style. */
const PathStrokeType& getStrokeType() const throw() { return strokeType; }
const PathStrokeType& getStrokeType() const throw() { return strokeType; }
/** @internal */
class FillAndStrokeState : public Drawable::ValueTreeWrapperBase
@ -62050,32 +62115,13 @@ public:
public:
FillAndStrokeState (const ValueTree& state);
const FillType getMainFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const;
ValueTree getMainFillState();
void setMainFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3,
ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager);
const FillType getStrokeFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const;
ValueTree getStrokeFillState();
void setStrokeFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3,
ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager);
ValueTree getFillState (const Identifier& fillOrStrokeType);
const RelativeFillType getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider*) const;
void setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill,
ComponentBuilder::ImageProvider*, UndoManager*);
const PathStrokeType getStrokeType() const;
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager);
static const FillType readFillType (const ValueTree& v, RelativePoint* gradientPoint1,
RelativePoint* gradientPoint2, RelativePoint* gradientPoint3,
Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider);
static void writeFillType (ValueTree& v, const FillType& fillType,
const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
const RelativePoint* gradientPoint3, ComponentBuilder::ImageProvider* imageProvider,
UndoManager* undoManager);
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager*);
static const Identifier type, colour, colours, fill, stroke, path, jointStyle, capStyle, strokeWidth,
gradientPoint1, gradientPoint2, gradientPoint3, radial, imageId, imageOpacity;
@ -62094,26 +62140,23 @@ protected:
void pathChanged();
/** Called when the cached stroke should be updated. */
void strokeChanged();
/** Implemented by subclasses to regenerate the path. */
virtual bool rebuildPath (Path& path) const = 0;
/** True if there's a stroke with a non-zero thickness and non-transparent colour. */
bool isStrokeVisible() const throw();
/** Updates the details from a FillAndStrokeState object, returning true if something changed. */
bool refreshFillTypes (const FillAndStrokeState& newState,
Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider);
void refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider*);
/** Writes the stroke and fill details to a FillAndStrokeState object. */
void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const;
void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider*, UndoManager*) const;
PathStrokeType strokeType;
Path path, strokePath;
private:
FillType mainFill, strokeFill;
class RelativePositioner;
RelativeFillType mainFill, strokeFill;
ScopedPointer<RelativeCoordinatePositionerBase> mainFillPositioner, strokeFillPositioner;
void setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill,
ScopedPointer<RelativeCoordinatePositionerBase>& positioner);
DrawableShape& operator= (const DrawableShape&);
};
@ -62184,24 +62227,24 @@ public:
int getNumControlPoints() const throw();
const RelativePoint getControlPoint (int index) const;
Value getControlPointValue (int index, UndoManager* undoManager) const;
Value getControlPointValue (int index, UndoManager*) const;
const RelativePoint getStartPoint() const;
const RelativePoint getEndPoint() const;
void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager);
float getLength (Expression::EvaluationContext* nameFinder) const;
void setControlPoint (int index, const RelativePoint& point, UndoManager*);
float getLength (Expression::EvaluationContext*) const;
ValueTreeWrapper getParent() const;
Element getPreviousElement() const;
const String getModeOfEndPoint() const;
void setModeOfEndPoint (const String& newMode, UndoManager* undoManager);
void setModeOfEndPoint (const String& newMode, UndoManager*);
void convertToLine (UndoManager* undoManager);
void convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager);
void convertToLine (UndoManager*);
void convertToCubic (Expression::EvaluationContext*, UndoManager*);
void convertToPathBreak (UndoManager* undoManager);
ValueTree insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager);
ValueTree insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext*, UndoManager*);
void removePoint (UndoManager* undoManager);
float findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder) const;
float findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext*) const;
static const Identifier mode, startSubPathElement, closeSubPathElement,
lineToElement, quadraticToElement, cubicToElement;
@ -62220,15 +62263,13 @@ public:
static const Identifier nonZeroWinding, point1, point2, point3;
};
protected:
bool rebuildPath (Path& path) const;
private:
ScopedPointer<RelativePointPath> relativePath;
class RelativePositioner;
friend class RelativePositioner;
void applyRelativePath (const RelativePointPath& newPath);
const RelativePointPath* getRelativePath() const;
void applyRelativePath (const RelativePointPath&, Expression::EvaluationContext*);
DrawablePath& operator= (const DrawablePath&);
JUCE_LEAK_DETECTOR (DrawablePath);
@ -62290,24 +62331,24 @@ public:
ValueTreeWrapper (const ValueTree& state);
const RelativeParallelogram getRectangle() const;
void setRectangle (const RelativeParallelogram& newBounds, UndoManager* undoManager);
void setRectangle (const RelativeParallelogram& newBounds, UndoManager*);
void setCornerSize (const RelativePoint& cornerSize, UndoManager* undoManager);
void setCornerSize (const RelativePoint& cornerSize, UndoManager*);
const RelativePoint getCornerSize() const;
Value getCornerSizeValue (UndoManager* undoManager) const;
Value getCornerSizeValue (UndoManager*) const;
static const Identifier topLeft, topRight, bottomLeft, cornerSize;
};
protected:
/** @internal */
bool rebuildPath (Path& path) const;
private:
friend class Drawable::Positioner<DrawableRectangle>;
RelativeParallelogram bounds;
RelativePoint cornerSize;
const AffineTransform calculateTransform() const;
void rebuildPath();
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);
DrawableRectangle& operator= (const DrawableRectangle&);
JUCE_LEAK_DETECTOR (DrawableRectangle);
@ -62425,12 +62466,17 @@ private:
RelativeParallelogram bounds;
RelativePoint fontSizeControlPoint;
Font font;
Point<float> resolvedPoints[3];
Font font, scaledFont;
String text;
Colour colour;
Justification justification;
friend class Drawable::Positioner<DrawableText>;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
void recalculateCoordinates (Expression::EvaluationContext*);
void refreshBounds();
const AffineTransform getArrangementAndTransform (GlyphArrangement& glyphs) const;
DrawableText& operator= (const DrawableText&);
JUCE_LEAK_DETECTOR (DrawableText);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -58,17 +58,14 @@ DrawableImage::~DrawableImage()
void DrawableImage::setImage (const Image& imageToUse)
{
image = imageToUse;
setBounds (imageToUse.getBounds());
if (image.isValid())
{
bounds.topLeft = RelativePoint (Point<float> (0.0f, 0.0f));
bounds.topRight = RelativePoint (Point<float> ((float) image.getWidth(), 0.0f));
bounds.bottomLeft = RelativePoint (Point<float> (0.0f, (float) image.getHeight()));
}
bounds.topLeft = RelativePoint (Point<float> (0.0f, 0.0f));
bounds.topRight = RelativePoint (Point<float> ((float) image.getWidth(), 0.0f));
bounds.bottomLeft = RelativePoint (Point<float> (0.0f, (float) image.getHeight()));
recalculateCoordinates (0);
refreshTransformFromBounds();
repaint();
}
void DrawableImage::setOpacity (const float newOpacity)
@ -83,17 +80,38 @@ void DrawableImage::setOverlayColour (const Colour& newOverlayColour)
void DrawableImage::setBoundingBox (const RelativeParallelogram& newBounds)
{
bounds = newBounds;
refreshTransformFromBounds();
if (bounds != newBounds)
{
bounds = newBounds;
if (bounds.isDynamic())
{
Drawable::Positioner<DrawableImage>* const p = new Drawable::Positioner<DrawableImage> (*this);
setPositioner (p);
p->apply();
}
else
{
setPositioner (0);
recalculateCoordinates (0);
}
}
}
//==============================================================================
void DrawableImage::refreshTransformFromBounds()
bool DrawableImage::registerCoordinates (RelativeCoordinatePositionerBase& positioner)
{
if (! image.isNull())
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.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);
}
}

View file

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

View file

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

View file

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

View file

@ -29,6 +29,8 @@ BEGIN_JUCE_NAMESPACE
#include "juce_DrawableRectangle.h"
#include "juce_DrawableComposite.h"
#include "../../components/positioning/juce_RelativeCoordinatePositioner.h"
//==============================================================================
DrawableRectangle::DrawableRectangle()
@ -36,7 +38,9 @@ DrawableRectangle::DrawableRectangle()
}
DrawableRectangle::DrawableRectangle (const DrawableRectangle& other)
: DrawableShape (other)
: DrawableShape (other),
bounds (other.bounds),
cornerSize (other.cornerSize)
{
}
@ -52,51 +56,72 @@ Drawable* DrawableRectangle::createCopy() const
//==============================================================================
void DrawableRectangle::setRectangle (const RelativeParallelogram& newBounds)
{
bounds = newBounds;
pathChanged();
strokeChanged();
if (bounds != newBounds)
{
bounds = newBounds;
rebuildPath();
}
}
void DrawableRectangle::setCornerSize (const RelativePoint& newSize)
{
cornerSize = newSize;
pathChanged();
strokeChanged();
if (cornerSize != newSize)
{
cornerSize = newSize;
rebuildPath();
}
}
//==============================================================================
bool DrawableRectangle::rebuildPath (Path& path) const
void DrawableRectangle::rebuildPath()
{
if (bounds.isDynamic() || cornerSize.isDynamic())
{
Drawable::Positioner<DrawableRectangle>* const p = new Drawable::Positioner<DrawableRectangle> (*this);
setPositioner (p);
p->apply();
}
else
{
setPositioner (0);
recalculateCoordinates (0);
}
}
bool DrawableRectangle::registerCoordinates (RelativeCoordinatePositionerBase& positioner)
{
bool ok = positioner.addPoint (bounds.topLeft);
ok = positioner.addPoint (bounds.topRight) && ok;
ok = positioner.addPoint (bounds.bottomLeft) && ok;
return positioner.addPoint (cornerSize) && ok;
}
void DrawableRectangle::recalculateCoordinates (Expression::EvaluationContext* context)
{
Point<float> points[3];
bounds.resolveThreePoints (points, getParent());
bounds.resolveThreePoints (points, context);
const float cornerSizeX = (float) cornerSize.x.resolve (context);
const float cornerSizeY = (float) cornerSize.y.resolve (context);
const float w = Line<float> (points[0], points[1]).getLength();
const float h = Line<float> (points[0], points[2]).getLength();
const float cornerSizeX = (float) cornerSize.x.resolve (getParent());
const float cornerSizeY = (float) cornerSize.y.resolve (getParent());
path.clear();
Path newPath;
if (cornerSizeX > 0 && cornerSizeY > 0)
path.addRoundedRectangle (0, 0, w, h, cornerSizeX, cornerSizeY);
newPath.addRoundedRectangle (0, 0, w, h, cornerSizeX, cornerSizeY);
else
path.addRectangle (0, 0, w, h);
newPath.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.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()));
const AffineTransform DrawableRectangle::calculateTransform() const
{
Point<float> resolved[3];
bounds.resolveThreePoints (resolved, getParent());
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

View file

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

View file

@ -50,20 +50,89 @@ 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::setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill,
ScopedPointer<RelativeCoordinatePositionerBase>& positioner)
{
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::setFill (const RelativeFillType& newFill)
{
setFillInternal (mainFill, newFill, mainFillPositioner);
}
void DrawableShape::setStrokeFill (const RelativeFillType& newFill)
{
setFillInternal (strokeFill, newFill, strokeFillPositioner);
}
void DrawableShape::setStrokeType (const PathStrokeType& newStrokeType)
{
strokeType = newStrokeType;
strokeChanged();
if (strokeType != newStrokeType)
{
strokeType = newStrokeType;
strokeChanged();
}
}
void DrawableShape::setStrokeThickness (const float newThickness)
@ -73,42 +142,19 @@ void DrawableShape::setStrokeThickness (const float newThickness)
bool DrawableShape::isStrokeVisible() const throw()
{
return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.isInvisible();
return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.fill.isInvisible();
}
bool DrawableShape::refreshFillTypes (const FillAndStrokeState& newState,
Expression::EvaluationContext* /*nameFinder*/,
ComponentBuilder::ImageProvider* imageProvider)
void DrawableShape::refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider* imageProvider)
{
bool hasChanged = false;
{
const FillType f (newState.getMainFill (getParent(), imageProvider));
if (mainFill != f)
{
hasChanged = true;
mainFill = f;
}
}
{
const FillType f (newState.getStrokeFill (getParent(), imageProvider));
if (strokeFill != f)
{
hasChanged = true;
strokeFill = f;
}
}
return hasChanged;
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();
}
@ -159,6 +204,183 @@ bool DrawableShape::hitTest (int x, int y) const
|| (isStrokeVisible() && strokePath.contains (globalX, globalY));
}
//==============================================================================
DrawableShape::RelativeFillType::RelativeFillType()
{
}
DrawableShape::RelativeFillType::RelativeFillType (const FillType& fill_)
: fill (fill_)
{
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;
}
}
DrawableShape::RelativeFillType::RelativeFillType (const RelativeFillType& other)
: fill (other.fill),
gradientPoint1 (other.gradientPoint1),
gradientPoint2 (other.gradientPoint2),
gradientPoint3 (other.gradientPoint3)
{
}
DrawableShape::RelativeFillType& DrawableShape::RelativeFillType::operator= (const RelativeFillType& other)
{
fill = other.fill;
gradientPoint1 = other.gradientPoint1;
gradientPoint2 = other.gradientPoint2;
gradientPoint3 = other.gradientPoint3;
return *this;
}
bool DrawableShape::RelativeFillType::operator== (const RelativeFillType& other) const
{
return fill == other.fill
&& ((! fill.isGradient())
|| (gradientPoint1 == other.gradientPoint1
&& gradientPoint2 == other.gradientPoint2
&& gradientPoint3 == other.gradientPoint3));
}
bool DrawableShape::RelativeFillType::operator!= (const RelativeFillType& other) const
{
return ! operator== (other);
}
bool DrawableShape::RelativeFillType::recalculateCoords (Expression::EvaluationContext* context)
{
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());
}
if (g.point1 != g1 || g.point2 != g2 || fill.transform != t)
{
g.point1 = g1;
g.point2 = g2;
fill.transform = t;
return true;
}
}
return false;
}
bool DrawableShape::RelativeFillType::isDynamic() const
{
return gradientPoint1.isDynamic() || gradientPoint2.isDynamic() || gradientPoint3.isDynamic();
}
void DrawableShape::RelativeFillType::writeTo (ValueTree& v, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const
{
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);
const ColourGradient& cg = *fill.gradient;
v.setProperty (FillAndStrokeState::radial, cg.isRadial, 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;
}
}
bool DrawableShape::RelativeFillType::readFrom (const ValueTree& v, ComponentBuilder::ImageProvider* imageProvider)
{
const String newType (v [FillAndStrokeState::type].toString());
if (newType == "solid")
{
const String colourString (v [FillAndStrokeState::colour].toString());
fill.setColour (Colour (colourString.isEmpty() ? (uint32) 0xff000000
: (uint32) colourString.getHexValue32()));
return true;
}
else if (newType == "gradient")
{
ColourGradient g;
g.isRadial = v [FillAndStrokeState::radial];
StringArray colourSteps;
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()));
fill.setGradient (g);
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 [FillAndStrokeState::imageId]);
fill.setTiledImage (im, AffineTransform::identity);
fill.setOpacity ((float) v.getProperty (FillAndStrokeState::imageOpacity, 1.0f));
return true;
}
jassertfalse;
return false;
}
//==============================================================================
const Identifier DrawableShape::FillAndStrokeState::type ("type");
const Identifier DrawableShape::FillAndStrokeState::colour ("colour");
@ -181,50 +403,28 @@ DrawableShape::FillAndStrokeState::FillAndStrokeState (const ValueTree& state_)
{
}
const FillType DrawableShape::FillAndStrokeState::getMainFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const
const DrawableShape::RelativeFillType DrawableShape::FillAndStrokeState::getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider* imageProvider) const
{
return readFillType (state.getChildWithName (fill), 0, 0, 0, nameFinder, imageProvider);
DrawableShape::RelativeFillType f;
f.readFrom (state.getChildWithName (fillOrStrokeType), imageProvider);
return f;
}
ValueTree DrawableShape::FillAndStrokeState::getMainFillState()
ValueTree DrawableShape::FillAndStrokeState::getFillState (const Identifier& fillOrStrokeType)
{
ValueTree v (state.getChildWithName (fill));
ValueTree v (state.getChildWithName (fillOrStrokeType));
if (v.isValid())
return v;
setMainFill (Colours::black, 0, 0, 0, 0, 0);
return getMainFillState();
setFill (fillOrStrokeType, FillType (Colours::black), 0, 0);
return getFillState (fillOrStrokeType);
}
void DrawableShape::FillAndStrokeState::setMainFill (const FillType& newFill, const RelativePoint* gp1, const RelativePoint* gp2,
const RelativePoint* gp3, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager)
void DrawableShape::FillAndStrokeState::setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill,
ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager)
{
ValueTree v (state.getOrCreateChildWithName (fill, undoManager));
writeFillType (v, newFill, gp1, gp2, gp3, imageProvider, undoManager);
}
const FillType DrawableShape::FillAndStrokeState::getStrokeFill (Expression::EvaluationContext* nameFinder,
ComponentBuilder::ImageProvider* imageProvider) const
{
return readFillType (state.getChildWithName (stroke), 0, 0, 0, nameFinder, imageProvider);
}
ValueTree DrawableShape::FillAndStrokeState::getStrokeFillState()
{
ValueTree v (state.getChildWithName (stroke));
if (v.isValid())
return v;
setStrokeFill (Colours::black, 0, 0, 0, 0, 0);
return getStrokeFillState();
}
void DrawableShape::FillAndStrokeState::setStrokeFill (const FillType& newFill, const RelativePoint* gp1, const RelativePoint* gp2,
const RelativePoint* gp3, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager)
{
ValueTree v (state.getOrCreateChildWithName (stroke, undoManager));
writeFillType (v, newFill, gp1, gp2, gp3, imageProvider, undoManager);
ValueTree v (state.getOrCreateChildWithName (fillOrStrokeType, undoManager));
newFill.writeTo (v, imageProvider, undoManager);
}
const PathStrokeType DrawableShape::FillAndStrokeState::getStrokeType() const
@ -250,121 +450,4 @@ void DrawableShape::FillAndStrokeState::setStrokeType (const PathStrokeType& new
? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager);
}
const FillType DrawableShape::FillAndStrokeState::readFillType (const ValueTree& v, RelativePoint* const gp1, RelativePoint* const gp2, RelativePoint* const gp3,
Expression::EvaluationContext* const nameFinder, ComponentBuilder::ImageProvider* imageProvider)
{
const String newType (v[type].toString());
if (newType == "solid")
{
const String colourString (v [colour].toString());
return FillType (Colour (colourString.isEmpty() ? (uint32) 0xff000000
: (uint32) colourString.getHexValue32()));
}
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];
StringArray colourSteps;
colourSteps.addTokens (v[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());
}
return fillType;
}
else if (newType == "image")
{
Image im;
if (imageProvider != 0)
im = imageProvider->getImageForIdentifier (v[imageId]);
FillType f (im, AffineTransform::identity);
f.setOpacity ((float) v.getProperty (imageOpacity, 1.0f));
return f;
}
jassert (! v.isValid());
return FillType();
}
namespace DrawableShapeHelpers
{
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);
}
}
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)
{
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);
v.setProperty (radial, fillType.gradient->isRadial, undoManager);
String s;
for (int i = 0; i < fillType.gradient->getNumColours(); ++i)
s << ' ' << fillType.gradient->getColourPosition (i)
<< ' ' << String::toHexString ((int) fillType.gradient->getColour(i).getARGB());
v.setProperty (colours, s.trimStart(), undoManager);
}
else if (fillType.isTiledImage())
{
v.setProperty (type, "image", undoManager);
if (imageProvider != 0)
v.setProperty (imageId, imageProvider->getIdentifierForImage (fillType.image), undoManager);
if (fillType.getOpacity() < 1.0f)
v.setProperty (imageOpacity, fillType.getOpacity(), undoManager);
else
v.removeProperty (imageOpacity, undoManager);
}
else
{
jassertfalse;
}
}
END_JUCE_NAMESPACE

View file

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

View file

@ -57,38 +57,38 @@ DrawableText::~DrawableText()
}
//==============================================================================
void DrawableText::refreshBounds()
{
setBoundsToEnclose (getDrawableBounds());
repaint();
}
void DrawableText::setText (const String& newText)
{
text = newText;
refreshBounds();
if (text != newText)
{
text = newText;
refreshBounds();
}
}
void DrawableText::setColour (const Colour& newColour)
{
colour = newColour;
repaint();
if (colour != newColour)
{
colour = newColour;
repaint();
}
}
void DrawableText::setFont (const Font& newFont, bool applySizeAndScale)
{
font = newFont;
if (applySizeAndScale)
if (font != newFont)
{
Point<float> corners[3];
bounds.resolveThreePoints (corners, getParent());
font = newFont;
setFontSizeControlPoint (RelativePoint (RelativeParallelogram::getPointForInternalCoord (corners,
Point<float> (font.getHorizontalScale() * font.getHeight(), font.getHeight()))));
if (applySizeAndScale)
{
setFontSizeControlPoint (RelativePoint (RelativeParallelogram::getPointForInternalCoord (resolvedPoints,
Point<float> (font.getHorizontalScale() * font.getHeight(), font.getHeight()))));
}
refreshBounds();
}
refreshBounds();
}
void DrawableText::setJustification (const Justification& newJustification)
@ -99,14 +99,74 @@ 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::refreshBounds()
{
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;
}
void DrawableText::recalculateCoordinates (Expression::EvaluationContext* context)
{
bounds.resolveThreePoints (resolvedPoints, context);
const float w = Line<float> (resolvedPoints[0], resolvedPoints[1]).getLength();
const float h = Line<float> (resolvedPoints[0], resolvedPoints[2]).getLength();
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());
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());
}
//==============================================================================
@ -114,32 +174,16 @@ void DrawableText::paint (Graphics& g)
{
transformContextToCorrectOrigin (g);
Point<float> points[3];
bounds.resolveThreePoints (points, getParent());
const float w = Line<float> (points[0], points[1]).getLength();
const float h = Line<float> (points[0], points[2]).getLength();
const Point<float> fontCoords (bounds.getInternalCoordForPoint (points, fontSizeControlPoint.resolve (getParent())));
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);
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);

View file

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

View file

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

View file

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