diff --git a/extras/Jucer (experimental)/Builds/Linux/Makefile b/extras/Jucer (experimental)/Builds/Linux/Makefile
index 80c31c32da..8724952953 100644
--- a/extras/Jucer (experimental)/Builds/Linux/Makefile
+++ b/extras/Jucer (experimental)/Builds/Linux/Makefile
@@ -47,6 +47,7 @@ OBJECTS := \
$(OBJDIR)/jucer_ComponentDocument.o \
$(OBJDIR)/jucer_ComponentTypeManager.o \
$(OBJDIR)/jucer_DrawableDocument.o \
+ $(OBJDIR)/jucer_DrawableTypeHandler.o \
$(OBJDIR)/jucer_NewFileWizard.o \
$(OBJDIR)/jucer_Project.o \
$(OBJDIR)/jucer_ProjectExporter.o \
@@ -113,6 +114,11 @@ $(OBJDIR)/jucer_DrawableDocument.o: ../../Source/model/Drawable/jucer_DrawableDo
@echo "Compiling jucer_DrawableDocument.cpp"
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+$(OBJDIR)/jucer_DrawableTypeHandler.o: ../../Source/model/Drawable/jucer_DrawableTypeHandler.cpp
+ -@mkdir -p $(OBJDIR)
+ @echo "Compiling jucer_DrawableTypeHandler.cpp"
+ @$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
$(OBJDIR)/jucer_NewFileWizard.o: ../../Source/model/Project/jucer_NewFileWizard.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling jucer_NewFileWizard.cpp"
diff --git a/extras/Jucer (experimental)/Builds/MacOSX/The Jucer.xcodeproj/project.pbxproj b/extras/Jucer (experimental)/Builds/MacOSX/The Jucer.xcodeproj/project.pbxproj
index 5a93e5cc50..6b46d457cd 100644
--- a/extras/Jucer (experimental)/Builds/MacOSX/The Jucer.xcodeproj/project.pbxproj
+++ b/extras/Jucer (experimental)/Builds/MacOSX/The Jucer.xcodeproj/project.pbxproj
@@ -21,6 +21,7 @@
061C981D0E9FB70DE5A3D32C = { isa = PBXBuildFile; fileRef = 829C5DA65FB46B99756428C5; };
FEDBCD721085272D356BBAEB = { isa = PBXBuildFile; fileRef = D08D9DB99315F76093CF6EE6; };
268807D7091702D29033CC27 = { isa = PBXBuildFile; fileRef = B1471E8698D193FBCF0DD13D; };
+ 91CCD0421DDD432C1C4903D4 = { isa = PBXBuildFile; fileRef = 330A51CC68AED92F7F5BEC15; };
06838545183964D8C1E60530 = { isa = PBXBuildFile; fileRef = 9DCB32BBD7053ACCB598CE79; };
048D33BDE7413EFE05D09901 = { isa = PBXBuildFile; fileRef = 4179D4C7BF616A4A3C3E11CA; };
9DA1913A62297D7111E0A6C9 = { isa = PBXBuildFile; fileRef = 48A4236550741B9D05208C60; };
@@ -84,6 +85,7 @@
E894E1F6D582678EE1F02763 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_Viewport.h; path = ../../Source/model/Component/Types/jucer_Viewport.h; sourceTree = SOURCE_ROOT; };
B1471E8698D193FBCF0DD13D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_DrawableDocument.cpp; path = ../../Source/model/Drawable/jucer_DrawableDocument.cpp; sourceTree = SOURCE_ROOT; };
739F94CA6213B43D867AB0FD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_DrawableDocument.h; path = ../../Source/model/Drawable/jucer_DrawableDocument.h; sourceTree = SOURCE_ROOT; };
+ 330A51CC68AED92F7F5BEC15 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_DrawableTypeHandler.cpp; path = ../../Source/model/Drawable/jucer_DrawableTypeHandler.cpp; sourceTree = SOURCE_ROOT; };
BDE8CD9273E1B0D0E500D283 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_DrawableTypeHandler.h; path = ../../Source/model/Drawable/jucer_DrawableTypeHandler.h; sourceTree = SOURCE_ROOT; };
9DCB32BBD7053ACCB598CE79 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_NewFileWizard.cpp; path = ../../Source/model/Project/jucer_NewFileWizard.cpp; sourceTree = SOURCE_ROOT; };
201DF0B7B4AA3E03B1AA5144 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_NewFileWizard.h; path = ../../Source/model/Project/jucer_NewFileWizard.h; sourceTree = SOURCE_ROOT; };
@@ -204,6 +206,7 @@
E70E3BE796E91EA86CFE10FE = { isa = PBXGroup; children = (
B1471E8698D193FBCF0DD13D,
739F94CA6213B43D867AB0FD,
+ 330A51CC68AED92F7F5BEC15,
BDE8CD9273E1B0D0E500D283 ); name = Drawable; sourceTree = ""; };
ADA17383E5554BCDF567AACC = { isa = PBXGroup; children = (
9DCB32BBD7053ACCB598CE79,
@@ -416,6 +419,7 @@
061C981D0E9FB70DE5A3D32C,
FEDBCD721085272D356BBAEB,
268807D7091702D29033CC27,
+ 91CCD0421DDD432C1C4903D4,
06838545183964D8C1E60530,
048D33BDE7413EFE05D09901,
9DA1913A62297D7111E0A6C9,
diff --git a/extras/Jucer (experimental)/Builds/VisualStudio2005/The Jucer.vcproj b/extras/Jucer (experimental)/Builds/VisualStudio2005/The Jucer.vcproj
index 042d820686..d90a3d7b35 100644
--- a/extras/Jucer (experimental)/Builds/VisualStudio2005/The Jucer.vcproj
+++ b/extras/Jucer (experimental)/Builds/VisualStudio2005/The Jucer.vcproj
@@ -154,6 +154,7 @@
+
diff --git a/extras/Jucer (experimental)/Builds/VisualStudio2008/The Jucer.vcproj b/extras/Jucer (experimental)/Builds/VisualStudio2008/The Jucer.vcproj
index 286e77a0f2..6a89ecf2b3 100644
--- a/extras/Jucer (experimental)/Builds/VisualStudio2008/The Jucer.vcproj
+++ b/extras/Jucer (experimental)/Builds/VisualStudio2008/The Jucer.vcproj
@@ -154,6 +154,7 @@
+
diff --git a/extras/Jucer (experimental)/Jucer.jucer b/extras/Jucer (experimental)/Jucer.jucer
index 6e4713feb0..18ffef8c3d 100644
--- a/extras/Jucer (experimental)/Jucer.jucer
+++ b/extras/Jucer (experimental)/Jucer.jucer
@@ -72,6 +72,8 @@
file="Source/model/Drawable/jucer_DrawableDocument.cpp"/>
+
diff --git a/extras/Jucer (experimental)/Source/jucer_Headers.h b/extras/Jucer (experimental)/Source/jucer_Headers.h
index 4e04d2e3ec..41f17c12eb 100644
--- a/extras/Jucer (experimental)/Source/jucer_Headers.h
+++ b/extras/Jucer (experimental)/Source/jucer_Headers.h
@@ -134,6 +134,7 @@ namespace Ids
DECLARE_ID (resource);
DECLARE_ID (className);
DECLARE_ID (classDesc);
+ DECLARE_ID (controlPoint);
const Identifier class_ ("class");
const Identifier id_ ("id");
}
diff --git a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp
index 64216fce73..370756f969 100644
--- a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp
+++ b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp
@@ -27,80 +27,6 @@
#include "jucer_DrawableTypeHandler.h"
-//==============================================================================
-class DrawableTypeManager : public DeletedAtShutdown
-{
-public:
- DrawableTypeManager()
- {
- handlers.add (new DrawablePathHandler());
- handlers.add (new DrawableImageHandler());
- handlers.add (new DrawableCompositeHandler());
- }
-
- ~DrawableTypeManager()
- {
- }
-
- juce_DeclareSingleton_SingleThreaded_Minimal (DrawableTypeManager);
-
- //==============================================================================
- int getNumHandlers() const { return handlers.size(); }
- DrawableTypeHandler* getHandler (const int index) const { return handlers[index]; }
-
- DrawableTypeHandler* getHandlerFor (const Identifier& type)
- {
- for (int i = handlers.size(); --i >= 0;)
- if (handlers.getUnchecked(i)->getValueTreeType() == type)
- return handlers.getUnchecked(i);
-
- jassertfalse;
- return 0;
- }
-
-private:
- OwnedArray handlers;
-};
-
-juce_ImplementSingleton_SingleThreaded (DrawableTypeManager);
-
-
-//==============================================================================
-DrawableTypeInstance::DrawableTypeInstance (DrawableDocument& document_, const ValueTree& state_)
- : document (document_), state (state_)
-{
-}
-
-Value DrawableTypeInstance::getValue (const Identifier& name) const
-{
- return state.getPropertyAsValue (name, document.getUndoManager());
-}
-
-void DrawableTypeInstance::createProperties (Array & props)
-{
- props.add (new TextPropertyComponent (getValue (Drawable::ValueTreeWrapperBase::idProperty), "Object ID", 128, false));
-
- getHandler()->createPropertyEditors (*this, props);
-}
-
-DrawableTypeHandler* DrawableTypeInstance::getHandler() const
-{
- DrawableTypeHandler* h = DrawableTypeManager::getInstance()->getHandlerFor (state.getType());
- jassert (h != 0);
- return h;
-}
-
-void DrawableTypeInstance::setBounds (Drawable* drawable, const Rectangle& newBounds)
-{
- return getHandler()->setBounds (*this, drawable, newBounds);
-}
-
-void DrawableTypeInstance::getAllControlPoints (Array & points)
-{
- return getHandler()->getAllControlPoints (*this, points);
-}
-
-
//==============================================================================
namespace Tags
{
@@ -158,12 +84,6 @@ void DrawableDocument::checkRootObject()
if (markersY == 0)
markersY = new MarkerList (*this, false);
-/* if ((int) getCanvasWidth().getValue() <= 0)
- getCanvasWidth() = 500;
-
- if ((int) getCanvasHeight().getValue() <= 0)
- getCanvasHeight() = 500;
-*/
DrawableComposite::ValueTreeWrapper rootObject (getRootDrawableNode());
recursivelyUpdateIDs (rootObject);
}
@@ -325,35 +245,30 @@ const int menuItemOffset = 0x63451fa4;
void DrawableDocument::addNewItemMenuItems (PopupMenu& menu) const
{
- DrawableTypeManager* const typeMan = DrawableTypeManager::getInstance();
+ const StringArray newItems (DrawableTypeManager::getInstance()->getNewItemList());
- for (int i = 0; i < typeMan->getNumHandlers(); ++i)
- if (typeMan->getHandler(i)->canBeCreated)
- menu.addItem (i + menuItemOffset, "New " + typeMan->getHandler(i)->getDisplayName());
+ for (int i = 0; i < newItems.size(); ++i)
+ menu.addItem (i + menuItemOffset, newItems[i]);
}
const ValueTree DrawableDocument::performNewItemMenuItem (int menuResultCode)
{
- DrawableTypeManager* const typeMan = DrawableTypeManager::getInstance();
+ const StringArray newItems (DrawableTypeManager::getInstance()->getNewItemList());
- if (menuResultCode >= menuItemOffset && menuResultCode < menuItemOffset + typeMan->getNumHandlers())
+ int index = menuResultCode - menuItemOffset;
+ if (index >= 0 && index < newItems.size())
{
- DrawableTypeHandler* handler = typeMan->getHandler (menuResultCode - menuItemOffset);
- jassert (handler != 0);
+ ValueTree state (DrawableTypeManager::getInstance()
+ ->createNewItem (index, *this,
+ Point (Random::getSystemRandom().nextFloat() * 100.0f + 100.0f,
+ Random::getSystemRandom().nextFloat() * 100.0f + 100.0f)));
- if (handler != 0)
- {
- ValueTree state (handler->createNewInstance (*this,
- Point (Random::getSystemRandom().nextFloat() * 100.0f + 100.0f,
- Random::getSystemRandom().nextFloat() * 100.0f + 100.0f)));
+ Drawable::ValueTreeWrapperBase wrapper (state);
+ recursivelyUpdateIDs (wrapper);
- Drawable::ValueTreeWrapperBase wrapper (state);
- recursivelyUpdateIDs (wrapper);
+ getRootDrawableNode().addDrawable (state, -1, getUndoManager());
- getRootDrawableNode().addDrawable (state, -1, getUndoManager());
-
- return state;
- }
+ return state;
}
return ValueTree::invalid;
@@ -391,23 +306,11 @@ const RelativeCoordinate DrawableDocument::findNamedCoordinate (const String& ob
{
if (objectName == "parent")
{
-// if (edge == "right") return RelativeCoordinate ((double) getCanvasWidth().getValue(), true);
- // if (edge == "bottom") return RelativeCoordinate ((double) getCanvasHeight().getValue(), false);
+ jassert (edge != "right" && edge != "bottom"); // drawables don't have a canvas size..
}
if (objectName.isNotEmpty() && edge.isNotEmpty())
{
-/* const ValueTree comp (getComponentWithMemberName (compName));
-
- if (comp.isValid())
- {
- const RelativeRectangle coords (getCoordsFor (comp));
-
- if (edge == RelativeCoordinate::leftName) return coords.left;
- if (edge == "right") return coords.right;
- if (edge == "top") return coords.top;
- if (edge == "bottom") return coords.bottom;
- }*/
}
{
@@ -473,8 +376,7 @@ const RelativeCoordinate DrawableDocument::MarkerList::findNamedCoordinate (cons
{
if (objectName == "parent")
{
-// if (edge == "right") return RelativeCoordinate ((double) document.getCanvasWidth().getValue(), true);
- // if (edge == "bottom") return RelativeCoordinate ((double) document.getCanvasHeight().getValue(), false);
+ jassert (edge != "right" && edge != "bottom"); // drawables don't have a canvas size..
}
const ValueTree marker (getMarkerNamed (objectName));
diff --git a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.cpp b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.cpp
new file mode 100644
index 0000000000..f4dc27cfff
--- /dev/null
+++ b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.cpp
@@ -0,0 +1,491 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-10 by Raw Material Software Ltd.
+
+ ------------------------------------------------------------------------------
+
+ JUCE can be redistributed and/or modified under the terms of the GNU General
+ Public License (Version 2), as published by the Free Software Foundation.
+ A copy of the license is included in the JUCE distribution, or can be found
+ online at www.gnu.org/licenses.
+
+ JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.rawmaterialsoftware.com/juce for more information.
+
+ ==============================================================================
+*/
+
+#include "jucer_DrawableTypeHandler.h"
+
+
+//==============================================================================
+class DrawablePathHandler : public DrawableTypeHandler
+{
+public:
+ DrawablePathHandler() : DrawableTypeHandler ("Polygon", DrawablePath::valueTreeType) {}
+ ~DrawablePathHandler() {}
+
+ static const ValueTree createNewPath (DrawableDocument& document, const Path& p)
+ {
+ DrawablePath dp;
+ dp.setPath (p);
+ dp.setFill (Colours::lightblue.withHue (Random::getSystemRandom().nextFloat()));
+ return dp.createValueTree (0);
+ }
+
+ static const ValueTree createNewTriangle (DrawableDocument& document, const Point& approxPosition)
+ {
+ Path p;
+ p.addTriangle (approxPosition.getX(), approxPosition.getY() - 50.0f,
+ approxPosition.getX() + 50.0f, approxPosition.getY() + 20.0f,
+ approxPosition.getX() - 50.0f, approxPosition.getY() + 20.0f);
+
+ return createNewPath (document, p);
+ }
+
+ static const ValueTree createNewRectangle (DrawableDocument& document, const Point& approxPosition)
+ {
+ Path p;
+ p.addRectangle (approxPosition.getX() - 50.0f, approxPosition.getY() - 50.0f,
+ 100.0f, 100.0f);
+
+ return createNewPath (document, p);
+ }
+
+ static const ValueTree createNewEllipse (DrawableDocument& document, const Point& approxPosition)
+ {
+ Path p;
+ p.addEllipse (approxPosition.getX() - 50.0f, approxPosition.getY() - 50.0f,
+ 100.0f, 100.0f);
+
+ return createNewPath (document, p);
+ }
+
+ class DrawablePathFillPropComp : public FillTypePropertyComponent
+ {
+ public:
+ DrawablePathFillPropComp (DrawableTypeInstance& item_, const String& name, const ValueTree& fill)
+ : FillTypePropertyComponent (item_.getDocument().getUndoManager(), name, fill),
+ item (item_)
+ {}
+
+ const ColourGradient getDefaultGradient()
+ {
+ const Rectangle bounds (item.getBounds());
+
+ return ColourGradient (Colours::blue,
+ bounds.getX() + bounds.getWidth() * 0.3f,
+ bounds.getY() + bounds.getHeight() * 0.3f,
+ Colours::red,
+ bounds.getX() + bounds.getWidth() * 0.7f,
+ bounds.getY() + bounds.getHeight() * 0.7f,
+ false);
+ }
+
+ private:
+ DrawableTypeInstance item;
+ };
+
+ void createPropertyEditors (DrawableTypeInstance& item, Array & props)
+ {
+ DrawablePath::ValueTreeWrapper wrapper (item.getState());
+
+ props.add (new DrawablePathFillPropComp (item, "Fill", wrapper.getMainFillState()));
+ props.add (new DrawablePathFillPropComp (item, "Stroke", wrapper.getStrokeFillState()));
+ }
+
+ void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item)
+ {
+ }
+
+ //==============================================================================
+ class GradientControlPoint : public ControlPoint
+ {
+ public:
+ GradientControlPoint (const ValueTree& item_,
+ const bool isStart_, const bool isStroke_)
+ : item (item_), isStart (isStart_), isStroke (isStroke_)
+ {}
+
+ ~GradientControlPoint() {}
+
+ const RelativePoint getPosition()
+ {
+ DrawablePath::ValueTreeWrapper wrapper (item);
+
+ RelativePoint p;
+ const FillType fill (Drawable::ValueTreeWrapperBase::readFillType (isStroke ? wrapper.getStrokeFillState() : wrapper.getMainFillState(),
+ isStart ? &p : 0,
+ isStart ? 0 : &p, 0));
+ jassert (fill.isGradient());
+ return p;
+ }
+
+ void setPosition (const RelativePoint& newPoint, UndoManager* undoManager)
+ {
+ DrawablePath::ValueTreeWrapper wrapper (item);
+
+ RelativePoint p1, p2;
+ ValueTree fillState (isStroke ? wrapper.getStrokeFillState() : wrapper.getMainFillState());
+ const FillType fill (Drawable::ValueTreeWrapperBase::readFillType (fillState, &p1, &p2, 0));
+ jassert (fill.isGradient());
+
+ if (isStart)
+ p1 = newPoint;
+ else
+ p2 = newPoint;
+
+ Drawable::ValueTreeWrapperBase::writeFillType (fillState, fill, &p1, &p2, undoManager);
+ }
+
+ bool hasLine() { return false; }
+ RelativePoint getEndOfLine() { return RelativePoint(); }
+
+ private:
+ ValueTree item;
+ bool isStart, isStroke;
+ };
+
+ //==============================================================================
+ class PathControlPoint : public ControlPoint
+ {
+ public:
+ PathControlPoint (const DrawablePath::ValueTreeWrapper::Element& element_, const int cpNum_)
+ : element (element_), cpNum (cpNum_)
+ {}
+
+ ~PathControlPoint() {}
+
+ const RelativePoint getPosition()
+ {
+ return element.getControlPoint (cpNum);
+ }
+
+ void setPosition (const RelativePoint& newPoint, UndoManager* undoManager)
+ {
+ element.setControlPoint (cpNum, newPoint, undoManager);
+ }
+
+ bool hasLine() { return false; }
+ RelativePoint getEndOfLine() { return RelativePoint(); }
+
+ private:
+ DrawablePath::ValueTreeWrapper::Element element;
+ int cpNum;
+ };
+
+ void getAllControlPoints (DrawableTypeInstance& item, OwnedArray & points)
+ {
+ DrawablePath::ValueTreeWrapper wrapper (item.getState());
+
+ const ValueTree pathTree (wrapper.getPathState());
+ const int numElements = pathTree.getNumChildren();
+
+ for (int i = 0; i < numElements; ++i)
+ {
+ const DrawablePath::ValueTreeWrapper::Element e (pathTree.getChild(i));
+ const int numCps = e.getNumControlPoints();
+
+ for (int j = 0; j < numCps; ++j)
+ points.add (new PathControlPoint (e, j));
+ }
+
+ const FillType fill (Drawable::ValueTreeWrapperBase::readFillType (wrapper.getMainFillState(), 0, 0, 0));
+
+ if (fill.isGradient())
+ {
+ points.add (new GradientControlPoint (item.getState(), true, false));
+ points.add (new GradientControlPoint (item.getState(), false, false));
+ }
+
+ const FillType stroke (Drawable::ValueTreeWrapperBase::readFillType (wrapper.getStrokeFillState(), 0, 0, 0));
+
+ if (stroke.isGradient())
+ {
+ points.add (new GradientControlPoint (item.getState(), true, true));
+ points.add (new GradientControlPoint (item.getState(), false, true));
+ }
+ }
+};
+
+//==============================================================================
+class DrawableImageHandler : public DrawableTypeHandler
+{
+public:
+ DrawableImageHandler() : DrawableTypeHandler ("Image", DrawableImage::valueTreeType) {}
+ ~DrawableImageHandler() {}
+
+ static const ValueTree createNewInstance (DrawableDocument& document, const Point& approxPosition)
+ {
+ Image tempImage (Image::ARGB, 100, 100, true);
+
+ {
+ Graphics g (tempImage);
+ g.fillAll (Colours::grey.withAlpha (0.3f));
+ g.setColour (Colours::red);
+ g.setFont (40.0f);
+ g.drawText ("?", 0, 0, 100, 100, Justification::centred, false);
+ }
+
+ DrawableImage di;
+ di.setTransform (RelativePoint (approxPosition),
+ RelativePoint (approxPosition + Point (100.0f, 0.0f)),
+ RelativePoint (approxPosition + Point (0.0f, 100.0f)));
+ return di.createValueTree (&document);
+ }
+
+ void createPropertyEditors (DrawableTypeInstance& item, Array & props)
+ {
+ }
+
+ void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item)
+ {
+ }
+
+ //==============================================================================
+ class ImageControlPoint : public ControlPoint
+ {
+ public:
+ ImageControlPoint (const DrawableTypeInstance& item_, const int cpNum_)
+ : item (item_), cpNum (cpNum_)
+ {}
+
+ ~ImageControlPoint() {}
+
+ const RelativePoint getPosition()
+ {
+ DrawableImage::ValueTreeWrapper wrapper (item.getState());
+
+ switch (cpNum)
+ {
+ case 0: return wrapper.getTargetPositionForTopLeft();
+ case 1: return wrapper.getTargetPositionForTopRight();
+ case 2: return wrapper.getTargetPositionForBottomLeft();
+ default: jassertfalse; break;
+ }
+
+ return RelativePoint();
+ }
+
+ void setPosition (const RelativePoint& newPoint, UndoManager* undoManager)
+ {
+ DrawableImage::ValueTreeWrapper wrapper (item.getState());
+
+ switch (cpNum)
+ {
+ case 0: wrapper.setTargetPositionForTopLeft (newPoint, undoManager); break;
+ case 1: wrapper.setTargetPositionForTopRight (newPoint, undoManager); break;
+ case 2: wrapper.setTargetPositionForBottomLeft (newPoint, undoManager); break;
+ default: jassertfalse; break;
+ }
+ }
+
+ bool hasLine() { return false; }
+ RelativePoint getEndOfLine() { return RelativePoint(); }
+
+ private:
+ DrawableTypeInstance item;
+ int cpNum;
+ };
+
+ void getAllControlPoints (DrawableTypeInstance& item, OwnedArray & points)
+ {
+ for (int i = 0; i < 3; ++i)
+ points.add (new ImageControlPoint (item, i));
+ }
+};
+
+//==============================================================================
+class DrawableCompositeHandler : public DrawableTypeHandler
+{
+public:
+ DrawableCompositeHandler() : DrawableTypeHandler ("Group", DrawableComposite::valueTreeType) {}
+ ~DrawableCompositeHandler() {}
+
+ void createPropertyEditors (DrawableTypeInstance& item, Array & props)
+ {
+ }
+
+ void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item)
+ {
+ }
+
+ const RelativeCoordinate findNamedCoordinate (const DrawableTypeInstance& item, const String& objectName, const String& edge) const
+ {
+ DrawableComposite::ValueTreeWrapper wrapper (const_cast (item).getState());
+
+ ValueTree markerState (wrapper.getMarkerState (true, objectName));
+ if (markerState.isValid())
+ return wrapper.getMarker (true, markerState).position;
+
+ markerState = wrapper.getMarkerState (false, objectName);
+ if (markerState.isValid())
+ return wrapper.getMarker (false, markerState).position;
+
+ return RelativeCoordinate();
+ }
+
+ //==============================================================================
+ class CompositeControlPoint : public ControlPoint
+ {
+ public:
+ CompositeControlPoint (const ValueTree& item_, const int cpNum_)
+ : item (item_), cpNum (cpNum_)
+ {}
+
+ ~CompositeControlPoint() {}
+
+ const RelativePoint getPosition()
+ {
+ DrawableComposite::ValueTreeWrapper wrapper (item);
+
+ switch (cpNum)
+ {
+ case 0: return wrapper.getTargetPositionForOrigin();
+ case 1: return wrapper.getTargetPositionForX1Y0();
+ case 2: return wrapper.getTargetPositionForX0Y1();
+ default: jassertfalse; break;
+ }
+
+ return RelativePoint();
+ }
+
+ void setPosition (const RelativePoint& newPoint, UndoManager* undoManager)
+ {
+ DrawableComposite::ValueTreeWrapper wrapper (item);
+
+ switch (cpNum)
+ {
+ case 0: wrapper.setTargetPositionForOrigin (newPoint, undoManager); break;
+ case 1: wrapper.setTargetPositionForX1Y0 (newPoint, undoManager); break;
+ case 2: wrapper.setTargetPositionForX0Y1 (newPoint, undoManager); break;
+ default: jassertfalse; break;
+ }
+ }
+
+ bool hasLine() { return false; }
+ RelativePoint getEndOfLine() { return RelativePoint(); }
+
+ private:
+ ValueTree item;
+ int cpNum;
+ };
+
+ void getAllControlPoints (DrawableTypeInstance& item, OwnedArray & points)
+ {
+ for (int i = 0; i < 3; ++i)
+ points.add (new CompositeControlPoint (item.getState(), i));
+ }
+};
+
+
+//==============================================================================
+DrawableTypeManager::DrawableTypeManager()
+{
+ handlers.add (new DrawablePathHandler());
+ handlers.add (new DrawableImageHandler());
+ handlers.add (new DrawableCompositeHandler());
+}
+
+DrawableTypeManager::~DrawableTypeManager()
+{
+}
+
+DrawableTypeHandler* DrawableTypeManager::getHandlerFor (const Identifier& type)
+{
+ for (int i = handlers.size(); --i >= 0;)
+ if (handlers.getUnchecked(i)->getValueTreeType() == type)
+ return handlers.getUnchecked(i);
+
+ jassertfalse;
+ return 0;
+}
+
+const StringArray DrawableTypeManager::getNewItemList()
+{
+ const char* types[] = { "New Triangle", "New Rectangle", "New Ellipse", "New Image", 0 };
+ return StringArray (types);
+}
+
+const ValueTree DrawableTypeManager::createNewItem (const int index, DrawableDocument& document, const Point& approxPosition)
+{
+ switch (index)
+ {
+ case 0: return DrawablePathHandler::createNewTriangle (document, approxPosition);
+ case 1: return DrawablePathHandler::createNewRectangle (document, approxPosition);
+ case 2: return DrawablePathHandler::createNewEllipse (document, approxPosition);
+ case 3: return DrawableImageHandler::createNewInstance (document, approxPosition);
+ default: jassertfalse; break;
+ }
+
+ return ValueTree::invalid;
+}
+
+juce_ImplementSingleton_SingleThreaded (DrawableTypeManager);
+
+
+//==============================================================================
+DrawableTypeInstance::DrawableTypeInstance (DrawableDocument& document_, const ValueTree& state_)
+ : document (document_), state (state_)
+{
+}
+
+Value DrawableTypeInstance::getValue (const Identifier& name) const
+{
+ return state.getPropertyAsValue (name, document.getUndoManager());
+}
+
+void DrawableTypeInstance::createProperties (Array & props)
+{
+ props.add (new TextPropertyComponent (getValue (Drawable::ValueTreeWrapperBase::idProperty), "Object ID", 128, false));
+
+ getHandler()->createPropertyEditors (*this, props);
+}
+
+DrawableTypeHandler* DrawableTypeInstance::getHandler() const
+{
+ DrawableTypeHandler* h = DrawableTypeManager::getInstance()->getHandlerFor (state.getType());
+ jassert (h != 0);
+ return h;
+}
+
+const RelativeCoordinate DrawableTypeInstance::findNamedCoordinate (const String& objectName, const String& edge) const
+{
+ return getHandler()->findNamedCoordinate (*this, objectName, edge);
+}
+
+const Rectangle DrawableTypeInstance::getBounds()
+{
+ OwnedArray points;
+ getAllControlPoints (points);
+
+ if (points.size() < 2)
+ return Rectangle();
+
+ DrawableTypeInstance parent (document, state.getParent());
+ const Point p1 (points.getUnchecked(0)->getPosition().resolve (&parent));
+ Rectangle r (p1, points.getUnchecked(1)->getPosition().resolve (&parent));
+
+ for (int i = 2; i < points.size(); ++i)
+ r = r.getUnion (Rectangle (p1, points.getUnchecked(i)->getPosition().resolve (&parent)));
+
+ return r;
+}
+
+void DrawableTypeInstance::setBounds (Drawable* drawable, const Rectangle& newBounds)
+{
+ return getHandler()->setBounds (*this, drawable, newBounds);
+}
+
+void DrawableTypeInstance::getAllControlPoints (OwnedArray & points)
+{
+ return getHandler()->getAllControlPoints (*this, points);
+}
diff --git a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h
index f296275357..e4b9b828fd 100644
--- a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h
+++ b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h
@@ -30,9 +30,22 @@
#include "../../utility/jucer_FillTypePropertyComponent.h"
class DrawableTypeHandler;
+//==============================================================================
+class ControlPoint
+{
+public:
+ ControlPoint() {}
+ virtual ~ControlPoint() {}
+
+ virtual const RelativePoint getPosition() = 0;
+ virtual void setPosition (const RelativePoint& newPoint, UndoManager* undoManager) = 0;
+
+ virtual bool hasLine() = 0;
+ virtual RelativePoint getEndOfLine() = 0;
+};
//==============================================================================
-class DrawableTypeInstance
+class DrawableTypeInstance : public RelativeCoordinate::NamedCoordinateFinder
{
public:
DrawableTypeInstance (DrawableDocument& document_, const ValueTree& state_);
@@ -43,8 +56,11 @@ public:
Value getValue (const Identifier& name) const;
void createProperties (Array & props);
+ const Rectangle getBounds();
void setBounds (Drawable* drawable, const Rectangle& newBounds);
- void getAllControlPoints (Array & points);
+ void getAllControlPoints (OwnedArray & points);
+
+ const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const;
//==============================================================================
DrawableTypeHandler* getHandler() const;
@@ -61,31 +77,26 @@ private:
class DrawableTypeHandler
{
public:
- DrawableTypeHandler (const String& displayName_, const Identifier& valueTreeType_, bool canBeCreated_)
- : displayName (displayName_), valueTreeType (valueTreeType_), canBeCreated (canBeCreated_)
+ DrawableTypeHandler (const String& displayName_, const Identifier& valueTreeType_)
+ : displayName (displayName_), valueTreeType (valueTreeType_)
{
}
virtual ~DrawableTypeHandler() {}
- virtual const ValueTree createNewInstance (DrawableDocument& document, const Point& approxPosition) = 0;
virtual void createPropertyEditors (DrawableTypeInstance& item, Array & props) = 0;
virtual void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item) = 0;
- virtual void setBounds (DrawableTypeInstance& item, Drawable* drawable, const Rectangle& newBounds) = 0;
- virtual void getAllControlPoints (DrawableTypeInstance& item, Array & points) = 0;
+ virtual void getAllControlPoints (DrawableTypeInstance& item, OwnedArray & points) = 0;
+ virtual const RelativeCoordinate findNamedCoordinate (const DrawableTypeInstance& item, const String& objectName, const String& edge) const { return RelativeCoordinate(); }
const String& getDisplayName() const { return displayName; }
const Identifier& getValueTreeType() const { return valueTreeType; }
- const bool canBeCreated;
-
-protected:
- static bool rescalePoints (RelativePoint* const points, const int numPoints,
- const Rectangle& oldBounds, Rectangle newBounds,
- RelativeCoordinate::NamedCoordinateFinder* nameFinder)
+ void setBounds (DrawableTypeInstance& item, Drawable* drawable, Rectangle newBounds)
{
+ const Rectangle oldBounds (drawable->getBounds());
if (oldBounds.isEmpty())
- return false;
+ return;
newBounds.setSize (jmax (1.0f, newBounds.getWidth()),
jmax (1.0f, newBounds.getHeight()));
@@ -101,20 +112,28 @@ protected:
if (xScale == 1.0 && yScale == 1.0
&& std::abs (newBounds.getX() - oldBounds.getX()) < tolerance
&& std::abs (newBounds.getY() - oldBounds.getY()) < tolerance)
- return false;
+ return;
const double xOffset = newBounds.getX() - xScale * oldBounds.getX();
const double yOffset = newBounds.getY() - yScale * oldBounds.getY();
- for (int i = 0; i < numPoints; ++i)
+ OwnedArray points;
+ getAllControlPoints (item, points);
+
+ RelativeCoordinate::NamedCoordinateFinder* const nameFinder = drawable->getParent();
+ UndoManager* undoManager = item.getDocument().getUndoManager();
+
+ for (int i = 0; i < points.size(); ++i)
{
- const Point p (points[i].resolve (nameFinder));
+ ControlPoint* cp = points.getUnchecked(i);
+ RelativePoint point (cp->getPosition());
+ const Point p (point.resolve (nameFinder));
- points[i].moveToAbsolute (Point ((float) (xOffset + xScale * p.getX()),
- (float) (yOffset + yScale * p.getY())), nameFinder);
+ point.moveToAbsolute (Point ((float) (xOffset + xScale * p.getX()),
+ (float) (yOffset + yScale * p.getY())), nameFinder);
+
+ cp->setPosition (point, undoManager);
}
-
- return true;
}
private:
@@ -124,200 +143,28 @@ private:
DrawableTypeHandler& operator= (const DrawableTypeHandler&);
};
-//==============================================================================
-class DrawablePathHandler : public DrawableTypeHandler
-{
-public:
- DrawablePathHandler() : DrawableTypeHandler ("Polygon", DrawablePath::valueTreeType, true) {}
- ~DrawablePathHandler() {}
-
- const ValueTree createNewInstance (DrawableDocument& document, const Point& approxPosition)
- {
- Path p;
- p.addTriangle (approxPosition.getX(), approxPosition.getY() - 50.0f,
- approxPosition.getX() + 50.0f, approxPosition.getY() + 20.0f,
- approxPosition.getX() - 50.0f, approxPosition.getY() + 20.0f);
-
- DrawablePath dp;
- dp.setPath (p);
- dp.setFill (Colours::lightblue.withHue (Random::getSystemRandom().nextFloat()));
- return dp.createValueTree (0);
- }
-
- void createPropertyEditors (DrawableTypeInstance& item, Array & props)
- {
- DrawablePath::ValueTreeWrapper wrapper (item.getState());
-
- props.add (new FillTypePropertyComponent (item.getDocument().getUndoManager(),
- "Fill", wrapper.getMainFillState()));
-
- props.add (new FillTypePropertyComponent (item.getDocument().getUndoManager(),
- "Stroke", wrapper.getStrokeFillState()));
- }
-
- void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item)
- {
- }
-
- void setBounds (DrawableTypeInstance& item, Drawable* drawable, const Rectangle& newBounds)
- {
- DrawablePath::ValueTreeWrapper wrapper (item.getState());
-
- RelativePointPath path;
- wrapper.getPath (path);
-
- Array points;
- int i;
- for (i = 0; i < path.elements.size(); ++i)
- {
- int numPoints;
- RelativePoint* elementPoints = path.elements.getUnchecked(i)->getControlPoints (numPoints);
-
- for (int j = 0; j < numPoints; ++j)
- points.add (elementPoints[j]);
- }
-
- if (rescalePoints (points.getRawDataPointer(), points.size(),
- drawable->getBounds(), newBounds, drawable->getParent()))
- {
- int n = 0;
- for (i = 0; i < path.elements.size(); ++i)
- {
- int numPoints;
- RelativePoint* elementPoints = path.elements.getUnchecked(i)->getControlPoints (numPoints);
-
- for (int j = 0; j < numPoints; ++j)
- elementPoints[j] = points [n++];
- }
-
- wrapper.setPath (path.toString(), item.getDocument().getUndoManager());
- }
- }
-
- void getAllControlPoints (DrawableTypeInstance& item, Array & points)
- {
- DrawablePath::ValueTreeWrapper wrapper (item.getState());
-
- RelativePointPath path;
- wrapper.getPath (path);
-
- for (int i = 0; i < path.elements.size(); ++i)
- {
- int numPoints;
- RelativePoint* elementPoints = path.elements.getUnchecked(i)->getControlPoints (numPoints);
-
- for (int j = 0; j < numPoints; ++j)
- points.add (elementPoints[j]);
- }
- }
-};
//==============================================================================
-class DrawableImageHandler : public DrawableTypeHandler
+class DrawableTypeManager : public DeletedAtShutdown
{
public:
- DrawableImageHandler() : DrawableTypeHandler ("Image", DrawableImage::valueTreeType, true) {}
- ~DrawableImageHandler() {}
+ DrawableTypeManager();
+ ~DrawableTypeManager();
- const ValueTree createNewInstance (DrawableDocument& document, const Point& approxPosition)
- {
- Image tempImage (Image::ARGB, 100, 100, true);
+ juce_DeclareSingleton_SingleThreaded_Minimal (DrawableTypeManager);
- {
- Graphics g (tempImage);
- g.fillAll (Colours::grey.withAlpha (0.3f));
- g.setColour (Colours::red);
- g.setFont (40.0f);
- g.drawText ("?", 0, 0, 100, 100, Justification::centred, false);
- }
+ //==============================================================================
+ int getNumHandlers() const { return handlers.size(); }
+ DrawableTypeHandler* getHandler (const int index) const { return handlers [index]; }
- DrawableImage di;
- di.setTransform (RelativePoint (approxPosition),
- RelativePoint (approxPosition + Point (100.0f, 0.0f)),
- RelativePoint (approxPosition + Point (0.0f, 100.0f)));
- return di.createValueTree (&document);
- }
+ DrawableTypeHandler* getHandlerFor (const Identifier& type);
- void createPropertyEditors (DrawableTypeInstance& item, Array & props)
- {
- }
+ const StringArray getNewItemList();
+ const ValueTree createNewItem (const int index, DrawableDocument& document, const Point& approxPosition);
- void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item)
- {
- }
-
- void setBounds (DrawableTypeInstance& item, Drawable* drawable, const Rectangle& newBounds)
- {
- DrawableImage::ValueTreeWrapper wrapper (item.getState());
-
- RelativePoint points[3] = { wrapper.getTargetPositionForTopLeft(),
- wrapper.getTargetPositionForTopRight(),
- wrapper.getTargetPositionForBottomLeft() };
-
- if (rescalePoints (points, 3, drawable->getBounds(), newBounds, drawable->getParent()))
- {
- UndoManager* undoManager = item.getDocument().getUndoManager();
- wrapper.setTargetPositionForTopLeft (points[0], undoManager);
- wrapper.setTargetPositionForTopRight (points[1], undoManager);
- wrapper.setTargetPositionForBottomLeft (points[2], undoManager);
- }
- }
-
- void getAllControlPoints (DrawableTypeInstance& item, Array & points)
- {
- DrawableImage::ValueTreeWrapper wrapper (item.getState());
-
- points.add (wrapper.getTargetPositionForTopLeft());
- points.add (wrapper.getTargetPositionForTopRight());
- points.add (wrapper.getTargetPositionForBottomLeft());
- }
+private:
+ OwnedArray handlers;
};
-//==============================================================================
-class DrawableCompositeHandler : public DrawableTypeHandler
-{
-public:
- DrawableCompositeHandler() : DrawableTypeHandler ("Group", DrawableComposite::valueTreeType, false) {}
- ~DrawableCompositeHandler() {}
-
- const ValueTree createNewInstance (DrawableDocument& document, const Point& approxPosition)
- {
- return ValueTree::invalid;
- }
-
- void createPropertyEditors (DrawableTypeInstance& item, Array & props)
- {
- }
-
- void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item)
- {
- }
-
- void setBounds (DrawableTypeInstance& item, Drawable* drawable, const Rectangle& newBounds)
- {
- DrawableComposite::ValueTreeWrapper wrapper (item.getState());
-
- RelativePoint points[3] = { wrapper.getTargetPositionForOrigin(),
- wrapper.getTargetPositionForX1Y0(),
- wrapper.getTargetPositionForX0Y1() };
-
- if (rescalePoints (points, 3, drawable->getBounds(), newBounds, drawable->getParent()))
- {
- UndoManager* undoManager = item.getDocument().getUndoManager();
- wrapper.setTargetPositionForOrigin (points[0], undoManager);
- wrapper.setTargetPositionForX1Y0 (points[1], undoManager);
- wrapper.setTargetPositionForX0Y1 (points[2], undoManager);
- }
- }
-
- void getAllControlPoints (DrawableTypeInstance& item, Array & points)
- {
- DrawableComposite::ValueTreeWrapper wrapper (item.getState());
-
- points.add (wrapper.getTargetPositionForOrigin());
- points.add (wrapper.getTargetPositionForX1Y0());
- points.add (wrapper.getTargetPositionForX0Y1());
- }
-};
#endif // __JUCER_DRAWABLETYPEHANDLER_H_7FB02E2F__
diff --git a/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h b/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h
index a1ee614db0..2b4a58ef56 100644
--- a/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h
+++ b/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h
@@ -146,7 +146,7 @@ public:
return getDocument().getCoordsFor (state);
}
- void updateExtraComponentsForObject (const ValueTree& state, Component* parent, OwnedArray& existingComps)
+ void updateControlPointComponents (Component* parent, OwnedArray& existingComps)
{
}
@@ -184,7 +184,6 @@ public:
~DragOperation()
{
- getUndoManager().beginNewTransaction();
}
protected:
diff --git a/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h b/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h
index 9a8af440f6..c9786bac85 100644
--- a/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h
+++ b/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h
@@ -35,6 +35,7 @@ class DrawableEditorCanvas : public EditorCanvasBase,
public Timer
{
public:
+ //==============================================================================
DrawableEditorCanvas (DrawableEditor& editor_)
: editor (editor_)
{
@@ -48,6 +49,11 @@ public:
shutdown();
}
+ //==============================================================================
+ UndoManager& getUndoManager() throw() { return *getDocument().getUndoManager(); }
+ DrawableEditor& getEditor() throw() { return editor; }
+ DrawableDocument& getDocument() throw() { return editor.getDocument(); }
+
Component* createComponentHolder()
{
return new DrawableComponent (this);
@@ -67,7 +73,7 @@ public:
else
{
const Rectangle damage (drawable->refreshFromValueTree (doc.getRootDrawableNode().getState(), &doc));
- getComponentHolder()->repaint (damage.getSmallestIntegerContainer());
+ getComponentHolder()->repaint (objectSpaceToScreenSpace (damage.getSmallestIntegerContainer()));
}
startTimer (500);
@@ -81,14 +87,10 @@ public:
void setCanvasBounds (const Rectangle& newBounds) {}
bool canResizeCanvas() const { return false; }
- MarkerListBase& getMarkerList (bool isX)
+ //==============================================================================
+ const ValueTree getObjectState (const String& objectId)
{
- return getDocument().getMarkerList (isX);
- }
-
- double limitMarkerPosition (double pos)
- {
- return pos;
+ return getDocument().findDrawableState (objectId, false);
}
const SelectedItems::ItemType findObjectIdAt (const Point& position)
@@ -130,30 +132,36 @@ public:
void objectDoubleClicked (const MouseEvent& e, const ValueTree& state)
{
+ if (state.hasType (DrawablePath::valueTreeType)
+ || state.hasType (DrawableImage::valueTreeType)
+ || state.hasType (DrawableText::valueTreeType))
+ {
+ enableControlPointMode (state);
+ }
+ else if (state.hasType (DrawableComposite::valueTreeType))
+ {
+ // xxx
+ }
}
bool hasSizeGuides() const { return false; }
- const ValueTree getObjectState (const String& objectId)
- {
- return getDocument().findDrawableState (objectId, false);
- }
-
void getObjectPositionDependencies (const ValueTree& state, Array& deps)
{
DrawableDocument& doc = getDocument();
DrawableTypeInstance item (doc, state);
- Array points;
+ OwnedArray points;
item.getAllControlPoints (points);
StringArray anchors;
for (int i = 0; i < points.size(); ++i)
{
- anchors.addIfNotAlreadyThere (points.getReference(i).x.getAnchorName1());
- anchors.addIfNotAlreadyThere (points.getReference(i).x.getAnchorName2());
- anchors.addIfNotAlreadyThere (points.getReference(i).y.getAnchorName1());
- anchors.addIfNotAlreadyThere (points.getReference(i).y.getAnchorName2());
+ const RelativePoint p (points.getUnchecked(i)->getPosition());
+ anchors.addIfNotAlreadyThere (p.x.getAnchorName1());
+ anchors.addIfNotAlreadyThere (p.x.getAnchorName2());
+ anchors.addIfNotAlreadyThere (p.y.getAnchorName1());
+ anchors.addIfNotAlreadyThere (p.y.getAnchorName2());
}
for (int i = 0; i < anchors.size(); ++i)
@@ -207,12 +215,15 @@ public:
return RelativeRectangle();
}
+ //==============================================================================
class ControlPointComponent : public OverlayItemComponent
{
public:
- ControlPointComponent (DrawableEditorCanvas* canvas)
- : OverlayItemComponent (canvas)
+ ControlPointComponent (DrawableEditorCanvas* canvas, const ValueTree& drawableState_, int controlPointNum_)
+ : OverlayItemComponent (canvas), drawableState (drawableState_),
+ controlPointNum (controlPointNum_), isDragging (false), mouseDownResult (false), selected (false)
{
+ selectionId = getControlPointId (drawableState, controlPointNum);
}
~ControlPointComponent()
@@ -221,29 +232,79 @@ public:
void paint (Graphics& g)
{
- g.fillAll (Colours::pink);
+ g.setColour (Colour (selected ? 0xaaaaaaaa : 0xaa333333));
+ g.drawRect (0, 0, getWidth(), getHeight());
+
+ g.setColour (Colour (selected ? 0xaa000000 : 0x99ffffff));
+ g.fillRect (1, 1, getWidth() - 2, getHeight() - 2);
}
void mouseDown (const MouseEvent& e)
{
+ isDragging = false;
+
+ if (e.mods.isPopupMenu())
+ {
+ canvas->showPopupMenu (true);
+ }
+ else
+ {
+ mouseDownResult = canvas->getSelection().addToSelectionOnMouseDown (selectionId, e.mods);
+ }
}
void mouseDrag (const MouseEvent& e)
{
+ if (! (isDragging || e.mouseWasClicked() || e.mods.isPopupMenu()))
+ {
+ canvas->getSelection().addToSelectionOnMouseUp (selectionId, e.mods, true, mouseDownResult);
+
+ isDragging = true;
+ canvas->beginDrag (e.withNewPosition (e.getMouseDownPosition()).getEventRelativeTo (getParentComponent()),
+ ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre));
+ }
+
+ if (isDragging)
+ {
+ canvas->continueDrag (e.getEventRelativeTo (getParentComponent()));
+ autoScrollForMouseEvent (e);
+ }
}
void mouseUp (const MouseEvent& e)
{
+ if (isDragging)
+ {
+ canvas->endDrag (e.getEventRelativeTo (getParentComponent()));
+ }
}
- void updatePosition (const RelativePoint& point, RelativeCoordinate::NamedCoordinateFinder* nameFinder)
+ void mouseDoubleClick (const MouseEvent& e)
{
- const Point p (point.resolve (nameFinder));
- setBoundsInTargetSpace (Rectangle (roundToInt (p.getX()) - 2, roundToInt (p.getY()) - 2, 5, 5));
}
+
+ void updatePosition (ControlPoint& point, RelativeCoordinate::NamedCoordinateFinder* nameFinder)
+ {
+ const Point p (point.getPosition().resolve (nameFinder));
+ setBoundsInTargetSpace (Rectangle (roundToInt (p.getX()) - 2, roundToInt (p.getY()) - 2, 7, 7));
+
+ const bool nowSelected = canvas->getSelection().isSelected (selectionId);
+
+ if (selected != nowSelected)
+ {
+ selected = nowSelected;
+ repaint();
+ }
+ }
+
+ private:
+ ValueTree drawableState;
+ int controlPointNum;
+ bool isDragging, mouseDownResult, selected;
+ String selectionId;
};
- void updateExtraComponentsForObject (const ValueTree& state, Component* parent, OwnedArray& comps)
+ void updateControlPointComponents (Component* parent, OwnedArray& comps)
{
if (drawable == 0)
{
@@ -251,11 +312,11 @@ public:
return;
}
- DrawableTypeInstance item (getDocument(), state);
- Array points;
+ DrawableTypeInstance item (getDocument(), controlPointEditingTarget);
+ OwnedArray points;
item.getAllControlPoints (points);
- Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID());
+ Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (controlPointEditingTarget).getID());
DrawableComposite* parentDrawable = d->getParent();
comps.removeRange (points.size(), comps.size());
@@ -269,15 +330,27 @@ public:
if (c == 0)
{
- c = new ControlPointComponent (this);
+ c = new ControlPointComponent (this, controlPointEditingTarget, i);
comps.set (i, c);
parent->addAndMakeVisible (c);
}
- c->updatePosition (points.getReference(i), parentDrawable);
+ c->updatePosition (*points.getUnchecked(i), parentDrawable);
}
}
+ //==============================================================================
+ MarkerListBase& getMarkerList (bool isX)
+ {
+ return getDocument().getMarkerList (isX);
+ }
+
+ double limitMarkerPosition (double pos)
+ {
+ return pos;
+ }
+
+ //==============================================================================
SelectedItems& getSelection()
{
return editor.getSelection();
@@ -303,25 +376,32 @@ public:
}
}
+ bool isControlPointId (const String& itemId)
+ {
+ return itemId.containsChar ('/');
+ }
+
+ static const String getControlPointId (const ValueTree& drawableState, int index)
+ {
+ return Drawable::ValueTreeWrapperBase (drawableState).getID() + "/" + String (index);
+ }
+
//==============================================================================
- class DragOperation : public EditorDragOperation
+ class ObjectDragOperation : public EditorDragOperation
{
public:
- DragOperation (DrawableEditorCanvas* canvas_,
- const MouseEvent& e, const Point& mousePos,
- Component* snapGuideParentComp_,
- const ResizableBorderComponent::Zone& zone_)
- : EditorDragOperation (canvas_, e, mousePos, snapGuideParentComp_, zone_)
+ ObjectDragOperation (DrawableEditorCanvas* canvas_,
+ const MouseEvent& e, const Point& mousePos,
+ Component* snapGuideParentComp_,
+ const ResizableBorderComponent::Zone& zone_)
+ : EditorDragOperation (canvas_, e, mousePos, snapGuideParentComp_, zone_), drawableCanvas (canvas_)
{
}
- ~DragOperation()
- {
- getUndoManager().beginNewTransaction();
- }
+ ~ObjectDragOperation() {}
protected:
- DrawableDocument& getDocument() throw() { return static_cast (canvas)->getDocument(); }
+ DrawableDocument& getDocument() throw() { return drawableCanvas->getDocument(); }
void getSnapPointsX (Array& points, bool /*includeCentre*/) { points.add (0.0f); }
void getSnapPointsY (Array& points, bool /*includeCentre*/) { points.add (0.0f); }
@@ -330,56 +410,144 @@ public:
void getObjectDependencies (const ValueTree& state, Array& deps)
{
- static_cast (canvas)->getObjectPositionDependencies (state, deps);
+ drawableCanvas->getObjectPositionDependencies (state, deps);
}
const Rectangle getObjectPosition (const ValueTree& state)
{
- return static_cast (canvas)->getObjectPositionFloat (state);
+ return drawableCanvas->getObjectPositionFloat (state);
}
void setObjectPosition (ValueTree& state, const Rectangle& newBounds)
{
- static_cast (canvas)->setObjectPositionFloat (state, newBounds);
+ drawableCanvas->setObjectPositionFloat (state, newBounds);
}
float getMarkerPosition (const ValueTree& marker, bool isX)
{
return 0;
}
+
+ private:
+ DrawableEditorCanvas* drawableCanvas;
};
+ //==============================================================================
+ class ControlPointDragOperation : public EditorDragOperation
+ {
+ public:
+ ControlPointDragOperation (DrawableEditorCanvas* canvas_,
+ const DrawableTypeInstance& drawableItem_,
+ Drawable* drawable_,
+ const MouseEvent& e, const Point& mousePos,
+ Component* snapGuideParentComp_,
+ const ResizableBorderComponent::Zone& zone_)
+ : EditorDragOperation (canvas_, e, mousePos, snapGuideParentComp_, zone_),
+ drawableCanvas (canvas_), drawableItem (drawableItem_), drawable (drawable_)
+ {
+ drawableItem.getAllControlPoints (points);
+ }
+
+ ~ControlPointDragOperation() {}
+
+ OwnedArray points;
+
+ protected:
+ DrawableDocument& getDocument() throw() { return drawableCanvas->getDocument(); }
+
+ void getSnapPointsX (Array& points, bool /*includeCentre*/) { points.add (0.0f); }
+ void getSnapPointsY (Array& points, bool /*includeCentre*/) { points.add (0.0f); }
+
+ UndoManager& getUndoManager() { return *getDocument().getUndoManager(); }
+
+ void getObjectDependencies (const ValueTree& state, Array& deps)
+ {
+ drawableCanvas->getObjectPositionDependencies (drawableItem.getState(), deps);
+ }
+
+ const Rectangle getObjectPosition (const ValueTree& state)
+ {
+ int index = state [Ids::id_].toString().fromFirstOccurrenceOf ("/", false, false).getIntValue();
+ ControlPoint* cp = points[index];
+ if (cp == 0)
+ return Rectangle();
+
+ Point p (cp->getPosition().resolve (drawable->getParent()));
+ return Rectangle (p, p);
+ }
+
+ void setObjectPosition (ValueTree& state, const Rectangle& newBounds)
+ {
+ int index = state [Ids::id_].toString().fromFirstOccurrenceOf ("/", false, false).getIntValue();
+ ControlPoint* cp = points[index];
+ if (cp != 0)
+ {
+ RelativePoint p (cp->getPosition());
+ p.moveToAbsolute (newBounds.getPosition(), drawable->getParent());
+ cp->setPosition (p, getDocument().getUndoManager());
+ }
+ }
+
+ float getMarkerPosition (const ValueTree& marker, bool isX)
+ {
+ return 0;
+ }
+
+ private:
+ DrawableEditorCanvas* drawableCanvas;
+ DrawableTypeInstance drawableItem;
+ Drawable* drawable;
+ };
+
+ //==============================================================================
DragOperation* createDragOperation (const MouseEvent& e, Component* snapGuideParentComponent,
const ResizableBorderComponent::Zone& zone)
{
- DragOperation* d = new DragOperation (this, e, e.getPosition() - origin, snapGuideParentComponent, zone);
-
Array selected, unselected;
+ EditorDragOperation* drag = 0;
- DrawableComposite::ValueTreeWrapper mainGroup (getDocument().getRootDrawableNode());
-
- for (int i = mainGroup.getNumDrawables(); --i >= 0;)
+ if (isControlPointMode())
{
- const ValueTree v (mainGroup.getDrawableState (i));
+ Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (controlPointEditingTarget).getID());
+ DrawableTypeInstance item (getDocument(), controlPointEditingTarget);
- if (editor.getSelection().isSelected (v[Drawable::ValueTreeWrapperBase::idProperty]))
- selected.add (v);
- else
- unselected.add (v);
+ ControlPointDragOperation* cpd = new ControlPointDragOperation (this, item, d, e, e.getPosition() - origin, snapGuideParentComponent, zone);
+ drag = cpd;
+
+ for (int i = 0; i < cpd->points.size(); ++i)
+ {
+ const String pointId (getControlPointId (item.getState(), i));
+
+ ValueTree v (Ids::controlPoint);
+ v.setProperty (Ids::id_, pointId, 0);
+
+ if (editor.getSelection().isSelected (pointId))
+ selected.add (v);
+ else
+ unselected.add (v);
+ }
+ }
+ else
+ {
+ drag = new ObjectDragOperation (this, e, e.getPosition() - origin, snapGuideParentComponent, zone);
+
+ DrawableComposite::ValueTreeWrapper mainGroup (getDocument().getRootDrawableNode());
+
+ for (int i = mainGroup.getNumDrawables(); --i >= 0;)
+ {
+ const ValueTree v (mainGroup.getDrawableState (i));
+
+ if (editor.getSelection().isSelected (v[Drawable::ValueTreeWrapperBase::idProperty]))
+ selected.add (v);
+ else
+ unselected.add (v);
+ }
}
- d->initialise (selected, unselected);
- return d;
+ drag->initialise (selected, unselected);
+ return drag;
}
- UndoManager& getUndoManager()
- {
- return *getDocument().getUndoManager();
- }
-
- DrawableEditor& getEditor() throw() { return editor; }
- DrawableDocument& getDocument() throw() { return editor.getDocument(); }
-
void timerCallback()
{
stopTimer();
diff --git a/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp b/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp
index 8797350cbe..ce536eeca1 100644
--- a/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp
+++ b/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp
@@ -69,7 +69,7 @@ public:
else
{
isDragging = true;
- canvas->beginDrag (e.getEventRelativeTo (getParentComponent()), dragZone);
+ canvas->beginDrag (e.withNewPosition (e.getMouseDownPosition()).getEventRelativeTo (getParentComponent()), dragZone);
canvas->showSizeGuides();
}
}
@@ -121,7 +121,6 @@ public:
sizeGuides.getUnchecked(i)->updatePosition (bounds);
}
- canvas->updateExtraComponentsForObject (objectState, getParentComponent(), extraEditorComps);
return true;
}
@@ -202,7 +201,6 @@ private:
const int borderThickness;
OwnedArray sizeGuides;
bool isDragging;
- OwnedArray extraEditorComps;
const Rectangle getCentreArea() const
{
@@ -404,6 +402,7 @@ public:
resizers.clear();
markersX.clear();
markersY.clear();
+ controlPoints.clear();
deleteAllChildren();
}
@@ -420,7 +419,10 @@ public:
if (e.mods.isPopupMenu())
{
if (underMouse.isNotEmpty() && ! getSelection().isSelected (underMouse))
+ {
+ canvas->enableResizingMode();
getSelection().selectOnly (underMouse);
+ }
canvas->showPopupMenu (underMouse.isNotEmpty());
}
@@ -436,6 +438,7 @@ public:
{
mouseDownCompUID = underMouse;
canvas->deselectNonDraggableObjects();
+ canvas->enableResizingMode();
mouseDownResult = getSelection().addToSelectionOnMouseDown (mouseDownCompUID, e.mods);
updateResizeFrames();
@@ -456,8 +459,9 @@ public:
if (! isDraggingClickedComp)
{
isDraggingClickedComp = true;
+ canvas->enableResizingMode();
getSelection().addToSelectionOnMouseUp (mouseDownCompUID, e.mods, true, mouseDownResult);
- canvas->beginDrag (e, ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre));
+ canvas->beginDrag (e.withNewPosition (e.getMouseDownPosition()), ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre));
}
canvas->continueDrag (e);
@@ -526,15 +530,9 @@ public:
SelectedItems& getSelection() { return canvas->getSelection(); }
SelectedItems& getLassoSelection() { return getSelection(); }
- void resized()
- {
- updateMarkers();
- updateResizeFrames();
- }
-
void changeListenerCallback (void*)
{
- updateResizeFrames();
+ update();
}
void modifierKeysChanged (const ModifierKeys&)
@@ -571,6 +569,7 @@ public:
void update()
{
updateResizeFrames();
+ updateControlPoints();
updateMarkers();
}
@@ -582,9 +581,16 @@ private:
SelectedItems::ItemType mouseDownCompUID;
OwnedArray resizers;
OwnedArray markersX, markersY;
+ OwnedArray controlPoints;
void updateResizeFrames()
{
+ if (! canvas->isResizingMode())
+ {
+ resizers.clear();
+ return;
+ }
+
SelectedItems& selection = getSelection();
StringArray requiredIds;
const int num = selection.getNumSelected();
@@ -630,6 +636,17 @@ private:
}
}
+ void updateControlPoints()
+ {
+ if (! canvas->isControlPointMode())
+ {
+ controlPoints.clear();
+ return;
+ }
+
+ canvas->updateControlPointComponents (this, controlPoints);
+ }
+
void updateMarkers (OwnedArray & markers, const bool isX)
{
MarkerListBase& markerList = canvas->getMarkerList (isX);
@@ -827,6 +844,21 @@ const Rectangle EditorCanvasBase::objectSpaceToScreenSpace (const Rectangle
return r + origin;
}
+void EditorCanvasBase::enableResizingMode()
+{
+ enableControlPointMode (ValueTree::invalid);
+}
+
+void EditorCanvasBase::enableControlPointMode (const ValueTree& objectToEdit)
+{
+ if (controlPointEditingTarget != objectToEdit)
+ {
+ controlPointEditingTarget = objectToEdit;
+ getSelection().deselectAll();
+ overlay->update();
+ }
+}
+
//==============================================================================
void EditorCanvasBase::paint (Graphics& g)
{
@@ -938,6 +970,8 @@ void EditorCanvasBase::endDrag (const MouseEvent& e)
{
dragger->drag (e, e.getPosition() - origin);
dragger = 0;
+
+ getUndoManager().beginNewTransaction();
}
}
diff --git a/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h b/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h
index aaf04bc51c..5d7a306303 100644
--- a/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h
+++ b/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h
@@ -88,6 +88,7 @@ public:
virtual void deselectNonDraggableObjects() = 0;
virtual void findLassoItemsInArea (Array & itemsFound, const Rectangle& area) = 0;
+ //==============================================================================
class DragOperation
{
public:
@@ -105,6 +106,12 @@ public:
void continueDrag (const MouseEvent& e);
void endDrag (const MouseEvent& e);
+ void enableResizingMode();
+ void enableControlPointMode (const ValueTree& objectToEdit);
+
+ bool isResizingMode() const { return ! isControlPointMode(); }
+ bool isControlPointMode() const { return controlPointEditingTarget.isValid(); }
+
//==============================================================================
Component* getComponentHolder() const { return componentHolder; }
EditorPanelBase* getPanel() const;
@@ -129,14 +136,15 @@ public:
};
//==============================================================================
- virtual void updateExtraComponentsForObject (const ValueTree& state, Component* parent,
- OwnedArray& existingComps) = 0;
+ virtual void updateControlPointComponents (Component* parent,
+ OwnedArray& existingComps) = 0;
protected:
//==============================================================================
const BorderSize border;
Point origin;
double scaleFactor;
+ ValueTree controlPointEditingTarget;
friend class OverlayItemComponent;
class ResizeFrame;
diff --git a/extras/Jucer (experimental)/Source/ui/jucer_MainWindow.cpp b/extras/Jucer (experimental)/Source/ui/jucer_MainWindow.cpp
index dd5d4b8afd..8ae7cea40a 100644
--- a/extras/Jucer (experimental)/Source/ui/jucer_MainWindow.cpp
+++ b/extras/Jucer (experimental)/Source/ui/jucer_MainWindow.cpp
@@ -83,7 +83,7 @@ MainWindow::MainWindow()
// don't want the window to take focus when the title-bar is clicked..
setWantsKeyboardFocus (false);
- //getPeer()->setCurrentRenderingEngine (0);
+ getPeer()->setCurrentRenderingEngine (0);
}
MainWindow::~MainWindow()
diff --git a/extras/Jucer (experimental)/Source/utility/jucer_FillTypePropertyComponent.h b/extras/Jucer (experimental)/Source/utility/jucer_FillTypePropertyComponent.h
index 88add5bdf3..2d53638a5d 100644
--- a/extras/Jucer (experimental)/Source/utility/jucer_FillTypePropertyComponent.h
+++ b/extras/Jucer (experimental)/Source/utility/jucer_FillTypePropertyComponent.h
@@ -26,6 +26,8 @@
#ifndef __JUCER_FILLTYPEPROPERTYCOMPONENT_H_88CF1300__
#define __JUCER_FILLTYPEPROPERTYCOMPONENT_H_88CF1300__
+class FillTypeEditorComponent;
+
//==============================================================================
class PopupFillSelector : public Component,
public ChangeListener,
@@ -33,8 +35,10 @@ class PopupFillSelector : public Component,
public ButtonListener
{
public:
- PopupFillSelector (const ValueTree& fillState_, UndoManager* undoManager_)
- : fillState (fillState_),
+ PopupFillSelector (const ValueTree& fillState_, const ColourGradient& defaultGradient_, UndoManager* undoManager_)
+ : gradientPicker (defaultGradient_),
+ defaultGradient (defaultGradient_),
+ fillState (fillState_),
undoManager (undoManager_)
{
colourButton.setButtonText ("Colour");
@@ -76,15 +80,6 @@ public:
imageButton.removeButtonListener (this);
}
- static void showAt (Component* comp, const ValueTree& fill, UndoManager* undoManager)
- {
- PopupFillSelector popup (fill, undoManager);
-
- PopupMenu m;
- m.addCustomItem (1234, &popup, 300, 400, false);
- m.showAt (comp);
- }
-
void resized()
{
const int y = 2, w = 80, h = 22;
@@ -99,18 +94,44 @@ public:
void buttonClicked (Button* b)
{
+ RelativePoint gp1, gp2;
+ FillType currentFill (readFillType (&gp1, &gp2));
+
if (b == &colourButton)
{
- setFillType (colourPicker.getCurrentColour());
+ if (! currentFill.isColour())
+ setFillType (colourPicker.getCurrentColour());
}
else if (b == &gradientButton)
{
- setFillType (gradientPicker.getGradient());
+ if (! currentFill.isGradient())
+ {
+ // Use a cunning trick to make the wrapper dig out the earlier gradient settings, if there are any..
+ FillType newFill (defaultGradient);
+ ValueTree temp ("dummy");
+ Drawable::ValueTreeWrapperBase::writeFillType (temp, newFill, 0, 0, 0);
+
+ fillState.setProperty (Drawable::ValueTreeWrapperBase::type, temp [Drawable::ValueTreeWrapperBase::type], undoManager);
+ newFill = readFillType (&gp1, &gp2);
+
+ if (newFill.gradient->getNumColours() <= 1)
+ {
+ newFill = FillType (defaultGradient);
+ Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, 0, 0, undoManager);
+ }
+ else
+ {
+ Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, &gp1, &gp2, undoManager);
+ }
+
+ refresh();
+ }
}
else if (b == &imageButton)
{
- setFillType (FillType (*StoredSettings::getInstance()->getFallbackImage(),
- AffineTransform::identity));
+ if (! currentFill.isTiledImage())
+ setFillType (FillType (*StoredSettings::getInstance()->getFallbackImage(),
+ AffineTransform::identity));
}
}
@@ -122,7 +143,7 @@ public:
void setFillType (const FillType& newFill)
{
RelativePoint gp1, gp2;
- const FillType currentFill (readFillType (&gp1, &gp2));
+ FillType currentFill (readFillType (&gp1, &gp2));
if (currentFill != newFill)
{
@@ -146,7 +167,7 @@ public:
void refresh()
{
- const FillType newFill (readFillType (0, 0));
+ FillType newFill (readFillType (0, 0));
colourPicker.setVisible (newFill.isColour());
gradientPicker.setVisible (newFill.isGradient());
@@ -158,6 +179,12 @@ public:
}
else if (newFill.isGradient())
{
+ if (newFill.gradient->getNumColours() <= 1)
+ {
+ newFill = FillType (defaultGradient);
+ Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, 0, 0, undoManager);
+ }
+
gradientButton.setToggleState (true, false);
gradientPicker.setGradient (*newFill.gradient);
}
@@ -178,8 +205,8 @@ private:
private ChangeListener
{
public:
- GradientDesigner()
- : gradient (Colours::red, 0.0f, 0.0f, Colours::blue, 200.0f, 200.0f, false),
+ GradientDesigner (const ColourGradient& gradient_)
+ : gradient (gradient_),
selectedPoint (-1),
dragging (false),
draggingNewPoint (false),
@@ -302,8 +329,10 @@ private:
void setGradient (const ColourGradient& newGradient)
{
- if (newGradient != gradient)
+ if (newGradient != gradient || selectedPoint < 0)
{
+ jassert (newGradient.getNumColours() > 1);
+
gradient = newGradient;
if (selectedPoint < 0)
@@ -375,8 +404,10 @@ private:
};
//==============================================================================
+ FillTypeEditorComponent* owner;
StoredSettings::ColourSelectorWithSwatches colourPicker;
GradientDesigner gradientPicker;
+ ColourGradient defaultGradient;
ValueTree fillState;
UndoManager* undoManager;
@@ -404,6 +435,8 @@ public:
{
}
+ const ColourGradient getDefaultGradient() const;
+
void paint (Graphics& g)
{
g.setColour (Colours::grey);
@@ -447,7 +480,12 @@ public:
void mouseDown (const MouseEvent& e)
{
undoManager->beginNewTransaction();
- PopupFillSelector::showAt (this, fillState, undoManager);
+
+ PopupFillSelector popup (fillState, getDefaultGradient(), undoManager);
+
+ PopupMenu m;
+ m.addCustomItem (1234, &popup, 300, 450, false);
+ m.showAt (this);
}
void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property) { refresh(); }
@@ -462,6 +500,7 @@ private:
FillType fillType;
};
+
//==============================================================================
class FillTypePropertyComponent : public PropertyComponent
{
@@ -484,6 +523,8 @@ public:
editor.setBounds (getLookAndFeel().getPropertyComponentContentPosition (*this));
}
+ virtual const ColourGradient getDefaultGradient() = 0;
+
void refresh() {}
protected:
diff --git a/extras/Jucer (experimental)/Source/utility/jucer_MiscUtilities.cpp b/extras/Jucer (experimental)/Source/utility/jucer_MiscUtilities.cpp
index 97562d450c..4fb15c2c33 100644
--- a/extras/Jucer (experimental)/Source/utility/jucer_MiscUtilities.cpp
+++ b/extras/Jucer (experimental)/Source/utility/jucer_MiscUtilities.cpp
@@ -24,6 +24,7 @@
*/
#include "../jucer_Headers.h"
+#include "jucer_FillTypePropertyComponent.h"
//==============================================================================
@@ -406,3 +407,11 @@ RelativeRectangleLayoutManager::ComponentPosition::ComponentPosition (Component*
: component (component_), name (name_), coords (coords_)
{
}
+
+//==============================================================================
+const ColourGradient FillTypeEditorComponent::getDefaultGradient() const
+{
+ FillTypePropertyComponent* p = dynamic_cast (getParentComponent());
+ jassert (p != 0);
+ return p->getDefaultGradient();
+}
diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp
index cd9ee73235..fd169a6eed 100644
--- a/juce_amalgamated.cpp
+++ b/juce_amalgamated.cpp
@@ -16322,6 +16322,18 @@ ValueTree ValueTree::SharedObject::getChildWithName (const Identifier& typeToMat
return ValueTree::invalid;
}
+ValueTree ValueTree::SharedObject::getOrCreateChildWithName (const Identifier& typeToMatch, UndoManager* undoManager)
+{
+ for (int i = 0; i < children.size(); ++i)
+ if (children.getUnchecked(i)->type == typeToMatch)
+ return ValueTree (static_cast (children.getUnchecked(i)));
+
+ SharedObject* const newObject = new SharedObject (typeToMatch);
+ addChild (newObject, -1, undoManager);
+ return ValueTree (newObject);
+
+}
+
ValueTree ValueTree::SharedObject::getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const
{
for (int i = 0; i < children.size(); ++i)
@@ -16654,6 +16666,11 @@ ValueTree ValueTree::getChildWithName (const Identifier& type) const
return object != 0 ? object->getChildWithName (type) : ValueTree::invalid;
}
+ValueTree ValueTree::getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager)
+{
+ return object != 0 ? object->getOrCreateChildWithName (type, undoManager) : ValueTree::invalid;
+}
+
ValueTree ValueTree::getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const
{
return object != 0 ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree::invalid;
@@ -78991,7 +79008,7 @@ int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlo
jassert (point1.getX() != 987654.0f);
#endif
- const int numEntries = jlimit (1, (colours.size() - 1) << 8,
+ const int numEntries = jlimit (1, jmax (1, (colours.size() - 1) << 8),
3 * (int) point1.transformedBy (transform)
.getDistanceFrom (point2.transformedBy (transform)));
lookupTable.malloc (numEntries);
@@ -83946,10 +83963,6 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType
{
v.setProperty (type, "solid", undoManager);
v.setProperty (colour, String::toHexString ((int) fillType.colour.getARGB()), undoManager);
- v.removeProperty (gradientPoint1, undoManager);
- v.removeProperty (gradientPoint2, undoManager);
- v.removeProperty (radial, undoManager);
- v.removeProperty (colours, undoManager);
}
else if (fillType.isGradient())
{
@@ -83964,19 +83977,12 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType
<< " " << String::toHexString ((int) fillType.gradient->getColour(i).getARGB());
v.setProperty (colours, s.trimStart(), undoManager);
- v.removeProperty (colour, undoManager);
}
else if (fillType.isTiledImage())
{
v.setProperty (type, "image", undoManager);
jassertfalse; //xxx todo
-
- v.removeProperty (gradientPoint1, undoManager);
- v.removeProperty (gradientPoint2, undoManager);
- v.removeProperty (radial, undoManager);
- v.removeProperty (colours, undoManager);
- v.removeProperty (colour, undoManager);
}
else
{
@@ -83984,21 +83990,6 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType
}
}
-void Drawable::ValueTreeWrapperBase::replaceFillType (const Identifier& tag, const FillType& fillType,
- const RelativePoint* gp1, const RelativePoint* gp2,
- UndoManager* const undoManager)
-{
- ValueTree v (state.getChildWithName (tag));
-
- if (! v.isValid())
- {
- state.addChild (ValueTree (tag), -1, undoManager);
- v = state.getChildWithName (tag);
- }
-
- writeFillType (v, fillType, gp1, gp2, undoManager);
-}
-
END_JUCE_NAMESPACE
/*** End of inlined file: juce_Drawable.cpp ***/
@@ -84325,12 +84316,7 @@ ValueTree DrawableComposite::ValueTreeWrapper::getChildList() const
ValueTree DrawableComposite::ValueTreeWrapper::getChildListCreating (UndoManager* undoManager)
{
- const ValueTree childList (getChildList());
- if (childList.isValid())
- return childList;
-
- state.addChild (ValueTree (childGroupTag), 0, undoManager);
- return getChildList();
+ return state.getOrCreateChildWithName (childGroupTag, undoManager);
}
int DrawableComposite::ValueTreeWrapper::getNumDrawables() const
@@ -84431,12 +84417,7 @@ ValueTree DrawableComposite::ValueTreeWrapper::getMarkerList (bool xAxis) const
ValueTree DrawableComposite::ValueTreeWrapper::getMarkerListCreating (bool xAxis, UndoManager* undoManager)
{
- const ValueTree markerList (getMarkerList (xAxis));
- if (markerList.isValid())
- return markerList;
-
- state.addChild (ValueTree (xAxis ? markerGroupTagX : markerGroupTagY), -1, undoManager);
- return getMarkerList (xAxis);
+ return state.getOrCreateChildWithName (xAxis ? markerGroupTagX : markerGroupTagY, undoManager);
}
int DrawableComposite::ValueTreeWrapper::getNumMarkers (bool xAxis) const
@@ -84919,6 +84900,8 @@ const Rectangle DrawableImage::refreshFromValueTree (const ValueTree& tre
|| controlPoints[1] != newControlPoint[1]
|| controlPoints[2] != newControlPoint[2])
{
+ const Rectangle damage (getBounds());
+
opacity = newOpacity;
overlayColour = newOverlayColour;
controlPoints[0] = newControlPoint[0];
@@ -84934,7 +84917,7 @@ const Rectangle DrawableImage::refreshFromValueTree (const ValueTree& tre
image = newImage;
}
- return getBounds();
+ return damage.getUnion (getBounds());
}
ImageCache::release (newImage);
@@ -85118,12 +85101,16 @@ Drawable* DrawablePath::createCopy() const
const Identifier DrawablePath::valueTreeType ("Path");
-const Identifier DrawablePath::ValueTreeWrapper::fill ("fill");
-const Identifier DrawablePath::ValueTreeWrapper::stroke ("stroke");
+const Identifier DrawablePath::ValueTreeWrapper::fill ("Fill");
+const Identifier DrawablePath::ValueTreeWrapper::stroke ("Stroke");
+const Identifier DrawablePath::ValueTreeWrapper::path ("Path");
const Identifier DrawablePath::ValueTreeWrapper::jointStyle ("jointStyle");
const Identifier DrawablePath::ValueTreeWrapper::capStyle ("capStyle");
const Identifier DrawablePath::ValueTreeWrapper::strokeWidth ("strokeWidth");
-const Identifier DrawablePath::ValueTreeWrapper::path ("path");
+const Identifier DrawablePath::ValueTreeWrapper::nonZeroWinding ("nonZeroWinding");
+const Identifier DrawablePath::ValueTreeWrapper::point1 ("p1");
+const Identifier DrawablePath::ValueTreeWrapper::point2 ("p2");
+const Identifier DrawablePath::ValueTreeWrapper::point3 ("p3");
DrawablePath::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
: ValueTreeWrapperBase (state_)
@@ -85131,6 +85118,11 @@ DrawablePath::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
jassert (state.hasType (valueTreeType));
}
+ValueTree DrawablePath::ValueTreeWrapper::getPathState()
+{
+ return state.getOrCreateChildWithName (path, 0);
+}
+
ValueTree DrawablePath::ValueTreeWrapper::getMainFillState()
{
ValueTree v (state.getChildWithName (fill));
@@ -85159,7 +85151,8 @@ const FillType DrawablePath::ValueTreeWrapper::getMainFill (RelativeCoordinate::
void DrawablePath::ValueTreeWrapper::setMainFill (const FillType& newFill, const RelativePoint* gp1,
const RelativePoint* gp2, UndoManager* undoManager)
{
- replaceFillType (fill, newFill, gp1, gp2, undoManager);
+ ValueTree v (state.getOrCreateChildWithName (fill, undoManager));
+ writeFillType (v, newFill, gp1, gp2, undoManager);
}
const FillType DrawablePath::ValueTreeWrapper::getStrokeFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const
@@ -85170,7 +85163,8 @@ const FillType DrawablePath::ValueTreeWrapper::getStrokeFill (RelativeCoordinate
void DrawablePath::ValueTreeWrapper::setStrokeFill (const FillType& newFill, const RelativePoint* gp1,
const RelativePoint* gp2, UndoManager* undoManager)
{
- replaceFillType (stroke, newFill, gp1, gp2, undoManager);
+ ValueTree v (state.getOrCreateChildWithName (stroke, undoManager));
+ writeFillType (v, newFill, gp1, gp2, undoManager);
}
const PathStrokeType DrawablePath::ValueTreeWrapper::getStrokeType() const
@@ -85196,15 +85190,50 @@ void DrawablePath::ValueTreeWrapper::setStrokeType (const PathStrokeType& newStr
? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager);
}
-void DrawablePath::ValueTreeWrapper::getPath (RelativePointPath& p) const
+bool DrawablePath::ValueTreeWrapper::usesNonZeroWinding() const
{
- RelativePointPath newPath (state [path]);
- p.swapWith (newPath);
+ return state [nonZeroWinding];
}
-void DrawablePath::ValueTreeWrapper::setPath (const String& newPath, UndoManager* undoManager)
+void DrawablePath::ValueTreeWrapper::setUsesNonZeroWinding (bool b, UndoManager* undoManager)
{
- state.setProperty (path, newPath, undoManager);
+ state.setProperty (nonZeroWinding, b, undoManager);
+}
+
+const Identifier DrawablePath::ValueTreeWrapper::Element::startSubPathElement ("Move");
+const Identifier DrawablePath::ValueTreeWrapper::Element::closeSubPathElement ("Close");
+const Identifier DrawablePath::ValueTreeWrapper::Element::lineToElement ("Line");
+const Identifier DrawablePath::ValueTreeWrapper::Element::quadraticToElement ("Quad");
+const Identifier DrawablePath::ValueTreeWrapper::Element::cubicToElement ("Cubic");
+
+DrawablePath::ValueTreeWrapper::Element::Element (const ValueTree& state_)
+ : state (state_)
+{
+}
+
+DrawablePath::ValueTreeWrapper::Element::~Element()
+{
+}
+
+int DrawablePath::ValueTreeWrapper::Element::getNumControlPoints() const throw()
+{
+ const Identifier i (state.getType());
+ if (i == startSubPathElement || i == lineToElement) return 1;
+ if (i == quadraticToElement) return 2;
+ if (i == cubicToElement) return 3;
+ return 0;
+}
+
+const RelativePoint DrawablePath::ValueTreeWrapper::Element::getControlPoint (const int index) const
+{
+ jassert (index >= 0 && index < getNumControlPoints());
+ return RelativePoint (state [index == 0 ? point1 : (index == 1 ? point2 : point3)].toString());
+}
+
+void DrawablePath::ValueTreeWrapper::Element::setControlPoint (const int index, const RelativePoint& point, UndoManager* undoManager)
+{
+ jassert (index >= 0 && index < getNumControlPoints());
+ return state.setProperty (index == 0 ? point1 : (index == 1 ? point2 : point3), point.toString(), undoManager);
}
const Rectangle DrawablePath::refreshFromValueTree (const ValueTree& tree, ImageProvider*)
@@ -85232,8 +85261,7 @@ const Rectangle DrawablePath::refreshFromValueTree (const ValueTree& tree
const PathStrokeType newStroke (v.getStrokeType());
- ScopedPointer newRelativePath (new RelativePointPath());
- v.getPath (*newRelativePath);
+ ScopedPointer newRelativePath (new RelativePointPath (tree));
Path newPath;
newRelativePath->createPath (newPath, parent);
@@ -85268,9 +85296,14 @@ const ValueTree DrawablePath::createValueTree (ImageProvider*) const
v.setStrokeType (strokeType, 0);
if (relativePath != 0)
- v.setPath (relativePath->toString(), 0);
+ {
+ relativePath->writeTo (tree, 0);
+ }
else
- v.setPath (path.toString(), 0);
+ {
+ RelativePointPath rp (path);
+ rp.writeTo (tree, 0);
+ }
return tree;
}
@@ -92784,6 +92817,11 @@ RelativePoint::RelativePoint (const Point& absolutePoint)
{
}
+RelativePoint::RelativePoint (const float x_, const float y_)
+ : x (x_, true), y (y_, false)
+{
+}
+
RelativePoint::RelativePoint (const RelativeCoordinate& x_, const RelativeCoordinate& y_)
: x (x_), y (y_)
{
@@ -92911,88 +92949,83 @@ RelativePointPath::RelativePointPath (const RelativePointPath& other)
: usesNonZeroWinding (true),
containsDynamicPoints (false)
{
- parseString (other.toString());
+ ValueTree state (DrawablePath::valueTreeType);
+ writeTo (state, 0);
+ parse (state);
}
-RelativePointPath::RelativePointPath (const String& s)
+RelativePointPath::RelativePointPath (const ValueTree& drawable)
: usesNonZeroWinding (true),
containsDynamicPoints (false)
{
- parseString (s);
+ parse (drawable);
}
-void RelativePointPath::parseString (const String& s)
+RelativePointPath::RelativePointPath (const Path& path)
{
- int i = 0;
- juce_wchar marker = 'm';
- int numValues = 2;
- RelativePoint points [3];
+ usesNonZeroWinding = path.isUsingNonZeroWinding();
- for (;;)
+ Path::Iterator i (path);
+
+ while (i.next())
{
- RelativeCoordinateHelpers::skipWhitespace (s, i);
- const juce_wchar firstChar = s[i];
-
- if (firstChar == 0)
- break;
-
- const juce_wchar secondChar = s[i + 1];
-
- if (secondChar == 0 || CharacterFunctions::isWhitespace (secondChar))
+ switch (i.elementType)
{
- if (firstChar == 'm' || firstChar == 'l')
- {
- ++i;
- marker = firstChar;
- numValues = 1;
- }
- else if (firstChar == 'q')
- {
- ++i;
- marker = firstChar;
- numValues = 2;
- }
- else if (firstChar == 'c')
- {
- ++i;
- marker = firstChar;
- numValues = 3;
- }
- else if (firstChar == 'z')
- {
- ++i;
- marker = 'm';
- numValues = 2;
- elements.add (new CloseSubPath());
- continue;
- }
- else if (firstChar == 'a')
- {
- ++i;
- usesNonZeroWinding = false;
- continue;
- }
+ case Path::Iterator::startNewSubPath: elements.add (new StartSubPath (RelativePoint (i.x1, i.y1))); break;
+ case Path::Iterator::lineTo: elements.add (new LineTo (RelativePoint (i.x1, i.y1))); break;
+ case Path::Iterator::quadraticTo: elements.add (new QuadraticTo (RelativePoint (i.x1, i.y1), RelativePoint (i.x2, i.y2))); break;
+ case Path::Iterator::cubicTo: elements.add (new CubicTo (RelativePoint (i.x1, i.y1), RelativePoint (i.x2, i.y2), RelativePoint (i.x3, i.y3))); break;
+ case Path::Iterator::closePath: elements.add (new CloseSubPath()); break;
+ default: jassertfalse; break;
}
+ }
+}
- if (firstChar == '#')
- ++i;
+void RelativePointPath::writeTo (ValueTree state, UndoManager* undoManager)
+{
+ DrawablePath::ValueTreeWrapper wrapper (state);
+ wrapper.setUsesNonZeroWinding (usesNonZeroWinding, undoManager);
- for (int j = 0; j < numValues; ++j)
+ ValueTree pathTree (wrapper.getPathState());
+ pathTree.removeAllChildren (undoManager);
+
+ for (int i = 0; i < elements.size(); ++i)
+ pathTree.addChild (elements.getUnchecked(i)->createTree(), -1, undoManager);
+}
+
+void RelativePointPath::parse (const ValueTree& state)
+{
+ DrawablePath::ValueTreeWrapper wrapper (state);
+ usesNonZeroWinding = wrapper.usesNonZeroWinding();
+ RelativePoint points[3];
+
+ const ValueTree pathTree (wrapper.getPathState());
+ const int num = pathTree.getNumChildren();
+ for (int i = 0; i < num; ++i)
+ {
+ const DrawablePath::ValueTreeWrapper::Element e (pathTree.getChild(i));
+
+ const int numCps = e.getNumControlPoints();
+ for (int j = 0; j < numCps; ++j)
{
- const RelativeCoordinate x (RelativeCoordinateHelpers::readNextCoordinate (s, i, true));
- const RelativeCoordinate y (RelativeCoordinateHelpers::readNextCoordinate (s, i, false));
- points[j] = RelativePoint (x, y);
+ points[j] = e.getControlPoint (j);
containsDynamicPoints = containsDynamicPoints || points[j].isDynamic();
}
- switch (marker)
- {
- case 'm': elements.add (new StartSubPath (points[0])); break;
- case 'l': elements.add (new LineTo (points[0])); break;
- case 'q': elements.add (new QuadraticTo (points[0], points[1])); break;
- case 'c': elements.add (new CubicTo (points[0], points[1], points[2])); break;
- default: jassertfalse; break; // illegal string format?
- }
+ const Identifier type (e.getType());
+
+ if (type == DrawablePath::ValueTreeWrapper::Element::startSubPathElement)
+ elements.add (new StartSubPath (points[0]));
+ else if (type == DrawablePath::ValueTreeWrapper::Element::closeSubPathElement)
+ elements.add (new CloseSubPath());
+ else if (type == DrawablePath::ValueTreeWrapper::Element::lineToElement)
+ elements.add (new LineTo (points[0]));
+ else if (type == DrawablePath::ValueTreeWrapper::Element::quadraticToElement)
+ elements.add (new QuadraticTo (points[0], points[1]));
+ else if (type == DrawablePath::ValueTreeWrapper::Element::cubicToElement)
+ elements.add (new CubicTo (points[0], points[1], points[2]));
+ else
+ jassertfalse;
}
}
@@ -93017,27 +93050,6 @@ bool RelativePointPath::containsAnyDynamicPoints() const
return containsDynamicPoints;
}
-const String RelativePointPath::toString() const
-{
- ElementType lastType = nullElement;
- MemoryOutputStream out;
-
- if (! usesNonZeroWinding)
- out << 'a';
-
- for (int i = 0; i < elements.size(); ++i)
- {
- if (out.getDataSize() > 0)
- out << ' ';
-
- const ElementBase* const e = elements.getUnchecked(i);
- e->write (out, lastType);
- lastType = e->type;
- }
-
- return out.toUTF8();
-}
-
RelativePointPath::ElementBase::ElementBase (const ElementType type_) : type (type_)
{
}
@@ -93047,16 +93059,11 @@ RelativePointPath::StartSubPath::StartSubPath (const RelativePoint& pos)
{
}
-void RelativePointPath::StartSubPath::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::StartSubPath::createTree() const
{
- const String p (startPos.toString());
-
- if (lastTypeWritten != startSubPathElement)
- out << "m ";
- else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p))
- out << '#';
-
- out << p;
+ ValueTree v (DrawablePath::ValueTreeWrapper::Element::startSubPathElement);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point1, startPos.toString(), 0);
+ return v;
}
void RelativePointPath::StartSubPath::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const
@@ -93076,10 +93083,9 @@ RelativePointPath::CloseSubPath::CloseSubPath()
{
}
-void RelativePointPath::CloseSubPath::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::CloseSubPath::createTree() const
{
- if (lastTypeWritten != closeSubPathElement)
- out << 'z';
+ return ValueTree (DrawablePath::ValueTreeWrapper::Element::closeSubPathElement);
}
void RelativePointPath::CloseSubPath::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder*) const
@@ -93098,16 +93104,11 @@ RelativePointPath::LineTo::LineTo (const RelativePoint& endPoint_)
{
}
-void RelativePointPath::LineTo::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::LineTo::createTree() const
{
- const String p (endPoint.toString());
-
- if (lastTypeWritten != lineToElement)
- out << "l ";
- else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p))
- out << '#';
-
- out << p;
+ ValueTree v (DrawablePath::ValueTreeWrapper::Element::lineToElement);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point1, endPoint.toString(), 0);
+ return v;
}
void RelativePointPath::LineTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const
@@ -93129,16 +93130,12 @@ RelativePointPath::QuadraticTo::QuadraticTo (const RelativePoint& controlPoint,
controlPoints[1] = endPoint;
}
-void RelativePointPath::QuadraticTo::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::QuadraticTo::createTree() const
{
- const String p1 (controlPoints[0].toString());
-
- if (lastTypeWritten != quadraticToElement)
- out << "q ";
- else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1))
- out << '#';
-
- out << p1 << ' ' << controlPoints[1].toString();
+ ValueTree v (DrawablePath::ValueTreeWrapper::Element::quadraticToElement);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point1, controlPoints[0].toString(), 0);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point2, controlPoints[1].toString(), 0);
+ return v;
}
void RelativePointPath::QuadraticTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const
@@ -93162,16 +93159,13 @@ RelativePointPath::CubicTo::CubicTo (const RelativePoint& controlPoint1, const R
controlPoints[2] = endPoint;
}
-void RelativePointPath::CubicTo::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::CubicTo::createTree() const
{
- const String p1 (controlPoints[0].toString());
-
- if (lastTypeWritten != cubicToElement)
- out << "c ";
- else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1))
- out << '#';
-
- out << p1 << ' ' << controlPoints[1].toString() << ' ' << controlPoints[2].toString();
+ ValueTree v (DrawablePath::ValueTreeWrapper::Element::cubicToElement);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point1, controlPoints[0].toString(), 0);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point2, controlPoints[1].toString(), 0);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point3, controlPoints[2].toString(), 0);
+ return v;
}
void RelativePointPath::CubicTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const
diff --git a/juce_amalgamated.h b/juce_amalgamated.h
index 40142ba5e0..e12f209efa 100644
--- a/juce_amalgamated.h
+++ b/juce_amalgamated.h
@@ -64,7 +64,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
-#define JUCE_BUILDNUMBER 7
+#define JUCE_BUILDNUMBER 8
/** Current Juce version number.
@@ -13094,12 +13094,22 @@ public:
*/
ValueTree getChild (int index) const;
- /** Looks for a child node with the speficied type name.
+ /** Returns the first child node with the speficied type name.
If no such node is found, it'll return an invalid node. (See isValid() to find out
whether a node is valid).
+ @see getOrCreateChildWithName
*/
ValueTree getChildWithName (const Identifier& type) const;
+ /** Returns the first child node with the speficied type name, creating and adding
+ a child with this name if there wasn't already one there.
+
+ The only time this will return an invalid object is when the object that you're calling
+ the method on is itself invalid.
+ @see getChildWithName
+ */
+ ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager);
+
/** Looks for the first child node that has the speficied property value.
This will scan the child nodes in order, until it finds one that has property that matches
@@ -13342,6 +13352,7 @@ private:
bool isAChildOf (const SharedObject* possibleParent) const;
int indexOf (const ValueTree& child) const;
ValueTree getChildWithName (const Identifier& type) const;
+ ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager);
ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const;
void addChild (SharedObject* child, int index, UndoManager*);
void removeChild (int childIndex, UndoManager*);
@@ -42124,6 +42135,9 @@ public:
/** Creates an absolute point, relative to the origin. */
RelativePoint (const Point& 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);
@@ -42246,7 +42260,8 @@ public:
RelativePointPath();
RelativePointPath (const RelativePointPath& other);
- RelativePointPath (const String& stringVersion);
+ RelativePointPath (const ValueTree& drawable);
+ RelativePointPath (const Path& path);
~RelativePointPath();
/** Resolves this points in this path and adds them to a normal Path object. */
@@ -42255,11 +42270,8 @@ public:
/** Returns true if the path contains any non-fixed points. */
bool containsAnyDynamicPoints() const;
- /** Returns a string version of the path.
- This has the same format as Path::toString(), but since it can contain RelativeCoordinate
- positions, it can't be parsed by the Path class if any of the points are dynamic.
- */
- const String toString() const;
+ /** Writes the path to this drawable encoding. */
+ void writeTo (ValueTree state, UndoManager* undoManager);
/** Quickly swaps the contents of this path with another. */
void swapWith (RelativePointPath& other) throw();
@@ -42284,7 +42296,7 @@ public:
public:
ElementBase (ElementType type);
virtual ~ElementBase() {}
- virtual void write (OutputStream& out, ElementType lastTypeWritten) const = 0;
+ virtual const ValueTree createTree() const = 0;
virtual void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const = 0;
virtual RelativePoint* getControlPoints (int& numPoints) = 0;
@@ -42300,7 +42312,7 @@ public:
public:
StartSubPath (const RelativePoint& pos);
~StartSubPath() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -42316,7 +42328,7 @@ public:
public:
CloseSubPath();
~CloseSubPath() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -42330,7 +42342,7 @@ public:
public:
LineTo (const RelativePoint& endPoint);
~LineTo() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -42346,7 +42358,7 @@ public:
public:
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint);
~QuadraticTo() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -42362,7 +42374,7 @@ public:
public:
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint);
~CubicTo() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -42379,7 +42391,7 @@ public:
private:
bool containsDynamicPoints;
- void parseString (const String& s);
+ void parse (const ValueTree& state);
RelativePointPath& operator= (const RelativePointPath&);
};
@@ -42601,13 +42613,8 @@ public:
const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
UndoManager* undoManager);
- protected:
ValueTree state;
static const Identifier type, gradientPoint1, gradientPoint2, colour, radial, colours;
-
- void replaceFillType (const Identifier& tag, const FillType& fillType,
- const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
- UndoManager* undoManager);
};
juce_UseDebuggingNewOperator
@@ -58599,7 +58606,7 @@ public:
/** @internal */
static const Identifier valueTreeType;
/** @internal */
- const Identifier getValueTreeType() const { return valueTreeType; }
+ const Identifier getValueTreeType() const { return valueTreeType; }
/** Internally-used class for wrapping a DrawablePath's state into a ValueTree. */
class ValueTreeWrapper : public ValueTreeWrapperBase
@@ -58620,10 +58627,31 @@ public:
const PathStrokeType getStrokeType() const;
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager);
- void getPath (RelativePointPath& path) const;
- void setPath (const String& newPath, UndoManager* undoManager);
+ bool usesNonZeroWinding() const;
+ void setUsesNonZeroWinding (bool b, UndoManager* undoManager);
- static const Identifier fill, stroke, jointStyle, capStyle, strokeWidth, path;
+ class Element
+ {
+ public:
+ explicit Element (const ValueTree& state);
+ ~Element();
+
+ const Identifier getType() const throw() { return state.getType(); }
+ int getNumControlPoints() const throw();
+
+ const RelativePoint getControlPoint (int index) const;
+ void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager);
+
+ static const Identifier startSubPathElement, closeSubPathElement,
+ lineToElement, quadraticToElement, cubicToElement;
+
+ ValueTree state;
+ };
+
+ ValueTree getPathState();
+
+ static const Identifier fill, stroke, path, jointStyle, capStyle, strokeWidth,
+ nonZeroWinding, point1, point2, point3;
};
juce_UseDebuggingNewOperator
diff --git a/src/containers/juce_ValueTree.cpp b/src/containers/juce_ValueTree.cpp
index a4d1f4d714..064a56c398 100644
--- a/src/containers/juce_ValueTree.cpp
+++ b/src/containers/juce_ValueTree.cpp
@@ -381,6 +381,18 @@ ValueTree ValueTree::SharedObject::getChildWithName (const Identifier& typeToMat
return ValueTree::invalid;
}
+ValueTree ValueTree::SharedObject::getOrCreateChildWithName (const Identifier& typeToMatch, UndoManager* undoManager)
+{
+ for (int i = 0; i < children.size(); ++i)
+ if (children.getUnchecked(i)->type == typeToMatch)
+ return ValueTree (static_cast (children.getUnchecked(i)));
+
+ SharedObject* const newObject = new SharedObject (typeToMatch);
+ addChild (newObject, -1, undoManager);
+ return ValueTree (newObject);
+
+}
+
ValueTree ValueTree::SharedObject::getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const
{
for (int i = 0; i < children.size(); ++i)
@@ -717,6 +729,11 @@ ValueTree ValueTree::getChildWithName (const Identifier& type) const
return object != 0 ? object->getChildWithName (type) : ValueTree::invalid;
}
+ValueTree ValueTree::getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager)
+{
+ return object != 0 ? object->getOrCreateChildWithName (type, undoManager) : ValueTree::invalid;
+}
+
ValueTree ValueTree::getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const
{
return object != 0 ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree::invalid;
diff --git a/src/containers/juce_ValueTree.h b/src/containers/juce_ValueTree.h
index e6067b6ea3..371c2e046e 100644
--- a/src/containers/juce_ValueTree.h
+++ b/src/containers/juce_ValueTree.h
@@ -214,12 +214,22 @@ public:
*/
ValueTree getChild (int index) const;
- /** Looks for a child node with the speficied type name.
+ /** Returns the first child node with the speficied type name.
If no such node is found, it'll return an invalid node. (See isValid() to find out
whether a node is valid).
+ @see getOrCreateChildWithName
*/
ValueTree getChildWithName (const Identifier& type) const;
+ /** Returns the first child node with the speficied type name, creating and adding
+ a child with this name if there wasn't already one there.
+
+ The only time this will return an invalid object is when the object that you're calling
+ the method on is itself invalid.
+ @see getChildWithName
+ */
+ ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager);
+
/** Looks for the first child node that has the speficied property value.
This will scan the child nodes in order, until it finds one that has property that matches
@@ -467,6 +477,7 @@ private:
bool isAChildOf (const SharedObject* possibleParent) const;
int indexOf (const ValueTree& child) const;
ValueTree getChildWithName (const Identifier& type) const;
+ ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager);
ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const;
void addChild (SharedObject* child, int index, UndoManager*);
void removeChild (int childIndex, UndoManager*);
diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h
index f8be6f2b85..2f8550bc1c 100644
--- a/src/core/juce_StandardHeader.h
+++ b/src/core/juce_StandardHeader.h
@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
-#define JUCE_BUILDNUMBER 7
+#define JUCE_BUILDNUMBER 8
/** Current Juce version number.
diff --git a/src/gui/graphics/colour/juce_ColourGradient.cpp b/src/gui/graphics/colour/juce_ColourGradient.cpp
index f8af3886e3..dc05e5c04e 100644
--- a/src/gui/graphics/colour/juce_ColourGradient.cpp
+++ b/src/gui/graphics/colour/juce_ColourGradient.cpp
@@ -160,7 +160,7 @@ int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlo
jassert (point1.getX() != 987654.0f);
#endif
- const int numEntries = jlimit (1, (colours.size() - 1) << 8,
+ const int numEntries = jlimit (1, jmax (1, (colours.size() - 1) << 8),
3 * (int) point1.transformedBy (transform)
.getDistanceFrom (point2.transformedBy (transform)));
lookupTable.malloc (numEntries);
diff --git a/src/gui/graphics/drawables/juce_Drawable.cpp b/src/gui/graphics/drawables/juce_Drawable.cpp
index 87f773b372..db22b8538b 100644
--- a/src/gui/graphics/drawables/juce_Drawable.cpp
+++ b/src/gui/graphics/drawables/juce_Drawable.cpp
@@ -238,10 +238,6 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType
{
v.setProperty (type, "solid", undoManager);
v.setProperty (colour, String::toHexString ((int) fillType.colour.getARGB()), undoManager);
- v.removeProperty (gradientPoint1, undoManager);
- v.removeProperty (gradientPoint2, undoManager);
- v.removeProperty (radial, undoManager);
- v.removeProperty (colours, undoManager);
}
else if (fillType.isGradient())
{
@@ -256,19 +252,12 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType
<< " " << String::toHexString ((int) fillType.gradient->getColour(i).getARGB());
v.setProperty (colours, s.trimStart(), undoManager);
- v.removeProperty (colour, undoManager);
}
else if (fillType.isTiledImage())
{
v.setProperty (type, "image", undoManager);
jassertfalse; //xxx todo
-
- v.removeProperty (gradientPoint1, undoManager);
- v.removeProperty (gradientPoint2, undoManager);
- v.removeProperty (radial, undoManager);
- v.removeProperty (colours, undoManager);
- v.removeProperty (colour, undoManager);
}
else
{
@@ -276,20 +265,5 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType
}
}
-void Drawable::ValueTreeWrapperBase::replaceFillType (const Identifier& tag, const FillType& fillType,
- const RelativePoint* gp1, const RelativePoint* gp2,
- UndoManager* const undoManager)
-{
- ValueTree v (state.getChildWithName (tag));
-
- if (! v.isValid())
- {
- state.addChild (ValueTree (tag), -1, undoManager);
- v = state.getChildWithName (tag);
- }
-
- writeFillType (v, fillType, gp1, gp2, undoManager);
-}
-
END_JUCE_NAMESPACE
diff --git a/src/gui/graphics/drawables/juce_Drawable.h b/src/gui/graphics/drawables/juce_Drawable.h
index fe797c5262..e083a59093 100644
--- a/src/gui/graphics/drawables/juce_Drawable.h
+++ b/src/gui/graphics/drawables/juce_Drawable.h
@@ -255,13 +255,8 @@ public:
const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
UndoManager* undoManager);
- protected:
ValueTree state;
static const Identifier type, gradientPoint1, gradientPoint2, colour, radial, colours;
-
- void replaceFillType (const Identifier& tag, const FillType& fillType,
- const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
- UndoManager* undoManager);
};
//==============================================================================
diff --git a/src/gui/graphics/drawables/juce_DrawableComposite.cpp b/src/gui/graphics/drawables/juce_DrawableComposite.cpp
index 9c837100d1..061ce52a67 100644
--- a/src/gui/graphics/drawables/juce_DrawableComposite.cpp
+++ b/src/gui/graphics/drawables/juce_DrawableComposite.cpp
@@ -360,12 +360,7 @@ ValueTree DrawableComposite::ValueTreeWrapper::getChildList() const
ValueTree DrawableComposite::ValueTreeWrapper::getChildListCreating (UndoManager* undoManager)
{
- const ValueTree childList (getChildList());
- if (childList.isValid())
- return childList;
-
- state.addChild (ValueTree (childGroupTag), 0, undoManager);
- return getChildList();
+ return state.getOrCreateChildWithName (childGroupTag, undoManager);
}
int DrawableComposite::ValueTreeWrapper::getNumDrawables() const
@@ -466,12 +461,7 @@ ValueTree DrawableComposite::ValueTreeWrapper::getMarkerList (bool xAxis) const
ValueTree DrawableComposite::ValueTreeWrapper::getMarkerListCreating (bool xAxis, UndoManager* undoManager)
{
- const ValueTree markerList (getMarkerList (xAxis));
- if (markerList.isValid())
- return markerList;
-
- state.addChild (ValueTree (xAxis ? markerGroupTagX : markerGroupTagY), -1, undoManager);
- return getMarkerList (xAxis);
+ return state.getOrCreateChildWithName (xAxis ? markerGroupTagX : markerGroupTagY, undoManager);
}
int DrawableComposite::ValueTreeWrapper::getNumMarkers (bool xAxis) const
diff --git a/src/gui/graphics/drawables/juce_DrawableImage.cpp b/src/gui/graphics/drawables/juce_DrawableImage.cpp
index 583a620810..ef13aeb4bd 100644
--- a/src/gui/graphics/drawables/juce_DrawableImage.cpp
+++ b/src/gui/graphics/drawables/juce_DrawableImage.cpp
@@ -313,6 +313,8 @@ const Rectangle DrawableImage::refreshFromValueTree (const ValueTree& tre
|| controlPoints[1] != newControlPoint[1]
|| controlPoints[2] != newControlPoint[2])
{
+ const Rectangle damage (getBounds());
+
opacity = newOpacity;
overlayColour = newOverlayColour;
controlPoints[0] = newControlPoint[0];
@@ -328,7 +330,7 @@ const Rectangle DrawableImage::refreshFromValueTree (const ValueTree& tre
image = newImage;
}
- return getBounds();
+ return damage.getUnion (getBounds());
}
ImageCache::release (newImage);
diff --git a/src/gui/graphics/drawables/juce_DrawablePath.cpp b/src/gui/graphics/drawables/juce_DrawablePath.cpp
index 98d9e88202..a8f3caf60e 100644
--- a/src/gui/graphics/drawables/juce_DrawablePath.cpp
+++ b/src/gui/graphics/drawables/juce_DrawablePath.cpp
@@ -183,12 +183,16 @@ Drawable* DrawablePath::createCopy() const
//==============================================================================
const Identifier DrawablePath::valueTreeType ("Path");
-const Identifier DrawablePath::ValueTreeWrapper::fill ("fill");
-const Identifier DrawablePath::ValueTreeWrapper::stroke ("stroke");
+const Identifier DrawablePath::ValueTreeWrapper::fill ("Fill");
+const Identifier DrawablePath::ValueTreeWrapper::stroke ("Stroke");
+const Identifier DrawablePath::ValueTreeWrapper::path ("Path");
const Identifier DrawablePath::ValueTreeWrapper::jointStyle ("jointStyle");
const Identifier DrawablePath::ValueTreeWrapper::capStyle ("capStyle");
const Identifier DrawablePath::ValueTreeWrapper::strokeWidth ("strokeWidth");
-const Identifier DrawablePath::ValueTreeWrapper::path ("path");
+const Identifier DrawablePath::ValueTreeWrapper::nonZeroWinding ("nonZeroWinding");
+const Identifier DrawablePath::ValueTreeWrapper::point1 ("p1");
+const Identifier DrawablePath::ValueTreeWrapper::point2 ("p2");
+const Identifier DrawablePath::ValueTreeWrapper::point3 ("p3");
//==============================================================================
DrawablePath::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
@@ -197,6 +201,11 @@ DrawablePath::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
jassert (state.hasType (valueTreeType));
}
+ValueTree DrawablePath::ValueTreeWrapper::getPathState()
+{
+ return state.getOrCreateChildWithName (path, 0);
+}
+
ValueTree DrawablePath::ValueTreeWrapper::getMainFillState()
{
ValueTree v (state.getChildWithName (fill));
@@ -225,7 +234,8 @@ const FillType DrawablePath::ValueTreeWrapper::getMainFill (RelativeCoordinate::
void DrawablePath::ValueTreeWrapper::setMainFill (const FillType& newFill, const RelativePoint* gp1,
const RelativePoint* gp2, UndoManager* undoManager)
{
- replaceFillType (fill, newFill, gp1, gp2, undoManager);
+ ValueTree v (state.getOrCreateChildWithName (fill, undoManager));
+ writeFillType (v, newFill, gp1, gp2, undoManager);
}
const FillType DrawablePath::ValueTreeWrapper::getStrokeFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const
@@ -236,7 +246,8 @@ const FillType DrawablePath::ValueTreeWrapper::getStrokeFill (RelativeCoordinate
void DrawablePath::ValueTreeWrapper::setStrokeFill (const FillType& newFill, const RelativePoint* gp1,
const RelativePoint* gp2, UndoManager* undoManager)
{
- replaceFillType (stroke, newFill, gp1, gp2, undoManager);
+ ValueTree v (state.getOrCreateChildWithName (stroke, undoManager));
+ writeFillType (v, newFill, gp1, gp2, undoManager);
}
const PathStrokeType DrawablePath::ValueTreeWrapper::getStrokeType() const
@@ -262,17 +273,54 @@ void DrawablePath::ValueTreeWrapper::setStrokeType (const PathStrokeType& newStr
? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager);
}
-void DrawablePath::ValueTreeWrapper::getPath (RelativePointPath& p) const
+bool DrawablePath::ValueTreeWrapper::usesNonZeroWinding() const
{
- RelativePointPath newPath (state [path]);
- p.swapWith (newPath);
+ return state [nonZeroWinding];
}
-void DrawablePath::ValueTreeWrapper::setPath (const String& newPath, UndoManager* undoManager)
+void DrawablePath::ValueTreeWrapper::setUsesNonZeroWinding (bool b, UndoManager* undoManager)
{
- state.setProperty (path, newPath, undoManager);
+ state.setProperty (nonZeroWinding, b, undoManager);
}
+const Identifier DrawablePath::ValueTreeWrapper::Element::startSubPathElement ("Move");
+const Identifier DrawablePath::ValueTreeWrapper::Element::closeSubPathElement ("Close");
+const Identifier DrawablePath::ValueTreeWrapper::Element::lineToElement ("Line");
+const Identifier DrawablePath::ValueTreeWrapper::Element::quadraticToElement ("Quad");
+const Identifier DrawablePath::ValueTreeWrapper::Element::cubicToElement ("Cubic");
+
+DrawablePath::ValueTreeWrapper::Element::Element (const ValueTree& state_)
+ : state (state_)
+{
+}
+
+DrawablePath::ValueTreeWrapper::Element::~Element()
+{
+}
+
+int DrawablePath::ValueTreeWrapper::Element::getNumControlPoints() const throw()
+{
+ const Identifier i (state.getType());
+ if (i == startSubPathElement || i == lineToElement) return 1;
+ if (i == quadraticToElement) return 2;
+ if (i == cubicToElement) return 3;
+ return 0;
+}
+
+const RelativePoint DrawablePath::ValueTreeWrapper::Element::getControlPoint (const int index) const
+{
+ jassert (index >= 0 && index < getNumControlPoints());
+ return RelativePoint (state [index == 0 ? point1 : (index == 1 ? point2 : point3)].toString());
+}
+
+void DrawablePath::ValueTreeWrapper::Element::setControlPoint (const int index, const RelativePoint& point, UndoManager* undoManager)
+{
+ jassert (index >= 0 && index < getNumControlPoints());
+ return state.setProperty (index == 0 ? point1 : (index == 1 ? point2 : point3), point.toString(), undoManager);
+}
+
+
+//==============================================================================
const Rectangle DrawablePath::refreshFromValueTree (const ValueTree& tree, ImageProvider*)
{
Rectangle damageRect;
@@ -298,8 +346,7 @@ const Rectangle DrawablePath::refreshFromValueTree (const ValueTree& tree
const PathStrokeType newStroke (v.getStrokeType());
- ScopedPointer newRelativePath (new RelativePointPath());
- v.getPath (*newRelativePath);
+ ScopedPointer newRelativePath (new RelativePointPath (tree));
Path newPath;
newRelativePath->createPath (newPath, parent);
@@ -334,9 +381,14 @@ const ValueTree DrawablePath::createValueTree (ImageProvider*) const
v.setStrokeType (strokeType, 0);
if (relativePath != 0)
- v.setPath (relativePath->toString(), 0);
+ {
+ relativePath->writeTo (tree, 0);
+ }
else
- v.setPath (path.toString(), 0);
+ {
+ RelativePointPath rp (path);
+ rp.writeTo (tree, 0);
+ }
return tree;
}
diff --git a/src/gui/graphics/drawables/juce_DrawablePath.h b/src/gui/graphics/drawables/juce_DrawablePath.h
index ec8486c490..2c76727e69 100644
--- a/src/gui/graphics/drawables/juce_DrawablePath.h
+++ b/src/gui/graphics/drawables/juce_DrawablePath.h
@@ -119,7 +119,7 @@ public:
/** @internal */
static const Identifier valueTreeType;
/** @internal */
- const Identifier getValueTreeType() const { return valueTreeType; }
+ const Identifier getValueTreeType() const { return valueTreeType; }
//==============================================================================
/** Internally-used class for wrapping a DrawablePath's state into a ValueTree. */
@@ -141,10 +141,31 @@ public:
const PathStrokeType getStrokeType() const;
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager);
- void getPath (RelativePointPath& path) const;
- void setPath (const String& newPath, UndoManager* undoManager);
+ bool usesNonZeroWinding() const;
+ void setUsesNonZeroWinding (bool b, UndoManager* undoManager);
- static const Identifier fill, stroke, jointStyle, capStyle, strokeWidth, path;
+ class Element
+ {
+ public:
+ explicit Element (const ValueTree& state);
+ ~Element();
+
+ const Identifier getType() const throw() { return state.getType(); }
+ int getNumControlPoints() const throw();
+
+ const RelativePoint getControlPoint (int index) const;
+ void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager);
+
+ static const Identifier startSubPathElement, closeSubPathElement,
+ lineToElement, quadraticToElement, cubicToElement;
+
+ ValueTree state;
+ };
+
+ ValueTree getPathState();
+
+ static const Identifier fill, stroke, path, jointStyle, capStyle, strokeWidth,
+ nonZeroWinding, point1, point2, point3;
};
//==============================================================================
diff --git a/src/gui/graphics/geometry/juce_RelativeCoordinate.cpp b/src/gui/graphics/geometry/juce_RelativeCoordinate.cpp
index 44721648bf..46072fb1c6 100644
--- a/src/gui/graphics/geometry/juce_RelativeCoordinate.cpp
+++ b/src/gui/graphics/geometry/juce_RelativeCoordinate.cpp
@@ -28,6 +28,7 @@
BEGIN_JUCE_NAMESPACE
#include "juce_RelativeCoordinate.h"
+#include "../drawables/juce_DrawablePath.h"
#include "../../../io/streams/juce_MemoryOutputStream.h"
@@ -494,6 +495,11 @@ RelativePoint::RelativePoint (const Point& absolutePoint)
{
}
+RelativePoint::RelativePoint (const float x_, const float y_)
+ : x (x_, true), y (y_, false)
+{
+}
+
RelativePoint::RelativePoint (const RelativeCoordinate& x_, const RelativeCoordinate& y_)
: x (x_), y (y_)
{
@@ -625,88 +631,83 @@ RelativePointPath::RelativePointPath (const RelativePointPath& other)
: usesNonZeroWinding (true),
containsDynamicPoints (false)
{
- parseString (other.toString());
+ ValueTree state (DrawablePath::valueTreeType);
+ writeTo (state, 0);
+ parse (state);
}
-RelativePointPath::RelativePointPath (const String& s)
+RelativePointPath::RelativePointPath (const ValueTree& drawable)
: usesNonZeroWinding (true),
containsDynamicPoints (false)
{
- parseString (s);
+ parse (drawable);
}
-void RelativePointPath::parseString (const String& s)
+RelativePointPath::RelativePointPath (const Path& path)
{
- int i = 0;
- juce_wchar marker = 'm';
- int numValues = 2;
- RelativePoint points [3];
+ usesNonZeroWinding = path.isUsingNonZeroWinding();
- for (;;)
+ Path::Iterator i (path);
+
+ while (i.next())
{
- RelativeCoordinateHelpers::skipWhitespace (s, i);
- const juce_wchar firstChar = s[i];
-
- if (firstChar == 0)
- break;
-
- const juce_wchar secondChar = s[i + 1];
-
- if (secondChar == 0 || CharacterFunctions::isWhitespace (secondChar))
+ switch (i.elementType)
{
- if (firstChar == 'm' || firstChar == 'l')
- {
- ++i;
- marker = firstChar;
- numValues = 1;
- }
- else if (firstChar == 'q')
- {
- ++i;
- marker = firstChar;
- numValues = 2;
- }
- else if (firstChar == 'c')
- {
- ++i;
- marker = firstChar;
- numValues = 3;
- }
- else if (firstChar == 'z')
- {
- ++i;
- marker = 'm';
- numValues = 2;
- elements.add (new CloseSubPath());
- continue;
- }
- else if (firstChar == 'a')
- {
- ++i;
- usesNonZeroWinding = false;
- continue;
- }
+ case Path::Iterator::startNewSubPath: elements.add (new StartSubPath (RelativePoint (i.x1, i.y1))); break;
+ case Path::Iterator::lineTo: elements.add (new LineTo (RelativePoint (i.x1, i.y1))); break;
+ case Path::Iterator::quadraticTo: elements.add (new QuadraticTo (RelativePoint (i.x1, i.y1), RelativePoint (i.x2, i.y2))); break;
+ case Path::Iterator::cubicTo: elements.add (new CubicTo (RelativePoint (i.x1, i.y1), RelativePoint (i.x2, i.y2), RelativePoint (i.x3, i.y3))); break;
+ case Path::Iterator::closePath: elements.add (new CloseSubPath()); break;
+ default: jassertfalse; break;
}
+ }
+}
- if (firstChar == '#')
- ++i;
+void RelativePointPath::writeTo (ValueTree state, UndoManager* undoManager)
+{
+ DrawablePath::ValueTreeWrapper wrapper (state);
+ wrapper.setUsesNonZeroWinding (usesNonZeroWinding, undoManager);
- for (int j = 0; j < numValues; ++j)
+ ValueTree pathTree (wrapper.getPathState());
+ pathTree.removeAllChildren (undoManager);
+
+ for (int i = 0; i < elements.size(); ++i)
+ pathTree.addChild (elements.getUnchecked(i)->createTree(), -1, undoManager);
+}
+
+void RelativePointPath::parse (const ValueTree& state)
+{
+ DrawablePath::ValueTreeWrapper wrapper (state);
+ usesNonZeroWinding = wrapper.usesNonZeroWinding();
+ RelativePoint points[3];
+
+ const ValueTree pathTree (wrapper.getPathState());
+ const int num = pathTree.getNumChildren();
+ for (int i = 0; i < num; ++i)
+ {
+ const DrawablePath::ValueTreeWrapper::Element e (pathTree.getChild(i));
+
+ const int numCps = e.getNumControlPoints();
+ for (int j = 0; j < numCps; ++j)
{
- const RelativeCoordinate x (RelativeCoordinateHelpers::readNextCoordinate (s, i, true));
- const RelativeCoordinate y (RelativeCoordinateHelpers::readNextCoordinate (s, i, false));
- points[j] = RelativePoint (x, y);
+ points[j] = e.getControlPoint (j);
containsDynamicPoints = containsDynamicPoints || points[j].isDynamic();
}
- switch (marker)
- {
- case 'm': elements.add (new StartSubPath (points[0])); break;
- case 'l': elements.add (new LineTo (points[0])); break;
- case 'q': elements.add (new QuadraticTo (points[0], points[1])); break;
- case 'c': elements.add (new CubicTo (points[0], points[1], points[2])); break;
- default: jassertfalse; break; // illegal string format?
- }
+ const Identifier type (e.getType());
+
+ if (type == DrawablePath::ValueTreeWrapper::Element::startSubPathElement)
+ elements.add (new StartSubPath (points[0]));
+ else if (type == DrawablePath::ValueTreeWrapper::Element::closeSubPathElement)
+ elements.add (new CloseSubPath());
+ else if (type == DrawablePath::ValueTreeWrapper::Element::lineToElement)
+ elements.add (new LineTo (points[0]));
+ else if (type == DrawablePath::ValueTreeWrapper::Element::quadraticToElement)
+ elements.add (new QuadraticTo (points[0], points[1]));
+ else if (type == DrawablePath::ValueTreeWrapper::Element::cubicToElement)
+ elements.add (new CubicTo (points[0], points[1], points[2]));
+ else
+ jassertfalse;
}
}
@@ -731,27 +732,6 @@ bool RelativePointPath::containsAnyDynamicPoints() const
return containsDynamicPoints;
}
-const String RelativePointPath::toString() const
-{
- ElementType lastType = nullElement;
- MemoryOutputStream out;
-
- if (! usesNonZeroWinding)
- out << 'a';
-
- for (int i = 0; i < elements.size(); ++i)
- {
- if (out.getDataSize() > 0)
- out << ' ';
-
- const ElementBase* const e = elements.getUnchecked(i);
- e->write (out, lastType);
- lastType = e->type;
- }
-
- return out.toUTF8();
-}
-
//==============================================================================
RelativePointPath::ElementBase::ElementBase (const ElementType type_) : type (type_)
{
@@ -763,16 +743,11 @@ RelativePointPath::StartSubPath::StartSubPath (const RelativePoint& pos)
{
}
-void RelativePointPath::StartSubPath::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::StartSubPath::createTree() const
{
- const String p (startPos.toString());
-
- if (lastTypeWritten != startSubPathElement)
- out << "m ";
- else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p))
- out << '#';
-
- out << p;
+ ValueTree v (DrawablePath::ValueTreeWrapper::Element::startSubPathElement);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point1, startPos.toString(), 0);
+ return v;
}
void RelativePointPath::StartSubPath::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const
@@ -793,10 +768,9 @@ RelativePointPath::CloseSubPath::CloseSubPath()
{
}
-void RelativePointPath::CloseSubPath::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::CloseSubPath::createTree() const
{
- if (lastTypeWritten != closeSubPathElement)
- out << 'z';
+ return ValueTree (DrawablePath::ValueTreeWrapper::Element::closeSubPathElement);
}
void RelativePointPath::CloseSubPath::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder*) const
@@ -816,16 +790,11 @@ RelativePointPath::LineTo::LineTo (const RelativePoint& endPoint_)
{
}
-void RelativePointPath::LineTo::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::LineTo::createTree() const
{
- const String p (endPoint.toString());
-
- if (lastTypeWritten != lineToElement)
- out << "l ";
- else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p))
- out << '#';
-
- out << p;
+ ValueTree v (DrawablePath::ValueTreeWrapper::Element::lineToElement);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point1, endPoint.toString(), 0);
+ return v;
}
void RelativePointPath::LineTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const
@@ -848,16 +817,12 @@ RelativePointPath::QuadraticTo::QuadraticTo (const RelativePoint& controlPoint,
controlPoints[1] = endPoint;
}
-void RelativePointPath::QuadraticTo::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::QuadraticTo::createTree() const
{
- const String p1 (controlPoints[0].toString());
-
- if (lastTypeWritten != quadraticToElement)
- out << "q ";
- else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1))
- out << '#';
-
- out << p1 << ' ' << controlPoints[1].toString();
+ ValueTree v (DrawablePath::ValueTreeWrapper::Element::quadraticToElement);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point1, controlPoints[0].toString(), 0);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point2, controlPoints[1].toString(), 0);
+ return v;
}
void RelativePointPath::QuadraticTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const
@@ -882,16 +847,13 @@ RelativePointPath::CubicTo::CubicTo (const RelativePoint& controlPoint1, const R
controlPoints[2] = endPoint;
}
-void RelativePointPath::CubicTo::write (OutputStream& out, ElementType lastTypeWritten) const
+const ValueTree RelativePointPath::CubicTo::createTree() const
{
- const String p1 (controlPoints[0].toString());
-
- if (lastTypeWritten != cubicToElement)
- out << "c ";
- else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1))
- out << '#';
-
- out << p1 << ' ' << controlPoints[1].toString() << ' ' << controlPoints[2].toString();
+ ValueTree v (DrawablePath::ValueTreeWrapper::Element::cubicToElement);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point1, controlPoints[0].toString(), 0);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point2, controlPoints[1].toString(), 0);
+ v.setProperty (DrawablePath::ValueTreeWrapper::point3, controlPoints[2].toString(), 0);
+ return v;
}
void RelativePointPath::CubicTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const
diff --git a/src/gui/graphics/geometry/juce_RelativeCoordinate.h b/src/gui/graphics/geometry/juce_RelativeCoordinate.h
index 377ef18054..5beecf5d59 100644
--- a/src/gui/graphics/geometry/juce_RelativeCoordinate.h
+++ b/src/gui/graphics/geometry/juce_RelativeCoordinate.h
@@ -29,6 +29,7 @@
#include "juce_Path.h"
#include "juce_Rectangle.h"
#include "../../../containers/juce_OwnedArray.h"
+#include "../../../containers/juce_ValueTree.h"
//==============================================================================
@@ -289,6 +290,9 @@ public:
/** Creates an absolute point, relative to the origin. */
RelativePoint (const Point& 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);
@@ -416,7 +420,8 @@ public:
//==============================================================================
RelativePointPath();
RelativePointPath (const RelativePointPath& other);
- RelativePointPath (const String& stringVersion);
+ RelativePointPath (const ValueTree& drawable);
+ RelativePointPath (const Path& path);
~RelativePointPath();
//==============================================================================
@@ -426,11 +431,8 @@ public:
/** Returns true if the path contains any non-fixed points. */
bool containsAnyDynamicPoints() const;
- /** Returns a string version of the path.
- This has the same format as Path::toString(), but since it can contain RelativeCoordinate
- positions, it can't be parsed by the Path class if any of the points are dynamic.
- */
- const String toString() const;
+ /** Writes the path to this drawable encoding. */
+ void writeTo (ValueTree state, UndoManager* undoManager);
/** Quickly swaps the contents of this path with another. */
void swapWith (RelativePointPath& other) throw();
@@ -457,7 +459,7 @@ public:
public:
ElementBase (ElementType type);
virtual ~ElementBase() {}
- virtual void write (OutputStream& out, ElementType lastTypeWritten) const = 0;
+ virtual const ValueTree createTree() const = 0;
virtual void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const = 0;
virtual RelativePoint* getControlPoints (int& numPoints) = 0;
@@ -473,7 +475,7 @@ public:
public:
StartSubPath (const RelativePoint& pos);
~StartSubPath() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -489,7 +491,7 @@ public:
public:
CloseSubPath();
~CloseSubPath() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -503,7 +505,7 @@ public:
public:
LineTo (const RelativePoint& endPoint);
~LineTo() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -519,7 +521,7 @@ public:
public:
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint);
~QuadraticTo() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -535,7 +537,7 @@ public:
public:
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint);
~CubicTo() {}
- void write (OutputStream& out, ElementType lastTypeWritten) const;
+ const ValueTree createTree() const;
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const;
RelativePoint* getControlPoints (int& numPoints);
@@ -553,7 +555,7 @@ public:
private:
bool containsDynamicPoints;
- void parseString (const String& s);
+ void parse (const ValueTree& state);
RelativePointPath& operator= (const RelativePointPath&);
};
diff --git a/src/io/network/juce_URL.cpp b/src/io/network/juce_URL.cpp
index 8df99b3396..269c1e983f 100644
--- a/src/io/network/juce_URL.cpp
+++ b/src/io/network/juce_URL.cpp
@@ -282,7 +282,7 @@ public:
timeOutMs);
if (responseHeaders != 0)
- juce_getInternetFileHeaders (handle, *responseHeaders);
+ juce_getInternetFileHeaders (handle, *responseHeaders);
}
~WebInputStream()
diff --git a/src/native/linux/juce_linux_Network.cpp b/src/native/linux/juce_linux_Network.cpp
index 8182792b84..5d8a4aa11b 100644
--- a/src/native/linux/juce_linux_Network.cpp
+++ b/src/native/linux/juce_linux_Network.cpp
@@ -1,481 +1,481 @@
-/*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-10 by Raw Material Software Ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the GNU General
- Public License (Version 2), as published by the Free Software Foundation.
- A copy of the license is included in the JUCE distribution, or can be found
- online at www.gnu.org/licenses.
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.rawmaterialsoftware.com/juce for more information.
-
- ==============================================================================
-*/
-
-// (This file gets included by juce_linux_NativeCode.cpp, rather than being
-// compiled on its own).
-#if JUCE_INCLUDED_FILE
-
-
-//==============================================================================
-int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian)
-{
- int numResults = 0;
-
- const int s = socket (AF_INET, SOCK_DGRAM, 0);
- if (s != -1)
- {
- char buf [1024];
- struct ifconf ifc;
- ifc.ifc_len = sizeof (buf);
- ifc.ifc_buf = buf;
- ioctl (s, SIOCGIFCONF, &ifc);
-
- for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
- {
- struct ifreq ifr;
- strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
-
- if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
- && (ifr.ifr_flags & IFF_LOOPBACK) == 0
- && ioctl (s, SIOCGIFHWADDR, &ifr) == 0
- && numResults < maxNum)
- {
- int64 a = 0;
- for (int j = 6; --j >= 0;)
- a = (a << 8) | (uint8) ifr.ifr_hwaddr.sa_data [littleEndian ? j : (5 - j)];
-
- *addresses++ = a;
- ++numResults;
- }
- }
-
- close (s);
- }
-
- return numResults;
-}
-
-
-bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
- const String& emailSubject,
- const String& bodyText,
- const StringArray& filesToAttach)
-{
- jassertfalse; // xxx todo
-
- return false;
-}
-
-//==============================================================================
-/** A HTTP input stream that uses sockets.
- */
-class JUCE_HTTPSocketStream
-{
-public:
- //==============================================================================
- JUCE_HTTPSocketStream()
- : readPosition (0),
- socketHandle (-1),
- levelsOfRedirection (0),
- timeoutSeconds (15)
- {
- }
-
- ~JUCE_HTTPSocketStream()
- {
- closeSocket();
- }
-
- //==============================================================================
- bool open (const String& url,
- const String& headers,
- const MemoryBlock& postData,
- const bool isPost,
- URL::OpenStreamProgressCallback* callback,
- void* callbackContext,
- int timeOutMs)
- {
- closeSocket();
-
- uint32 timeOutTime = Time::getMillisecondCounter();
-
- if (timeOutMs == 0)
- timeOutTime += 60000;
- else if (timeOutMs < 0)
- timeOutTime = 0xffffffff;
- else
- timeOutTime += timeOutMs;
-
- String hostName, hostPath;
- int hostPort;
-
- if (! decomposeURL (url, hostName, hostPath, hostPort))
- return false;
-
- const struct hostent* host = 0;
- int port = 0;
-
- String proxyName, proxyPath;
- int proxyPort = 0;
-
- String proxyURL (getenv ("http_proxy"));
- if (proxyURL.startsWithIgnoreCase ("http://"))
- {
- if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
- return false;
-
- host = gethostbyname (proxyName.toUTF8());
- port = proxyPort;
- }
- else
- {
- host = gethostbyname (hostName.toUTF8());
- port = hostPort;
- }
-
- if (host == 0)
- return false;
-
- struct sockaddr_in address;
- zerostruct (address);
- memcpy (&address.sin_addr, host->h_addr, host->h_length);
- address.sin_family = host->h_addrtype;
- address.sin_port = htons (port);
-
- socketHandle = socket (host->h_addrtype, SOCK_STREAM, 0);
-
- if (socketHandle == -1)
- return false;
-
- int receiveBufferSize = 16384;
- setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
- setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
-
-#if JUCE_MAC
- setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
-#endif
-
- if (connect (socketHandle, (struct sockaddr*) &address, sizeof (address)) == -1)
- {
- closeSocket();
- return false;
- }
-
- const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort,
- proxyName, proxyPort,
- hostPath, url,
- headers, postData,
- isPost));
- size_t totalHeaderSent = 0;
-
- while (totalHeaderSent < requestHeader.getSize())
- {
- if (Time::getMillisecondCounter() > timeOutTime)
- {
- closeSocket();
- return false;
- }
-
- const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
-
- if (send (socketHandle,
- ((const char*) requestHeader.getData()) + totalHeaderSent,
- numToSend, 0)
- != numToSend)
- {
- closeSocket();
- return false;
- }
-
- totalHeaderSent += numToSend;
-
- if (callback != 0 && ! callback (callbackContext, totalHeaderSent, requestHeader.getSize()))
- {
- closeSocket();
- return false;
- }
- }
-
- const String responseHeader (readResponse (timeOutTime));
-
- if (responseHeader.isNotEmpty())
- {
- //DBG (responseHeader);
-
- headerLines.clear();
- headerLines.addLines (responseHeader);
-
- const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
- .substring (0, 3).getIntValue();
-
- //int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
- //bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
-
- String location (findHeaderItem (headerLines, "Location:"));
-
- if (statusCode >= 300 && statusCode < 400
- && location.isNotEmpty())
- {
- if (! location.startsWithIgnoreCase ("http://"))
- location = "http://" + location;
-
- if (levelsOfRedirection++ < 3)
- return open (location, headers, postData, isPost, callback, callbackContext, timeOutMs);
- }
- else
- {
- levelsOfRedirection = 0;
- return true;
- }
- }
-
- closeSocket();
- return false;
- }
-
- //==============================================================================
- int read (void* buffer, int bytesToRead)
- {
- fd_set readbits;
- FD_ZERO (&readbits);
- FD_SET (socketHandle, &readbits);
-
- struct timeval tv;
- tv.tv_sec = timeoutSeconds;
- tv.tv_usec = 0;
-
- if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
- return 0; // (timeout)
-
- const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
- readPosition += bytesRead;
- return bytesRead;
- }
-
- //==============================================================================
- int readPosition;
- StringArray headerLines;
-
- //==============================================================================
- juce_UseDebuggingNewOperator
-
-private:
- int socketHandle, levelsOfRedirection;
- const int timeoutSeconds;
-
- //==============================================================================
- void closeSocket()
- {
- if (socketHandle >= 0)
- close (socketHandle);
-
- socketHandle = -1;
- }
-
- const MemoryBlock createRequestHeader (const String& hostName,
- const int hostPort,
- const String& proxyName,
- const int proxyPort,
- const String& hostPath,
- const String& originalURL,
- const String& headers,
- const MemoryBlock& postData,
- const bool isPost)
- {
- String header (isPost ? "POST " : "GET ");
-
- if (proxyName.isEmpty())
- {
- header << hostPath << " HTTP/1.0\r\nHost: "
- << hostName << ':' << hostPort;
- }
- else
- {
- header << originalURL << " HTTP/1.0\r\nHost: "
- << proxyName << ':' << proxyPort;
- }
-
- header << "\r\nUser-Agent: JUCE/"
- << JUCE_MAJOR_VERSION << '.' << JUCE_MINOR_VERSION
- << "\r\nConnection: Close\r\nContent-Length: "
- << postData.getSize() << "\r\n"
- << headers << "\r\n";
-
- MemoryBlock mb;
- mb.append (header.toUTF8(), (int) strlen (header.toUTF8()));
- mb.append (postData.getData(), postData.getSize());
-
- return mb;
- }
-
- const String readResponse (const uint32 timeOutTime)
- {
- int bytesRead = 0, numConsecutiveLFs = 0;
- MemoryBlock buffer (1024, true);
-
- while (numConsecutiveLFs < 2 && bytesRead < 32768
- && Time::getMillisecondCounter() <= timeOutTime)
- {
- fd_set readbits;
- FD_ZERO (&readbits);
- FD_SET (socketHandle, &readbits);
-
- struct timeval tv;
- tv.tv_sec = timeoutSeconds;
- tv.tv_usec = 0;
-
- if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
- return String::empty; // (timeout)
-
- buffer.ensureSize (bytesRead + 8, true);
- char* const dest = (char*) buffer.getData() + bytesRead;
-
- if (recv (socketHandle, dest, 1, 0) == -1)
- return String::empty;
-
- const char lastByte = *dest;
- ++bytesRead;
-
- if (lastByte == '\n')
- ++numConsecutiveLFs;
- else if (lastByte != '\r')
- numConsecutiveLFs = 0;
- }
-
- const String header (String::fromUTF8 ((const char*) buffer.getData()));
-
- if (header.startsWithIgnoreCase ("HTTP/"))
- return header.trimEnd();
-
- return String::empty;
- }
-
- //==============================================================================
- static bool decomposeURL (const String& url,
- String& host, String& path, int& port)
- {
- if (! url.startsWithIgnoreCase ("http://"))
- return false;
-
- const int nextSlash = url.indexOfChar (7, '/');
- int nextColon = url.indexOfChar (7, ':');
- if (nextColon > nextSlash && nextSlash > 0)
- nextColon = -1;
-
- if (nextColon >= 0)
- {
- host = url.substring (7, nextColon);
-
- if (nextSlash >= 0)
- port = url.substring (nextColon + 1, nextSlash).getIntValue();
- else
- port = url.substring (nextColon + 1).getIntValue();
- }
- else
- {
- port = 80;
-
- if (nextSlash >= 0)
- host = url.substring (7, nextSlash);
- else
- host = url.substring (7);
- }
-
- if (nextSlash >= 0)
- path = url.substring (nextSlash);
- else
- path = "/";
-
- return true;
- }
-
- //==============================================================================
- static const String findHeaderItem (const StringArray& lines, const String& itemName)
- {
- for (int i = 0; i < lines.size(); ++i)
- if (lines[i].startsWithIgnoreCase (itemName))
- return lines[i].substring (itemName.length()).trim();
-
- return String::empty;
- }
-};
-
-//==============================================================================
-void* juce_openInternetFile (const String& url,
- const String& headers,
- const MemoryBlock& postData,
- const bool isPost,
- URL::OpenStreamProgressCallback* callback,
- void* callbackContext,
- int timeOutMs)
-{
- ScopedPointer s (new JUCE_HTTPSocketStream());
-
- if (s->open (url, headers, postData, isPost, callback, callbackContext, timeOutMs))
- return s.release();
-
- return 0;
-}
-
-void juce_closeInternetFile (void* handle)
-{
- delete static_cast (handle);
-}
-
-int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead)
-{
- JUCE_HTTPSocketStream* const s = static_cast (handle);
-
- return s != 0 ? s->read (buffer, bytesToRead) : 0;
-}
-
-int64 juce_getInternetFileContentLength (void* handle)
-{
- JUCE_HTTPSocketStream* const s = static_cast (handle);
-
- if (s != 0)
- {
- //xxx todo
- jassertfalse
- }
-
- return -1;
-}
-
-bool juce_getInternetFileHeaders (void* handle, StringPairArray& headers)
-{
- JUCE_HTTPSocketStream* const s = static_cast (handle);
-
- if (s != 0)
- {
- for (int i = 0; i < s->headerLines.size(); ++i)
- {
- const String& headersEntry = s->headerLines[i];
- const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
- const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
- const String previousValue (headers [key]);
- headers.set (key, previousValue.isEmpty() ? value : (previousValue + ";" + value));
- }
- }
-}
-
-int juce_seekInInternetFile (void* handle, int newPosition)
-{
- JUCE_HTTPSocketStream* const s = static_cast (handle);
-
- return s != 0 ? s->readPosition : 0;
-}
-
-#endif
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-10 by Raw Material Software Ltd.
+
+ ------------------------------------------------------------------------------
+
+ JUCE can be redistributed and/or modified under the terms of the GNU General
+ Public License (Version 2), as published by the Free Software Foundation.
+ A copy of the license is included in the JUCE distribution, or can be found
+ online at www.gnu.org/licenses.
+
+ JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.rawmaterialsoftware.com/juce for more information.
+
+ ==============================================================================
+*/
+
+// (This file gets included by juce_linux_NativeCode.cpp, rather than being
+// compiled on its own).
+#if JUCE_INCLUDED_FILE
+
+
+//==============================================================================
+int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian)
+{
+ int numResults = 0;
+
+ const int s = socket (AF_INET, SOCK_DGRAM, 0);
+ if (s != -1)
+ {
+ char buf [1024];
+ struct ifconf ifc;
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+ ioctl (s, SIOCGIFCONF, &ifc);
+
+ for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
+ {
+ struct ifreq ifr;
+ strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
+
+ if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
+ && (ifr.ifr_flags & IFF_LOOPBACK) == 0
+ && ioctl (s, SIOCGIFHWADDR, &ifr) == 0
+ && numResults < maxNum)
+ {
+ int64 a = 0;
+ for (int j = 6; --j >= 0;)
+ a = (a << 8) | (uint8) ifr.ifr_hwaddr.sa_data [littleEndian ? j : (5 - j)];
+
+ *addresses++ = a;
+ ++numResults;
+ }
+ }
+
+ close (s);
+ }
+
+ return numResults;
+}
+
+
+bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
+ const String& emailSubject,
+ const String& bodyText,
+ const StringArray& filesToAttach)
+{
+ jassertfalse; // xxx todo
+
+ return false;
+}
+
+//==============================================================================
+/** A HTTP input stream that uses sockets.
+ */
+class JUCE_HTTPSocketStream
+{
+public:
+ //==============================================================================
+ JUCE_HTTPSocketStream()
+ : readPosition (0),
+ socketHandle (-1),
+ levelsOfRedirection (0),
+ timeoutSeconds (15)
+ {
+ }
+
+ ~JUCE_HTTPSocketStream()
+ {
+ closeSocket();
+ }
+
+ //==============================================================================
+ bool open (const String& url,
+ const String& headers,
+ const MemoryBlock& postData,
+ const bool isPost,
+ URL::OpenStreamProgressCallback* callback,
+ void* callbackContext,
+ int timeOutMs)
+ {
+ closeSocket();
+
+ uint32 timeOutTime = Time::getMillisecondCounter();
+
+ if (timeOutMs == 0)
+ timeOutTime += 60000;
+ else if (timeOutMs < 0)
+ timeOutTime = 0xffffffff;
+ else
+ timeOutTime += timeOutMs;
+
+ String hostName, hostPath;
+ int hostPort;
+
+ if (! decomposeURL (url, hostName, hostPath, hostPort))
+ return false;
+
+ const struct hostent* host = 0;
+ int port = 0;
+
+ String proxyName, proxyPath;
+ int proxyPort = 0;
+
+ String proxyURL (getenv ("http_proxy"));
+ if (proxyURL.startsWithIgnoreCase ("http://"))
+ {
+ if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
+ return false;
+
+ host = gethostbyname (proxyName.toUTF8());
+ port = proxyPort;
+ }
+ else
+ {
+ host = gethostbyname (hostName.toUTF8());
+ port = hostPort;
+ }
+
+ if (host == 0)
+ return false;
+
+ struct sockaddr_in address;
+ zerostruct (address);
+ memcpy (&address.sin_addr, host->h_addr, host->h_length);
+ address.sin_family = host->h_addrtype;
+ address.sin_port = htons (port);
+
+ socketHandle = socket (host->h_addrtype, SOCK_STREAM, 0);
+
+ if (socketHandle == -1)
+ return false;
+
+ int receiveBufferSize = 16384;
+ setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
+ setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
+
+#if JUCE_MAC
+ setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
+#endif
+
+ if (connect (socketHandle, (struct sockaddr*) &address, sizeof (address)) == -1)
+ {
+ closeSocket();
+ return false;
+ }
+
+ const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort,
+ proxyName, proxyPort,
+ hostPath, url,
+ headers, postData,
+ isPost));
+ size_t totalHeaderSent = 0;
+
+ while (totalHeaderSent < requestHeader.getSize())
+ {
+ if (Time::getMillisecondCounter() > timeOutTime)
+ {
+ closeSocket();
+ return false;
+ }
+
+ const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
+
+ if (send (socketHandle,
+ ((const char*) requestHeader.getData()) + totalHeaderSent,
+ numToSend, 0)
+ != numToSend)
+ {
+ closeSocket();
+ return false;
+ }
+
+ totalHeaderSent += numToSend;
+
+ if (callback != 0 && ! callback (callbackContext, totalHeaderSent, requestHeader.getSize()))
+ {
+ closeSocket();
+ return false;
+ }
+ }
+
+ const String responseHeader (readResponse (timeOutTime));
+
+ if (responseHeader.isNotEmpty())
+ {
+ //DBG (responseHeader);
+
+ headerLines.clear();
+ headerLines.addLines (responseHeader);
+
+ const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
+ .substring (0, 3).getIntValue();
+
+ //int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
+ //bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
+
+ String location (findHeaderItem (headerLines, "Location:"));
+
+ if (statusCode >= 300 && statusCode < 400
+ && location.isNotEmpty())
+ {
+ if (! location.startsWithIgnoreCase ("http://"))
+ location = "http://" + location;
+
+ if (levelsOfRedirection++ < 3)
+ return open (location, headers, postData, isPost, callback, callbackContext, timeOutMs);
+ }
+ else
+ {
+ levelsOfRedirection = 0;
+ return true;
+ }
+ }
+
+ closeSocket();
+ return false;
+ }
+
+ //==============================================================================
+ int read (void* buffer, int bytesToRead)
+ {
+ fd_set readbits;
+ FD_ZERO (&readbits);
+ FD_SET (socketHandle, &readbits);
+
+ struct timeval tv;
+ tv.tv_sec = timeoutSeconds;
+ tv.tv_usec = 0;
+
+ if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
+ return 0; // (timeout)
+
+ const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
+ readPosition += bytesRead;
+ return bytesRead;
+ }
+
+ //==============================================================================
+ int readPosition;
+ StringArray headerLines;
+
+ //==============================================================================
+ juce_UseDebuggingNewOperator
+
+private:
+ int socketHandle, levelsOfRedirection;
+ const int timeoutSeconds;
+
+ //==============================================================================
+ void closeSocket()
+ {
+ if (socketHandle >= 0)
+ close (socketHandle);
+
+ socketHandle = -1;
+ }
+
+ const MemoryBlock createRequestHeader (const String& hostName,
+ const int hostPort,
+ const String& proxyName,
+ const int proxyPort,
+ const String& hostPath,
+ const String& originalURL,
+ const String& headers,
+ const MemoryBlock& postData,
+ const bool isPost)
+ {
+ String header (isPost ? "POST " : "GET ");
+
+ if (proxyName.isEmpty())
+ {
+ header << hostPath << " HTTP/1.0\r\nHost: "
+ << hostName << ':' << hostPort;
+ }
+ else
+ {
+ header << originalURL << " HTTP/1.0\r\nHost: "
+ << proxyName << ':' << proxyPort;
+ }
+
+ header << "\r\nUser-Agent: JUCE/"
+ << JUCE_MAJOR_VERSION << '.' << JUCE_MINOR_VERSION
+ << "\r\nConnection: Close\r\nContent-Length: "
+ << postData.getSize() << "\r\n"
+ << headers << "\r\n";
+
+ MemoryBlock mb;
+ mb.append (header.toUTF8(), (int) strlen (header.toUTF8()));
+ mb.append (postData.getData(), postData.getSize());
+
+ return mb;
+ }
+
+ const String readResponse (const uint32 timeOutTime)
+ {
+ int bytesRead = 0, numConsecutiveLFs = 0;
+ MemoryBlock buffer (1024, true);
+
+ while (numConsecutiveLFs < 2 && bytesRead < 32768
+ && Time::getMillisecondCounter() <= timeOutTime)
+ {
+ fd_set readbits;
+ FD_ZERO (&readbits);
+ FD_SET (socketHandle, &readbits);
+
+ struct timeval tv;
+ tv.tv_sec = timeoutSeconds;
+ tv.tv_usec = 0;
+
+ if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
+ return String::empty; // (timeout)
+
+ buffer.ensureSize (bytesRead + 8, true);
+ char* const dest = (char*) buffer.getData() + bytesRead;
+
+ if (recv (socketHandle, dest, 1, 0) == -1)
+ return String::empty;
+
+ const char lastByte = *dest;
+ ++bytesRead;
+
+ if (lastByte == '\n')
+ ++numConsecutiveLFs;
+ else if (lastByte != '\r')
+ numConsecutiveLFs = 0;
+ }
+
+ const String header (String::fromUTF8 ((const char*) buffer.getData()));
+
+ if (header.startsWithIgnoreCase ("HTTP/"))
+ return header.trimEnd();
+
+ return String::empty;
+ }
+
+ //==============================================================================
+ static bool decomposeURL (const String& url,
+ String& host, String& path, int& port)
+ {
+ if (! url.startsWithIgnoreCase ("http://"))
+ return false;
+
+ const int nextSlash = url.indexOfChar (7, '/');
+ int nextColon = url.indexOfChar (7, ':');
+ if (nextColon > nextSlash && nextSlash > 0)
+ nextColon = -1;
+
+ if (nextColon >= 0)
+ {
+ host = url.substring (7, nextColon);
+
+ if (nextSlash >= 0)
+ port = url.substring (nextColon + 1, nextSlash).getIntValue();
+ else
+ port = url.substring (nextColon + 1).getIntValue();
+ }
+ else
+ {
+ port = 80;
+
+ if (nextSlash >= 0)
+ host = url.substring (7, nextSlash);
+ else
+ host = url.substring (7);
+ }
+
+ if (nextSlash >= 0)
+ path = url.substring (nextSlash);
+ else
+ path = "/";
+
+ return true;
+ }
+
+ //==============================================================================
+ static const String findHeaderItem (const StringArray& lines, const String& itemName)
+ {
+ for (int i = 0; i < lines.size(); ++i)
+ if (lines[i].startsWithIgnoreCase (itemName))
+ return lines[i].substring (itemName.length()).trim();
+
+ return String::empty;
+ }
+};
+
+//==============================================================================
+void* juce_openInternetFile (const String& url,
+ const String& headers,
+ const MemoryBlock& postData,
+ const bool isPost,
+ URL::OpenStreamProgressCallback* callback,
+ void* callbackContext,
+ int timeOutMs)
+{
+ ScopedPointer s (new JUCE_HTTPSocketStream());
+
+ if (s->open (url, headers, postData, isPost, callback, callbackContext, timeOutMs))
+ return s.release();
+
+ return 0;
+}
+
+void juce_closeInternetFile (void* handle)
+{
+ delete static_cast (handle);
+}
+
+int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead)
+{
+ JUCE_HTTPSocketStream* const s = static_cast (handle);
+
+ return s != 0 ? s->read (buffer, bytesToRead) : 0;
+}
+
+int64 juce_getInternetFileContentLength (void* handle)
+{
+ JUCE_HTTPSocketStream* const s = static_cast (handle);
+
+ if (s != 0)
+ {
+ //xxx todo
+ jassertfalse
+ }
+
+ return -1;
+}
+
+bool juce_getInternetFileHeaders (void* handle, StringPairArray& headers)
+{
+ JUCE_HTTPSocketStream* const s = static_cast (handle);
+
+ if (s != 0)
+ {
+ for (int i = 0; i < s->headerLines.size(); ++i)
+ {
+ const String& headersEntry = s->headerLines[i];
+ const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
+ const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
+ const String previousValue (headers [key]);
+ headers.set (key, previousValue.isEmpty() ? value : (previousValue + ";" + value));
+ }
+ }
+}
+
+int juce_seekInInternetFile (void* handle, int newPosition)
+{
+ JUCE_HTTPSocketStream* const s = static_cast (handle);
+
+ return s != 0 ? s->readPosition : 0;
+}
+
+#endif