diff --git a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp index 2f9bb4fbdd..5f38028e28 100644 --- a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp +++ b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp @@ -35,6 +35,7 @@ public: { handlers.add (new DrawablePathHandler()); handlers.add (new DrawableImageHandler()); + handlers.add (new DrawableCompositeHandler()); } ~DrawableTypeManager() @@ -57,16 +58,6 @@ public: return 0; } - const StringArray getDisplayNames() - { - StringArray s; - - for (int i = 0; i < handlers.size(); ++i) - s.add (handlers.getUnchecked(i)->getDisplayName()); - - return s; - } - private: OwnedArray handlers; }; @@ -74,6 +65,37 @@ private: 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; +} + +bool DrawableTypeInstance::setBounds (Drawable* drawable, const Rectangle& newBounds) +{ + return getHandler()->setBounds (*this, drawable, newBounds); +} + + //============================================================================== namespace Tags { @@ -103,24 +125,42 @@ DrawableDocument::~DrawableDocument() root.removeListener (this); } -DrawableComposite::ValueTreeWrapper DrawableDocument::getRootDrawableNode() const +void DrawableDocument::recursivelyUpdateIDs (Drawable::ValueTreeWrapperBase& d) { - return DrawableComposite::ValueTreeWrapper (root.getChild (0)); + if (d.getID().isEmpty()) + d.setID (createUniqueID (d.getState().getType().toString().toLowerCase() + "1"), 0); + + if (d.getState().getType() == DrawableComposite::valueTreeType) + { + const DrawableComposite::ValueTreeWrapper composite (d.getState()); + + for (int i = 0; i < composite.getNumDrawables(); ++i) + { + Drawable::ValueTreeWrapperBase child (composite.getDrawableState (i)); + recursivelyUpdateIDs (child); + } + } } void DrawableDocument::checkRootObject() { + if (! root.hasProperty (Ids::id_)) + root.setProperty (Ids::id_, createAlphaNumericUID(), 0); + if (markersX == 0) markersX = new MarkerList (*this, true); if (markersY == 0) markersY = new MarkerList (*this, false); - if ((int) getCanvasWidth().getValue() <= 0) +/* if ((int) getCanvasWidth().getValue() <= 0) getCanvasWidth() = 500; if ((int) getCanvasHeight().getValue() <= 0) getCanvasHeight() = 500; +*/ + DrawableComposite::ValueTreeWrapper rootObject (getRootDrawableNode()); + recursivelyUpdateIDs (rootObject); } //============================================================================== @@ -134,15 +174,6 @@ const String DrawableDocument::getName() const return root [Ids::name]; } -void DrawableDocument::addMissingIds (ValueTree tree) const -{ - if (! tree.hasProperty (Ids::id_)) - tree.setProperty (Ids::id_, createAlphaNumericUID(), 0); - - for (int i = tree.getNumChildren(); --i >= 0;) - addMissingIds (tree.getChild(i)); -} - bool DrawableDocument::hasChangedSinceLastSave() const { return needsSaving; @@ -213,8 +244,6 @@ bool DrawableDocument::load (InputStream& input) if (loadedTree.hasType (Tags::drawableTag)) { - addMissingIds (loadedTree); - root.removeListener (this); root = loadedTree; root.addListener (this); @@ -236,24 +265,74 @@ void DrawableDocument::changed() sendChangeMessage (this); } +DrawableComposite::ValueTreeWrapper DrawableDocument::getRootDrawableNode() const +{ + return DrawableComposite::ValueTreeWrapper (root.getChild (0)); +} + +ValueTree DrawableDocument::findDrawableState (const String& objectId, bool recursive) const +{ + return getRootDrawableNode().getDrawableWithId (objectId, recursive); +} + +const String DrawableDocument::createUniqueID (const String& name) const +{ + String n (CodeHelpers::makeValidIdentifier (name, false, true, false)); + int suffix = 2; + + while (markersX->getMarkerNamed (n).isValid() || markersY->getMarkerNamed (n).isValid() + || findDrawableState (n, true).isValid()) + n = n.trimCharactersAtEnd ("0123456789") + String (suffix++); + + return n; +} + +bool DrawableDocument::createItemProperties (Array & props, const String& itemId) +{ + ValueTree drawable (findDrawableState (itemId, false)); + + if (drawable.isValid()) + { + DrawableTypeInstance item (*this, drawable); + item.createProperties (props); + return true; + } + + if (markersX->createProperties (props, itemId) + || markersY->createProperties (props, itemId)) + return true; + + return false; +} + +void DrawableDocument::createItemProperties (Array & props, const StringArray& selectedItemIds) +{ + if (selectedItemIds.size() != 1) + return; //xxx + + for (int i = 0; i < selectedItemIds.size(); ++i) + createItemProperties (props, selectedItemIds[i]); +} + //============================================================================== const int menuItemOffset = 0x63451fa4; void DrawableDocument::addNewItemMenuItems (PopupMenu& menu) const { - const StringArray displayNames (DrawableTypeManager::getInstance()->getDisplayNames()); + DrawableTypeManager* const typeMan = DrawableTypeManager::getInstance(); - for (int i = 0; i < displayNames.size(); ++i) - menu.addItem (i + menuItemOffset, "New " + displayNames[i]); + for (int i = 0; i < typeMan->getNumHandlers(); ++i) + if (typeMan->getHandler(i)->canBeCreated) + menu.addItem (i + menuItemOffset, "New " + typeMan->getHandler(i)->getDisplayName()); } const ValueTree DrawableDocument::performNewItemMenuItem (int menuResultCode) { - const StringArray displayNames (DrawableTypeManager::getInstance()->getDisplayNames()); + DrawableTypeManager* const typeMan = DrawableTypeManager::getInstance(); - if (menuResultCode >= menuItemOffset && menuResultCode < menuItemOffset + displayNames.size()) + if (menuResultCode >= menuItemOffset && menuResultCode < menuItemOffset + typeMan->getNumHandlers()) { - DrawableTypeHandler* handler = DrawableTypeManager::getInstance()->getHandler (menuResultCode - menuItemOffset); + DrawableTypeHandler* handler = typeMan->getHandler (menuResultCode - menuItemOffset); jassert (handler != 0); if (handler != 0) @@ -262,6 +341,9 @@ const ValueTree DrawableDocument::performNewItemMenuItem (int menuResultCode) Point (Random::getSystemRandom().nextFloat() * 100.0f + 100.0f, Random::getSystemRandom().nextFloat() * 100.0f + 100.0f))); + Drawable::ValueTreeWrapperBase wrapper (state); + recursivelyUpdateIDs (wrapper); + getRootDrawableNode().addDrawable (state, -1, getUndoManager()); return state; @@ -303,8 +385,8 @@ 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); +// if (edge == "right") return RelativeCoordinate ((double) getCanvasWidth().getValue(), true); + // if (edge == "bottom") return RelativeCoordinate ((double) getCanvasHeight().getValue(), false); } if (objectName.isNotEmpty() && edge.isNotEmpty()) @@ -337,6 +419,7 @@ const RelativeCoordinate DrawableDocument::findNamedCoordinate (const String& ob return RelativeCoordinate(); } +//============================================================================== DrawableDocument::MarkerList::MarkerList (DrawableDocument& document_, bool isX_) : MarkerListBase (document_.getRoot().getChildWithName (isX_ ? Tags::markersGroupXTag : Tags::markersGroupYTag), isX_), document (document_) @@ -347,8 +430,8 @@ 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); +// if (edge == "right") return RelativeCoordinate ((double) document.getCanvasWidth().getValue(), true); + // if (edge == "bottom") return RelativeCoordinate ((double) document.getCanvasHeight().getValue(), false); } const ValueTree marker (getMarkerNamed (objectName)); diff --git a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.h b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.h index fbd113f2cc..e97716104c 100644 --- a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.h +++ b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.h @@ -53,8 +53,13 @@ public: ValueTree& getRoot() { return root; } DrawableComposite::ValueTreeWrapper getRootDrawableNode() const; - Value getCanvasWidth() const { return getRootValueNonUndoable (Ids::width); } - Value getCanvasHeight() const { return getRootValueNonUndoable (Ids::height); } +// Value getCanvasWidth() const { return getRootValueNonUndoable (Ids::width); } + // Value getCanvasHeight() const { return getRootValueNonUndoable (Ids::height); } + + ValueTree findDrawableState (const String& objectId, bool recursive) const; + const String createUniqueID (const String& suggestion) const; + + void createItemProperties (Array & props, const StringArray& selectedItemIds); void addNewItemMenuItems (PopupMenu& menu) const; const ValueTree performNewItemMenuItem (int menuResultCode); @@ -107,6 +112,7 @@ private: bool saveAsXml, needsSaving; void checkRootObject(); + void recursivelyUpdateIDs (Drawable::ValueTreeWrapperBase& d); Value getRootValueUndoable (const Identifier& name) const { return root.getPropertyAsValue (name, getUndoManager()); } Value getRootValueNonUndoable (const Identifier& name) const { return root.getPropertyAsValue (name, 0); } @@ -114,8 +120,7 @@ private: void save (OutputStream& output); bool load (InputStream& input); - void addMissingIds (ValueTree tree) const; - void addDrawable (Drawable& d); + bool createItemProperties (Array & props, const String& itemId); const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const; void addMarkerMenuItem (int i, const RelativeCoordinate& coord, const String& objectName, const String& edge, diff --git a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h index 44ba2a510d..cc7afab1ea 100644 --- a/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h +++ b/extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h @@ -27,24 +27,91 @@ #define __JUCER_DRAWABLETYPEHANDLER_H_7FB02E2F__ #include "jucer_DrawableDocument.h" +class DrawableTypeHandler; +//============================================================================== +class DrawableTypeInstance +{ +public: + DrawableTypeInstance (DrawableDocument& document_, const ValueTree& state_); + + //============================================================================== + DrawableDocument& getDocument() throw() { return document; } + ValueTree& getState() throw() { return state; } + + Value getValue (const Identifier& name) const; + void createProperties (Array & props); + bool setBounds (Drawable* drawable, const Rectangle& newBounds); + + //============================================================================== + DrawableTypeHandler* getHandler() const; + +private: + //============================================================================== + DrawableDocument& document; + ValueTree state; +}; + //============================================================================== class DrawableTypeHandler { public: - DrawableTypeHandler (const String& displayName_, const Identifier& valueTreeType_) - : displayName (displayName_), valueTreeType (valueTreeType_) + DrawableTypeHandler (const String& displayName_, const Identifier& valueTreeType_, bool canBeCreated_) + : displayName (displayName_), valueTreeType (valueTreeType_), canBeCreated (canBeCreated_) { } 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 bool setBounds (DrawableTypeInstance& item, Drawable* drawable, const Rectangle& newBounds) = 0; 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) + { + if (oldBounds.isEmpty()) + return false; + + newBounds.setSize (jmax (1.0f, newBounds.getWidth()), + jmax (1.0f, newBounds.getHeight())); + + const double tolerance = 0.1; + + double xScale = newBounds.getWidth() / (double) oldBounds.getWidth(); + double yScale = newBounds.getHeight() / (double) oldBounds.getHeight(); + + if (std::abs (xScale - 1.0) < tolerance) xScale = 1.0; + if (std::abs (yScale - 1.0) < tolerance) yScale = 1.0; + + if (xScale == 1.0 && yScale == 1.0 + && std::abs (newBounds.getX() - oldBounds.getX()) < tolerance + && std::abs (newBounds.getY() - oldBounds.getY()) < tolerance) + return false; + + const double xOffset = newBounds.getX() - xScale * oldBounds.getX(); + const double yOffset = newBounds.getY() - yScale * oldBounds.getY(); + + for (int i = 0; i < numPoints; ++i) + { + const Point p (points[i].resolve (nameFinder)); + + points[i].moveToAbsolute (Point ((float) (xOffset + xScale * p.getX()), + (float) (yOffset + yScale * p.getY())), nameFinder); + } + + return true; + } + private: const String displayName; const Identifier valueTreeType; @@ -54,7 +121,7 @@ private: class DrawablePathHandler : public DrawableTypeHandler { public: - DrawablePathHandler() : DrawableTypeHandler ("Polygon", DrawablePath::valueTreeType) {} + DrawablePathHandler() : DrawableTypeHandler ("Polygon", DrawablePath::valueTreeType, true) {} ~DrawablePathHandler() {} const ValueTree createNewInstance (DrawableDocument& document, const Point& approxPosition) @@ -69,13 +136,57 @@ public: dp.setFill (Colours::lightblue.withHue (Random::getSystemRandom().nextFloat())); return dp.createValueTree (0); } + + void createPropertyEditors (DrawableTypeInstance& item, Array & props) + { + } + + void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item) + { + } + + bool 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())) + return false; + + 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()); + return true; + } }; //============================================================================== class DrawableImageHandler : public DrawableTypeHandler { public: - DrawableImageHandler() : DrawableTypeHandler ("Image", DrawableImage::valueTreeType) {} + DrawableImageHandler() : DrawableTypeHandler ("Image", DrawableImage::valueTreeType, true) {} ~DrawableImageHandler() {} const ValueTree createNewInstance (DrawableDocument& document, const Point& approxPosition) @@ -96,8 +207,71 @@ public: RelativePoint (approxPosition + Point (0.0f, 100.0f))); return di.createValueTree (&document); } + + void createPropertyEditors (DrawableTypeInstance& item, Array & props) + { + } + + void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item) + { + } + + bool 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())) + return false; + + UndoManager* undoManager = item.getDocument().getUndoManager(); + wrapper.setTargetPositionForTopLeft (points[0], undoManager); + wrapper.setTargetPositionForTopRight (points[1], undoManager); + wrapper.setTargetPositionForBottomLeft (points[2], undoManager); + return true; + } }; +//============================================================================== +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) + { + } + + bool 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())) + return false; + + UndoManager* undoManager = item.getDocument().getUndoManager(); + wrapper.setTargetPositionForOrigin (points[0], undoManager); + wrapper.setTargetPositionForX1Y0 (points[1], undoManager); + wrapper.setTargetPositionForX0Y1 (points[2], undoManager); + return true; + } +}; #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 1292ec2b55..8257118a85 100644 --- a/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h +++ b/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h @@ -62,16 +62,27 @@ public: return new ComponentHolder (getDocument().getBackgroundColour()); } - void updateComponents() + void documentChanged() { getDocument().updateComponentsIn (getComponentHolder()); startTimer (500); } - int getCanvasWidth() { return getDocument().getCanvasWidth().getValue(); } - int getCanvasHeight() { return getDocument().getCanvasHeight().getValue(); } - void setCanvasWidth (int w) { getDocument().getCanvasWidth() = w; } - void setCanvasHeight (int h) { getDocument().getCanvasHeight() = h; } + const Rectangle getCanvasBounds() + { + return Rectangle (0, 0, getDocument().getCanvasWidth().getValue(), + getDocument().getCanvasHeight().getValue()); + } + + void setCanvasBounds (const Rectangle& newBounds) + { + jassert (newBounds.getPosition().isOrigin()); + + getDocument().getCanvasWidth() = newBounds.getWidth(); + getDocument().getCanvasHeight() = newBounds.getHeight(); + } + + bool canResizeCanvas() const { return true; } ComponentDocument::MarkerList& getMarkerList (bool isX) { @@ -123,6 +134,8 @@ public: return getDocument().getCoordsFor (state).resolve (&getDocument()).getSmallestIntegerContainer(); } + bool hasSizeGuides() const { return true; } + RelativeRectangle getObjectCoords (const ValueTree& state) { return getDocument().getCoordsFor (state); @@ -168,6 +181,26 @@ public: protected: ComponentDocument& getDocument() throw() { return static_cast (canvas)->getDocument(); } + void getSnapPointsX (Array& points, bool includeCentre) + { + const float width = getDocument().getCanvasWidth().getValue(); + points.add (0.0f); + points.add (width); + + if (includeCentre) + points.add (width / 2.0f); + } + + void getSnapPointsY (Array& points, bool includeCentre) + { + const float height = getDocument().getCanvasHeight().getValue(); + points.add (0.0f); + points.add (height); + + if (includeCentre) + points.add (height / 2.0f); + } + int getCanvasWidth() { return getDocument().getCanvasWidth().getValue(); } int getCanvasHeight() { return getDocument().getCanvasHeight().getValue(); } diff --git a/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.cpp b/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.cpp index 0c938e5810..be85a1f61a 100644 --- a/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.cpp +++ b/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.cpp @@ -61,9 +61,9 @@ public: return editor.getSelection(); } - void getSelectedItemProperties (Array& newComps) + void getSelectedItemProperties (Array& props) { - //editor.getSelectedItemProperties (newComps); + editor.getDocument().createItemProperties (props, editor.getSelectedIds()); } private: @@ -103,6 +103,16 @@ void DrawableEditor::resized() } //============================================================================== +const StringArray DrawableEditor::getSelectedIds() const +{ + StringArray ids; + const int num = selection.getNumSelected(); + for (int i = 0; i < num; ++i) + ids.add (selection.getSelectedItem(i)); + + return ids; +} + void DrawableEditor::deleteSelection() { } diff --git a/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.h b/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.h index 06ad22c253..7482fde09c 100644 --- a/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.h +++ b/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.h @@ -51,6 +51,7 @@ public: void resized(); //============================================================================== + const StringArray getSelectedIds() const; void deleteSelection(); void selectionToFront(); void selectionToBack(); 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 2f56863bd1..9ed79b51a1 100644 --- a/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h +++ b/extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h @@ -27,6 +27,7 @@ #define __JUCER_DRAWABLEOBJECTCOMPONENT_JUCEHEADER__ #include "jucer_DrawableEditor.h" +#include "../../model/Drawable/jucer_DrawableTypeHandler.h" //============================================================================== @@ -38,12 +39,12 @@ public: : editor (editor_) { initialise(); - editor.getDocument().getRoot().addListener (this); + getDocument().getRoot().addListener (this); } ~DrawableEditorCanvas() { - editor.getDocument().getRoot().removeListener (this); + getDocument().getRoot().removeListener (this); shutdown(); } @@ -52,13 +53,15 @@ public: return new DrawableComponent (this); } - void updateComponents() + void documentChanged() { - DrawableDocument& doc = getEditor().getDocument(); + DrawableDocument& doc = getDocument(); if (drawable == 0) { - drawable = Drawable::createFromValueTree (doc.getRootDrawableNode().getState(), &doc); + Drawable* newDrawable = Drawable::createFromValueTree (doc.getRootDrawableNode().getState(), &doc); + drawable = dynamic_cast (newDrawable); + jassert (drawable != 0); getComponentHolder()->repaint(); } else @@ -70,10 +73,13 @@ public: startTimer (500); } - int getCanvasWidth() { return getDocument().getCanvasWidth().getValue(); } - int getCanvasHeight() { return getDocument().getCanvasHeight().getValue(); } - void setCanvasWidth (int w) { getDocument().getCanvasWidth() = w; } - void setCanvasHeight (int h) { getDocument().getCanvasHeight() = h; } + const Rectangle getCanvasBounds() + { + return drawable->getBounds().getSmallestIntegerContainer(); + } + + void setCanvasBounds (const Rectangle& newBounds) {} + bool canResizeCanvas() const { return false; } MarkerListBase& getMarkerList (bool isX) { @@ -82,6 +88,17 @@ public: const SelectedItems::ItemType findObjectIdAt (const Point& position) { + if (drawable != 0) + { + for (int i = drawable->getNumDrawables(); --i >= 0;) + { + Drawable* d = drawable->getDrawable (i); + + if (d->hitTest ((float) position.getX(), (float) position.getY())) + return d->getName(); + } + } + return String::empty; } @@ -110,20 +127,51 @@ public: { } + bool hasSizeGuides() const { return false; } + const ValueTree getObjectState (const String& objectId) { - return ValueTree(); + return getDocument().findDrawableState (objectId, false); + } + + const Rectangle getObjectPositionFloat (const ValueTree& state) + { + if (drawable != 0) + { + Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID()); + + if (d != 0) + return d->getBounds(); + } + + return Rectangle(); + } + + bool setObjectPositionFloat (const ValueTree& state, const Rectangle& newPos) + { + if (drawable != 0) + { + Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID()); + + if (d != 0) + { + d->refreshFromValueTree (state, &getDocument()); + DrawableTypeInstance di (getDocument(), state); + return di.setBounds (d, newPos); + } + } + + return false; } const Rectangle getObjectPosition (const ValueTree& state) { - return Rectangle();//getDocument().getCoordsFor (state).resolve (getDocument()); + return getObjectPositionFloat (state).getSmallestIntegerContainer(); } RelativeRectangle getObjectCoords (const ValueTree& state) { return RelativeRectangle(); -// return getDocument().getCoordsFor (state); } SelectedItems& getSelection() @@ -137,6 +185,18 @@ public: void findLassoItemsInArea (Array & itemsFound, const Rectangle& area) { + const Rectangle floatArea (area.toFloat()); + + if (drawable != 0) + { + for (int i = drawable->getNumDrawables(); --i >= 0;) + { + Drawable* d = drawable->getDrawable (i); + + if (d->getBounds().intersects (floatArea)) + itemsFound.add (d->getName()); + } + } } //============================================================================== @@ -159,19 +219,19 @@ public: protected: DrawableDocument& getDocument() throw() { return static_cast (canvas)->getDocument(); } - int getCanvasWidth() { return getDocument().getCanvasWidth().getValue(); } - int getCanvasHeight() { return getDocument().getCanvasHeight().getValue(); } + 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(); } const Rectangle getObjectPosition (const ValueTree& state) { - return Rectangle (); + return static_cast (canvas)->getObjectPositionFloat (state); } bool setObjectPosition (ValueTree& state, const Rectangle& newBounds) { - return false; + return static_cast (canvas)->setObjectPositionFloat (state, newBounds); } float getMarkerPosition (const ValueTree& marker, bool isX) @@ -187,14 +247,17 @@ public: Array selected, unselected; - /*for (int i = getDocument().getNumComponents(); --i >= 0;) + DrawableComposite::ValueTreeWrapper mainGroup (getDocument().getRootDrawableNode()); + + for (int i = mainGroup.getNumDrawables(); --i >= 0;) { - const ValueTree v (getDocument().getComponent (i)); - if (editor.getSelection().isSelected (v [ComponentDocument::idProperty])) + 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; @@ -238,6 +301,22 @@ public: void paint (Graphics& g) { g.fillAll (Colours::white); + + const Point origin (canvas->getOrigin()); + g.setOrigin (origin.getX(), origin.getY()); + + if (origin.getX() > 0) + { + g.setColour (Colour::greyLevel (0.8f)); + g.drawVerticalLine (0, 0, 10000.0f); + } + + if (origin.getY() > 0) + { + g.setColour (Colour::greyLevel (0.8f)); + g.drawHorizontalLine (0, 0, 10000.0f); + } + canvas->drawable->draw (g, 1.0f); } @@ -246,7 +325,7 @@ public: DrawableEditor& getEditor() const { return canvas->getEditor(); } }; - ScopedPointer drawable; + ScopedPointer drawable; private: //============================================================================== 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 0c0c00902c..9b5a743f5a 100644 --- a/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp +++ b/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp @@ -179,7 +179,7 @@ public: void showSizeGuides() { - if (sizeGuides.size() == 0) + if (sizeGuides.size() == 0 && canvas->hasSizeGuides()) { sizeGuides.add (new SizeGuideComponent (canvas, objectState, SizeGuideComponent::left)); sizeGuides.add (new SizeGuideComponent (canvas, objectState, SizeGuideComponent::right)); @@ -408,7 +408,7 @@ public: isDraggingClickedComp = false; const MouseEvent e2 (e.getEventRelativeTo (canvas->getComponentHolder())); - const SelectedItems::ItemType underMouse (canvas->findObjectIdAt (e2.getPosition())); + const SelectedItems::ItemType underMouse (canvas->findObjectIdAt (canvas->screenSpaceToObjectSpace (e2.getPosition()))); if (e.mods.isPopupMenu()) { @@ -498,7 +498,7 @@ public: else { const MouseEvent e2 (e.getEventRelativeTo (canvas->getComponentHolder())); - const SelectedItems::ItemType underMouse (canvas->findObjectIdAt (e2.getPosition())); + const SelectedItems::ItemType underMouse (canvas->findObjectIdAt (canvas->screenSpaceToObjectSpace (e2.getPosition()))); if (underMouse.isNotEmpty()) { @@ -510,7 +510,8 @@ public: void findLassoItemsInArea (Array & itemsFound, const Rectangle& area) { - canvas->findLassoItemsInArea (itemsFound, area + relativePositionToOtherComponent (canvas->getComponentHolder(), Point())); + const Rectangle sourceArea (area + relativePositionToOtherComponent (canvas->getComponentHolder(), Point())); + canvas->findLassoItemsInArea (itemsFound, canvas->screenSpaceToObjectSpace (sourceArea)); } SelectedItems& getSelection() { return canvas->getSelection(); } @@ -534,21 +535,27 @@ public: void showSizeGuides() { - for (int i = getNumChildComponents(); --i >= 0;) + if (canvas->hasSizeGuides()) { - ResizeFrame* resizer = dynamic_cast (getChildComponent(i)); - if (resizer != 0) - resizer->showSizeGuides(); + for (int i = getNumChildComponents(); --i >= 0;) + { + ResizeFrame* resizer = dynamic_cast (getChildComponent(i)); + if (resizer != 0) + resizer->showSizeGuides(); + } } } void hideSizeGuides() { - for (int i = getNumChildComponents(); --i >= 0;) + if (canvas->hasSizeGuides()) { - ResizeFrame* resizer = dynamic_cast (getChildComponent(i)); - if (resizer != 0) - resizer->hideSizeGuides(); + for (int i = getNumChildComponents(); --i >= 0;) + { + ResizeFrame* resizer = dynamic_cast (getChildComponent(i)); + if (resizer != 0) + resizer->hideSizeGuides(); + } } } @@ -667,7 +674,7 @@ class EditorCanvasBase::DocumentResizeFrame : public Component { public: DocumentResizeFrame (EditorCanvasBase* canvas_) - : canvas (canvas_), dragStartWidth (0), dragStartHeight (0), resizerThickness (4) + : canvas (canvas_), resizerThickness (4) { } @@ -698,18 +705,21 @@ public: void mouseDown (const MouseEvent& e) { updateDragZone (e.getPosition()); - dragStartWidth = canvas->getCanvasWidth(); - dragStartHeight = canvas->getCanvasHeight(); + dragStartBounds = canvas->getCanvasBounds(); canvas->showSizeGuides(); } void mouseDrag (const MouseEvent& e) { + Rectangle newBounds (dragStartBounds); + if (dragZone.isDraggingRightEdge()) - canvas->setCanvasWidth (jmax (1, dragStartWidth + e.getDistanceFromDragStartX())); + newBounds.setWidth (jmax (1, newBounds.getWidth() + e.getDistanceFromDragStartX())); if (dragZone.isDraggingBottomEdge()) - canvas->setCanvasHeight (jmax (1, dragStartHeight + e.getDistanceFromDragStartY())); + newBounds.setHeight (jmax (1, newBounds.getHeight() + e.getDistanceFromDragStartY())); + + canvas->setCanvasBounds (newBounds); } void mouseUp (const MouseEvent& e) @@ -733,6 +743,9 @@ public: bool hitTest (int x, int y) { + if (! canvas->canResizeCanvas()) + return false; + const Rectangle content (getContentArea()); return (x >= content.getRight() || y >= content.getBottom()) @@ -743,7 +756,7 @@ public: private: EditorCanvasBase* canvas; ResizableBorderComponent::Zone dragZone; - int dragStartWidth, dragStartHeight; + Rectangle dragStartBounds; const int resizerThickness; const Rectangle getContentArea() const { return canvas->getContentArea(); } @@ -752,7 +765,8 @@ private: //============================================================================== EditorCanvasBase::EditorCanvasBase() - : border (14) + : border (14), + scaleFactor (1.0) { //setOpaque (true); } @@ -783,6 +797,26 @@ EditorPanelBase* EditorCanvasBase::getPanel() const return findParentComponentOfClass ((EditorPanelBase*) 0); } +const Point EditorCanvasBase::screenSpaceToObjectSpace (const Point& p) const +{ + return p - origin; +} + +const Point EditorCanvasBase::objectSpaceToScreenSpace (const Point& p) const +{ + return p + origin; +} + +const Rectangle EditorCanvasBase::screenSpaceToObjectSpace (const Rectangle& r) const +{ + return r - origin; +} + +const Rectangle EditorCanvasBase::objectSpaceToScreenSpace (const Rectangle& r) const +{ + return r + origin; +} + //============================================================================== void EditorCanvasBase::paint (Graphics& g) { @@ -798,7 +832,7 @@ void EditorCanvasBase::paint (Graphics& g) void EditorCanvasBase::drawXAxis (Graphics& g, const Rectangle& r) { - TickIterator ticks (0, r.getWidth(), 1.0, 10, 50); + TickIterator ticks (-origin.getX(), r.getWidth(), 1.0, 10, 50); float pos, tickLength; String label; @@ -814,7 +848,7 @@ void EditorCanvasBase::drawXAxis (Graphics& g, const Rectangle& r) void EditorCanvasBase::drawYAxis (Graphics& g, const Rectangle& r) { - TickIterator ticks (0, r.getHeight(), 1.0, 10, 80); + TickIterator ticks (-origin.getY(), r.getHeight(), 1.0, 10, 80); float pos, tickLength; String label; @@ -837,10 +871,20 @@ const Rectangle EditorCanvasBase::getContentArea() const //============================================================================== void EditorCanvasBase::handleAsyncUpdate() { - setSize ((int) getCanvasWidth() + border.getLeftAndRight(), - (int) getCanvasHeight() + border.getTopAndBottom()); + documentChanged(); + + const Rectangle canvasBounds (getCanvasBounds()); + + const Point newOrigin (jmax (0, -canvasBounds.getX()), jmax (0, -canvasBounds.getY())); + if (origin != newOrigin) + { + repaint(); + origin = newOrigin; + } + + setSize (jmax (canvasBounds.getWidth(), canvasBounds.getRight()) + border.getLeftAndRight(), + jmax (canvasBounds.getHeight(), canvasBounds.getBottom()) + border.getTopAndBottom()); - updateComponents(); overlay->update(); } @@ -849,7 +893,6 @@ void EditorCanvasBase::resized() componentHolder->setBounds (getContentArea()); overlay->setBounds (getLocalBounds()); resizeFrame->setBounds (getLocalBounds()); - updateComponents(); overlay->update(); } @@ -891,5 +934,6 @@ EditorCanvasBase::OverlayItemComponent::~OverlayItemComponent() void EditorCanvasBase::OverlayItemComponent::setBoundsInTargetSpace (const Rectangle& r) { - setBounds (r + canvas->getComponentHolder()->relativePositionToOtherComponent (getParentComponent(), Point())); + setBounds (canvas->objectSpaceToScreenSpace (r) + + canvas->getComponentHolder()->relativePositionToOtherComponent (getParentComponent(), Point())); } 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 a5dbaef5eb..a4a6ed9dba 100644 --- a/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h +++ b/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h @@ -64,11 +64,10 @@ public: void hideSizeGuides(); //============================================================================== - virtual void updateComponents() = 0; - virtual int getCanvasWidth() = 0; - virtual int getCanvasHeight() = 0; - virtual void setCanvasWidth (int w) = 0; - virtual void setCanvasHeight (int h) = 0; + virtual void documentChanged() = 0; + virtual const Rectangle getCanvasBounds() = 0; + virtual void setCanvasBounds (const Rectangle& newBounds) = 0; + virtual bool canResizeCanvas() const = 0; virtual MarkerListBase& getMarkerList (bool isX) = 0; virtual const SelectedItems::ItemType findObjectIdAt (const Point& position) = 0; @@ -77,6 +76,8 @@ public: virtual const ValueTree getObjectState (const String& objectId) = 0; virtual const Rectangle getObjectPosition (const ValueTree& state) = 0; + + virtual bool hasSizeGuides() const = 0; virtual RelativeRectangle getObjectCoords (const ValueTree& state) = 0; virtual SelectedItems& getSelection() = 0; virtual UndoManager& getUndoManager() = 0; @@ -106,6 +107,12 @@ public: Component* getComponentHolder() const { return componentHolder; } EditorPanelBase* getPanel() const; + const Point& getOrigin() const throw() { return origin; } + const Point screenSpaceToObjectSpace (const Point& p) const; + const Point objectSpaceToScreenSpace (const Point& p) const; + const Rectangle screenSpaceToObjectSpace (const Rectangle& r) const; + const Rectangle objectSpaceToScreenSpace (const Rectangle& r) const; + //============================================================================== class OverlayItemComponent : public Component { @@ -119,9 +126,11 @@ public: EditorCanvasBase* canvas; }; -private: +protected: //============================================================================== const BorderSize border; + Point origin; + double scaleFactor; friend class OverlayItemComponent; class ResizeFrame; diff --git a/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorDragOperation.h b/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorDragOperation.h index 210cbdc525..e0e7534545 100644 --- a/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorDragOperation.h +++ b/extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorDragOperation.h @@ -80,11 +80,14 @@ public: if (isDraggingLeftRight()) { const float y1 = -100.0f, y2 = 10000.0f; - verticalSnapTargets.add (SnapLine (0, y1, y2)); - verticalSnapTargets.add (SnapLine ((float) getCanvasWidth(), y1, y2)); - if (zone.isDraggingWholeObject() || (zone.isDraggingLeftEdge() && zone.isDraggingRightEdge())) - verticalSnapTargets.add (SnapLine ((float) getCanvasWidth() / 2.0f, y1, y2)); + { + Array points; + getSnapPointsX (points, zone.isDraggingWholeObject() || (zone.isDraggingLeftEdge() && zone.isDraggingRightEdge())); + + for (int i = 0; i < points.size(); ++i) + verticalSnapTargets.add (SnapLine (points[i], y1, y2)); + } MarkerListBase& markers = canvas->getMarkerList (true); for (int i = markers.size(); --i >= 0;) @@ -94,11 +97,14 @@ public: if (isDraggingUpDown()) { const float x1 = -100.0f, x2 = 10000.0f; - horizontalSnapTargets.add (SnapLine (0, x1, x2)); - horizontalSnapTargets.add (SnapLine ((float) getCanvasHeight(), x1, x2)); - if (zone.isDraggingWholeObject() || (zone.isDraggingTopEdge() && zone.isDraggingBottomEdge())) - horizontalSnapTargets.add (SnapLine ((float) getCanvasHeight() / 2.0f, x1, x2)); + { + Array points; + getSnapPointsY (points, zone.isDraggingWholeObject() || (zone.isDraggingTopEdge() && zone.isDraggingBottomEdge())); + + for (int i = 0; i < points.size(); ++i) + horizontalSnapTargets.add (SnapLine (points[i], x1, x2)); + } MarkerListBase& markers = canvas->getMarkerList (false); for (int i = markers.size(); --i >= 0;) @@ -181,9 +187,6 @@ public: //============================================================================== void drag (const MouseEvent& e) { -// if (draggedObjects.size() > 5) - // canvas->repaint(); // more efficient than having to repaint a highly fragmented region - getUndoManager().undoCurrentTransactionOnly(); // (can't use getOffsetFromDragStart() because of auto-scrolling) @@ -232,8 +235,8 @@ public: protected: //============================================================================== - virtual int getCanvasWidth() = 0; - virtual int getCanvasHeight() = 0; + virtual void getSnapPointsX (Array& points, bool includeCentre) = 0; + virtual void getSnapPointsY (Array& points, bool includeCentre) = 0; virtual float getMarkerPosition (const ValueTree& marker, bool isX) = 0; virtual const Rectangle getObjectPosition (const ValueTree& state) = 0; diff --git a/extras/Jucer (experimental)/Source/utility/jucer_MiscUtilities.cpp b/extras/Jucer (experimental)/Source/utility/jucer_MiscUtilities.cpp index b76d1ef0fd..97562d450c 100644 --- a/extras/Jucer (experimental)/Source/utility/jucer_MiscUtilities.cpp +++ b/extras/Jucer (experimental)/Source/utility/jucer_MiscUtilities.cpp @@ -38,10 +38,10 @@ const String createAlphaNumericUID() static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random r (Random::getSystemRandom().nextInt64()); - for (int i = 9; --i >= 0;) + for (int i = 7; --i >= 0;) { r.setSeedRandomly(); - uid << (juce_wchar) chars [r.nextInt (sizeof (chars))]; + uid << chars [r.nextInt (numElementsInArray (chars))]; } return uid; diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 72108f5ac1..1a92b4c3b4 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -41654,8 +41654,7 @@ void Desktop::refreshMonitorSizes() monitorCoordsUnclipped.clear(); juce_updateMultiMonitorInfo (monitorCoordsClipped, true); juce_updateMultiMonitorInfo (monitorCoordsUnclipped, false); - jassert (monitorCoordsClipped.size() > 0 - && monitorCoordsClipped.size() == monitorCoordsUnclipped.size()); + jassert (monitorCoordsClipped.size() == monitorCoordsUnclipped.size()); if (oldClipped != monitorCoordsClipped || oldUnclipped != monitorCoordsUnclipped) @@ -63787,10 +63786,14 @@ void LookAndFeel::setColour (const int colourId, const Colour& colour) throw() const int index = colourIds.indexOf (colourId); if (index >= 0) + { colours.set (index, colour); - - colourIds.add (colourId); - colours.add (colour); + } + else + { + colourIds.add (colourId); + colours.add (colour); + } } bool LookAndFeel::isColourSpecified (const int colourId) const throw() @@ -84026,6 +84029,15 @@ void DrawableComposite::removeDrawable (const int index, const bool deleteDrawab drawables.remove (index, deleteDrawable); } +Drawable* DrawableComposite::getDrawableWithName (const String& name) const throw() +{ + for (int i = drawables.size(); --i >= 0;) + if (drawables.getUnchecked(i)->getName() == name) + return drawables.getUnchecked(i); + + return 0; +} + void DrawableComposite::bringToFront (const int index) { if (index >= 0 && index < drawables.size() - 1) @@ -84255,11 +84267,44 @@ int DrawableComposite::ValueTreeWrapper::getNumDrawables() const return getChildList().getNumChildren(); } -const ValueTree DrawableComposite::ValueTreeWrapper::getDrawableState (int index) const +ValueTree DrawableComposite::ValueTreeWrapper::getDrawableState (int index) const { return getChildList().getChild (index); } +ValueTree DrawableComposite::ValueTreeWrapper::getDrawableWithId (const String& objectId, bool recursive) const +{ + if (getID() == objectId) + return state; + + if (! recursive) + { + return getChildList().getChildWithProperty (idProperty, objectId); + } + else + { + const ValueTree childList (getChildList()); + + for (int i = getNumDrawables(); --i >= 0;) + { + const ValueTree& child = childList.getChild (i); + + if (child [Drawable::ValueTreeWrapperBase::idProperty] == objectId) + return child; + + if (child.hasType (DrawableComposite::valueTreeType)) + { + ValueTree v (DrawableComposite::ValueTreeWrapper (child).getDrawableWithId (objectId, true)); + + if (v.isValid()) + return v; + } + } + + return ValueTree::invalid; + } +} + void DrawableComposite::ValueTreeWrapper::addDrawable (const ValueTree& newDrawableState, int index, UndoManager* undoManager) { getChildListCreating (undoManager).addChild (newDrawableState, index, undoManager); @@ -92307,6 +92352,9 @@ namespace RelativeCoordinateHelpers static const String limitedAccuracyString (const double n) { + if (! (n < -0.001 || n > 0.001)) // to detect NaN and inf as well as for rounding + return "0"; + return String (n, 3).trimCharactersAtEnd ("0").trimCharactersAtEnd ("."); } @@ -92874,6 +92922,12 @@ void RelativePointPath::StartSubPath::addToPath (Path& path, RelativeCoordinate: path.startNewSubPath (p.getX(), p.getY()); } +RelativePoint* RelativePointPath::StartSubPath::getControlPoints (int& numPoints) +{ + numPoints = 1; + return &startPos; +} + RelativePointPath::CloseSubPath::CloseSubPath() : ElementBase (closeSubPathElement) { @@ -92890,6 +92944,12 @@ void RelativePointPath::CloseSubPath::addToPath (Path& path, RelativeCoordinate: path.closeSubPath(); } +RelativePoint* RelativePointPath::CloseSubPath::getControlPoints (int& numPoints) +{ + numPoints = 0; + return 0; +} + RelativePointPath::LineTo::LineTo (const RelativePoint& endPoint_) : ElementBase (lineToElement), endPoint (endPoint_) { @@ -92913,55 +92973,78 @@ void RelativePointPath::LineTo::addToPath (Path& path, RelativeCoordinate::Named path.lineTo (p.getX(), p.getY()); } -RelativePointPath::QuadraticTo::QuadraticTo (const RelativePoint& controlPoint_, const RelativePoint& endPoint_) - : ElementBase (quadraticToElement), controlPoint (controlPoint_), endPoint (endPoint_) +RelativePoint* RelativePointPath::LineTo::getControlPoints (int& numPoints) { + numPoints = 1; + return &endPoint; +} + +RelativePointPath::QuadraticTo::QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint) + : ElementBase (quadraticToElement) +{ + controlPoints[0] = controlPoint; + controlPoints[1] = endPoint; } void RelativePointPath::QuadraticTo::write (OutputStream& out, ElementType lastTypeWritten) const { - const String p1 (controlPoint.toString()); + const String p1 (controlPoints[0].toString()); if (lastTypeWritten != quadraticToElement) out << "q "; else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1)) out << '#'; - out << p1 << ' ' << endPoint.toString(); + out << p1 << ' ' << controlPoints[1].toString(); } void RelativePointPath::QuadraticTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const { - const Point p1 (controlPoint.resolve (coordFinder)); - const Point p2 (endPoint.resolve (coordFinder)); + const Point p1 (controlPoints[0].resolve (coordFinder)); + const Point p2 (controlPoints[1].resolve (coordFinder)); path.quadraticTo (p1.getX(), p1.getY(), p2.getX(), p2.getY()); } -RelativePointPath::CubicTo::CubicTo (const RelativePoint& controlPoint1_, const RelativePoint& controlPoint2_, const RelativePoint& endPoint_) - : ElementBase (cubicToElement), controlPoint1 (controlPoint1_), controlPoint2 (controlPoint2_), endPoint (endPoint_) +RelativePoint* RelativePointPath::QuadraticTo::getControlPoints (int& numPoints) { + numPoints = 2; + return controlPoints; +} + +RelativePointPath::CubicTo::CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint) + : ElementBase (cubicToElement) +{ + controlPoints[0] = controlPoint1; + controlPoints[1] = controlPoint2; + controlPoints[2] = endPoint; } void RelativePointPath::CubicTo::write (OutputStream& out, ElementType lastTypeWritten) const { - const String p1 (controlPoint1.toString()); + const String p1 (controlPoints[0].toString()); if (lastTypeWritten != cubicToElement) out << "c "; else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1)) out << '#'; - out << p1 << ' ' << controlPoint2.toString() << ' ' << endPoint.toString(); + out << p1 << ' ' << controlPoints[1].toString() << ' ' << controlPoints[2].toString(); } void RelativePointPath::CubicTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const { - const Point p1 (controlPoint1.resolve (coordFinder)); - const Point p2 (controlPoint2.resolve (coordFinder)); - const Point p3 (endPoint.resolve (coordFinder)); + const Point p1 (controlPoints[0].resolve (coordFinder)); + const Point p2 (controlPoints[1].resolve (coordFinder)); + const Point p3 (controlPoints[2].resolve (coordFinder)); path.cubicTo (p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY()); } +RelativePoint* RelativePointPath::CubicTo::getControlPoints (int& numPoints) +{ + numPoints = 3; + return controlPoints; +} + END_JUCE_NAMESPACE /*** End of inlined file: juce_RelativeCoordinate.cpp ***/ @@ -255499,9 +255582,7 @@ public: clientMsg.data.l[0] = IconicState; ScopedXLock xlock; - XSendEvent (display, root, false, - SubstructureRedirectMask | SubstructureNotifyMask, - (XEvent*) &clientMsg); + XSendEvent (display, root, false, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*) &clientMsg); } else { @@ -255662,26 +255743,7 @@ public: bool setAlwaysOnTop (bool alwaysOnTop) { - if (windowH != 0) - { - const bool wasVisible = component->isVisible(); - - if (wasVisible) - setVisible (false); // doesn't always seem to work if the window is visible when this is done.. - - { - ScopedXLock xlock; - XSetWindowAttributes swa; - swa.override_redirect = alwaysOnTop ? True : False; - - XChangeWindowAttributes (display, windowH, CWOverrideRedirect, &swa); - } - - if (wasVisible) - setVisible (true); - } - - return true; + return false; } void toFront (bool makeActive) @@ -255708,14 +255770,12 @@ public: { ScopedXLock xlock; XSendEvent (display, RootWindow (display, DefaultScreen (display)), - False, - SubstructureRedirectMask | SubstructureNotifyMask, - &ev); + False, SubstructureRedirectMask | SubstructureNotifyMask, &ev); XWindowAttributes attr; XGetWindowAttributes (display, windowH, &attr); - if (attr.override_redirect) + if (component->isAlwaysOnTop()) XRaiseWindow (display, windowH); XSync (display, False); @@ -255742,7 +255802,7 @@ public: bool isFocused() const { - int revert; + int revert = 0; Window focusedWindow = 0; ScopedXLock xlock; XGetInputFocus (display, &focusedWindow, &revert); @@ -256814,49 +256874,49 @@ private: int netHints [6]; int num = 0; - netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_RESIZE", (styleFlags & windowIsResizable) ? True : False); - netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_FULLSCREEN", (styleFlags & windowHasMaximiseButton) ? True : False); - netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_MINIMIZE", (styleFlags & windowHasMinimiseButton) ? True : False); - netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_CLOSE", (styleFlags & windowHasCloseButton) ? True : False); + if ((styleFlags & windowIsResizable) != 0) + netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_RESIZE", True); - XChangeProperty (display, wndH, hints, XA_ATOM, 32, PropModeReplace, - (unsigned char*) &netHints, num); + if ((styleFlags & windowHasMaximiseButton) != 0) + netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_FULLSCREEN", True); + + if ((styleFlags & windowHasMinimiseButton) != 0) + netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_MINIMIZE", True); + + if ((styleFlags & windowHasCloseButton) != 0) + netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_CLOSE", True); + + XChangeProperty (display, wndH, hints, XA_ATOM, 32, PropModeReplace, (unsigned char*) &netHints, num); } } - void setWindowType (Window wndH) + void setWindowType() { int netHints [2]; int numHints = 0; if ((styleFlags & windowIsTemporary) != 0 || ((styleFlags & windowHasDropShadow) == 0 && Desktop::canUseSemiTransparentWindows())) - { - netHints [numHints] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_COMBO", True); - } + netHints [numHints++] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_COMBO", True); else - { - netHints [numHints] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_NORMAL", True); - } + netHints [numHints++] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_NORMAL", True); - if (netHints [numHints] != 0) - ++numHints; + netHints[numHints++] = XInternAtom (display, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True); - netHints[numHints] = XInternAtom (display, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True); - - if (netHints [numHints] != 0) - ++numHints; - - XChangeProperty (display, wndH, Atoms::WindowType, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::WindowType, XA_ATOM, 32, PropModeReplace, (unsigned char*) &netHints, numHints); - if ((styleFlags & windowAppearsOnTaskbar) == 0) - { - Atom skipTaskbar = XInternAtom (display, "_NET_WM_STATE_SKIP_TASKBAR", False); + numHints = 0; - XChangeProperty (display, wndH, Atoms::WindowState, XA_ATOM, 32, PropModeReplace, - (unsigned char*) &skipTaskbar, 1); - } + if ((styleFlags & windowAppearsOnTaskbar) == 0) + netHints [numHints++] = XInternAtom (display, "_NET_WM_STATE_SKIP_TASKBAR", True); + + if (component->isAlwaysOnTop()) + netHints [numHints++] = XInternAtom (display, "_NET_WM_STATE_ABOVE", True); + + if (numHints > 0) + XChangeProperty (display, windowH, Atoms::WindowState, XA_ATOM, 32, PropModeReplace, + (unsigned char*) &netHints, numHints); } void createWindow() @@ -256887,27 +256947,27 @@ private: swa.border_pixel = 0; swa.background_pixmap = None; swa.colormap = colormap; - swa.override_redirect = getComponent()->isAlwaysOnTop() ? True : False; swa.event_mask = getAllEventsMask(); - Window wndH = XCreateWindow (display, root, - 0, 0, 1, 1, - 0, depth, InputOutput, visual, - CWBorderPixel | CWColormap | CWBackPixmap | CWEventMask | CWOverrideRedirect, - &swa); + windowH = XCreateWindow (display, root, + 0, 0, 1, 1, + 0, depth, InputOutput, visual, + CWBorderPixel | CWColormap | CWBackPixmap | CWEventMask, + &swa); - XGrabButton (display, AnyButton, AnyModifier, wndH, False, + XGrabButton (display, AnyButton, AnyModifier, windowH, False, ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None); // Set the window context to identify the window handle object - if (XSaveContext (display, (XID) wndH, windowHandleXContext, (XPointer) this)) + if (XSaveContext (display, (XID) windowH, windowHandleXContext, (XPointer) this)) { // Failed jassertfalse; Logger::outputDebugString ("Failed to create context information for window.\n"); - XDestroyWindow (display, wndH); - wndH = 0; + XDestroyWindow (display, windowH); + windowH = 0; + return; } // Set window manager hints @@ -256915,42 +256975,42 @@ private: wmHints->flags = InputHint | StateHint; wmHints->input = True; // Locally active input model wmHints->initial_state = NormalState; - XSetWMHints (display, wndH, wmHints); + XSetWMHints (display, windowH, wmHints); XFree (wmHints); // Set the window type - setWindowType (wndH); + setWindowType(); // Define decoration if ((styleFlags & windowHasTitleBar) == 0) - removeWindowDecorations (wndH); + removeWindowDecorations (windowH); else - addWindowButtons (wndH); + addWindowButtons (windowH); // Set window name - setWindowTitle (wndH, getComponent()->getName()); + setWindowTitle (windowH, getComponent()->getName()); // Associate the PID, allowing to be shut down when something goes wrong unsigned long pid = getpid(); - XChangeProperty (display, wndH, Atoms::Pid, XA_CARDINAL, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::Pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &pid, 1); // Set window manager protocols - XChangeProperty (display, wndH, Atoms::Protocols, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::Protocols, XA_ATOM, 32, PropModeReplace, (unsigned char*) Atoms::ProtocolList, 2); // Set drag and drop flags - XChangeProperty (display, wndH, Atoms::XdndTypeList, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::XdndTypeList, XA_ATOM, 32, PropModeReplace, (const unsigned char*) Atoms::allowedMimeTypes, numElementsInArray (Atoms::allowedMimeTypes)); - XChangeProperty (display, wndH, Atoms::XdndActionList, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::XdndActionList, XA_ATOM, 32, PropModeReplace, (const unsigned char*) Atoms::allowedActions, numElementsInArray (Atoms::allowedActions)); - XChangeProperty (display, wndH, Atoms::XdndActionDescription, XA_STRING, 8, PropModeReplace, + XChangeProperty (display, windowH, Atoms::XdndActionDescription, XA_STRING, 8, PropModeReplace, (const unsigned char*) "", 0); unsigned long dndVersion = Atoms::DndVersion; - XChangeProperty (display, wndH, Atoms::XdndAware, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::XdndAware, XA_ATOM, 32, PropModeReplace, (const unsigned char*) &dndVersion, 1); // Initialise the pointer and keyboard mapping @@ -256985,8 +257045,6 @@ private: updateModifierMappings(); } - - windowH = wndH; } void destroyWindow() diff --git a/juce_amalgamated.h b/juce_amalgamated.h index cdcb8f1b75..6cb5cb4e03 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -42225,6 +42225,7 @@ public: virtual ~ElementBase() {} virtual void write (OutputStream& out, ElementType lastTypeWritten) const = 0; virtual void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const = 0; + virtual RelativePoint* getControlPoints (int& numPoints) = 0; const ElementType type; }; @@ -42236,6 +42237,7 @@ public: ~StartSubPath() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); RelativePoint startPos; }; @@ -42247,6 +42249,7 @@ public: ~CloseSubPath() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); }; class JUCE_API LineTo : public ElementBase @@ -42256,6 +42259,7 @@ public: ~LineTo() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); RelativePoint endPoint; }; @@ -42267,8 +42271,9 @@ public: ~QuadraticTo() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); - RelativePoint controlPoint, endPoint; + RelativePoint controlPoints[2]; }; class JUCE_API CubicTo : public ElementBase @@ -42278,8 +42283,9 @@ public: ~CubicTo() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); - RelativePoint controlPoint1, controlPoint2, endPoint; + RelativePoint controlPoints[3]; }; OwnedArray elements; @@ -42406,6 +42412,9 @@ public: /** Assigns a name to this drawable. */ void setName (const String& newName) throw() { name = newName; } + /** Returns the DrawableComposite that contains this object, if there is one. */ + DrawableComposite* getParent() const throw() { return parent; } + /** Tries to turn some kind of image file into a drawable. The data could be an image that the ImageFileFormat class understands, or it @@ -42498,10 +42507,11 @@ public: const String getID() const; void setID (const String& newID, UndoManager* undoManager); + static const Identifier idProperty; protected: ValueTree state; - static const Identifier idProperty, type, x1, x2, y1, y2, colour, radial, colours; + static const Identifier type, x1, x2, y1, y2, colour, radial, colours; static const FillType readFillType (const ValueTree& v); void replaceFillType (const Identifier& tag, const FillType& fillType, UndoManager* undoManager); @@ -58102,6 +58112,9 @@ public: */ Drawable* getDrawable (int index) const throw() { return drawables [index]; } + /** Looks for a child drawable with the specified name. */ + Drawable* getDrawableWithName (const String& name) const throw(); + /** Brings one of the Drawables to the front. @param index the index of the drawable to move, between 0 @@ -58186,7 +58199,8 @@ public: ValueTreeWrapper (const ValueTree& state); int getNumDrawables() const; - const ValueTree getDrawableState (int index) const; + ValueTree getDrawableState (int index) const; + ValueTree getDrawableWithId (const String& objectId, bool recursive) const; void addDrawable (const ValueTree& newDrawableState, int index, UndoManager* undoManager); void moveDrawableOrder (int currentIndex, int newIndex, UndoManager* undoManager); void removeDrawable (int index, UndoManager* undoManager); diff --git a/src/gui/components/juce_Desktop.cpp b/src/gui/components/juce_Desktop.cpp index 62b7f15088..68aa23a4f9 100644 --- a/src/gui/components/juce_Desktop.cpp +++ b/src/gui/components/juce_Desktop.cpp @@ -77,8 +77,7 @@ void Desktop::refreshMonitorSizes() monitorCoordsUnclipped.clear(); juce_updateMultiMonitorInfo (monitorCoordsClipped, true); juce_updateMultiMonitorInfo (monitorCoordsUnclipped, false); - jassert (monitorCoordsClipped.size() > 0 - && monitorCoordsClipped.size() == monitorCoordsUnclipped.size()); + jassert (monitorCoordsClipped.size() == monitorCoordsUnclipped.size()); if (oldClipped != monitorCoordsClipped || oldUnclipped != monitorCoordsUnclipped) diff --git a/src/gui/components/lookandfeel/juce_LookAndFeel.cpp b/src/gui/components/lookandfeel/juce_LookAndFeel.cpp index de50bd92fd..72c1830c80 100644 --- a/src/gui/components/lookandfeel/juce_LookAndFeel.cpp +++ b/src/gui/components/lookandfeel/juce_LookAndFeel.cpp @@ -256,10 +256,14 @@ void LookAndFeel::setColour (const int colourId, const Colour& colour) throw() const int index = colourIds.indexOf (colourId); if (index >= 0) + { colours.set (index, colour); - - colourIds.add (colourId); - colours.add (colour); + } + else + { + colourIds.add (colourId); + colours.add (colour); + } } bool LookAndFeel::isColourSpecified (const int colourId) const throw() diff --git a/src/gui/graphics/drawables/juce_Drawable.h b/src/gui/graphics/drawables/juce_Drawable.h index be16e60540..88d43e8b9b 100644 --- a/src/gui/graphics/drawables/juce_Drawable.h +++ b/src/gui/graphics/drawables/juce_Drawable.h @@ -148,6 +148,9 @@ public: /** Assigns a name to this drawable. */ void setName (const String& newName) throw() { name = newName; } + /** Returns the DrawableComposite that contains this object, if there is one. */ + DrawableComposite* getParent() const throw() { return parent; } + //============================================================================== /** Tries to turn some kind of image file into a drawable. @@ -243,10 +246,11 @@ public: const String getID() const; void setID (const String& newID, UndoManager* undoManager); + static const Identifier idProperty; protected: ValueTree state; - static const Identifier idProperty, type, x1, x2, y1, y2, colour, radial, colours; + static const Identifier type, x1, x2, y1, y2, colour, radial, colours; static const FillType readFillType (const ValueTree& v); void replaceFillType (const Identifier& tag, const FillType& fillType, UndoManager* undoManager); diff --git a/src/gui/graphics/drawables/juce_DrawableComposite.cpp b/src/gui/graphics/drawables/juce_DrawableComposite.cpp index a906ee5786..abe8ddc472 100644 --- a/src/gui/graphics/drawables/juce_DrawableComposite.cpp +++ b/src/gui/graphics/drawables/juce_DrawableComposite.cpp @@ -80,6 +80,15 @@ void DrawableComposite::removeDrawable (const int index, const bool deleteDrawab drawables.remove (index, deleteDrawable); } +Drawable* DrawableComposite::getDrawableWithName (const String& name) const throw() +{ + for (int i = drawables.size(); --i >= 0;) + if (drawables.getUnchecked(i)->getName() == name) + return drawables.getUnchecked(i); + + return 0; +} + void DrawableComposite::bringToFront (const int index) { if (index >= 0 && index < drawables.size() - 1) @@ -314,11 +323,44 @@ int DrawableComposite::ValueTreeWrapper::getNumDrawables() const return getChildList().getNumChildren(); } -const ValueTree DrawableComposite::ValueTreeWrapper::getDrawableState (int index) const +ValueTree DrawableComposite::ValueTreeWrapper::getDrawableState (int index) const { return getChildList().getChild (index); } +ValueTree DrawableComposite::ValueTreeWrapper::getDrawableWithId (const String& objectId, bool recursive) const +{ + if (getID() == objectId) + return state; + + if (! recursive) + { + return getChildList().getChildWithProperty (idProperty, objectId); + } + else + { + const ValueTree childList (getChildList()); + + for (int i = getNumDrawables(); --i >= 0;) + { + const ValueTree& child = childList.getChild (i); + + if (child [Drawable::ValueTreeWrapperBase::idProperty] == objectId) + return child; + + if (child.hasType (DrawableComposite::valueTreeType)) + { + ValueTree v (DrawableComposite::ValueTreeWrapper (child).getDrawableWithId (objectId, true)); + + if (v.isValid()) + return v; + } + } + + return ValueTree::invalid; + } +} + void DrawableComposite::ValueTreeWrapper::addDrawable (const ValueTree& newDrawableState, int index, UndoManager* undoManager) { getChildListCreating (undoManager).addChild (newDrawableState, index, undoManager); diff --git a/src/gui/graphics/drawables/juce_DrawableComposite.h b/src/gui/graphics/drawables/juce_DrawableComposite.h index 25bf4a64dc..a3e48df2d6 100644 --- a/src/gui/graphics/drawables/juce_DrawableComposite.h +++ b/src/gui/graphics/drawables/juce_DrawableComposite.h @@ -107,6 +107,9 @@ public: */ Drawable* getDrawable (int index) const throw() { return drawables [index]; } + /** Looks for a child drawable with the specified name. */ + Drawable* getDrawableWithName (const String& name) const throw(); + /** Brings one of the Drawables to the front. @param index the index of the drawable to move, between 0 @@ -194,7 +197,8 @@ public: ValueTreeWrapper (const ValueTree& state); int getNumDrawables() const; - const ValueTree getDrawableState (int index) const; + ValueTree getDrawableState (int index) const; + ValueTree getDrawableWithId (const String& objectId, bool recursive) const; void addDrawable (const ValueTree& newDrawableState, int index, UndoManager* undoManager); void moveDrawableOrder (int currentIndex, int newIndex, UndoManager* undoManager); void removeDrawable (int index, UndoManager* undoManager); diff --git a/src/gui/graphics/geometry/juce_RelativeCoordinate.cpp b/src/gui/graphics/geometry/juce_RelativeCoordinate.cpp index 29475b19c7..44721648bf 100644 --- a/src/gui/graphics/geometry/juce_RelativeCoordinate.cpp +++ b/src/gui/graphics/geometry/juce_RelativeCoordinate.cpp @@ -198,6 +198,9 @@ namespace RelativeCoordinateHelpers static const String limitedAccuracyString (const double n) { + if (! (n < -0.001 || n > 0.001)) // to detect NaN and inf as well as for rounding + return "0"; + return String (n, 3).trimCharactersAtEnd ("0").trimCharactersAtEnd ("."); } @@ -778,6 +781,12 @@ void RelativePointPath::StartSubPath::addToPath (Path& path, RelativeCoordinate: path.startNewSubPath (p.getX(), p.getY()); } +RelativePoint* RelativePointPath::StartSubPath::getControlPoints (int& numPoints) +{ + numPoints = 1; + return &startPos; +} + //============================================================================== RelativePointPath::CloseSubPath::CloseSubPath() : ElementBase (closeSubPathElement) @@ -795,6 +804,12 @@ void RelativePointPath::CloseSubPath::addToPath (Path& path, RelativeCoordinate: path.closeSubPath(); } +RelativePoint* RelativePointPath::CloseSubPath::getControlPoints (int& numPoints) +{ + numPoints = 0; + return 0; +} + //============================================================================== RelativePointPath::LineTo::LineTo (const RelativePoint& endPoint_) : ElementBase (lineToElement), endPoint (endPoint_) @@ -819,56 +834,79 @@ void RelativePointPath::LineTo::addToPath (Path& path, RelativeCoordinate::Named path.lineTo (p.getX(), p.getY()); } -//============================================================================== -RelativePointPath::QuadraticTo::QuadraticTo (const RelativePoint& controlPoint_, const RelativePoint& endPoint_) - : ElementBase (quadraticToElement), controlPoint (controlPoint_), endPoint (endPoint_) +RelativePoint* RelativePointPath::LineTo::getControlPoints (int& numPoints) { + numPoints = 1; + return &endPoint; +} + +//============================================================================== +RelativePointPath::QuadraticTo::QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint) + : ElementBase (quadraticToElement) +{ + controlPoints[0] = controlPoint; + controlPoints[1] = endPoint; } void RelativePointPath::QuadraticTo::write (OutputStream& out, ElementType lastTypeWritten) const { - const String p1 (controlPoint.toString()); + const String p1 (controlPoints[0].toString()); if (lastTypeWritten != quadraticToElement) out << "q "; else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1)) out << '#'; - out << p1 << ' ' << endPoint.toString(); + out << p1 << ' ' << controlPoints[1].toString(); } void RelativePointPath::QuadraticTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const { - const Point p1 (controlPoint.resolve (coordFinder)); - const Point p2 (endPoint.resolve (coordFinder)); + const Point p1 (controlPoints[0].resolve (coordFinder)); + const Point p2 (controlPoints[1].resolve (coordFinder)); path.quadraticTo (p1.getX(), p1.getY(), p2.getX(), p2.getY()); } -//============================================================================== -RelativePointPath::CubicTo::CubicTo (const RelativePoint& controlPoint1_, const RelativePoint& controlPoint2_, const RelativePoint& endPoint_) - : ElementBase (cubicToElement), controlPoint1 (controlPoint1_), controlPoint2 (controlPoint2_), endPoint (endPoint_) +RelativePoint* RelativePointPath::QuadraticTo::getControlPoints (int& numPoints) { + numPoints = 2; + return controlPoints; +} + +//============================================================================== +RelativePointPath::CubicTo::CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint) + : ElementBase (cubicToElement) +{ + controlPoints[0] = controlPoint1; + controlPoints[1] = controlPoint2; + controlPoints[2] = endPoint; } void RelativePointPath::CubicTo::write (OutputStream& out, ElementType lastTypeWritten) const { - const String p1 (controlPoint1.toString()); + const String p1 (controlPoints[0].toString()); if (lastTypeWritten != cubicToElement) out << "c "; else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1)) out << '#'; - out << p1 << ' ' << controlPoint2.toString() << ' ' << endPoint.toString(); + out << p1 << ' ' << controlPoints[1].toString() << ' ' << controlPoints[2].toString(); } void RelativePointPath::CubicTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const { - const Point p1 (controlPoint1.resolve (coordFinder)); - const Point p2 (controlPoint2.resolve (coordFinder)); - const Point p3 (endPoint.resolve (coordFinder)); + const Point p1 (controlPoints[0].resolve (coordFinder)); + const Point p2 (controlPoints[1].resolve (coordFinder)); + const Point p3 (controlPoints[2].resolve (coordFinder)); path.cubicTo (p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY()); } +RelativePoint* RelativePointPath::CubicTo::getControlPoints (int& numPoints) +{ + numPoints = 3; + return controlPoints; +} + END_JUCE_NAMESPACE diff --git a/src/gui/graphics/geometry/juce_RelativeCoordinate.h b/src/gui/graphics/geometry/juce_RelativeCoordinate.h index d2955c1165..74c380fc1e 100644 --- a/src/gui/graphics/geometry/juce_RelativeCoordinate.h +++ b/src/gui/graphics/geometry/juce_RelativeCoordinate.h @@ -459,6 +459,7 @@ public: virtual ~ElementBase() {} virtual void write (OutputStream& out, ElementType lastTypeWritten) const = 0; virtual void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const = 0; + virtual RelativePoint* getControlPoints (int& numPoints) = 0; const ElementType type; }; @@ -470,6 +471,7 @@ public: ~StartSubPath() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); RelativePoint startPos; }; @@ -481,6 +483,7 @@ public: ~CloseSubPath() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); }; class JUCE_API LineTo : public ElementBase @@ -490,6 +493,7 @@ public: ~LineTo() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); RelativePoint endPoint; }; @@ -501,8 +505,9 @@ public: ~QuadraticTo() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); - RelativePoint controlPoint, endPoint; + RelativePoint controlPoints[2]; }; class JUCE_API CubicTo : public ElementBase @@ -512,8 +517,9 @@ public: ~CubicTo() {} void write (OutputStream& out, ElementType lastTypeWritten) const; void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; + RelativePoint* getControlPoints (int& numPoints); - RelativePoint controlPoint1, controlPoint2, endPoint; + RelativePoint controlPoints[3]; }; //============================================================================== diff --git a/src/native/linux/juce_linux_Windowing.cpp b/src/native/linux/juce_linux_Windowing.cpp index a16b21f4c2..735283de95 100644 --- a/src/native/linux/juce_linux_Windowing.cpp +++ b/src/native/linux/juce_linux_Windowing.cpp @@ -821,9 +821,7 @@ public: clientMsg.data.l[0] = IconicState; ScopedXLock xlock; - XSendEvent (display, root, false, - SubstructureRedirectMask | SubstructureNotifyMask, - (XEvent*) &clientMsg); + XSendEvent (display, root, false, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*) &clientMsg); } else { @@ -984,26 +982,7 @@ public: bool setAlwaysOnTop (bool alwaysOnTop) { - if (windowH != 0) - { - const bool wasVisible = component->isVisible(); - - if (wasVisible) - setVisible (false); // doesn't always seem to work if the window is visible when this is done.. - - { - ScopedXLock xlock; - XSetWindowAttributes swa; - swa.override_redirect = alwaysOnTop ? True : False; - - XChangeWindowAttributes (display, windowH, CWOverrideRedirect, &swa); - } - - if (wasVisible) - setVisible (true); - } - - return true; + return false; } void toFront (bool makeActive) @@ -1030,14 +1009,12 @@ public: { ScopedXLock xlock; XSendEvent (display, RootWindow (display, DefaultScreen (display)), - False, - SubstructureRedirectMask | SubstructureNotifyMask, - &ev); + False, SubstructureRedirectMask | SubstructureNotifyMask, &ev); XWindowAttributes attr; XGetWindowAttributes (display, windowH, &attr); - if (attr.override_redirect) + if (component->isAlwaysOnTop()) XRaiseWindow (display, windowH); XSync (display, False); @@ -1064,7 +1041,7 @@ public: bool isFocused() const { - int revert; + int revert = 0; Window focusedWindow = 0; ScopedXLock xlock; XGetInputFocus (display, &focusedWindow, &revert); @@ -2140,49 +2117,49 @@ private: int netHints [6]; int num = 0; - netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_RESIZE", (styleFlags & windowIsResizable) ? True : False); - netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_FULLSCREEN", (styleFlags & windowHasMaximiseButton) ? True : False); - netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_MINIMIZE", (styleFlags & windowHasMinimiseButton) ? True : False); - netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_CLOSE", (styleFlags & windowHasCloseButton) ? True : False); + if ((styleFlags & windowIsResizable) != 0) + netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_RESIZE", True); - XChangeProperty (display, wndH, hints, XA_ATOM, 32, PropModeReplace, - (unsigned char*) &netHints, num); + if ((styleFlags & windowHasMaximiseButton) != 0) + netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_FULLSCREEN", True); + + if ((styleFlags & windowHasMinimiseButton) != 0) + netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_MINIMIZE", True); + + if ((styleFlags & windowHasCloseButton) != 0) + netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_CLOSE", True); + + XChangeProperty (display, wndH, hints, XA_ATOM, 32, PropModeReplace, (unsigned char*) &netHints, num); } } - void setWindowType (Window wndH) + void setWindowType() { int netHints [2]; int numHints = 0; if ((styleFlags & windowIsTemporary) != 0 || ((styleFlags & windowHasDropShadow) == 0 && Desktop::canUseSemiTransparentWindows())) - { - netHints [numHints] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_COMBO", True); - } + netHints [numHints++] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_COMBO", True); else - { - netHints [numHints] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_NORMAL", True); - } + netHints [numHints++] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_NORMAL", True); - if (netHints [numHints] != 0) - ++numHints; + netHints[numHints++] = XInternAtom (display, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True); - netHints[numHints] = XInternAtom (display, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True); - - if (netHints [numHints] != 0) - ++numHints; - - XChangeProperty (display, wndH, Atoms::WindowType, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::WindowType, XA_ATOM, 32, PropModeReplace, (unsigned char*) &netHints, numHints); - if ((styleFlags & windowAppearsOnTaskbar) == 0) - { - Atom skipTaskbar = XInternAtom (display, "_NET_WM_STATE_SKIP_TASKBAR", False); + numHints = 0; - XChangeProperty (display, wndH, Atoms::WindowState, XA_ATOM, 32, PropModeReplace, - (unsigned char*) &skipTaskbar, 1); - } + if ((styleFlags & windowAppearsOnTaskbar) == 0) + netHints [numHints++] = XInternAtom (display, "_NET_WM_STATE_SKIP_TASKBAR", True); + + if (component->isAlwaysOnTop()) + netHints [numHints++] = XInternAtom (display, "_NET_WM_STATE_ABOVE", True); + + if (numHints > 0) + XChangeProperty (display, windowH, Atoms::WindowState, XA_ATOM, 32, PropModeReplace, + (unsigned char*) &netHints, numHints); } void createWindow() @@ -2213,27 +2190,27 @@ private: swa.border_pixel = 0; swa.background_pixmap = None; swa.colormap = colormap; - swa.override_redirect = getComponent()->isAlwaysOnTop() ? True : False; swa.event_mask = getAllEventsMask(); - Window wndH = XCreateWindow (display, root, - 0, 0, 1, 1, - 0, depth, InputOutput, visual, - CWBorderPixel | CWColormap | CWBackPixmap | CWEventMask | CWOverrideRedirect, - &swa); + windowH = XCreateWindow (display, root, + 0, 0, 1, 1, + 0, depth, InputOutput, visual, + CWBorderPixel | CWColormap | CWBackPixmap | CWEventMask, + &swa); - XGrabButton (display, AnyButton, AnyModifier, wndH, False, + XGrabButton (display, AnyButton, AnyModifier, windowH, False, ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None); // Set the window context to identify the window handle object - if (XSaveContext (display, (XID) wndH, windowHandleXContext, (XPointer) this)) + if (XSaveContext (display, (XID) windowH, windowHandleXContext, (XPointer) this)) { // Failed jassertfalse; Logger::outputDebugString ("Failed to create context information for window.\n"); - XDestroyWindow (display, wndH); - wndH = 0; + XDestroyWindow (display, windowH); + windowH = 0; + return; } // Set window manager hints @@ -2241,42 +2218,42 @@ private: wmHints->flags = InputHint | StateHint; wmHints->input = True; // Locally active input model wmHints->initial_state = NormalState; - XSetWMHints (display, wndH, wmHints); + XSetWMHints (display, windowH, wmHints); XFree (wmHints); // Set the window type - setWindowType (wndH); + setWindowType(); // Define decoration if ((styleFlags & windowHasTitleBar) == 0) - removeWindowDecorations (wndH); + removeWindowDecorations (windowH); else - addWindowButtons (wndH); + addWindowButtons (windowH); // Set window name - setWindowTitle (wndH, getComponent()->getName()); + setWindowTitle (windowH, getComponent()->getName()); // Associate the PID, allowing to be shut down when something goes wrong unsigned long pid = getpid(); - XChangeProperty (display, wndH, Atoms::Pid, XA_CARDINAL, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::Pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &pid, 1); // Set window manager protocols - XChangeProperty (display, wndH, Atoms::Protocols, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::Protocols, XA_ATOM, 32, PropModeReplace, (unsigned char*) Atoms::ProtocolList, 2); // Set drag and drop flags - XChangeProperty (display, wndH, Atoms::XdndTypeList, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::XdndTypeList, XA_ATOM, 32, PropModeReplace, (const unsigned char*) Atoms::allowedMimeTypes, numElementsInArray (Atoms::allowedMimeTypes)); - XChangeProperty (display, wndH, Atoms::XdndActionList, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::XdndActionList, XA_ATOM, 32, PropModeReplace, (const unsigned char*) Atoms::allowedActions, numElementsInArray (Atoms::allowedActions)); - XChangeProperty (display, wndH, Atoms::XdndActionDescription, XA_STRING, 8, PropModeReplace, + XChangeProperty (display, windowH, Atoms::XdndActionDescription, XA_STRING, 8, PropModeReplace, (const unsigned char*) "", 0); unsigned long dndVersion = Atoms::DndVersion; - XChangeProperty (display, wndH, Atoms::XdndAware, XA_ATOM, 32, PropModeReplace, + XChangeProperty (display, windowH, Atoms::XdndAware, XA_ATOM, 32, PropModeReplace, (const unsigned char*) &dndVersion, 1); // Initialise the pointer and keyboard mapping @@ -2311,8 +2288,6 @@ private: updateModifierMappings(); } - - windowH = wndH; } void destroyWindow()