From 7478c7f9ab4e78fcdf844da8d96075537bd9b8b2 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Tue, 4 Jan 2011 23:04:51 +0000 Subject: [PATCH] win32 font fix. Tidied up warnings in plugin host. More drawable refactoring. TabbedComponent fix. --- .../Source/GraphEditorPanel.cpp | 4 +- .../Source/MainHostWindow.cpp | 2 +- juce_amalgamated.cpp | 1165 +++++++++-------- juce_amalgamated.h | 722 +++++----- src/core/juce_StandardHeader.h | 2 +- .../layout/juce_ComponentBuilder.cpp | 8 +- .../layout/juce_TabbedComponent.cpp | 156 +-- .../components/layout/juce_TabbedComponent.h | 11 +- .../juce_RelativeCoordinatePositioner.cpp | 6 + .../juce_RelativeCoordinatePositioner.h | 5 +- .../juce_RelativeParallelogram.cpp | 12 + .../positioning/juce_RelativeParallelogram.h | 2 + src/gui/graphics/drawables/juce_Drawable.h | 22 + .../drawables/juce_DrawableComposite.cpp | 68 +- .../drawables/juce_DrawableComposite.h | 11 +- .../graphics/drawables/juce_DrawableImage.cpp | 55 +- .../graphics/drawables/juce_DrawableImage.h | 4 +- .../graphics/drawables/juce_DrawablePath.cpp | 106 +- .../graphics/drawables/juce_DrawablePath.h | 24 +- .../drawables/juce_DrawableRectangle.cpp | 103 +- .../drawables/juce_DrawableRectangle.h | 16 +- .../graphics/drawables/juce_DrawableShape.cpp | 435 +++--- .../graphics/drawables/juce_DrawableShape.h | 96 +- .../graphics/drawables/juce_DrawableText.cpp | 123 +- .../graphics/drawables/juce_DrawableText.h | 7 +- src/gui/graphics/fonts/juce_Font.cpp | 7 +- .../mac/juce_mac_CoreGraphicsContext.mm | 49 +- 27 files changed, 1770 insertions(+), 1451 deletions(-) diff --git a/extras/audio plugin host/Source/GraphEditorPanel.cpp b/extras/audio plugin host/Source/GraphEditorPanel.cpp index bbeb396a39..8e46d06c3a 100644 --- a/extras/audio plugin host/Source/GraphEditorPanel.cpp +++ b/extras/audio plugin host/Source/GraphEditorPanel.cpp @@ -231,7 +231,7 @@ public: void mouseDown (const MouseEvent& e) { - originalPos = relativePositionToGlobal (Point()); + originalPos = localPointToGlobal (Point()); toFront (true); @@ -277,7 +277,7 @@ public: Point pos (originalPos + Point (e.getDistanceFromDragStartX(), e.getDistanceFromDragStartY())); if (getParentComponent() != 0) - pos = getParentComponent()->globalPositionToRelative (pos); + pos = getParentComponent()->getLocalPoint (0, pos); graph.setNodePosition (filterID, (pos.getX() + getWidth() / 2) / (double) getParentWidth(), diff --git a/extras/audio plugin host/Source/MainHostWindow.cpp b/extras/audio plugin host/Source/MainHostWindow.cpp index 26e59aa8f6..dc5988809b 100644 --- a/extras/audio plugin host/Source/MainHostWindow.cpp +++ b/extras/audio plugin host/Source/MainHostWindow.cpp @@ -498,7 +498,7 @@ void MainHostWindow::filesDropped (const StringArray& files, int x, int y) Point pos (x, y); if (graphEditor != 0) - pos = relativePositionToOtherComponent (graphEditor, pos); + pos = graphEditor->getLocalPoint (this, pos); for (int i = 0; i < jmin (5, typesFound.size()); ++i) createPlugin (typesFound.getUnchecked(i), pos.getX(), pos.getY()); diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index eb045ba751..38d992b73b 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -61408,8 +61408,9 @@ namespace ComponentBuilderHelpers if (topLevelComp != 0) { ComponentBuilder::TypeHandler* const type = builder.getHandlerForState (state); + const String uid (getStateId (state)); - if (type == 0) + if (type == 0 || uid.isEmpty()) { // ..handle the case where a child of the actual state node has changed. if (state.getParent().isValid()) @@ -61417,20 +61418,19 @@ namespace ComponentBuilderHelpers } else { - Component* const changedComp = findComponentWithID (topLevelComp, getStateId (state)); + Component* const changedComp = findComponentWithID (topLevelComp, uid); if (changedComp != 0) type->updateComponentFromState (changedComp, state); } } } - } const Identifier ComponentBuilder::idProperty ("id"); ComponentBuilder::ComponentBuilder (const ValueTree& state_) - : state (state_) + : state (state_), imageProvider (0) { state.addListener (this); } @@ -64198,17 +64198,38 @@ END_JUCE_NAMESPACE /*** Start of inlined file: juce_TabbedComponent.cpp ***/ BEGIN_JUCE_NAMESPACE -class TabCompButtonBar : public TabbedButtonBar +namespace TabbedComponentHelpers { -public: - TabCompButtonBar (TabbedComponent& owner_, - const TabbedButtonBar::Orientation orientation_) - : TabbedButtonBar (orientation_), - owner (owner_) + const Identifier deleteComponentId ("deleteByTabComp_"); + + void deleteIfNecessary (Component* const comp) { + if (comp != 0 && (bool) comp->getProperties() [deleteComponentId]) + delete comp; } - ~TabCompButtonBar() + const Rectangle getTabArea (Rectangle& content, BorderSize& outline, + const TabbedButtonBar::Orientation orientation, const int tabDepth) + { + switch (orientation) + { + case TabbedButtonBar::TabsAtTop: outline.setTop (0); return content.removeFromTop (tabDepth); + case TabbedButtonBar::TabsAtBottom: outline.setBottom (0); return content.removeFromBottom (tabDepth); + case TabbedButtonBar::TabsAtLeft: outline.setLeft (0); return content.removeFromLeft (tabDepth); + case TabbedButtonBar::TabsAtRight: outline.setRight (0); return content.removeFromRight (tabDepth); + default: jassertfalse; break; + } + + return Rectangle(); + } +} + +class TabbedComponent::ButtonBar : public TabbedButtonBar +{ +public: + ButtonBar (TabbedComponent& owner_, const TabbedButtonBar::Orientation orientation_) + : TabbedButtonBar (orientation_), + owner (owner_) { } @@ -64235,7 +64256,7 @@ public: private: TabbedComponent& owner; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabCompButtonBar); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonBar); }; TabbedComponent::TabbedComponent (const TabbedButtonBar::Orientation orientation) @@ -64243,7 +64264,7 @@ TabbedComponent::TabbedComponent (const TabbedButtonBar::Orientation orientation outlineThickness (1), edgeIndent (0) { - addAndMakeVisible (tabs = new TabCompButtonBar (*this, orientation)); + addAndMakeVisible (tabs = new ButtonBar (*this, orientation)); } TabbedComponent::~TabbedComponent() @@ -64277,8 +64298,6 @@ TabBarButton* TabbedComponent::createTabButton (const String& tabName, const int return new TabBarButton (tabName, *tabs); } -const Identifier TabbedComponent::deleteComponentId ("deleteByTabComp_"); - void TabbedComponent::clearTabs() { if (panelComponent != 0) @@ -64291,12 +64310,7 @@ void TabbedComponent::clearTabs() tabs->clearTabs(); for (int i = contentComponents.size(); --i >= 0;) - { - WeakReference& c = *contentComponents.getUnchecked (i); - - if (c != 0 && (bool) c->getProperties() [deleteComponentId]) - delete c.get(); - } + TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (i)); contentComponents.clear(); } @@ -64307,10 +64321,10 @@ void TabbedComponent::addTab (const String& tabName, const bool deleteComponentWhenNotNeeded, const int insertIndex) { - contentComponents.insert (insertIndex, new WeakReference (contentComponent)); + contentComponents.insert (insertIndex, WeakReference (contentComponent)); - if (contentComponent != 0) - contentComponent->getProperties().set (deleteComponentId, deleteComponentWhenNotNeeded); + if (deleteComponentWhenNotNeeded && contentComponent != 0) + contentComponent->getProperties().set (TabbedComponentHelpers::deleteComponentId, true); tabs->addTab (tabName, tabBackgroundColour, insertIndex); } @@ -64322,13 +64336,9 @@ void TabbedComponent::setTabName (const int tabIndex, const String& newName) void TabbedComponent::removeTab (const int tabIndex) { - WeakReference* c = contentComponents [tabIndex]; - - if (c != 0) + if (isPositiveAndBelow (tabIndex, contentComponents.size())) { - if ((bool) ((*c)->getProperties() [deleteComponentId])) - delete c->get(); - + TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (tabIndex)); contentComponents.remove (tabIndex); tabs->removeTab (tabIndex); } @@ -64346,8 +64356,7 @@ const StringArray TabbedComponent::getTabNames() const Component* TabbedComponent::getTabContentComponent (const int tabIndex) const throw() { - WeakReference* const c = contentComponents [tabIndex]; - return c != 0 ? *c : 0; + return contentComponents [tabIndex]; } const Colour TabbedComponent::getTabBackgroundColour (const int tabIndex) const throw() @@ -64378,99 +64387,62 @@ const String TabbedComponent::getCurrentTabName() const return tabs->getCurrentTabName(); } -void TabbedComponent::setOutline (int thickness) +void TabbedComponent::setOutline (const int thickness) { outlineThickness = thickness; + resized(); repaint(); } void TabbedComponent::setIndent (const int indentThickness) { edgeIndent = indentThickness; + resized(); + repaint(); } void TabbedComponent::paint (Graphics& g) { g.fillAll (findColour (backgroundColourId)); - const TabbedButtonBar::Orientation o = getOrientation(); + Rectangle content (getLocalBounds()); + BorderSize outline (outlineThickness); + TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth); - int x = 0; - int y = 0; - int r = getWidth(); - int b = getHeight(); - - if (o == TabbedButtonBar::TabsAtTop) - y += tabDepth; - else if (o == TabbedButtonBar::TabsAtBottom) - b -= tabDepth; - else if (o == TabbedButtonBar::TabsAtLeft) - x += tabDepth; - else if (o == TabbedButtonBar::TabsAtRight) - r -= tabDepth; - - g.reduceClipRegion (x, y, r - x, b - y); + g.reduceClipRegion (content); g.fillAll (tabs->getTabBackgroundColour (getCurrentTabIndex())); if (outlineThickness > 0) { - if (o == TabbedButtonBar::TabsAtTop) - --y; - else if (o == TabbedButtonBar::TabsAtBottom) - ++b; - else if (o == TabbedButtonBar::TabsAtLeft) - --x; - else if (o == TabbedButtonBar::TabsAtRight) - ++r; + RectangleList rl (content); + rl.subtract (outline.subtractedFrom (content)); - g.setColour (findColour (outlineColourId)); - g.drawRect (x, y, r - x, b - y, outlineThickness); + g.reduceClipRegion (rl); + g.fillAll (findColour (outlineColourId)); } } void TabbedComponent::resized() { - const TabbedButtonBar::Orientation o = getOrientation(); - const int indent = edgeIndent + outlineThickness; - BorderSize indents (indent); + Rectangle content (getLocalBounds()); + BorderSize outline (outlineThickness); - if (o == TabbedButtonBar::TabsAtTop) - { - tabs->setBounds (0, 0, getWidth(), tabDepth); - indents.setTop (tabDepth + edgeIndent); - } - else if (o == TabbedButtonBar::TabsAtBottom) - { - tabs->setBounds (0, getHeight() - tabDepth, getWidth(), tabDepth); - indents.setBottom (tabDepth + edgeIndent); - } - else if (o == TabbedButtonBar::TabsAtLeft) - { - tabs->setBounds (0, 0, tabDepth, getHeight()); - indents.setLeft (tabDepth + edgeIndent); - } - else if (o == TabbedButtonBar::TabsAtRight) - { - tabs->setBounds (getWidth() - tabDepth, 0, tabDepth, getHeight()); - indents.setRight (tabDepth + edgeIndent); - } - - const Rectangle bounds (indents.subtractedFrom (getLocalBounds())); + tabs->setBounds (TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth)); + content = BorderSize (edgeIndent).subtractedFrom (outline.subtractedFrom (content)); for (int i = contentComponents.size(); --i >= 0;) - if (*contentComponents.getUnchecked (i) != 0) - (*contentComponents.getUnchecked (i))->setBounds (bounds); + if (contentComponents.getReference (i) != 0) + contentComponents.getReference (i)->setBounds (content); } void TabbedComponent::lookAndFeelChanged() { for (int i = contentComponents.size(); --i >= 0;) - if (*contentComponents.getUnchecked (i) != 0) - (*contentComponents.getUnchecked (i))->lookAndFeelChanged(); + if (contentComponents.getReference (i) != 0) + contentComponents.getReference (i)->lookAndFeelChanged(); } -void TabbedComponent::changeCallback (const int newCurrentTabIndex, - const String& newTabName) +void TabbedComponent::changeCallback (const int newCurrentTabIndex, const String& newTabName) { if (panelComponent != 0) { @@ -64500,13 +64472,8 @@ void TabbedComponent::changeCallback (const int newCurrentTabIndex, currentTabChanged (newCurrentTabIndex, newTabName); } -void TabbedComponent::currentTabChanged (const int, const String&) -{ -} - -void TabbedComponent::popupMenuClickOnTab (const int, const String&) -{ -} +void TabbedComponent::currentTabChanged (const int, const String&) {} +void TabbedComponent::popupMenuClickOnTab (const int, const String&) {} END_JUCE_NAMESPACE /*** End of inlined file: juce_TabbedComponent.cpp ***/ @@ -80436,6 +80403,11 @@ const AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::E corners[2].getX(), corners[2].getY(), newBottomLeft.getX(), newBottomLeft.getY()); } +bool RelativeParallelogram::isDynamic() const +{ + return topLeft.isDynamic() || topRight.isDynamic() || bottomLeft.isDynamic(); +} + bool RelativeParallelogram::operator== (const RelativeParallelogram& other) const throw() { return topLeft == other.topLeft && topRight == other.topRight && bottomLeft == other.bottomLeft; @@ -80463,6 +80435,12 @@ const Point RelativeParallelogram::getPointForInternalCoord (const Point< + Line (Point(), corners[2] - corners[0]).getPointAlongLine (point.getY()); } +const Rectangle RelativeParallelogram::getBoundingBox (const Point* const p) throw() +{ + const Point points[] = { p[0], p[1], p[2], p[1] + (p[2] - p[0]) }; + return Rectangle::findAreaContainingPoints (points, 4); +} + END_JUCE_NAMESPACE /*** End of inlined file: juce_RelativeParallelogram.cpp ***/ @@ -80560,6 +80538,12 @@ bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate& return registerListeners (coord.getExpression()); } +bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point) +{ + const bool ok = addCoordinate (point.x); + return addCoordinate (point.y) && ok; +} + bool RelativeCoordinatePositionerBase::registerListeners (const Expression& e) { bool ok = true; @@ -86614,65 +86598,110 @@ DrawableShape::~DrawableShape() { } +class DrawableShape::RelativePositioner : public RelativeCoordinatePositionerBase +{ +public: + RelativePositioner (DrawableShape& component_, const DrawableShape::RelativeFillType& fill_, bool isMainFill_) + : RelativeCoordinatePositionerBase (component_), + owner (component_), + fill (fill_), + isMainFill (isMainFill_) + { + } + + bool registerCoordinates() + { + bool ok = addPoint (fill.gradientPoint1); + ok = addPoint (fill.gradientPoint2) && ok; + return addPoint (fill.gradientPoint3) && ok; + } + + void applyToComponentBounds() + { + if (isMainFill ? owner.mainFill.recalculateCoords (this) + : owner.strokeFill.recalculateCoords (this)) + owner.repaint(); + } + +private: + DrawableShape& owner; + const DrawableShape::RelativeFillType fill; + const bool isMainFill; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativePositioner); +}; + void DrawableShape::setFill (const FillType& newFill) { - mainFill = newFill; + setFill (RelativeFillType (newFill)); } void DrawableShape::setStrokeFill (const FillType& newFill) { - strokeFill = newFill; + setStrokeFill (RelativeFillType (newFill)); } -void DrawableShape::setStrokeType (const PathStrokeType& newStrokeType) +void DrawableShape::setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill, + ScopedPointer& positioner) { - strokeType = newStrokeType; - strokeChanged(); + if (fill != newFill) + { + fill = newFill; + positioner = 0; + + if (fill.isDynamic()) + { + positioner = new RelativePositioner (*this, fill, true); + positioner->apply(); + } + else + { + fill.recalculateCoords (0); + } + + repaint(); + } } -void DrawableShape::setStrokeThickness (const float newThickness) +void DrawableShape::setFill (const RelativeFillType& newFill) { - setStrokeType (PathStrokeType (newThickness, strokeType.getJointStyle(), strokeType.getEndStyle())); + setFillInternal (mainFill, newFill, mainFillPositioner); } -bool DrawableShape::isStrokeVisible() const throw() +void DrawableShape::setStrokeFill (const RelativeFillType& newFill) { - return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.isInvisible(); + setFillInternal (strokeFill, newFill, strokeFillPositioner); } -bool DrawableShape::refreshFillTypes (const FillAndStrokeState& newState, - Expression::EvaluationContext* /*nameFinder*/, - ComponentBuilder::ImageProvider* imageProvider) +void DrawableShape::setStrokeType (const PathStrokeType& newStrokeType) { - bool hasChanged = false; - + if (strokeType != newStrokeType) { - const FillType f (newState.getMainFill (getParent(), imageProvider)); - - if (mainFill != f) - { - hasChanged = true; - mainFill = f; - } + strokeType = newStrokeType; + strokeChanged(); } +} - { - const FillType f (newState.getStrokeFill (getParent(), imageProvider)); +void DrawableShape::setStrokeThickness (const float newThickness) +{ + setStrokeType (PathStrokeType (newThickness, strokeType.getJointStyle(), strokeType.getEndStyle())); +} - if (strokeFill != f) - { - hasChanged = true; - strokeFill = f; - } - } +bool DrawableShape::isStrokeVisible() const throw() +{ + return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.fill.isInvisible(); +} - return hasChanged; +void DrawableShape::refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider* imageProvider) +{ + setFill (newState.getFill (FillAndStrokeState::fill, imageProvider)); + setStrokeFill (newState.getFill (FillAndStrokeState::stroke, imageProvider)); } void DrawableShape::writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const { - state.setMainFill (mainFill, 0, 0, 0, imageProvider, undoManager); - state.setStrokeFill (strokeFill, 0, 0, 0, imageProvider, undoManager); + state.setFill (FillAndStrokeState::fill, mainFill, imageProvider, undoManager); + state.setFill (FillAndStrokeState::stroke, strokeFill, imageProvider, undoManager); state.setStrokeType (strokeType, undoManager); } @@ -86680,19 +86709,18 @@ void DrawableShape::paint (Graphics& g) { transformContextToCorrectOrigin (g); - g.setFillType (mainFill); + g.setFillType (mainFill.fill); g.fillPath (path); if (isStrokeVisible()) { - g.setFillType (strokeFill); + g.setFillType (strokeFill.fill); g.fillPath (strokePath); } } void DrawableShape::pathChanged() { - rebuildPath (path); strokeChanged(); } @@ -86722,211 +86750,248 @@ bool DrawableShape::hitTest (int x, int y) const || (isStrokeVisible() && strokePath.contains (globalX, globalY)); } -const Identifier DrawableShape::FillAndStrokeState::type ("type"); -const Identifier DrawableShape::FillAndStrokeState::colour ("colour"); -const Identifier DrawableShape::FillAndStrokeState::colours ("colours"); -const Identifier DrawableShape::FillAndStrokeState::fill ("Fill"); -const Identifier DrawableShape::FillAndStrokeState::stroke ("Stroke"); -const Identifier DrawableShape::FillAndStrokeState::path ("Path"); -const Identifier DrawableShape::FillAndStrokeState::jointStyle ("jointStyle"); -const Identifier DrawableShape::FillAndStrokeState::capStyle ("capStyle"); -const Identifier DrawableShape::FillAndStrokeState::strokeWidth ("strokeWidth"); -const Identifier DrawableShape::FillAndStrokeState::gradientPoint1 ("point1"); -const Identifier DrawableShape::FillAndStrokeState::gradientPoint2 ("point2"); -const Identifier DrawableShape::FillAndStrokeState::gradientPoint3 ("point3"); -const Identifier DrawableShape::FillAndStrokeState::radial ("radial"); -const Identifier DrawableShape::FillAndStrokeState::imageId ("imageId"); -const Identifier DrawableShape::FillAndStrokeState::imageOpacity ("imageOpacity"); - -DrawableShape::FillAndStrokeState::FillAndStrokeState (const ValueTree& state_) - : Drawable::ValueTreeWrapperBase (state_) +DrawableShape::RelativeFillType::RelativeFillType() { } -const FillType DrawableShape::FillAndStrokeState::getMainFill (Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider) const +DrawableShape::RelativeFillType::RelativeFillType (const FillType& fill_) + : fill (fill_) { - return readFillType (state.getChildWithName (fill), 0, 0, 0, nameFinder, imageProvider); + if (fill.isGradient()) + { + const ColourGradient& g = *fill.gradient; + + gradientPoint1 = g.point1.transformedBy (fill.transform); + gradientPoint2 = g.point2.transformedBy (fill.transform); + gradientPoint3 = Point (g.point1.getX() + g.point2.getY() - g.point1.getY(), + g.point1.getY() + g.point1.getX() - g.point2.getX()) + .transformedBy (fill.transform); + fill.transform = AffineTransform::identity; + } } -ValueTree DrawableShape::FillAndStrokeState::getMainFillState() +DrawableShape::RelativeFillType::RelativeFillType (const RelativeFillType& other) + : fill (other.fill), + gradientPoint1 (other.gradientPoint1), + gradientPoint2 (other.gradientPoint2), + gradientPoint3 (other.gradientPoint3) { - ValueTree v (state.getChildWithName (fill)); - if (v.isValid()) - return v; +} - setMainFill (Colours::black, 0, 0, 0, 0, 0); - return getMainFillState(); +DrawableShape::RelativeFillType& DrawableShape::RelativeFillType::operator= (const RelativeFillType& other) +{ + fill = other.fill; + gradientPoint1 = other.gradientPoint1; + gradientPoint2 = other.gradientPoint2; + gradientPoint3 = other.gradientPoint3; + return *this; } -void DrawableShape::FillAndStrokeState::setMainFill (const FillType& newFill, const RelativePoint* gp1, const RelativePoint* gp2, - const RelativePoint* gp3, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) +bool DrawableShape::RelativeFillType::operator== (const RelativeFillType& other) const { - ValueTree v (state.getOrCreateChildWithName (fill, undoManager)); - writeFillType (v, newFill, gp1, gp2, gp3, imageProvider, undoManager); + return fill == other.fill + && ((! fill.isGradient()) + || (gradientPoint1 == other.gradientPoint1 + && gradientPoint2 == other.gradientPoint2 + && gradientPoint3 == other.gradientPoint3)); } -const FillType DrawableShape::FillAndStrokeState::getStrokeFill (Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider) const +bool DrawableShape::RelativeFillType::operator!= (const RelativeFillType& other) const { - return readFillType (state.getChildWithName (stroke), 0, 0, 0, nameFinder, imageProvider); + return ! operator== (other); } -ValueTree DrawableShape::FillAndStrokeState::getStrokeFillState() +bool DrawableShape::RelativeFillType::recalculateCoords (Expression::EvaluationContext* context) { - ValueTree v (state.getChildWithName (stroke)); - if (v.isValid()) - return v; + if (fill.isGradient()) + { + const Point g1 (gradientPoint1.resolve (context)); + const Point g2 (gradientPoint2.resolve (context)); + AffineTransform t; + + ColourGradient& g = *fill.gradient; + + if (g.isRadial) + { + const Point g3 (gradientPoint3.resolve (context)); + const Point g3Source (g1.getX() + g2.getY() - g1.getY(), + g1.getY() + g1.getX() - g2.getX()); + + t = AffineTransform::fromTargetPoints (g1.getX(), g1.getY(), g1.getX(), g1.getY(), + g2.getX(), g2.getY(), g2.getX(), g2.getY(), + g3Source.getX(), g3Source.getY(), g3.getX(), g3.getY()); + } - setStrokeFill (Colours::black, 0, 0, 0, 0, 0); - return getStrokeFillState(); + if (g.point1 != g1 || g.point2 != g2 || fill.transform != t) + { + g.point1 = g1; + g.point2 = g2; + fill.transform = t; + return true; + } + } + + return false; } -void DrawableShape::FillAndStrokeState::setStrokeFill (const FillType& newFill, const RelativePoint* gp1, const RelativePoint* gp2, - const RelativePoint* gp3, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) +bool DrawableShape::RelativeFillType::isDynamic() const { - ValueTree v (state.getOrCreateChildWithName (stroke, undoManager)); - writeFillType (v, newFill, gp1, gp2, gp3, imageProvider, undoManager); + return gradientPoint1.isDynamic() || gradientPoint2.isDynamic() || gradientPoint3.isDynamic(); } -const PathStrokeType DrawableShape::FillAndStrokeState::getStrokeType() const +void DrawableShape::RelativeFillType::writeTo (ValueTree& v, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const { - const String jointStyleString (state [jointStyle].toString()); - const String capStyleString (state [capStyle].toString()); + if (fill.isColour()) + { + v.setProperty (FillAndStrokeState::type, "solid", undoManager); + v.setProperty (FillAndStrokeState::colour, String::toHexString ((int) fill.colour.getARGB()), undoManager); + } + else if (fill.isGradient()) + { + v.setProperty (FillAndStrokeState::type, "gradient", undoManager); + v.setProperty (FillAndStrokeState::gradientPoint1, gradientPoint1.toString(), undoManager); + v.setProperty (FillAndStrokeState::gradientPoint2, gradientPoint2.toString(), undoManager); + v.setProperty (FillAndStrokeState::gradientPoint3, gradientPoint3.toString(), undoManager); - return PathStrokeType (state [strokeWidth], - jointStyleString == "curved" ? PathStrokeType::curved - : (jointStyleString == "bevel" ? PathStrokeType::beveled - : PathStrokeType::mitered), - capStyleString == "square" ? PathStrokeType::square - : (capStyleString == "round" ? PathStrokeType::rounded - : PathStrokeType::butt)); -} + const ColourGradient& cg = *fill.gradient; + v.setProperty (FillAndStrokeState::radial, cg.isRadial, undoManager); -void DrawableShape::FillAndStrokeState::setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager) -{ - state.setProperty (strokeWidth, (double) newStrokeType.getStrokeThickness(), undoManager); - state.setProperty (jointStyle, newStrokeType.getJointStyle() == PathStrokeType::mitered - ? "miter" : (newStrokeType.getJointStyle() == PathStrokeType::curved ? "curved" : "bevel"), undoManager); - state.setProperty (capStyle, newStrokeType.getEndStyle() == PathStrokeType::butt - ? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager); + String s; + for (int i = 0; i < cg.getNumColours(); ++i) + s << ' ' << cg.getColourPosition (i) + << ' ' << String::toHexString ((int) cg.getColour(i).getARGB()); + + v.setProperty (FillAndStrokeState::colours, s.trimStart(), undoManager); + } + else if (fill.isTiledImage()) + { + v.setProperty (FillAndStrokeState::type, "image", undoManager); + + if (imageProvider != 0) + v.setProperty (FillAndStrokeState::imageId, imageProvider->getIdentifierForImage (fill.image), undoManager); + + if (fill.getOpacity() < 1.0f) + v.setProperty (FillAndStrokeState::imageOpacity, fill.getOpacity(), undoManager); + else + v.removeProperty (FillAndStrokeState::imageOpacity, undoManager); + } + else + { + jassertfalse; + } } -const FillType DrawableShape::FillAndStrokeState::readFillType (const ValueTree& v, RelativePoint* const gp1, RelativePoint* const gp2, RelativePoint* const gp3, - Expression::EvaluationContext* const nameFinder, ComponentBuilder::ImageProvider* imageProvider) +bool DrawableShape::RelativeFillType::readFrom (const ValueTree& v, ComponentBuilder::ImageProvider* imageProvider) { - const String newType (v[type].toString()); + const String newType (v [FillAndStrokeState::type].toString()); if (newType == "solid") { - const String colourString (v [colour].toString()); - return FillType (Colour (colourString.isEmpty() ? (uint32) 0xff000000 - : (uint32) colourString.getHexValue32())); + const String colourString (v [FillAndStrokeState::colour].toString()); + fill.setColour (Colour (colourString.isEmpty() ? (uint32) 0xff000000 + : (uint32) colourString.getHexValue32())); + return true; } else if (newType == "gradient") { - RelativePoint p1 (v [gradientPoint1]), p2 (v [gradientPoint2]), p3 (v [gradientPoint3]); - ColourGradient g; - - if (gp1 != 0) *gp1 = p1; - if (gp2 != 0) *gp2 = p2; - if (gp3 != 0) *gp3 = p3; - - g.point1 = p1.resolve (nameFinder); - g.point2 = p2.resolve (nameFinder); - g.isRadial = v[radial]; + g.isRadial = v [FillAndStrokeState::radial]; StringArray colourSteps; - colourSteps.addTokens (v[colours].toString(), false); + colourSteps.addTokens (v [FillAndStrokeState::colours].toString(), false); for (int i = 0; i < colourSteps.size() / 2; ++i) g.addColour (colourSteps[i * 2].getDoubleValue(), Colour ((uint32) colourSteps[i * 2 + 1].getHexValue32())); - FillType fillType (g); - - if (g.isRadial) - { - const Point point3 (p3.resolve (nameFinder)); - const Point point3Source (g.point1.getX() + g.point2.getY() - g.point1.getY(), - g.point1.getY() + g.point1.getX() - g.point2.getX()); - - fillType.transform = AffineTransform::fromTargetPoints (g.point1.getX(), g.point1.getY(), g.point1.getX(), g.point1.getY(), - g.point2.getX(), g.point2.getY(), g.point2.getX(), g.point2.getY(), - point3Source.getX(), point3Source.getY(), point3.getX(), point3.getY()); - } + fill.setGradient (g); - return fillType; + gradientPoint1 = RelativePoint (v [FillAndStrokeState::gradientPoint1]); + gradientPoint2 = RelativePoint (v [FillAndStrokeState::gradientPoint2]); + gradientPoint3 = RelativePoint (v [FillAndStrokeState::gradientPoint3]); + return true; } else if (newType == "image") { Image im; if (imageProvider != 0) - im = imageProvider->getImageForIdentifier (v[imageId]); + im = imageProvider->getImageForIdentifier (v [FillAndStrokeState::imageId]); - FillType f (im, AffineTransform::identity); - f.setOpacity ((float) v.getProperty (imageOpacity, 1.0f)); - return f; + fill.setTiledImage (im, AffineTransform::identity); + fill.setOpacity ((float) v.getProperty (FillAndStrokeState::imageOpacity, 1.0f)); + return true; } - jassert (! v.isValid()); - return FillType(); + jassertfalse; + return false; } -namespace DrawableShapeHelpers +const Identifier DrawableShape::FillAndStrokeState::type ("type"); +const Identifier DrawableShape::FillAndStrokeState::colour ("colour"); +const Identifier DrawableShape::FillAndStrokeState::colours ("colours"); +const Identifier DrawableShape::FillAndStrokeState::fill ("Fill"); +const Identifier DrawableShape::FillAndStrokeState::stroke ("Stroke"); +const Identifier DrawableShape::FillAndStrokeState::path ("Path"); +const Identifier DrawableShape::FillAndStrokeState::jointStyle ("jointStyle"); +const Identifier DrawableShape::FillAndStrokeState::capStyle ("capStyle"); +const Identifier DrawableShape::FillAndStrokeState::strokeWidth ("strokeWidth"); +const Identifier DrawableShape::FillAndStrokeState::gradientPoint1 ("point1"); +const Identifier DrawableShape::FillAndStrokeState::gradientPoint2 ("point2"); +const Identifier DrawableShape::FillAndStrokeState::gradientPoint3 ("point3"); +const Identifier DrawableShape::FillAndStrokeState::radial ("radial"); +const Identifier DrawableShape::FillAndStrokeState::imageId ("imageId"); +const Identifier DrawableShape::FillAndStrokeState::imageOpacity ("imageOpacity"); + +DrawableShape::FillAndStrokeState::FillAndStrokeState (const ValueTree& state_) + : Drawable::ValueTreeWrapperBase (state_) { - const Point calcThirdGradientPoint (const FillType& fillType) - { - const ColourGradient& g = *fillType.gradient; - const Point point3Source (g.point1.getX() + g.point2.getY() - g.point1.getY(), - g.point1.getY() + g.point1.getX() - g.point2.getX()); +} - return point3Source.transformedBy (fillType.transform); - } +const DrawableShape::RelativeFillType DrawableShape::FillAndStrokeState::getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider* imageProvider) const +{ + DrawableShape::RelativeFillType f; + f.readFrom (state.getChildWithName (fillOrStrokeType), imageProvider); + return f; } -void DrawableShape::FillAndStrokeState::writeFillType (ValueTree& v, const FillType& fillType, - const RelativePoint* const gp1, const RelativePoint* const gp2, const RelativePoint* gp3, - ComponentBuilder::ImageProvider* imageProvider, UndoManager* const undoManager) +ValueTree DrawableShape::FillAndStrokeState::getFillState (const Identifier& fillOrStrokeType) { - if (fillType.isColour()) - { - v.setProperty (type, "solid", undoManager); - v.setProperty (colour, String::toHexString ((int) fillType.colour.getARGB()), undoManager); - } - else if (fillType.isGradient()) - { - v.setProperty (type, "gradient", undoManager); - v.setProperty (gradientPoint1, gp1 != 0 ? gp1->toString() : fillType.gradient->point1.toString(), undoManager); - v.setProperty (gradientPoint2, gp2 != 0 ? gp2->toString() : fillType.gradient->point2.toString(), undoManager); - v.setProperty (gradientPoint3, gp3 != 0 ? gp3->toString() : DrawableShapeHelpers::calcThirdGradientPoint (fillType).toString(), undoManager); + ValueTree v (state.getChildWithName (fillOrStrokeType)); + if (v.isValid()) + return v; - v.setProperty (radial, fillType.gradient->isRadial, undoManager); + setFill (fillOrStrokeType, FillType (Colours::black), 0, 0); + return getFillState (fillOrStrokeType); +} - String s; - for (int i = 0; i < fillType.gradient->getNumColours(); ++i) - s << ' ' << fillType.gradient->getColourPosition (i) - << ' ' << String::toHexString ((int) fillType.gradient->getColour(i).getARGB()); +void DrawableShape::FillAndStrokeState::setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill, + ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) +{ + ValueTree v (state.getOrCreateChildWithName (fillOrStrokeType, undoManager)); + newFill.writeTo (v, imageProvider, undoManager); +} - v.setProperty (colours, s.trimStart(), undoManager); - } - else if (fillType.isTiledImage()) - { - v.setProperty (type, "image", undoManager); +const PathStrokeType DrawableShape::FillAndStrokeState::getStrokeType() const +{ + const String jointStyleString (state [jointStyle].toString()); + const String capStyleString (state [capStyle].toString()); - if (imageProvider != 0) - v.setProperty (imageId, imageProvider->getIdentifierForImage (fillType.image), undoManager); + return PathStrokeType (state [strokeWidth], + jointStyleString == "curved" ? PathStrokeType::curved + : (jointStyleString == "bevel" ? PathStrokeType::beveled + : PathStrokeType::mitered), + capStyleString == "square" ? PathStrokeType::square + : (capStyleString == "round" ? PathStrokeType::rounded + : PathStrokeType::butt)); +} - if (fillType.getOpacity() < 1.0f) - v.setProperty (imageOpacity, fillType.getOpacity(), undoManager); - else - v.removeProperty (imageOpacity, undoManager); - } - else - { - jassertfalse; - } +void DrawableShape::FillAndStrokeState::setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager) +{ + state.setProperty (strokeWidth, (double) newStrokeType.getStrokeThickness(), undoManager); + state.setProperty (jointStyle, newStrokeType.getJointStyle() == PathStrokeType::mitered + ? "miter" : (newStrokeType.getJointStyle() == PathStrokeType::curved ? "curved" : "bevel"), undoManager); + state.setProperty (capStyle, newStrokeType.getEndStyle() == PathStrokeType::butt + ? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager); } END_JUCE_NAMESPACE @@ -86966,6 +87031,11 @@ DrawableComposite::~DrawableComposite() deleteAllChildren(); } +Drawable* DrawableComposite::createCopy() const +{ + return new DrawableComposite (*this); +} + const Rectangle DrawableComposite::getDrawableBounds() const { Rectangle r; @@ -87002,13 +87072,26 @@ void DrawableComposite::setContentArea (const RelativeRectangle& newArea) markersX.setMarker (contentRightMarkerName, newArea.right); markersY.setMarker (contentTopMarkerName, newArea.top); markersY.setMarker (contentBottomMarkerName, newArea.bottom); - refreshTransformFromBounds(); } -void DrawableComposite::setBoundingBox (const RelativeParallelogram& newBoundingBox) +void DrawableComposite::setBoundingBox (const RelativeParallelogram& newBounds) { - bounds = newBoundingBox; - refreshTransformFromBounds(); + if (bounds != newBounds) + { + bounds = newBounds; + + if (bounds.isDynamic()) + { + Drawable::Positioner* const p = new Drawable::Positioner (*this); + setPositioner (p); + p->apply(); + } + else + { + setPositioner (0); + recalculateCoordinates (0); + } + } } void DrawableComposite::resetBoundingBoxToContentArea() @@ -87031,12 +87114,19 @@ void DrawableComposite::resetContentAreaAndBoundingBoxToFitChildren() resetBoundingBoxToContentArea(); } -void DrawableComposite::refreshTransformFromBounds() +bool DrawableComposite::registerCoordinates (RelativeCoordinatePositionerBase& positioner) +{ + bool ok = positioner.addPoint (bounds.topLeft); + ok = positioner.addPoint (bounds.topRight) && ok; + return positioner.addPoint (bounds.bottomLeft) && ok; +} + +void DrawableComposite::recalculateCoordinates (Expression::EvaluationContext* context) { Point resolved[3]; - bounds.resolveThreePoints (resolved, getParent()); + bounds.resolveThreePoints (resolved, context); - const Rectangle content (getContentArea().resolve (getParent())); + const Rectangle content (getContentArea().resolve (context)); AffineTransform t (AffineTransform::fromTargetPoints (content.getX(), content.getY(), resolved[0].getX(), resolved[0].getY(), content.getRight(), content.getY(), resolved[1].getX(), resolved[1].getY(), @@ -87115,26 +87205,6 @@ const char* const DrawableComposite::contentRightMarkerName = "right"; const char* const DrawableComposite::contentTopMarkerName = "top"; const char* const DrawableComposite::contentBottomMarkerName = "bottom"; -const Expression DrawableComposite::getSymbolValue (const String& symbol, const String& member) const -{ - jassert (member.isEmpty()) // the only symbols available in a Drawable are markers. - - const MarkerList::Marker* m = markersX.getMarker (symbol); - - if (m == 0) - m = markersY.getMarker (symbol); - - if (m != 0) - return m->position.getExpression(); - - throw Expression::EvaluationError (symbol, member); -} - -Drawable* DrawableComposite::createCopy() const -{ - return new DrawableComposite (*this); -} - const Identifier DrawableComposite::valueTreeType ("Group"); const Identifier DrawableComposite::ValueTreeWrapper::topLeft ("topLeft"); @@ -87220,16 +87290,12 @@ void DrawableComposite::refreshFromValueTree (const ValueTree& tree, ComponentBu const ValueTreeWrapper wrapper (tree); setComponentID (wrapper.getID()); - const RelativeParallelogram newBounds (wrapper.getBoundingBox()); - if (bounds != newBounds) - bounds = newBounds; - wrapper.getMarkerList (true).applyTo (markersX); wrapper.getMarkerList (false).applyTo (markersY); - builder.updateChildComponents (*this, wrapper.getChildList()); + setBoundingBox (wrapper.getBoundingBox()); - refreshTransformFromBounds(); + builder.updateChildComponents (*this, wrapper.getChildList()); } const ValueTree DrawableComposite::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const @@ -87287,17 +87353,14 @@ DrawableImage::~DrawableImage() void DrawableImage::setImage (const Image& imageToUse) { image = imageToUse; - setBounds (imageToUse.getBounds()); - if (image.isValid()) - { - bounds.topLeft = RelativePoint (Point (0.0f, 0.0f)); - bounds.topRight = RelativePoint (Point ((float) image.getWidth(), 0.0f)); - bounds.bottomLeft = RelativePoint (Point (0.0f, (float) image.getHeight())); - } + bounds.topLeft = RelativePoint (Point (0.0f, 0.0f)); + bounds.topRight = RelativePoint (Point ((float) image.getWidth(), 0.0f)); + bounds.bottomLeft = RelativePoint (Point (0.0f, (float) image.getHeight())); + recalculateCoordinates (0); - refreshTransformFromBounds(); + repaint(); } void DrawableImage::setOpacity (const float newOpacity) @@ -87312,16 +87375,37 @@ void DrawableImage::setOverlayColour (const Colour& newOverlayColour) void DrawableImage::setBoundingBox (const RelativeParallelogram& newBounds) { - bounds = newBounds; - refreshTransformFromBounds(); + if (bounds != newBounds) + { + bounds = newBounds; + + if (bounds.isDynamic()) + { + Drawable::Positioner* const p = new Drawable::Positioner (*this); + setPositioner (p); + p->apply(); + } + else + { + setPositioner (0); + recalculateCoordinates (0); + } + } +} + +bool DrawableImage::registerCoordinates (RelativeCoordinatePositionerBase& positioner) +{ + bool ok = positioner.addPoint (bounds.topLeft); + ok = positioner.addPoint (bounds.topRight) && ok; + return positioner.addPoint (bounds.bottomLeft) && ok; } -void DrawableImage::refreshTransformFromBounds() +void DrawableImage::recalculateCoordinates (Expression::EvaluationContext* context) { - if (! image.isNull()) + if (image.isValid()) { Point resolved[3]; - bounds.resolveThreePoints (resolved, getParent()); + bounds.resolveThreePoints (resolved, context); const Point tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth()); const Point bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight()); @@ -87330,8 +87414,10 @@ void DrawableImage::refreshTransformFromBounds() tr.getX(), tr.getY(), bl.getX(), bl.getY())); - if (! t.isSingularity()) - setTransform (t); + if (t.isSingularity()) + t = AffineTransform::identity; + + setTransform (t); } } @@ -87473,12 +87559,11 @@ void DrawableImage::refreshFromValueTree (const ValueTree& tree, ComponentBuilde repaint(); opacity = newOpacity; overlayColour = newOverlayColour; - bounds = newBounds; if (image != newImage) setImage (newImage); - else - refreshTransformFromBounds(); + + setBoundingBox (newBounds); } } @@ -87517,10 +87602,8 @@ DrawablePath::DrawablePath() DrawablePath::DrawablePath (const DrawablePath& other) : DrawableShape (other) { - const RelativePointPath* const relativePath = other.getRelativePath(); - - if (relativePath != 0) - setPath (*relativePath); + if (other.relativePath != 0) + setPath (*other.relativePath); else setPath (other.path); } @@ -87550,15 +87633,10 @@ const Path& DrawablePath::getStrokePath() const return strokePath; } -bool DrawablePath::rebuildPath (Path&) const -{ - return false; -} - -void DrawablePath::applyRelativePath (const RelativePointPath& relativePath) +void DrawablePath::applyRelativePath (const RelativePointPath& newRelativePath, Expression::EvaluationContext* context) { Path newPath; - relativePath.createPath (newPath, 0); + newRelativePath.createPath (newPath, context); if (path != newPath) { @@ -87570,9 +87648,8 @@ void DrawablePath::applyRelativePath (const RelativePointPath& relativePath) class DrawablePath::RelativePositioner : public RelativeCoordinatePositionerBase { public: - RelativePositioner (DrawablePath& component_, const RelativePointPath& path_) + RelativePositioner (DrawablePath& component_) : RelativeCoordinatePositionerBase (component_), - path (path_), owner (component_) { } @@ -87581,6 +87658,9 @@ public: { bool ok = true; + jassert (owner.relativePath != 0); + const RelativePointPath& path = *owner.relativePath; + for (int i = 0; i < path.elements.size(); ++i) { RelativePointPath::ElementBase* const e = path.elements.getUnchecked(i); @@ -87589,10 +87669,7 @@ public: RelativePoint* const points = e->getControlPoints (numPoints); for (int j = numPoints; --j >= 0;) - { - ok = addCoordinate (points[j].x) && ok; - ok = addCoordinate (points[j].y) && ok; - } + ok = addPoint (points[j]) && ok; } return ok; @@ -87600,39 +87677,33 @@ public: void applyToComponentBounds() { - owner.applyRelativePath (path); + jassert (owner.relativePath != 0); + owner.applyRelativePath (*owner.relativePath, this); } - const RelativePointPath path; - private: DrawablePath& owner; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativePositioner); }; -const RelativePointPath* DrawablePath::getRelativePath() const -{ - RelativePositioner* current = dynamic_cast (getPositioner()); - return current != 0 ? &(current->path) : 0; -} - void DrawablePath::setPath (const RelativePointPath& newRelativePath) { if (newRelativePath.containsAnyDynamicPoints()) { - const RelativePointPath* current = getRelativePath(); - - if (current == 0 || newRelativePath != *current) + if (relativePath == 0 || newRelativePath != *relativePath) { - RelativePositioner* const p = new RelativePositioner (*this, newRelativePath); + relativePath = new RelativePointPath (newRelativePath); + + RelativePositioner* const p = new RelativePositioner (*this); setPositioner (p); p->apply(); } } else { - applyRelativePath (newRelativePath); + relativePath = 0; + applyRelativePath (newRelativePath, 0); } } @@ -87785,26 +87856,26 @@ const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const return RelativePoint(); } -float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::EvaluationContext* nameFinder) const +float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::EvaluationContext* context) const { const Identifier i (state.getType()); if (i == lineToElement || i == closeSubPathElement) - return getEndPoint().resolve (nameFinder).getDistanceFrom (getStartPoint().resolve (nameFinder)); + return getEndPoint().resolve (context).getDistanceFrom (getStartPoint().resolve (context)); if (i == cubicToElement) { Path p; - p.startNewSubPath (getStartPoint().resolve (nameFinder)); - p.cubicTo (getControlPoint (0).resolve (nameFinder), getControlPoint (1).resolve (nameFinder), getControlPoint (2).resolve (nameFinder)); + p.startNewSubPath (getStartPoint().resolve (context)); + p.cubicTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context), getControlPoint (2).resolve (context)); return p.getLength(); } if (i == quadraticToElement) { Path p; - p.startNewSubPath (getStartPoint().resolve (nameFinder)); - p.quadraticTo (getControlPoint (0).resolve (nameFinder), getControlPoint (1).resolve (nameFinder)); + p.startNewSubPath (getStartPoint().resolve (context)); + p.quadraticTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context)); return p.getLength(); } @@ -87836,7 +87907,7 @@ void DrawablePath::ValueTreeWrapper::Element::convertToLine (UndoManager* undoMa } } -void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager) +void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::EvaluationContext* context, UndoManager* undoManager) { const Identifier i (state.getType()); @@ -87847,8 +87918,8 @@ void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::Evalua const RelativePoint start (getStartPoint()); const RelativePoint end (getEndPoint()); - const Point startResolved (start.resolve (nameFinder)); - const Point endResolved (end.resolve (nameFinder)); + const Point startResolved (start.resolve (context)); + const Point endResolved (end.resolve (context)); e.setControlPoint (0, startResolved + (endResolved - startResolved) * 0.3f, undoManager); e.setControlPoint (1, startResolved + (endResolved - startResolved) * 0.7f, undoManager); e.setControlPoint (2, end, undoManager); @@ -87893,7 +87964,7 @@ namespace DrawablePathHelpers } } -float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext* nameFinder) const +float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext* context) const { using namespace DrawablePathHelpers; const Identifier type (state.getType()); @@ -87903,7 +87974,7 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po { RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint()); - const Point points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; + const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) }; float bestDistance = std::numeric_limits::max(); @@ -87923,7 +87994,7 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po else if (type == quadraticToElement) { RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); - const Point points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; + const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context) }; float bestDistance = std::numeric_limits::max(); @@ -87943,24 +88014,24 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po else if (type == lineToElement) { RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint()); - const Line line (rp1.resolve (nameFinder), rp2.resolve (nameFinder)); + const Line line (rp1.resolve (context), rp2.resolve (context)); bestProp = line.findNearestProportionalPositionTo (targetPoint); } return bestProp; } -ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager) +ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& targetPoint, Expression::EvaluationContext* context, UndoManager* undoManager) { ValueTree newTree; const Identifier type (state.getType()); if (type == cubicToElement) { - float bestProp = findProportionAlongLine (targetPoint, nameFinder); + float bestProp = findProportionAlongLine (targetPoint, context); RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint()); - const Point points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; + const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) }; const Point mid1 (points[0] + (points[1] - points[0]) * bestProp), mid2 (points[1] + (points[2] - points[1]) * bestProp), @@ -87985,10 +88056,10 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; + const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context) }; const Point mid1 (points[0] + (points[1] - points[0]) * bestProp), mid2 (points[1] + (points[2] - points[1]) * bestProp); @@ -88008,7 +88079,7 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point line (rp1.resolve (nameFinder), rp2.resolve (nameFinder)); + const Line line (rp1.resolve (context), rp2.resolve (context)); const Point newPoint (line.findNearestPointTo (targetPoint)); setControlPoint (0, newPoint, undoManager); @@ -88035,15 +88106,8 @@ void DrawablePath::refreshFromValueTree (const ValueTree& tree, ComponentBuilder ValueTreeWrapper v (tree); setComponentID (v.getID()); - if (refreshFillTypes (v, getParent(), builder.getImageProvider())) - repaint(); - - const PathStrokeType newStroke (v.getStrokeType()); - if (strokeType != newStroke) - { - strokeType = newStroke; - strokeChanged(); - } + refreshFillTypes (v, builder.getImageProvider()); + setStrokeType (v.getStrokeType()); RelativePointPath newRelativePath; v.writeTo (newRelativePath); @@ -88058,17 +88122,10 @@ const ValueTree DrawablePath::createValueTree (ComponentBuilder::ImageProvider* v.setID (getComponentID()); writeTo (v, imageProvider, 0); - const RelativePointPath* const relativePath = getRelativePath(); - if (relativePath != 0) - { v.readFrom (*relativePath, 0); - } else - { - RelativePointPath rp (path); - v.readFrom (rp, 0); - } + v.readFrom (RelativePointPath (path), 0); return tree; } @@ -88085,7 +88142,9 @@ DrawableRectangle::DrawableRectangle() } DrawableRectangle::DrawableRectangle (const DrawableRectangle& other) - : DrawableShape (other) + : DrawableShape (other), + bounds (other.bounds), + cornerSize (other.cornerSize) { } @@ -88100,50 +88159,72 @@ Drawable* DrawableRectangle::createCopy() const void DrawableRectangle::setRectangle (const RelativeParallelogram& newBounds) { - bounds = newBounds; - pathChanged(); - strokeChanged(); + if (bounds != newBounds) + { + bounds = newBounds; + rebuildPath(); + } } void DrawableRectangle::setCornerSize (const RelativePoint& newSize) { - cornerSize = newSize; - pathChanged(); - strokeChanged(); + if (cornerSize != newSize) + { + cornerSize = newSize; + rebuildPath(); + } } -bool DrawableRectangle::rebuildPath (Path& path) const +void DrawableRectangle::rebuildPath() +{ + if (bounds.isDynamic() || cornerSize.isDynamic()) + { + Drawable::Positioner* const p = new Drawable::Positioner (*this); + setPositioner (p); + p->apply(); + } + else + { + setPositioner (0); + recalculateCoordinates (0); + } +} + +bool DrawableRectangle::registerCoordinates (RelativeCoordinatePositionerBase& positioner) +{ + bool ok = positioner.addPoint (bounds.topLeft); + ok = positioner.addPoint (bounds.topRight) && ok; + ok = positioner.addPoint (bounds.bottomLeft) && ok; + return positioner.addPoint (cornerSize) && ok; +} + +void DrawableRectangle::recalculateCoordinates (Expression::EvaluationContext* context) { Point points[3]; - bounds.resolveThreePoints (points, getParent()); + bounds.resolveThreePoints (points, context); + + const float cornerSizeX = (float) cornerSize.x.resolve (context); + const float cornerSizeY = (float) cornerSize.y.resolve (context); const float w = Line (points[0], points[1]).getLength(); const float h = Line (points[0], points[2]).getLength(); - const float cornerSizeX = (float) cornerSize.x.resolve (getParent()); - const float cornerSizeY = (float) cornerSize.y.resolve (getParent()); - - path.clear(); + Path newPath; if (cornerSizeX > 0 && cornerSizeY > 0) - path.addRoundedRectangle (0, 0, w, h, cornerSizeX, cornerSizeY); + newPath.addRoundedRectangle (0, 0, w, h, cornerSizeX, cornerSizeY); else - path.addRectangle (0, 0, w, h); - - path.applyTransform (AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(), - w, 0, points[1].getX(), points[1].getY(), - 0, h, points[2].getX(), points[2].getY())); - return true; -} + newPath.addRectangle (0, 0, w, h); -const AffineTransform DrawableRectangle::calculateTransform() const -{ - Point resolved[3]; - bounds.resolveThreePoints (resolved, getParent()); + newPath.applyTransform (AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(), + w, 0, points[1].getX(), points[1].getY(), + 0, h, points[2].getX(), points[2].getY())); - return AffineTransform::fromTargetPoints (resolved[0].getX(), resolved[0].getY(), - resolved[1].getX(), resolved[1].getY(), - resolved[2].getX(), resolved[2].getY()); + if (path != newPath) + { + path.swapWithPath (newPath); + pathChanged(); + } } const Identifier DrawableRectangle::valueTreeType ("Rectangle"); @@ -88192,22 +88273,10 @@ void DrawableRectangle::refreshFromValueTree (const ValueTree& tree, ComponentBu ValueTreeWrapper v (tree); setComponentID (v.getID()); - if (refreshFillTypes (v, getParent(), builder.getImageProvider())) - repaint(); - - RelativeParallelogram newBounds (v.getRectangle()); - - const PathStrokeType newStroke (v.getStrokeType()); - const RelativePoint newCornerSize (v.getCornerSize()); - - if (strokeType != newStroke || newBounds != bounds || newCornerSize != cornerSize) - { - repaint(); - bounds = newBounds; - strokeType = newStroke; - cornerSize = newCornerSize; - pathChanged(); - } + refreshFillTypes (v, builder.getImageProvider()); + setStrokeType (v.getStrokeType()); + setRectangle (v.getRectangle()); + setCornerSize (v.getCornerSize()); } const ValueTree DrawableRectangle::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const @@ -88254,38 +88323,38 @@ DrawableText::~DrawableText() { } -void DrawableText::refreshBounds() -{ - setBoundsToEnclose (getDrawableBounds()); - repaint(); -} - void DrawableText::setText (const String& newText) { - text = newText; - refreshBounds(); + if (text != newText) + { + text = newText; + refreshBounds(); + } } void DrawableText::setColour (const Colour& newColour) { - colour = newColour; - repaint(); + if (colour != newColour) + { + colour = newColour; + repaint(); + } } void DrawableText::setFont (const Font& newFont, bool applySizeAndScale) { - font = newFont; - - if (applySizeAndScale) + if (font != newFont) { - Point corners[3]; - bounds.resolveThreePoints (corners, getParent()); + font = newFont; - setFontSizeControlPoint (RelativePoint (RelativeParallelogram::getPointForInternalCoord (corners, - Point (font.getHorizontalScale() * font.getHeight(), font.getHeight())))); - } + if (applySizeAndScale) + { + setFontSizeControlPoint (RelativePoint (RelativeParallelogram::getPointForInternalCoord (resolvedPoints, + Point (font.getHorizontalScale() * font.getHeight(), font.getHeight())))); + } - refreshBounds(); + refreshBounds(); + } } void DrawableText::setJustification (const Justification& newJustification) @@ -88296,46 +88365,90 @@ void DrawableText::setJustification (const Justification& newJustification) void DrawableText::setBoundingBox (const RelativeParallelogram& newBounds) { - bounds = newBounds; - refreshBounds(); + if (bounds != newBounds) + { + bounds = newBounds; + refreshBounds(); + } } void DrawableText::setFontSizeControlPoint (const RelativePoint& newPoint) { - fontSizeControlPoint = newPoint; - refreshBounds(); + if (fontSizeControlPoint != newPoint) + { + fontSizeControlPoint = newPoint; + refreshBounds(); + } } -void DrawableText::paint (Graphics& g) +void DrawableText::refreshBounds() { - transformContextToCorrectOrigin (g); + if (bounds.isDynamic() || fontSizeControlPoint.isDynamic()) + { + Drawable::Positioner* const p = new Drawable::Positioner (*this); + setPositioner (p); + p->apply(); + } + else + { + setPositioner (0); + recalculateCoordinates (0); + } +} - Point points[3]; - bounds.resolveThreePoints (points, getParent()); +bool DrawableText::registerCoordinates (RelativeCoordinatePositionerBase& positioner) +{ + bool ok = positioner.addPoint (bounds.topLeft); + ok = positioner.addPoint (bounds.topRight) && ok; + ok = positioner.addPoint (bounds.bottomLeft) && ok; + return positioner.addPoint (fontSizeControlPoint) && ok; +} - const float w = Line (points[0], points[1]).getLength(); - const float h = Line (points[0], points[2]).getLength(); +void DrawableText::recalculateCoordinates (Expression::EvaluationContext* context) +{ + bounds.resolveThreePoints (resolvedPoints, context); + + const float w = Line (resolvedPoints[0], resolvedPoints[1]).getLength(); + const float h = Line (resolvedPoints[0], resolvedPoints[2]).getLength(); - const Point fontCoords (bounds.getInternalCoordForPoint (points, fontSizeControlPoint.resolve (getParent()))); + const Point fontCoords (RelativeParallelogram::getInternalCoordForPoint (resolvedPoints, fontSizeControlPoint.resolve (context))); const float fontHeight = jlimit (0.01f, jmax (0.01f, h), fontCoords.getY()); const float fontWidth = jlimit (0.01f, jmax (0.01f, w), fontCoords.getX()); - Font f (font); - f.setHeight (fontHeight); - f.setHorizontalScale (fontWidth / fontHeight); + scaledFont = font; + scaledFont.setHeight (fontHeight); + scaledFont.setHorizontalScale (fontWidth / fontHeight); + + setBoundsToEnclose (getDrawableBounds()); + repaint(); +} + +const AffineTransform DrawableText::getArrangementAndTransform (GlyphArrangement& glyphs) const +{ + const float w = Line (resolvedPoints[0], resolvedPoints[1]).getLength(); + const float h = Line (resolvedPoints[0], resolvedPoints[2]).getLength(); + + glyphs.addFittedText (scaledFont, text, 0, 0, w, h, justification, 0x100000); + + return AffineTransform::fromTargetPoints (0, 0, resolvedPoints[0].getX(), resolvedPoints[0].getY(), + w, 0, resolvedPoints[1].getX(), resolvedPoints[1].getY(), + 0, h, resolvedPoints[2].getX(), resolvedPoints[2].getY()); +} + +void DrawableText::paint (Graphics& g) +{ + transformContextToCorrectOrigin (g); g.setColour (colour); GlyphArrangement ga; - ga.addFittedText (f, text, 0, 0, w, h, justification, 0x100000); - ga.draw (g, AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(), - w, 0, points[1].getX(), points[1].getY(), - 0, h, points[2].getX(), points[2].getY())); + const AffineTransform transform (getArrangementAndTransform (ga)); + ga.draw (g, transform); } const Rectangle DrawableText::getDrawableBounds() const { - return bounds.getBounds (getParent()); + return RelativeParallelogram::getBoundingBox (resolvedPoints); } Drawable* DrawableText::createCopy() const @@ -88447,7 +88560,6 @@ void DrawableText::refreshFromValueTree (const ValueTree& tree, ComponentBuilder if (text != newText || font != newFont || justification != newJustification || colour != newColour || bounds != newBounds || newFontPoint != fontSizeControlPoint) { - repaint(); setBoundingBox (newBounds); setFontSizeControlPoint (newFontPoint); setColour (newColour); @@ -89910,10 +90022,6 @@ public: const Typeface::Ptr findTypefaceFor (const Font& font) { - // (can't initialise defaultFace in the constructor or in getDefaultTypeface() because of recursion). - if (defaultFace == 0) - defaultFace = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (Font()); - const int flags = font.getStyleFlags() & (Font::bold | Font::italic); const String faceName (font.getTypefaceName()); @@ -89952,6 +90060,9 @@ public: face.typeface = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (font); jassert (face.typeface != 0); // the look and feel must return a typeface! + if (defaultFace == 0 && font == Font()) + defaultFace = face.typeface; + return face.typeface; } @@ -266236,7 +266347,7 @@ public: } } -#if JUCE_MAC + #if JUCE_MAC static NSImage* createNSImage (const Image& image) { const ScopedAutoReleasePool pool; @@ -266257,7 +266368,7 @@ public: return im; } -#endif + #endif CGContextRef context; HeapBlock imageDataAllocated; @@ -266265,11 +266376,11 @@ public: private: static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) { -#if JUCE_BIG_ENDIAN + #if JUCE_BIG_ENDIAN return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) : kCGBitmapByteOrderDefault; -#else + #else return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) : kCGBitmapByteOrderDefault; -#endif + #endif } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImage); @@ -266277,11 +266388,11 @@ private: Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage) { -#if USE_COREGRAPHICS_RENDERING + #if USE_COREGRAPHICS_RENDERING return new CoreGraphicsImage (format == RGB ? ARGB : format, width, height, clearImage); -#else + #else return createSoftwareImage (format, width, height, clearImage); -#endif + #endif } class CoreGraphicsContext : public LowLevelGraphicsContext @@ -266522,16 +266633,16 @@ public: { if (replaceExistingContents) { -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 + #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 CGContextClearRect (context, cgRect); -#else - #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + #else + #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 if (CGContextDrawLinearGradient == 0) // (just a way of checking whether we're running in 10.5 or later) CGContextClearRect (context, cgRect); else - #endif + #endif CGContextSetBlendMode (context, kCGBlendModeCopy); -#endif + #endif fillCGRect (cgRect, false); CGContextSetBlendMode (context, kCGBlendModeNormal); @@ -266607,16 +266718,16 @@ public: if (fillEntireClipAsTiles) { -#if JUCE_IOS + #if JUCE_IOS CGContextDrawTiledImage (context, imageRect, image); -#else - #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + #else + #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 // There's a bug in CGContextDrawTiledImage that makes it incredibly slow // if it's doing a transformation - it's quicker to just draw lots of images manually if (CGContextDrawTiledImage != 0 && transform.isOnlyTranslation()) CGContextDrawTiledImage (context, imageRect, image); else - #endif + #endif { // Fallback to manually doing a tiled fill on 10.4 CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context)); @@ -266636,7 +266747,7 @@ public: y += ih; } } -#endif + #endif } else { @@ -266820,8 +266931,7 @@ private: CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient) { - numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable); - --numGradientLookupEntries; + numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable) - 1; CGShadingRef result = 0; CGFunctionRef function = CGFunctionCreate (this, 1, 0, 4, 0, &gradientCallbacks); @@ -266941,7 +267051,7 @@ const Image juce_loadWithCoreImage (InputStream& input) MemoryBlock data; input.readIntoMemoryBlock (data, -1); -#if JUCE_IOS + #if JUCE_IOS JUCE_AUTORELEASEPOOL UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() length: data.getSize() @@ -266951,7 +267061,7 @@ const Image juce_loadWithCoreImage (InputStream& input) { CGImageRef loadedImage = image.CGImage; -#else + #else CGDataProviderRef provider = CGDataProviderCreateWithData (0, data.getData(), data.getSize(), 0); CGImageSourceRef imageSource = CGImageSourceCreateWithDataProvider (provider, 0); CGDataProviderRelease (provider); @@ -266960,7 +267070,7 @@ const Image juce_loadWithCoreImage (InputStream& input) { CGImageRef loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, 0); CFRelease (imageSource); -#endif + #endif if (loadedImage != 0) { @@ -266979,9 +267089,9 @@ const Image juce_loadWithCoreImage (InputStream& input) CGContextDrawImage (cgImage->context, CGRectMake (0, 0, image.getWidth(), image.getHeight()), loadedImage); CGContextFlush (cgImage->context); -#if ! JUCE_IOS + #if ! JUCE_IOS CFRelease (loadedImage); -#endif + #endif // Because it's impossible to create a truly 24-bit CG image, this flag allows a user // to find out whether the file they just loaded the image from had an alpha channel or not. @@ -270935,7 +271045,7 @@ public: } } -#if JUCE_MAC + #if JUCE_MAC static NSImage* createNSImage (const Image& image) { const ScopedAutoReleasePool pool; @@ -270956,7 +271066,7 @@ public: return im; } -#endif + #endif CGContextRef context; HeapBlock imageDataAllocated; @@ -270964,11 +271074,11 @@ public: private: static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) { -#if JUCE_BIG_ENDIAN + #if JUCE_BIG_ENDIAN return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) : kCGBitmapByteOrderDefault; -#else + #else return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) : kCGBitmapByteOrderDefault; -#endif + #endif } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImage); @@ -270976,11 +271086,11 @@ private: Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage) { -#if USE_COREGRAPHICS_RENDERING + #if USE_COREGRAPHICS_RENDERING return new CoreGraphicsImage (format == RGB ? ARGB : format, width, height, clearImage); -#else + #else return createSoftwareImage (format, width, height, clearImage); -#endif + #endif } class CoreGraphicsContext : public LowLevelGraphicsContext @@ -271221,16 +271331,16 @@ public: { if (replaceExistingContents) { -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 + #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 CGContextClearRect (context, cgRect); -#else - #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + #else + #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 if (CGContextDrawLinearGradient == 0) // (just a way of checking whether we're running in 10.5 or later) CGContextClearRect (context, cgRect); else - #endif + #endif CGContextSetBlendMode (context, kCGBlendModeCopy); -#endif + #endif fillCGRect (cgRect, false); CGContextSetBlendMode (context, kCGBlendModeNormal); @@ -271306,16 +271416,16 @@ public: if (fillEntireClipAsTiles) { -#if JUCE_IOS + #if JUCE_IOS CGContextDrawTiledImage (context, imageRect, image); -#else - #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + #else + #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 // There's a bug in CGContextDrawTiledImage that makes it incredibly slow // if it's doing a transformation - it's quicker to just draw lots of images manually if (CGContextDrawTiledImage != 0 && transform.isOnlyTranslation()) CGContextDrawTiledImage (context, imageRect, image); else - #endif + #endif { // Fallback to manually doing a tiled fill on 10.4 CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context)); @@ -271335,7 +271445,7 @@ public: y += ih; } } -#endif + #endif } else { @@ -271519,8 +271629,7 @@ private: CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient) { - numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable); - --numGradientLookupEntries; + numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable) - 1; CGShadingRef result = 0; CGFunctionRef function = CGFunctionCreate (this, 1, 0, 4, 0, &gradientCallbacks); @@ -271640,7 +271749,7 @@ const Image juce_loadWithCoreImage (InputStream& input) MemoryBlock data; input.readIntoMemoryBlock (data, -1); -#if JUCE_IOS + #if JUCE_IOS JUCE_AUTORELEASEPOOL UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() length: data.getSize() @@ -271650,7 +271759,7 @@ const Image juce_loadWithCoreImage (InputStream& input) { CGImageRef loadedImage = image.CGImage; -#else + #else CGDataProviderRef provider = CGDataProviderCreateWithData (0, data.getData(), data.getSize(), 0); CGImageSourceRef imageSource = CGImageSourceCreateWithDataProvider (provider, 0); CGDataProviderRelease (provider); @@ -271659,7 +271768,7 @@ const Image juce_loadWithCoreImage (InputStream& input) { CGImageRef loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, 0); CFRelease (imageSource); -#endif + #endif if (loadedImage != 0) { @@ -271678,9 +271787,9 @@ const Image juce_loadWithCoreImage (InputStream& input) CGContextDrawImage (cgImage->context, CGRectMake (0, 0, image.getWidth(), image.getHeight()), loadedImage); CGContextFlush (cgImage->context); -#if ! JUCE_IOS + #if ! JUCE_IOS CFRelease (loadedImage); -#endif + #endif // Because it's impossible to create a truly 24-bit CG image, this flag allows a user // to find out whether the file they just loaded the image from had an alpha channel or not. diff --git a/juce_amalgamated.h b/juce_amalgamated.h index fd82dfd416..fa781d80c4 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 6 +#define JUCE_BUILDNUMBER 7 /** Current Juce version number. @@ -45451,6 +45451,273 @@ private: /*** End of inlined file: juce_RelativeCoordinate.h ***/ +/*** Start of inlined file: juce_RelativeCoordinatePositioner.h ***/ +#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__ +#define __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__ + + +/*** Start of inlined file: juce_RelativePoint.h ***/ +#ifndef __JUCE_RELATIVEPOINT_JUCEHEADER__ +#define __JUCE_RELATIVEPOINT_JUCEHEADER__ + +/** + An X-Y position stored as a pair of RelativeCoordinate values. + + @see RelativeCoordinate, RelativeRectangle +*/ +class JUCE_API RelativePoint +{ +public: + /** Creates a point at the origin. */ + RelativePoint(); + + /** Creates an absolute point, relative to the origin. */ + RelativePoint (const Point& absolutePoint); + + /** Creates an absolute point, relative to the origin. */ + RelativePoint (float absoluteX, float absoluteY); + + /** Creates an absolute point from two coordinates. */ + RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y); + + /** Creates a point from a stringified representation. + The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate + strings is explained in the RelativeCoordinate class. + @see toString + */ + RelativePoint (const String& stringVersion); + + bool operator== (const RelativePoint& other) const throw(); + bool operator!= (const RelativePoint& other) const throw(); + + /** Calculates the absolute position of this point. + + You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may + be needed to calculate the result. + */ + const Point resolve (const Expression::EvaluationContext* evaluationContext) const; + + /** Changes the values of this point's coordinates to make it resolve to the specified position. + + Calling this will leave any anchor points unchanged, but will set any absolute + or relative positions to whatever values are necessary to make the resultant position + match the position that is provided. + */ + void moveToAbsolute (const Point& newPos, const Expression::EvaluationContext* evaluationContext); + + /** Returns a string which represents this point. + This returns a comma-separated pair of coordinates. For details of the string syntax used by the + coordinates, see the RelativeCoordinate constructor notes. + The string that is returned can be passed to the RelativePoint constructor to recreate the point. + */ + const String toString() const; + + /** Renames a symbol if it is used by any of the coordinates. + This calls RelativeCoordinate::renameAnchorIfUsed() on its X and Y coordinates. + */ + void renameSymbolIfUsed (const String& oldName, const String& newName); + + /** Returns true if this point depends on any other coordinates for its position. */ + bool isDynamic() const; + + // The actual X and Y coords... + RelativeCoordinate x, y; +}; + +#endif // __JUCE_RELATIVEPOINT_JUCEHEADER__ +/*** End of inlined file: juce_RelativePoint.h ***/ + + +/*** Start of inlined file: juce_MarkerList.h ***/ +#ifndef __JUCE_MARKERLIST_JUCEHEADER__ +#define __JUCE_MARKERLIST_JUCEHEADER__ + +/** + Holds a set of named marker points along a one-dimensional axis. + + This class is used to store sets of X and Y marker points in components. + @see Component::getMarkers(). +*/ +class JUCE_API MarkerList +{ +public: + + /** Creates an empty marker list. */ + MarkerList(); + /** Creates a copy of another marker list. */ + MarkerList (const MarkerList& other); + /** Copies another marker list to this one. */ + MarkerList& operator= (const MarkerList& other); + /** Destructor. */ + ~MarkerList(); + + /** Represents a marker in a MarkerList. */ + class JUCE_API Marker + { + public: + /** Creates a copy of another Marker. */ + Marker (const Marker& other); + /** Creates a Marker with a given name and position. */ + Marker (const String& name, const RelativeCoordinate& position); + + /** The marker's name. */ + String name; + + /** The marker's position. */ + RelativeCoordinate position; + + /** Returns true if both the names and positions of these two markers match. */ + bool operator== (const Marker&) const throw(); + /** Returns true if either the name or position of these two markers differ. */ + bool operator!= (const Marker&) const throw(); + }; + + /** Returns the number of markers in the list. */ + int getNumMarkers() const throw(); + + /** Returns one of the markers in the list, by its index. */ + const Marker* getMarker (int index) const throw(); + + /** Returns a named marker, or 0 if no such name is found. + Note that name comparisons are case-sensitive. + */ + const Marker* getMarker (const String& name) const throw(); + + /** Sets the position of a marker. + + If the name already exists, then the existing marker is moved; if it doesn't exist, then a + new marker is added. + */ + void setMarker (const String& name, const RelativeCoordinate& position); + + /** Deletes the marker at the given list index. */ + void removeMarker (int index); + + /** Deletes the marker with the given name. */ + void removeMarker (const String& name); + + /** Returns true if all the markers in these two lists match exactly. */ + bool operator== (const MarkerList& other) const throw(); + /** Returns true if not all the markers in these two lists match exactly. */ + bool operator!= (const MarkerList& other) const throw(); + + /** + A class for receiving events when changes are made to a MarkerList. + + You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener() + method, and it will be called when markers are moved, added, or deleted. + + @see MarkerList::addListener, MarkerList::removeListener + */ + class JUCE_API Listener + { + public: + /** Destructor. */ + virtual ~Listener() {} + + /** Called when something in the given marker list changes. */ + virtual void markersChanged (MarkerList* markerList) = 0; + + /** Called when the given marker list is being deleted. */ + virtual void markerListBeingDeleted (MarkerList* markerList); + }; + + /** Registers a listener that will be called when the markers are changed. */ + void addListener (Listener* listener); + + /** Deregisters a previously-registered listener. */ + void removeListener (Listener* listener); + + /** Synchronously calls markersChanged() on all the registered listeners. */ + void markersHaveChanged(); + + /** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */ + class ValueTreeWrapper + { + public: + ValueTreeWrapper (const ValueTree& state); + + ValueTree& getState() throw() { return state; } + int getNumMarkers() const; + const ValueTree getMarkerState (int index) const; + const ValueTree getMarkerState (const String& name) const; + bool containsMarker (const ValueTree& state) const; + const MarkerList::Marker getMarker (const ValueTree& state) const; + void setMarker (const MarkerList::Marker& marker, UndoManager* undoManager); + void removeMarker (const ValueTree& state, UndoManager* undoManager); + + void applyTo (MarkerList& markerList); + void readFrom (const MarkerList& markerList, UndoManager* undoManager); + + static const Identifier markerTag, nameProperty, posProperty; + + private: + ValueTree state; + }; + +private: + + OwnedArray markers; + ListenerList listeners; + + JUCE_LEAK_DETECTOR (MarkerList); +}; + +#endif // __JUCE_MARKERLIST_JUCEHEADER__ +/*** End of inlined file: juce_MarkerList.h ***/ + +/** + Base class for Component::Positioners that are based upon relative coordinates. +*/ +class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner, + public ComponentListener, + public MarkerList::Listener, + public Expression::EvaluationContext +{ +public: + RelativeCoordinatePositionerBase (Component& component_); + ~RelativeCoordinatePositionerBase(); + + const Expression getSymbolValue (const String& objectName, const String& member) const; + + void componentMovedOrResized (Component&, bool, bool); + void componentParentHierarchyChanged (Component&); + void componentBeingDeleted (Component& component); + void markersChanged (MarkerList*); + void markerListBeingDeleted (MarkerList* markerList); + + void apply(); + + bool addCoordinate (const RelativeCoordinate& coord); + bool addPoint (const RelativePoint& point); + +protected: + virtual bool registerCoordinates() = 0; + virtual void applyToComponentBounds() = 0; + +private: + Array sourceComponents; + Array sourceMarkerLists; + bool registeredOk; + + bool registerListeners (const Expression& e); + bool registerComponent (const String& componentID); + bool registerMarker (const String markerName); + void registerComponentListener (Component* const comp); + void registerMarkerListListener (MarkerList* const list); + void unregisterListeners(); + Component* findComponent (const String& componentID) const; + Component* getSourceComponent (const String& objectName) const; + const Expression xToExpression (const Component* const source, const int x) const; + const Expression yToExpression (const Component* const source, const int y) const; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeCoordinatePositionerBase); +}; + +#endif // __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__ +/*** End of inlined file: juce_RelativeCoordinatePositioner.h ***/ + + /*** Start of inlined file: juce_ComponentBuilder.h ***/ #ifndef __JUCE_COMPONENTBUILDER_JUCEHEADER__ #define __JUCE_COMPONENTBUILDER_JUCEHEADER__ @@ -45841,6 +46108,27 @@ protected: Point originRelativeToComponent; + #ifndef DOXYGEN + /** Internal utility class used by Drawables. */ + template + class Positioner : public RelativeCoordinatePositionerBase + { + public: + Positioner (DrawableType& component_) + : RelativeCoordinatePositionerBase (component_), + owner (component_) + {} + + bool registerCoordinates() { return owner.registerCoordinates (*this); } + void applyToComponentBounds() { owner.recalculateCoordinates (this); } + + private: + DrawableType& owner; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner); + }; + #endif + private: void nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform); @@ -54179,8 +54467,6 @@ public: protected: - ScopedPointer tabs; - /** This creates one of the tab buttons. If you need to use custom tab components, you can override this method and @@ -54188,15 +54474,18 @@ protected: */ virtual TabBarButton* createTabButton (const String& tabName, int tabIndex); + /** @internal */ + ScopedPointer tabs; + private: - OwnedArray > contentComponents; + Array > contentComponents; WeakReference panelComponent; int tabDepth; int outlineThickness, edgeIndent; - static const Identifier deleteComponentId; - friend class TabCompButtonBar; + class ButtonBar; + friend class ButtonBar; void changeCallback (int newCurrentTabIndex, const String& newTabName); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabbedComponent); @@ -57419,206 +57708,12 @@ private: #endif #ifndef __JUCE_MARKERLIST_JUCEHEADER__ -/*** Start of inlined file: juce_MarkerList.h ***/ -#ifndef __JUCE_MARKERLIST_JUCEHEADER__ -#define __JUCE_MARKERLIST_JUCEHEADER__ - -/** - Holds a set of named marker points along a one-dimensional axis. - - This class is used to store sets of X and Y marker points in components. - @see Component::getMarkers(). -*/ -class JUCE_API MarkerList -{ -public: - - /** Creates an empty marker list. */ - MarkerList(); - /** Creates a copy of another marker list. */ - MarkerList (const MarkerList& other); - /** Copies another marker list to this one. */ - MarkerList& operator= (const MarkerList& other); - /** Destructor. */ - ~MarkerList(); - - /** Represents a marker in a MarkerList. */ - class JUCE_API Marker - { - public: - /** Creates a copy of another Marker. */ - Marker (const Marker& other); - /** Creates a Marker with a given name and position. */ - Marker (const String& name, const RelativeCoordinate& position); - - /** The marker's name. */ - String name; - - /** The marker's position. */ - RelativeCoordinate position; - - /** Returns true if both the names and positions of these two markers match. */ - bool operator== (const Marker&) const throw(); - /** Returns true if either the name or position of these two markers differ. */ - bool operator!= (const Marker&) const throw(); - }; - - /** Returns the number of markers in the list. */ - int getNumMarkers() const throw(); - - /** Returns one of the markers in the list, by its index. */ - const Marker* getMarker (int index) const throw(); - - /** Returns a named marker, or 0 if no such name is found. - Note that name comparisons are case-sensitive. - */ - const Marker* getMarker (const String& name) const throw(); - - /** Sets the position of a marker. - - If the name already exists, then the existing marker is moved; if it doesn't exist, then a - new marker is added. - */ - void setMarker (const String& name, const RelativeCoordinate& position); - - /** Deletes the marker at the given list index. */ - void removeMarker (int index); - - /** Deletes the marker with the given name. */ - void removeMarker (const String& name); - - /** Returns true if all the markers in these two lists match exactly. */ - bool operator== (const MarkerList& other) const throw(); - /** Returns true if not all the markers in these two lists match exactly. */ - bool operator!= (const MarkerList& other) const throw(); - - /** - A class for receiving events when changes are made to a MarkerList. - - You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener() - method, and it will be called when markers are moved, added, or deleted. - - @see MarkerList::addListener, MarkerList::removeListener - */ - class JUCE_API Listener - { - public: - /** Destructor. */ - virtual ~Listener() {} - - /** Called when something in the given marker list changes. */ - virtual void markersChanged (MarkerList* markerList) = 0; - - /** Called when the given marker list is being deleted. */ - virtual void markerListBeingDeleted (MarkerList* markerList); - }; - - /** Registers a listener that will be called when the markers are changed. */ - void addListener (Listener* listener); - - /** Deregisters a previously-registered listener. */ - void removeListener (Listener* listener); - - /** Synchronously calls markersChanged() on all the registered listeners. */ - void markersHaveChanged(); - - /** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */ - class ValueTreeWrapper - { - public: - ValueTreeWrapper (const ValueTree& state); - - ValueTree& getState() throw() { return state; } - int getNumMarkers() const; - const ValueTree getMarkerState (int index) const; - const ValueTree getMarkerState (const String& name) const; - bool containsMarker (const ValueTree& state) const; - const MarkerList::Marker getMarker (const ValueTree& state) const; - void setMarker (const MarkerList::Marker& marker, UndoManager* undoManager); - void removeMarker (const ValueTree& state, UndoManager* undoManager); - - void applyTo (MarkerList& markerList); - void readFrom (const MarkerList& markerList, UndoManager* undoManager); - - static const Identifier markerTag, nameProperty, posProperty; - - private: - ValueTree state; - }; - -private: - - OwnedArray markers; - ListenerList listeners; - - JUCE_LEAK_DETECTOR (MarkerList); -}; - -#endif // __JUCE_MARKERLIST_JUCEHEADER__ -/*** End of inlined file: juce_MarkerList.h ***/ - - #endif #ifndef __JUCE_RELATIVECOORDINATE_JUCEHEADER__ #endif #ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__ -/*** Start of inlined file: juce_RelativeCoordinatePositioner.h ***/ -#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__ -#define __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__ - -/** - Base class for Component::Positioners that are based upon relative coordinates. -*/ -class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner, - public ComponentListener, - public MarkerList::Listener, - public Expression::EvaluationContext -{ -public: - RelativeCoordinatePositionerBase (Component& component_); - ~RelativeCoordinatePositionerBase(); - - const Expression getSymbolValue (const String& objectName, const String& member) const; - - void componentMovedOrResized (Component&, bool, bool); - void componentParentHierarchyChanged (Component&); - void componentBeingDeleted (Component& component); - void markersChanged (MarkerList*); - void markerListBeingDeleted (MarkerList* markerList); - - void apply(); - -protected: - bool addCoordinate (const RelativeCoordinate& coord); - - virtual bool registerCoordinates() = 0; - virtual void applyToComponentBounds() = 0; - -private: - Array sourceComponents; - Array sourceMarkerLists; - bool registeredOk; - - bool registerListeners (const Expression& e); - bool registerComponent (const String& componentID); - bool registerMarker (const String markerName); - void registerComponentListener (Component* const comp); - void registerMarkerListListener (MarkerList* const list); - void unregisterListeners(); - Component* findComponent (const String& componentID) const; - Component* getSourceComponent (const String& objectName) const; - const Expression xToExpression (const Component* const source, const int x) const; - const Expression yToExpression (const Component* const source, const int y) const; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeCoordinatePositionerBase); -}; - -#endif // __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__ -/*** End of inlined file: juce_RelativeCoordinatePositioner.h ***/ - - #endif #ifndef __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__ @@ -57626,78 +57721,6 @@ private: #ifndef __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__ #define __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__ - -/*** Start of inlined file: juce_RelativePoint.h ***/ -#ifndef __JUCE_RELATIVEPOINT_JUCEHEADER__ -#define __JUCE_RELATIVEPOINT_JUCEHEADER__ - -/** - An X-Y position stored as a pair of RelativeCoordinate values. - - @see RelativeCoordinate, RelativeRectangle -*/ -class JUCE_API RelativePoint -{ -public: - /** Creates a point at the origin. */ - RelativePoint(); - - /** Creates an absolute point, relative to the origin. */ - RelativePoint (const Point& absolutePoint); - - /** Creates an absolute point, relative to the origin. */ - RelativePoint (float absoluteX, float absoluteY); - - /** Creates an absolute point from two coordinates. */ - RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y); - - /** Creates a point from a stringified representation. - The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate - strings is explained in the RelativeCoordinate class. - @see toString - */ - RelativePoint (const String& stringVersion); - - bool operator== (const RelativePoint& other) const throw(); - bool operator!= (const RelativePoint& other) const throw(); - - /** Calculates the absolute position of this point. - - You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may - be needed to calculate the result. - */ - const Point resolve (const Expression::EvaluationContext* evaluationContext) const; - - /** Changes the values of this point's coordinates to make it resolve to the specified position. - - Calling this will leave any anchor points unchanged, but will set any absolute - or relative positions to whatever values are necessary to make the resultant position - match the position that is provided. - */ - void moveToAbsolute (const Point& newPos, const Expression::EvaluationContext* evaluationContext); - - /** Returns a string which represents this point. - This returns a comma-separated pair of coordinates. For details of the string syntax used by the - coordinates, see the RelativeCoordinate constructor notes. - The string that is returned can be passed to the RelativePoint constructor to recreate the point. - */ - const String toString() const; - - /** Renames a symbol if it is used by any of the coordinates. - This calls RelativeCoordinate::renameAnchorIfUsed() on its X and Y coordinates. - */ - void renameSymbolIfUsed (const String& oldName, const String& newName); - - /** Returns true if this point depends on any other coordinates for its position. */ - bool isDynamic() const; - - // The actual X and Y coords... - RelativeCoordinate x, y; -}; - -#endif // __JUCE_RELATIVEPOINT_JUCEHEADER__ -/*** End of inlined file: juce_RelativePoint.h ***/ - /** A parallelogram defined by three RelativePoint positions. @@ -57718,12 +57741,14 @@ public: const Rectangle getBounds (Expression::EvaluationContext* coordFinder) const; void getPath (Path& path, Expression::EvaluationContext* coordFinder) const; const AffineTransform resetToPerpendicular (Expression::EvaluationContext* coordFinder); + bool isDynamic() const; bool operator== (const RelativeParallelogram& other) const throw(); bool operator!= (const RelativeParallelogram& other) const throw(); static const Point getInternalCoordForPoint (const Point* parallelogramCorners, Point point) throw(); static const Point getPointForInternalCoord (const Point* parallelogramCorners, const Point& internalPoint) throw(); + static const Rectangle getBoundingBox (const Point* parallelogramCorners) throw(); RelativePoint topLeft, topRight, bottomLeft; }; @@ -61744,8 +61769,8 @@ protected: @see Drawable */ -class JUCE_API DrawableComposite : public Drawable, - public Expression::EvaluationContext +class JUCE_API DrawableComposite : public Drawable//, +// public Expression::EvaluationContext { public: @@ -61810,8 +61835,6 @@ public: /** @internal */ static const Identifier valueTreeType; /** @internal */ - const Expression getSymbolValue (const String& symbol, const String& member) const; - /** @internal */ const Rectangle getDrawableBounds() const; /** @internal */ void childBoundsChanged (Component*); @@ -61853,7 +61876,10 @@ private: MarkerList markersX, markersY; bool updateBoundsReentrant; - void refreshTransformFromBounds(); + friend class Drawable::Positioner; + bool registerCoordinates (RelativeCoordinatePositionerBase&); + void recalculateCoordinates (Expression::EvaluationContext*); + void updateBoundsToFitChildren(); DrawableComposite& operator= (const DrawableComposite&); @@ -61967,7 +61993,9 @@ private: Colour overlayColour; RelativeParallelogram bounds; - void refreshTransformFromBounds(); + friend class Drawable::Positioner; + bool registerCoordinates (RelativeCoordinatePositionerBase&); + void recalculateCoordinates (Expression::EvaluationContext*); DrawableImage& operator= (const DrawableImage&); JUCE_LEAK_DETECTOR (DrawableImage); @@ -62006,6 +62034,29 @@ public: /** Destructor. */ ~DrawableShape(); + /** A FillType wrapper that allows the gradient coordinates to be implemented using RelativePoint. + */ + class RelativeFillType + { + public: + RelativeFillType(); + RelativeFillType (const FillType& fill); + RelativeFillType (const RelativeFillType&); + RelativeFillType& operator= (const RelativeFillType&); + + bool operator== (const RelativeFillType&) const; + bool operator!= (const RelativeFillType&) const; + + bool isDynamic() const; + bool recalculateCoords (Expression::EvaluationContext* context); + + void writeTo (ValueTree& v, ComponentBuilder::ImageProvider*, UndoManager*) const; + bool readFrom (const ValueTree& v, ComponentBuilder::ImageProvider*); + + FillType fill; + RelativePoint gradientPoint1, gradientPoint2, gradientPoint3; + }; + /** Sets a fill type for the path. This colour is used to fill the path - if you don't want the path to be filled (e.g. if you're just drawing an outline), set this to a transparent @@ -62015,20 +62066,34 @@ public: */ void setFill (const FillType& newFill); + /** Sets a fill type for the path. + This colour is used to fill the path - if you don't want the path to be + filled (e.g. if you're just drawing an outline), set this to a transparent + colour. + + @see setPath, setStrokeFill + */ + void setFill (const RelativeFillType& newFill); + /** Returns the current fill type. @see setFill */ - const FillType& getFill() const throw() { return mainFill; } + const RelativeFillType& getFill() const throw() { return mainFill; } /** Sets the fill type with which the outline will be drawn. @see setFill */ void setStrokeFill (const FillType& newStrokeFill); + /** Sets the fill type with which the outline will be drawn. + @see setFill + */ + void setStrokeFill (const RelativeFillType& newStrokeFill); + /** Returns the current stroke fill. @see setStrokeFill */ - const FillType& getStrokeFill() const throw() { return strokeFill; } + const RelativeFillType& getStrokeFill() const throw() { return strokeFill; } /** Changes the properties of the outline that will be drawn around the path. If the stroke has 0 thickness, no stroke will be drawn. @@ -62042,7 +62107,7 @@ public: void setStrokeThickness (float newThickness); /** Returns the current outline style. */ - const PathStrokeType& getStrokeType() const throw() { return strokeType; } + const PathStrokeType& getStrokeType() const throw() { return strokeType; } /** @internal */ class FillAndStrokeState : public Drawable::ValueTreeWrapperBase @@ -62050,32 +62115,13 @@ public: public: FillAndStrokeState (const ValueTree& state); - const FillType getMainFill (Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider) const; - ValueTree getMainFillState(); - void setMainFill (const FillType& newFill, const RelativePoint* gradientPoint1, - const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3, - ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager); - - const FillType getStrokeFill (Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider) const; - ValueTree getStrokeFillState(); - void setStrokeFill (const FillType& newFill, const RelativePoint* gradientPoint1, - const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3, - ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager); + ValueTree getFillState (const Identifier& fillOrStrokeType); + const RelativeFillType getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider*) const; + void setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill, + ComponentBuilder::ImageProvider*, UndoManager*); const PathStrokeType getStrokeType() const; - void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager); - - static const FillType readFillType (const ValueTree& v, RelativePoint* gradientPoint1, - RelativePoint* gradientPoint2, RelativePoint* gradientPoint3, - Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider); - - static void writeFillType (ValueTree& v, const FillType& fillType, - const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2, - const RelativePoint* gradientPoint3, ComponentBuilder::ImageProvider* imageProvider, - UndoManager* undoManager); + void setStrokeType (const PathStrokeType& newStrokeType, UndoManager*); static const Identifier type, colour, colours, fill, stroke, path, jointStyle, capStyle, strokeWidth, gradientPoint1, gradientPoint2, gradientPoint3, radial, imageId, imageOpacity; @@ -62094,26 +62140,23 @@ protected: void pathChanged(); /** Called when the cached stroke should be updated. */ void strokeChanged(); - - /** Implemented by subclasses to regenerate the path. */ - virtual bool rebuildPath (Path& path) const = 0; - /** True if there's a stroke with a non-zero thickness and non-transparent colour. */ bool isStrokeVisible() const throw(); - /** Updates the details from a FillAndStrokeState object, returning true if something changed. */ - bool refreshFillTypes (const FillAndStrokeState& newState, - Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider); - + void refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider*); /** Writes the stroke and fill details to a FillAndStrokeState object. */ - void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const; + void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider*, UndoManager*) const; PathStrokeType strokeType; Path path, strokePath; private: - FillType mainFill, strokeFill; + class RelativePositioner; + RelativeFillType mainFill, strokeFill; + ScopedPointer mainFillPositioner, strokeFillPositioner; + + void setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill, + ScopedPointer& positioner); DrawableShape& operator= (const DrawableShape&); }; @@ -62184,24 +62227,24 @@ public: int getNumControlPoints() const throw(); const RelativePoint getControlPoint (int index) const; - Value getControlPointValue (int index, UndoManager* undoManager) const; + Value getControlPointValue (int index, UndoManager*) const; const RelativePoint getStartPoint() const; const RelativePoint getEndPoint() const; - void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager); - float getLength (Expression::EvaluationContext* nameFinder) const; + void setControlPoint (int index, const RelativePoint& point, UndoManager*); + float getLength (Expression::EvaluationContext*) const; ValueTreeWrapper getParent() const; Element getPreviousElement() const; const String getModeOfEndPoint() const; - void setModeOfEndPoint (const String& newMode, UndoManager* undoManager); + void setModeOfEndPoint (const String& newMode, UndoManager*); - void convertToLine (UndoManager* undoManager); - void convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager); + void convertToLine (UndoManager*); + void convertToCubic (Expression::EvaluationContext*, UndoManager*); void convertToPathBreak (UndoManager* undoManager); - ValueTree insertPoint (const Point& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager); + ValueTree insertPoint (const Point& targetPoint, Expression::EvaluationContext*, UndoManager*); void removePoint (UndoManager* undoManager); - float findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext* nameFinder) const; + float findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext*) const; static const Identifier mode, startSubPathElement, closeSubPathElement, lineToElement, quadraticToElement, cubicToElement; @@ -62220,15 +62263,13 @@ public: static const Identifier nonZeroWinding, point1, point2, point3; }; -protected: - bool rebuildPath (Path& path) const; - private: + ScopedPointer relativePath; + class RelativePositioner; friend class RelativePositioner; - void applyRelativePath (const RelativePointPath& newPath); - const RelativePointPath* getRelativePath() const; + void applyRelativePath (const RelativePointPath&, Expression::EvaluationContext*); DrawablePath& operator= (const DrawablePath&); JUCE_LEAK_DETECTOR (DrawablePath); @@ -62290,24 +62331,24 @@ public: ValueTreeWrapper (const ValueTree& state); const RelativeParallelogram getRectangle() const; - void setRectangle (const RelativeParallelogram& newBounds, UndoManager* undoManager); + void setRectangle (const RelativeParallelogram& newBounds, UndoManager*); - void setCornerSize (const RelativePoint& cornerSize, UndoManager* undoManager); + void setCornerSize (const RelativePoint& cornerSize, UndoManager*); const RelativePoint getCornerSize() const; - Value getCornerSizeValue (UndoManager* undoManager) const; + Value getCornerSizeValue (UndoManager*) const; static const Identifier topLeft, topRight, bottomLeft, cornerSize; }; -protected: - /** @internal */ - bool rebuildPath (Path& path) const; - private: + friend class Drawable::Positioner; + RelativeParallelogram bounds; RelativePoint cornerSize; - const AffineTransform calculateTransform() const; + void rebuildPath(); + bool registerCoordinates (RelativeCoordinatePositionerBase&); + void recalculateCoordinates (Expression::EvaluationContext*); DrawableRectangle& operator= (const DrawableRectangle&); JUCE_LEAK_DETECTOR (DrawableRectangle); @@ -62425,12 +62466,17 @@ private: RelativeParallelogram bounds; RelativePoint fontSizeControlPoint; - Font font; + Point resolvedPoints[3]; + Font font, scaledFont; String text; Colour colour; Justification justification; + friend class Drawable::Positioner; + bool registerCoordinates (RelativeCoordinatePositionerBase&); + void recalculateCoordinates (Expression::EvaluationContext*); void refreshBounds(); + const AffineTransform getArrangementAndTransform (GlyphArrangement& glyphs) const; DrawableText& operator= (const DrawableText&); JUCE_LEAK_DETECTOR (DrawableText); diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index 450e334036..88c3c93b05 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 53 -#define JUCE_BUILDNUMBER 6 +#define JUCE_BUILDNUMBER 7 /** Current Juce version number. diff --git a/src/gui/components/layout/juce_ComponentBuilder.cpp b/src/gui/components/layout/juce_ComponentBuilder.cpp index 82b217f5b9..1c944e9e6d 100644 --- a/src/gui/components/layout/juce_ComponentBuilder.cpp +++ b/src/gui/components/layout/juce_ComponentBuilder.cpp @@ -86,8 +86,9 @@ namespace ComponentBuilderHelpers if (topLevelComp != 0) { ComponentBuilder::TypeHandler* const type = builder.getHandlerForState (state); + const String uid (getStateId (state)); - if (type == 0) + if (type == 0 || uid.isEmpty()) { // ..handle the case where a child of the actual state node has changed. if (state.getParent().isValid()) @@ -95,21 +96,20 @@ namespace ComponentBuilderHelpers } else { - Component* const changedComp = findComponentWithID (topLevelComp, getStateId (state)); + Component* const changedComp = findComponentWithID (topLevelComp, uid); if (changedComp != 0) type->updateComponentFromState (changedComp, state); } } } - } //============================================================================= const Identifier ComponentBuilder::idProperty ("id"); ComponentBuilder::ComponentBuilder (const ValueTree& state_) - : state (state_) + : state (state_), imageProvider (0) { state.addListener (this); } diff --git a/src/gui/components/layout/juce_TabbedComponent.cpp b/src/gui/components/layout/juce_TabbedComponent.cpp index 00f9e3b6c0..a1f0f2ac59 100644 --- a/src/gui/components/layout/juce_TabbedComponent.cpp +++ b/src/gui/components/layout/juce_TabbedComponent.cpp @@ -32,17 +32,39 @@ BEGIN_JUCE_NAMESPACE //============================================================================== -class TabCompButtonBar : public TabbedButtonBar +namespace TabbedComponentHelpers { -public: - TabCompButtonBar (TabbedComponent& owner_, - const TabbedButtonBar::Orientation orientation_) - : TabbedButtonBar (orientation_), - owner (owner_) + const Identifier deleteComponentId ("deleteByTabComp_"); + + void deleteIfNecessary (Component* const comp) { + if (comp != 0 && (bool) comp->getProperties() [deleteComponentId]) + delete comp; } - ~TabCompButtonBar() + const Rectangle getTabArea (Rectangle& content, BorderSize& outline, + const TabbedButtonBar::Orientation orientation, const int tabDepth) + { + switch (orientation) + { + case TabbedButtonBar::TabsAtTop: outline.setTop (0); return content.removeFromTop (tabDepth); + case TabbedButtonBar::TabsAtBottom: outline.setBottom (0); return content.removeFromBottom (tabDepth); + case TabbedButtonBar::TabsAtLeft: outline.setLeft (0); return content.removeFromLeft (tabDepth); + case TabbedButtonBar::TabsAtRight: outline.setRight (0); return content.removeFromRight (tabDepth); + default: jassertfalse; break; + } + + return Rectangle(); + } +} + +//============================================================================== +class TabbedComponent::ButtonBar : public TabbedButtonBar +{ +public: + ButtonBar (TabbedComponent& owner_, const TabbedButtonBar::Orientation orientation_) + : TabbedButtonBar (orientation_), + owner (owner_) { } @@ -69,16 +91,17 @@ public: private: TabbedComponent& owner; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabCompButtonBar); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonBar); }; +//============================================================================== TabbedComponent::TabbedComponent (const TabbedButtonBar::Orientation orientation) : tabDepth (30), outlineThickness (1), edgeIndent (0) { - addAndMakeVisible (tabs = new TabCompButtonBar (*this, orientation)); + addAndMakeVisible (tabs = new ButtonBar (*this, orientation)); } TabbedComponent::~TabbedComponent() @@ -114,8 +137,6 @@ TabBarButton* TabbedComponent::createTabButton (const String& tabName, const int } //============================================================================== -const Identifier TabbedComponent::deleteComponentId ("deleteByTabComp_"); - void TabbedComponent::clearTabs() { if (panelComponent != 0) @@ -128,12 +149,7 @@ void TabbedComponent::clearTabs() tabs->clearTabs(); for (int i = contentComponents.size(); --i >= 0;) - { - WeakReference& c = *contentComponents.getUnchecked (i); - - if (c != 0 && (bool) c->getProperties() [deleteComponentId]) - delete c.get(); - } + TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (i)); contentComponents.clear(); } @@ -144,10 +160,10 @@ void TabbedComponent::addTab (const String& tabName, const bool deleteComponentWhenNotNeeded, const int insertIndex) { - contentComponents.insert (insertIndex, new WeakReference (contentComponent)); + contentComponents.insert (insertIndex, WeakReference (contentComponent)); - if (contentComponent != 0) - contentComponent->getProperties().set (deleteComponentId, deleteComponentWhenNotNeeded); + if (deleteComponentWhenNotNeeded && contentComponent != 0) + contentComponent->getProperties().set (TabbedComponentHelpers::deleteComponentId, true); tabs->addTab (tabName, tabBackgroundColour, insertIndex); } @@ -159,13 +175,9 @@ void TabbedComponent::setTabName (const int tabIndex, const String& newName) void TabbedComponent::removeTab (const int tabIndex) { - WeakReference* c = contentComponents [tabIndex]; - - if (c != 0) + if (isPositiveAndBelow (tabIndex, contentComponents.size())) { - if ((bool) ((*c)->getProperties() [deleteComponentId])) - delete c->get(); - + TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (tabIndex)); contentComponents.remove (tabIndex); tabs->removeTab (tabIndex); } @@ -183,8 +195,7 @@ const StringArray TabbedComponent::getTabNames() const Component* TabbedComponent::getTabContentComponent (const int tabIndex) const throw() { - WeakReference* const c = contentComponents [tabIndex]; - return c != 0 ? *c : 0; + return contentComponents [tabIndex]; } const Colour TabbedComponent::getTabBackgroundColour (const int tabIndex) const throw() @@ -215,99 +226,62 @@ const String TabbedComponent::getCurrentTabName() const return tabs->getCurrentTabName(); } -void TabbedComponent::setOutline (int thickness) +void TabbedComponent::setOutline (const int thickness) { outlineThickness = thickness; + resized(); repaint(); } void TabbedComponent::setIndent (const int indentThickness) { edgeIndent = indentThickness; + resized(); + repaint(); } void TabbedComponent::paint (Graphics& g) { g.fillAll (findColour (backgroundColourId)); - const TabbedButtonBar::Orientation o = getOrientation(); - - int x = 0; - int y = 0; - int r = getWidth(); - int b = getHeight(); + Rectangle content (getLocalBounds()); + BorderSize outline (outlineThickness); + TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth); - if (o == TabbedButtonBar::TabsAtTop) - y += tabDepth; - else if (o == TabbedButtonBar::TabsAtBottom) - b -= tabDepth; - else if (o == TabbedButtonBar::TabsAtLeft) - x += tabDepth; - else if (o == TabbedButtonBar::TabsAtRight) - r -= tabDepth; - - g.reduceClipRegion (x, y, r - x, b - y); + g.reduceClipRegion (content); g.fillAll (tabs->getTabBackgroundColour (getCurrentTabIndex())); if (outlineThickness > 0) { - if (o == TabbedButtonBar::TabsAtTop) - --y; - else if (o == TabbedButtonBar::TabsAtBottom) - ++b; - else if (o == TabbedButtonBar::TabsAtLeft) - --x; - else if (o == TabbedButtonBar::TabsAtRight) - ++r; - - g.setColour (findColour (outlineColourId)); - g.drawRect (x, y, r - x, b - y, outlineThickness); + RectangleList rl (content); + rl.subtract (outline.subtractedFrom (content)); + + g.reduceClipRegion (rl); + g.fillAll (findColour (outlineColourId)); } } void TabbedComponent::resized() { - const TabbedButtonBar::Orientation o = getOrientation(); - const int indent = edgeIndent + outlineThickness; - BorderSize indents (indent); + Rectangle content (getLocalBounds()); + BorderSize outline (outlineThickness); - if (o == TabbedButtonBar::TabsAtTop) - { - tabs->setBounds (0, 0, getWidth(), tabDepth); - indents.setTop (tabDepth + edgeIndent); - } - else if (o == TabbedButtonBar::TabsAtBottom) - { - tabs->setBounds (0, getHeight() - tabDepth, getWidth(), tabDepth); - indents.setBottom (tabDepth + edgeIndent); - } - else if (o == TabbedButtonBar::TabsAtLeft) - { - tabs->setBounds (0, 0, tabDepth, getHeight()); - indents.setLeft (tabDepth + edgeIndent); - } - else if (o == TabbedButtonBar::TabsAtRight) - { - tabs->setBounds (getWidth() - tabDepth, 0, tabDepth, getHeight()); - indents.setRight (tabDepth + edgeIndent); - } - - const Rectangle bounds (indents.subtractedFrom (getLocalBounds())); + tabs->setBounds (TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth)); + content = BorderSize (edgeIndent).subtractedFrom (outline.subtractedFrom (content)); for (int i = contentComponents.size(); --i >= 0;) - if (*contentComponents.getUnchecked (i) != 0) - (*contentComponents.getUnchecked (i))->setBounds (bounds); + if (contentComponents.getReference (i) != 0) + contentComponents.getReference (i)->setBounds (content); } void TabbedComponent::lookAndFeelChanged() { for (int i = contentComponents.size(); --i >= 0;) - if (*contentComponents.getUnchecked (i) != 0) - (*contentComponents.getUnchecked (i))->lookAndFeelChanged(); + if (contentComponents.getReference (i) != 0) + contentComponents.getReference (i)->lookAndFeelChanged(); } -void TabbedComponent::changeCallback (const int newCurrentTabIndex, - const String& newTabName) +void TabbedComponent::changeCallback (const int newCurrentTabIndex, const String& newTabName) { if (panelComponent != 0) { @@ -337,12 +311,8 @@ void TabbedComponent::changeCallback (const int newCurrentTabIndex, currentTabChanged (newCurrentTabIndex, newTabName); } -void TabbedComponent::currentTabChanged (const int, const String&) -{ -} +void TabbedComponent::currentTabChanged (const int, const String&) {} +void TabbedComponent::popupMenuClickOnTab (const int, const String&) {} -void TabbedComponent::popupMenuClickOnTab (const int, const String&) -{ -} END_JUCE_NAMESPACE diff --git a/src/gui/components/layout/juce_TabbedComponent.h b/src/gui/components/layout/juce_TabbedComponent.h index 2b258cdb08..3ec07c9562 100644 --- a/src/gui/components/layout/juce_TabbedComponent.h +++ b/src/gui/components/layout/juce_TabbedComponent.h @@ -214,8 +214,6 @@ public: protected: //============================================================================== - ScopedPointer tabs; - /** This creates one of the tab buttons. If you need to use custom tab components, you can override this method and @@ -223,15 +221,18 @@ protected: */ virtual TabBarButton* createTabButton (const String& tabName, int tabIndex); + /** @internal */ + ScopedPointer tabs; + private: //============================================================================== - OwnedArray > contentComponents; + Array > contentComponents; WeakReference panelComponent; int tabDepth; int outlineThickness, edgeIndent; - static const Identifier deleteComponentId; - friend class TabCompButtonBar; + class ButtonBar; + friend class ButtonBar; void changeCallback (int newCurrentTabIndex, const String& newTabName); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabbedComponent); diff --git a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp index 7e77fcb9cf..60e8d9cdbb 100644 --- a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp +++ b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp @@ -121,6 +121,12 @@ bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate& return registerListeners (coord.getExpression()); } +bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point) +{ + const bool ok = addCoordinate (point.x); + return addCoordinate (point.y) && ok; +} + bool RelativeCoordinatePositionerBase::registerListeners (const Expression& e) { bool ok = true; diff --git a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h index b1043fd55f..84a689467f 100644 --- a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h +++ b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h @@ -26,7 +26,7 @@ #ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__ #define __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__ -#include "juce_RelativeCoordinate.h" +#include "juce_RelativePoint.h" #include "juce_MarkerList.h" #include "../juce_Component.h" @@ -54,9 +54,10 @@ public: void apply(); -protected: bool addCoordinate (const RelativeCoordinate& coord); + bool addPoint (const RelativePoint& point); +protected: virtual bool registerCoordinates() = 0; virtual void applyToComponentBounds() = 0; diff --git a/src/gui/components/positioning/juce_RelativeParallelogram.cpp b/src/gui/components/positioning/juce_RelativeParallelogram.cpp index 2a142df1f0..d451b5a4f8 100644 --- a/src/gui/components/positioning/juce_RelativeParallelogram.cpp +++ b/src/gui/components/positioning/juce_RelativeParallelogram.cpp @@ -103,6 +103,11 @@ const AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::E corners[2].getX(), corners[2].getY(), newBottomLeft.getX(), newBottomLeft.getY()); } +bool RelativeParallelogram::isDynamic() const +{ + return topLeft.isDynamic() || topRight.isDynamic() || bottomLeft.isDynamic(); +} + bool RelativeParallelogram::operator== (const RelativeParallelogram& other) const throw() { return topLeft == other.topLeft && topRight == other.topRight && bottomLeft == other.bottomLeft; @@ -130,4 +135,11 @@ const Point RelativeParallelogram::getPointForInternalCoord (const Point< + Line (Point(), corners[2] - corners[0]).getPointAlongLine (point.getY()); } +const Rectangle RelativeParallelogram::getBoundingBox (const Point* const p) throw() +{ + const Point points[] = { p[0], p[1], p[2], p[1] + (p[2] - p[0]) }; + return Rectangle::findAreaContainingPoints (points, 4); +} + + END_JUCE_NAMESPACE diff --git a/src/gui/components/positioning/juce_RelativeParallelogram.h b/src/gui/components/positioning/juce_RelativeParallelogram.h index 1d3c5bd41d..a0dbe94bff 100644 --- a/src/gui/components/positioning/juce_RelativeParallelogram.h +++ b/src/gui/components/positioning/juce_RelativeParallelogram.h @@ -51,12 +51,14 @@ public: const Rectangle getBounds (Expression::EvaluationContext* coordFinder) const; void getPath (Path& path, Expression::EvaluationContext* coordFinder) const; const AffineTransform resetToPerpendicular (Expression::EvaluationContext* coordFinder); + bool isDynamic() const; bool operator== (const RelativeParallelogram& other) const throw(); bool operator!= (const RelativeParallelogram& other) const throw(); static const Point getInternalCoordForPoint (const Point* parallelogramCorners, Point point) throw(); static const Point getPointForInternalCoord (const Point* parallelogramCorners, const Point& internalPoint) throw(); + static const Rectangle getBoundingBox (const Point* parallelogramCorners) throw(); //============================================================================== RelativePoint topLeft, topRight, bottomLeft; diff --git a/src/gui/graphics/drawables/juce_Drawable.h b/src/gui/graphics/drawables/juce_Drawable.h index 7489c54bdc..883cd291ac 100644 --- a/src/gui/graphics/drawables/juce_Drawable.h +++ b/src/gui/graphics/drawables/juce_Drawable.h @@ -28,6 +28,7 @@ #include "../../components/juce_Component.h" #include "../../components/positioning/juce_RelativeCoordinate.h" +#include "../../components/positioning/juce_RelativeCoordinatePositioner.h" #include "../../../containers/juce_ValueTree.h" #include "../../components/layout/juce_ComponentBuilder.h" class DrawableComposite; @@ -215,6 +216,27 @@ protected: Point originRelativeToComponent; + #ifndef DOXYGEN + /** Internal utility class used by Drawables. */ + template + class Positioner : public RelativeCoordinatePositionerBase + { + public: + Positioner (DrawableType& component_) + : RelativeCoordinatePositionerBase (component_), + owner (component_) + {} + + bool registerCoordinates() { return owner.registerCoordinates (*this); } + void applyToComponentBounds() { owner.recalculateCoordinates (this); } + + private: + DrawableType& owner; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner); + }; + #endif + private: void nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform); diff --git a/src/gui/graphics/drawables/juce_DrawableComposite.cpp b/src/gui/graphics/drawables/juce_DrawableComposite.cpp index 83759b064d..3caa048288 100644 --- a/src/gui/graphics/drawables/juce_DrawableComposite.cpp +++ b/src/gui/graphics/drawables/juce_DrawableComposite.cpp @@ -61,6 +61,11 @@ DrawableComposite::~DrawableComposite() deleteAllChildren(); } +Drawable* DrawableComposite::createCopy() const +{ + return new DrawableComposite (*this); +} + //============================================================================== const Rectangle DrawableComposite::getDrawableBounds() const { @@ -98,13 +103,26 @@ void DrawableComposite::setContentArea (const RelativeRectangle& newArea) markersX.setMarker (contentRightMarkerName, newArea.right); markersY.setMarker (contentTopMarkerName, newArea.top); markersY.setMarker (contentBottomMarkerName, newArea.bottom); - refreshTransformFromBounds(); } -void DrawableComposite::setBoundingBox (const RelativeParallelogram& newBoundingBox) +void DrawableComposite::setBoundingBox (const RelativeParallelogram& newBounds) { - bounds = newBoundingBox; - refreshTransformFromBounds(); + if (bounds != newBounds) + { + bounds = newBounds; + + if (bounds.isDynamic()) + { + Drawable::Positioner* const p = new Drawable::Positioner (*this); + setPositioner (p); + p->apply(); + } + else + { + setPositioner (0); + recalculateCoordinates (0); + } + } } void DrawableComposite::resetBoundingBoxToContentArea() @@ -127,12 +145,19 @@ void DrawableComposite::resetContentAreaAndBoundingBoxToFitChildren() resetBoundingBoxToContentArea(); } -void DrawableComposite::refreshTransformFromBounds() +bool DrawableComposite::registerCoordinates (RelativeCoordinatePositionerBase& positioner) +{ + bool ok = positioner.addPoint (bounds.topLeft); + ok = positioner.addPoint (bounds.topRight) && ok; + return positioner.addPoint (bounds.bottomLeft) && ok; +} + +void DrawableComposite::recalculateCoordinates (Expression::EvaluationContext* context) { Point resolved[3]; - bounds.resolveThreePoints (resolved, getParent()); + bounds.resolveThreePoints (resolved, context); - const Rectangle content (getContentArea().resolve (getParent())); + const Rectangle content (getContentArea().resolve (context)); AffineTransform t (AffineTransform::fromTargetPoints (content.getX(), content.getY(), resolved[0].getX(), resolved[0].getY(), content.getRight(), content.getY(), resolved[1].getX(), resolved[1].getY(), @@ -212,27 +237,6 @@ const char* const DrawableComposite::contentRightMarkerName = "right"; const char* const DrawableComposite::contentTopMarkerName = "top"; const char* const DrawableComposite::contentBottomMarkerName = "bottom"; -//============================================================================== -const Expression DrawableComposite::getSymbolValue (const String& symbol, const String& member) const -{ - jassert (member.isEmpty()) // the only symbols available in a Drawable are markers. - - const MarkerList::Marker* m = markersX.getMarker (symbol); - - if (m == 0) - m = markersY.getMarker (symbol); - - if (m != 0) - return m->position.getExpression(); - - throw Expression::EvaluationError (symbol, member); -} - -Drawable* DrawableComposite::createCopy() const -{ - return new DrawableComposite (*this); -} - //============================================================================== const Identifier DrawableComposite::valueTreeType ("Group"); @@ -321,16 +325,12 @@ void DrawableComposite::refreshFromValueTree (const ValueTree& tree, ComponentBu const ValueTreeWrapper wrapper (tree); setComponentID (wrapper.getID()); - const RelativeParallelogram newBounds (wrapper.getBoundingBox()); - if (bounds != newBounds) - bounds = newBounds; - wrapper.getMarkerList (true).applyTo (markersX); wrapper.getMarkerList (false).applyTo (markersY); - builder.updateChildComponents (*this, wrapper.getChildList()); + setBoundingBox (wrapper.getBoundingBox()); - refreshTransformFromBounds(); + builder.updateChildComponents (*this, wrapper.getChildList()); } const ValueTree DrawableComposite::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const diff --git a/src/gui/graphics/drawables/juce_DrawableComposite.h b/src/gui/graphics/drawables/juce_DrawableComposite.h index f3c32657ff..899204cfae 100644 --- a/src/gui/graphics/drawables/juce_DrawableComposite.h +++ b/src/gui/graphics/drawables/juce_DrawableComposite.h @@ -38,8 +38,8 @@ @see Drawable */ -class JUCE_API DrawableComposite : public Drawable, - public Expression::EvaluationContext +class JUCE_API DrawableComposite : public Drawable//, +// public Expression::EvaluationContext { public: //============================================================================== @@ -107,8 +107,6 @@ public: /** @internal */ static const Identifier valueTreeType; /** @internal */ - const Expression getSymbolValue (const String& symbol, const String& member) const; - /** @internal */ const Rectangle getDrawableBounds() const; /** @internal */ void childBoundsChanged (Component*); @@ -151,7 +149,10 @@ private: MarkerList markersX, markersY; bool updateBoundsReentrant; - void refreshTransformFromBounds(); + friend class Drawable::Positioner; + bool registerCoordinates (RelativeCoordinatePositionerBase&); + void recalculateCoordinates (Expression::EvaluationContext*); + void updateBoundsToFitChildren(); DrawableComposite& operator= (const DrawableComposite&); diff --git a/src/gui/graphics/drawables/juce_DrawableImage.cpp b/src/gui/graphics/drawables/juce_DrawableImage.cpp index 43ae0d6d8b..419b0e3f31 100644 --- a/src/gui/graphics/drawables/juce_DrawableImage.cpp +++ b/src/gui/graphics/drawables/juce_DrawableImage.cpp @@ -58,17 +58,14 @@ DrawableImage::~DrawableImage() void DrawableImage::setImage (const Image& imageToUse) { image = imageToUse; - setBounds (imageToUse.getBounds()); - if (image.isValid()) - { - bounds.topLeft = RelativePoint (Point (0.0f, 0.0f)); - bounds.topRight = RelativePoint (Point ((float) image.getWidth(), 0.0f)); - bounds.bottomLeft = RelativePoint (Point (0.0f, (float) image.getHeight())); - } + bounds.topLeft = RelativePoint (Point (0.0f, 0.0f)); + bounds.topRight = RelativePoint (Point ((float) image.getWidth(), 0.0f)); + bounds.bottomLeft = RelativePoint (Point (0.0f, (float) image.getHeight())); + recalculateCoordinates (0); - refreshTransformFromBounds(); + repaint(); } void DrawableImage::setOpacity (const float newOpacity) @@ -83,17 +80,38 @@ void DrawableImage::setOverlayColour (const Colour& newOverlayColour) void DrawableImage::setBoundingBox (const RelativeParallelogram& newBounds) { - bounds = newBounds; - refreshTransformFromBounds(); + if (bounds != newBounds) + { + bounds = newBounds; + + if (bounds.isDynamic()) + { + Drawable::Positioner* const p = new Drawable::Positioner (*this); + setPositioner (p); + p->apply(); + } + else + { + setPositioner (0); + recalculateCoordinates (0); + } + } } //============================================================================== -void DrawableImage::refreshTransformFromBounds() +bool DrawableImage::registerCoordinates (RelativeCoordinatePositionerBase& positioner) +{ + bool ok = positioner.addPoint (bounds.topLeft); + ok = positioner.addPoint (bounds.topRight) && ok; + return positioner.addPoint (bounds.bottomLeft) && ok; +} + +void DrawableImage::recalculateCoordinates (Expression::EvaluationContext* context) { - if (! image.isNull()) + if (image.isValid()) { Point resolved[3]; - bounds.resolveThreePoints (resolved, getParent()); + bounds.resolveThreePoints (resolved, context); const Point tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth()); const Point bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight()); @@ -102,8 +120,10 @@ void DrawableImage::refreshTransformFromBounds() tr.getX(), tr.getY(), bl.getX(), bl.getY())); - if (! t.isSingularity()) - setTransform (t); + if (t.isSingularity()) + t = AffineTransform::identity; + + setTransform (t); } } @@ -251,12 +271,11 @@ void DrawableImage::refreshFromValueTree (const ValueTree& tree, ComponentBuilde repaint(); opacity = newOpacity; overlayColour = newOverlayColour; - bounds = newBounds; if (image != newImage) setImage (newImage); - else - refreshTransformFromBounds(); + + setBoundingBox (newBounds); } } diff --git a/src/gui/graphics/drawables/juce_DrawableImage.h b/src/gui/graphics/drawables/juce_DrawableImage.h index 624efd7b0f..4537b90181 100644 --- a/src/gui/graphics/drawables/juce_DrawableImage.h +++ b/src/gui/graphics/drawables/juce_DrawableImage.h @@ -131,7 +131,9 @@ private: Colour overlayColour; RelativeParallelogram bounds; - void refreshTransformFromBounds(); + friend class Drawable::Positioner; + bool registerCoordinates (RelativeCoordinatePositionerBase&); + void recalculateCoordinates (Expression::EvaluationContext*); DrawableImage& operator= (const DrawableImage&); JUCE_LEAK_DETECTOR (DrawableImage); diff --git a/src/gui/graphics/drawables/juce_DrawablePath.cpp b/src/gui/graphics/drawables/juce_DrawablePath.cpp index 8440ae44ed..477c6c4dff 100644 --- a/src/gui/graphics/drawables/juce_DrawablePath.cpp +++ b/src/gui/graphics/drawables/juce_DrawablePath.cpp @@ -40,10 +40,8 @@ DrawablePath::DrawablePath() DrawablePath::DrawablePath (const DrawablePath& other) : DrawableShape (other) { - const RelativePointPath* const relativePath = other.getRelativePath(); - - if (relativePath != 0) - setPath (*relativePath); + if (other.relativePath != 0) + setPath (*other.relativePath); else setPath (other.path); } @@ -74,15 +72,10 @@ const Path& DrawablePath::getStrokePath() const return strokePath; } -bool DrawablePath::rebuildPath (Path&) const -{ - return false; -} - -void DrawablePath::applyRelativePath (const RelativePointPath& relativePath) +void DrawablePath::applyRelativePath (const RelativePointPath& newRelativePath, Expression::EvaluationContext* context) { Path newPath; - relativePath.createPath (newPath, 0); + newRelativePath.createPath (newPath, context); if (path != newPath) { @@ -95,9 +88,8 @@ void DrawablePath::applyRelativePath (const RelativePointPath& relativePath) class DrawablePath::RelativePositioner : public RelativeCoordinatePositionerBase { public: - RelativePositioner (DrawablePath& component_, const RelativePointPath& path_) + RelativePositioner (DrawablePath& component_) : RelativeCoordinatePositionerBase (component_), - path (path_), owner (component_) { } @@ -106,6 +98,9 @@ public: { bool ok = true; + jassert (owner.relativePath != 0); + const RelativePointPath& path = *owner.relativePath; + for (int i = 0; i < path.elements.size(); ++i) { RelativePointPath::ElementBase* const e = path.elements.getUnchecked(i); @@ -114,10 +109,7 @@ public: RelativePoint* const points = e->getControlPoints (numPoints); for (int j = numPoints; --j >= 0;) - { - ok = addCoordinate (points[j].x) && ok; - ok = addCoordinate (points[j].y) && ok; - } + ok = addPoint (points[j]) && ok; } return ok; @@ -125,39 +117,33 @@ public: void applyToComponentBounds() { - owner.applyRelativePath (path); + jassert (owner.relativePath != 0); + owner.applyRelativePath (*owner.relativePath, this); } - const RelativePointPath path; - private: DrawablePath& owner; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativePositioner); }; -const RelativePointPath* DrawablePath::getRelativePath() const -{ - RelativePositioner* current = dynamic_cast (getPositioner()); - return current != 0 ? &(current->path) : 0; -} - void DrawablePath::setPath (const RelativePointPath& newRelativePath) { if (newRelativePath.containsAnyDynamicPoints()) { - const RelativePointPath* current = getRelativePath(); - - if (current == 0 || newRelativePath != *current) + if (relativePath == 0 || newRelativePath != *relativePath) { - RelativePositioner* const p = new RelativePositioner (*this, newRelativePath); + relativePath = new RelativePointPath (newRelativePath); + + RelativePositioner* const p = new RelativePositioner (*this); setPositioner (p); p->apply(); } } else { - applyRelativePath (newRelativePath); + relativePath = 0; + applyRelativePath (newRelativePath, 0); } } @@ -313,26 +299,26 @@ const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const return RelativePoint(); } -float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::EvaluationContext* nameFinder) const +float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::EvaluationContext* context) const { const Identifier i (state.getType()); if (i == lineToElement || i == closeSubPathElement) - return getEndPoint().resolve (nameFinder).getDistanceFrom (getStartPoint().resolve (nameFinder)); + return getEndPoint().resolve (context).getDistanceFrom (getStartPoint().resolve (context)); if (i == cubicToElement) { Path p; - p.startNewSubPath (getStartPoint().resolve (nameFinder)); - p.cubicTo (getControlPoint (0).resolve (nameFinder), getControlPoint (1).resolve (nameFinder), getControlPoint (2).resolve (nameFinder)); + p.startNewSubPath (getStartPoint().resolve (context)); + p.cubicTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context), getControlPoint (2).resolve (context)); return p.getLength(); } if (i == quadraticToElement) { Path p; - p.startNewSubPath (getStartPoint().resolve (nameFinder)); - p.quadraticTo (getControlPoint (0).resolve (nameFinder), getControlPoint (1).resolve (nameFinder)); + p.startNewSubPath (getStartPoint().resolve (context)); + p.quadraticTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context)); return p.getLength(); } @@ -364,7 +350,7 @@ void DrawablePath::ValueTreeWrapper::Element::convertToLine (UndoManager* undoMa } } -void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager) +void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::EvaluationContext* context, UndoManager* undoManager) { const Identifier i (state.getType()); @@ -375,8 +361,8 @@ void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::Evalua const RelativePoint start (getStartPoint()); const RelativePoint end (getEndPoint()); - const Point startResolved (start.resolve (nameFinder)); - const Point endResolved (end.resolve (nameFinder)); + const Point startResolved (start.resolve (context)); + const Point endResolved (end.resolve (context)); e.setControlPoint (0, startResolved + (endResolved - startResolved) * 0.3f, undoManager); e.setControlPoint (1, startResolved + (endResolved - startResolved) * 0.7f, undoManager); e.setControlPoint (2, end, undoManager); @@ -421,7 +407,7 @@ namespace DrawablePathHelpers } } -float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext* nameFinder) const +float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext* context) const { using namespace DrawablePathHelpers; const Identifier type (state.getType()); @@ -431,7 +417,7 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po { RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint()); - const Point points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; + const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) }; float bestDistance = std::numeric_limits::max(); @@ -451,7 +437,7 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po else if (type == quadraticToElement) { RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); - const Point points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; + const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context) }; float bestDistance = std::numeric_limits::max(); @@ -471,24 +457,24 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po else if (type == lineToElement) { RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint()); - const Line line (rp1.resolve (nameFinder), rp2.resolve (nameFinder)); + const Line line (rp1.resolve (context), rp2.resolve (context)); bestProp = line.findNearestProportionalPositionTo (targetPoint); } return bestProp; } -ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager) +ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& targetPoint, Expression::EvaluationContext* context, UndoManager* undoManager) { ValueTree newTree; const Identifier type (state.getType()); if (type == cubicToElement) { - float bestProp = findProportionAlongLine (targetPoint, nameFinder); + float bestProp = findProportionAlongLine (targetPoint, context); RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint()); - const Point points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder), rp4.resolve (nameFinder) }; + const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) }; const Point mid1 (points[0] + (points[1] - points[0]) * bestProp), mid2 (points[1] + (points[2] - points[1]) * bestProp), @@ -513,10 +499,10 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point points[] = { rp1.resolve (nameFinder), rp2.resolve (nameFinder), rp3.resolve (nameFinder) }; + const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context) }; const Point mid1 (points[0] + (points[1] - points[0]) * bestProp), mid2 (points[1] + (points[2] - points[1]) * bestProp); @@ -536,7 +522,7 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point line (rp1.resolve (nameFinder), rp2.resolve (nameFinder)); + const Line line (rp1.resolve (context), rp2.resolve (context)); const Point newPoint (line.findNearestPointTo (targetPoint)); setControlPoint (0, newPoint, undoManager); @@ -564,15 +550,8 @@ void DrawablePath::refreshFromValueTree (const ValueTree& tree, ComponentBuilder ValueTreeWrapper v (tree); setComponentID (v.getID()); - if (refreshFillTypes (v, getParent(), builder.getImageProvider())) - repaint(); - - const PathStrokeType newStroke (v.getStrokeType()); - if (strokeType != newStroke) - { - strokeType = newStroke; - strokeChanged(); - } + refreshFillTypes (v, builder.getImageProvider()); + setStrokeType (v.getStrokeType()); RelativePointPath newRelativePath; v.writeTo (newRelativePath); @@ -587,17 +566,10 @@ const ValueTree DrawablePath::createValueTree (ComponentBuilder::ImageProvider* v.setID (getComponentID()); writeTo (v, imageProvider, 0); - const RelativePointPath* const relativePath = getRelativePath(); - if (relativePath != 0) - { v.readFrom (*relativePath, 0); - } else - { - RelativePointPath rp (path); - v.readFrom (rp, 0); - } + v.readFrom (RelativePointPath (path), 0); return tree; } diff --git a/src/gui/graphics/drawables/juce_DrawablePath.h b/src/gui/graphics/drawables/juce_DrawablePath.h index 16dc035331..b7a223709b 100644 --- a/src/gui/graphics/drawables/juce_DrawablePath.h +++ b/src/gui/graphics/drawables/juce_DrawablePath.h @@ -97,24 +97,24 @@ public: int getNumControlPoints() const throw(); const RelativePoint getControlPoint (int index) const; - Value getControlPointValue (int index, UndoManager* undoManager) const; + Value getControlPointValue (int index, UndoManager*) const; const RelativePoint getStartPoint() const; const RelativePoint getEndPoint() const; - void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager); - float getLength (Expression::EvaluationContext* nameFinder) const; + void setControlPoint (int index, const RelativePoint& point, UndoManager*); + float getLength (Expression::EvaluationContext*) const; ValueTreeWrapper getParent() const; Element getPreviousElement() const; const String getModeOfEndPoint() const; - void setModeOfEndPoint (const String& newMode, UndoManager* undoManager); + void setModeOfEndPoint (const String& newMode, UndoManager*); - void convertToLine (UndoManager* undoManager); - void convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager); + void convertToLine (UndoManager*); + void convertToCubic (Expression::EvaluationContext*, UndoManager*); void convertToPathBreak (UndoManager* undoManager); - ValueTree insertPoint (const Point& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager); + ValueTree insertPoint (const Point& targetPoint, Expression::EvaluationContext*, UndoManager*); void removePoint (UndoManager* undoManager); - float findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext* nameFinder) const; + float findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext*) const; static const Identifier mode, startSubPathElement, closeSubPathElement, lineToElement, quadraticToElement, cubicToElement; @@ -133,15 +133,13 @@ public: static const Identifier nonZeroWinding, point1, point2, point3; }; -protected: - bool rebuildPath (Path& path) const; - private: //============================================================================== + ScopedPointer relativePath; + class RelativePositioner; friend class RelativePositioner; - void applyRelativePath (const RelativePointPath& newPath); - const RelativePointPath* getRelativePath() const; + void applyRelativePath (const RelativePointPath&, Expression::EvaluationContext*); DrawablePath& operator= (const DrawablePath&); JUCE_LEAK_DETECTOR (DrawablePath); diff --git a/src/gui/graphics/drawables/juce_DrawableRectangle.cpp b/src/gui/graphics/drawables/juce_DrawableRectangle.cpp index 855bd8938b..3752ab5eea 100644 --- a/src/gui/graphics/drawables/juce_DrawableRectangle.cpp +++ b/src/gui/graphics/drawables/juce_DrawableRectangle.cpp @@ -29,6 +29,8 @@ BEGIN_JUCE_NAMESPACE #include "juce_DrawableRectangle.h" #include "juce_DrawableComposite.h" +#include "../../components/positioning/juce_RelativeCoordinatePositioner.h" + //============================================================================== DrawableRectangle::DrawableRectangle() @@ -36,7 +38,9 @@ DrawableRectangle::DrawableRectangle() } DrawableRectangle::DrawableRectangle (const DrawableRectangle& other) - : DrawableShape (other) + : DrawableShape (other), + bounds (other.bounds), + cornerSize (other.cornerSize) { } @@ -52,51 +56,72 @@ Drawable* DrawableRectangle::createCopy() const //============================================================================== void DrawableRectangle::setRectangle (const RelativeParallelogram& newBounds) { - bounds = newBounds; - pathChanged(); - strokeChanged(); + if (bounds != newBounds) + { + bounds = newBounds; + rebuildPath(); + } } void DrawableRectangle::setCornerSize (const RelativePoint& newSize) { - cornerSize = newSize; - pathChanged(); - strokeChanged(); + if (cornerSize != newSize) + { + cornerSize = newSize; + rebuildPath(); + } } -//============================================================================== -bool DrawableRectangle::rebuildPath (Path& path) const +void DrawableRectangle::rebuildPath() +{ + if (bounds.isDynamic() || cornerSize.isDynamic()) + { + Drawable::Positioner* const p = new Drawable::Positioner (*this); + setPositioner (p); + p->apply(); + } + else + { + setPositioner (0); + recalculateCoordinates (0); + } +} + +bool DrawableRectangle::registerCoordinates (RelativeCoordinatePositionerBase& positioner) +{ + bool ok = positioner.addPoint (bounds.topLeft); + ok = positioner.addPoint (bounds.topRight) && ok; + ok = positioner.addPoint (bounds.bottomLeft) && ok; + return positioner.addPoint (cornerSize) && ok; +} + +void DrawableRectangle::recalculateCoordinates (Expression::EvaluationContext* context) { Point points[3]; - bounds.resolveThreePoints (points, getParent()); + bounds.resolveThreePoints (points, context); + + const float cornerSizeX = (float) cornerSize.x.resolve (context); + const float cornerSizeY = (float) cornerSize.y.resolve (context); const float w = Line (points[0], points[1]).getLength(); const float h = Line (points[0], points[2]).getLength(); - const float cornerSizeX = (float) cornerSize.x.resolve (getParent()); - const float cornerSizeY = (float) cornerSize.y.resolve (getParent()); - - path.clear(); + Path newPath; if (cornerSizeX > 0 && cornerSizeY > 0) - path.addRoundedRectangle (0, 0, w, h, cornerSizeX, cornerSizeY); + newPath.addRoundedRectangle (0, 0, w, h, cornerSizeX, cornerSizeY); else - path.addRectangle (0, 0, w, h); - - path.applyTransform (AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(), - w, 0, points[1].getX(), points[1].getY(), - 0, h, points[2].getX(), points[2].getY())); - return true; -} + newPath.addRectangle (0, 0, w, h); -const AffineTransform DrawableRectangle::calculateTransform() const -{ - Point resolved[3]; - bounds.resolveThreePoints (resolved, getParent()); + newPath.applyTransform (AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(), + w, 0, points[1].getX(), points[1].getY(), + 0, h, points[2].getX(), points[2].getY())); - return AffineTransform::fromTargetPoints (resolved[0].getX(), resolved[0].getY(), - resolved[1].getX(), resolved[1].getY(), - resolved[2].getX(), resolved[2].getY()); + if (path != newPath) + { + path.swapWithPath (newPath); + pathChanged(); + } } //============================================================================== @@ -148,22 +173,10 @@ void DrawableRectangle::refreshFromValueTree (const ValueTree& tree, ComponentBu ValueTreeWrapper v (tree); setComponentID (v.getID()); - if (refreshFillTypes (v, getParent(), builder.getImageProvider())) - repaint(); - - RelativeParallelogram newBounds (v.getRectangle()); - - const PathStrokeType newStroke (v.getStrokeType()); - const RelativePoint newCornerSize (v.getCornerSize()); - - if (strokeType != newStroke || newBounds != bounds || newCornerSize != cornerSize) - { - repaint(); - bounds = newBounds; - strokeType = newStroke; - cornerSize = newCornerSize; - pathChanged(); - } + refreshFillTypes (v, builder.getImageProvider()); + setStrokeType (v.getStrokeType()); + setRectangle (v.getRectangle()); + setCornerSize (v.getCornerSize()); } const ValueTree DrawableRectangle::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const diff --git a/src/gui/graphics/drawables/juce_DrawableRectangle.h b/src/gui/graphics/drawables/juce_DrawableRectangle.h index 9dca2b4976..0b5a55869c 100644 --- a/src/gui/graphics/drawables/juce_DrawableRectangle.h +++ b/src/gui/graphics/drawables/juce_DrawableRectangle.h @@ -79,25 +79,25 @@ public: ValueTreeWrapper (const ValueTree& state); const RelativeParallelogram getRectangle() const; - void setRectangle (const RelativeParallelogram& newBounds, UndoManager* undoManager); + void setRectangle (const RelativeParallelogram& newBounds, UndoManager*); - void setCornerSize (const RelativePoint& cornerSize, UndoManager* undoManager); + void setCornerSize (const RelativePoint& cornerSize, UndoManager*); const RelativePoint getCornerSize() const; - Value getCornerSizeValue (UndoManager* undoManager) const; + Value getCornerSizeValue (UndoManager*) const; static const Identifier topLeft, topRight, bottomLeft, cornerSize; }; -protected: - /** @internal */ - bool rebuildPath (Path& path) const; - private: + friend class Drawable::Positioner; + RelativeParallelogram bounds; RelativePoint cornerSize; - const AffineTransform calculateTransform() const; + void rebuildPath(); + bool registerCoordinates (RelativeCoordinatePositionerBase&); + void recalculateCoordinates (Expression::EvaluationContext*); DrawableRectangle& operator= (const DrawableRectangle&); JUCE_LEAK_DETECTOR (DrawableRectangle); diff --git a/src/gui/graphics/drawables/juce_DrawableShape.cpp b/src/gui/graphics/drawables/juce_DrawableShape.cpp index 6ff8e267da..82d8300ed7 100644 --- a/src/gui/graphics/drawables/juce_DrawableShape.cpp +++ b/src/gui/graphics/drawables/juce_DrawableShape.cpp @@ -50,65 +50,111 @@ DrawableShape::~DrawableShape() { } +//============================================================================== +class DrawableShape::RelativePositioner : public RelativeCoordinatePositionerBase +{ +public: + RelativePositioner (DrawableShape& component_, const DrawableShape::RelativeFillType& fill_, bool isMainFill_) + : RelativeCoordinatePositionerBase (component_), + owner (component_), + fill (fill_), + isMainFill (isMainFill_) + { + } + + bool registerCoordinates() + { + bool ok = addPoint (fill.gradientPoint1); + ok = addPoint (fill.gradientPoint2) && ok; + return addPoint (fill.gradientPoint3) && ok; + } + + void applyToComponentBounds() + { + if (isMainFill ? owner.mainFill.recalculateCoords (this) + : owner.strokeFill.recalculateCoords (this)) + owner.repaint(); + } + +private: + DrawableShape& owner; + const DrawableShape::RelativeFillType fill; + const bool isMainFill; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativePositioner); +}; + void DrawableShape::setFill (const FillType& newFill) { - mainFill = newFill; + setFill (RelativeFillType (newFill)); } void DrawableShape::setStrokeFill (const FillType& newFill) { - strokeFill = newFill; + setStrokeFill (RelativeFillType (newFill)); } -void DrawableShape::setStrokeType (const PathStrokeType& newStrokeType) +void DrawableShape::setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill, + ScopedPointer& positioner) { - strokeType = newStrokeType; - strokeChanged(); + if (fill != newFill) + { + fill = newFill; + positioner = 0; + + if (fill.isDynamic()) + { + positioner = new RelativePositioner (*this, fill, true); + positioner->apply(); + } + else + { + fill.recalculateCoords (0); + } + + repaint(); + } } -void DrawableShape::setStrokeThickness (const float newThickness) +void DrawableShape::setFill (const RelativeFillType& newFill) { - setStrokeType (PathStrokeType (newThickness, strokeType.getJointStyle(), strokeType.getEndStyle())); + setFillInternal (mainFill, newFill, mainFillPositioner); } -bool DrawableShape::isStrokeVisible() const throw() +void DrawableShape::setStrokeFill (const RelativeFillType& newFill) { - return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.isInvisible(); + setFillInternal (strokeFill, newFill, strokeFillPositioner); } -bool DrawableShape::refreshFillTypes (const FillAndStrokeState& newState, - Expression::EvaluationContext* /*nameFinder*/, - ComponentBuilder::ImageProvider* imageProvider) +void DrawableShape::setStrokeType (const PathStrokeType& newStrokeType) { - bool hasChanged = false; - + if (strokeType != newStrokeType) { - const FillType f (newState.getMainFill (getParent(), imageProvider)); - - if (mainFill != f) - { - hasChanged = true; - mainFill = f; - } + strokeType = newStrokeType; + strokeChanged(); } +} - { - const FillType f (newState.getStrokeFill (getParent(), imageProvider)); +void DrawableShape::setStrokeThickness (const float newThickness) +{ + setStrokeType (PathStrokeType (newThickness, strokeType.getJointStyle(), strokeType.getEndStyle())); +} - if (strokeFill != f) - { - hasChanged = true; - strokeFill = f; - } - } +bool DrawableShape::isStrokeVisible() const throw() +{ + return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.fill.isInvisible(); +} - return hasChanged; +void DrawableShape::refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider* imageProvider) +{ + setFill (newState.getFill (FillAndStrokeState::fill, imageProvider)); + setStrokeFill (newState.getFill (FillAndStrokeState::stroke, imageProvider)); } void DrawableShape::writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const { - state.setMainFill (mainFill, 0, 0, 0, imageProvider, undoManager); - state.setStrokeFill (strokeFill, 0, 0, 0, imageProvider, undoManager); + state.setFill (FillAndStrokeState::fill, mainFill, imageProvider, undoManager); + state.setFill (FillAndStrokeState::stroke, strokeFill, imageProvider, undoManager); state.setStrokeType (strokeType, undoManager); } @@ -117,19 +163,18 @@ void DrawableShape::paint (Graphics& g) { transformContextToCorrectOrigin (g); - g.setFillType (mainFill); + g.setFillType (mainFill.fill); g.fillPath (path); if (isStrokeVisible()) { - g.setFillType (strokeFill); + g.setFillType (strokeFill.fill); g.fillPath (strokePath); } } void DrawableShape::pathChanged() { - rebuildPath (path); strokeChanged(); } @@ -160,211 +205,249 @@ bool DrawableShape::hitTest (int x, int y) const } //============================================================================== -const Identifier DrawableShape::FillAndStrokeState::type ("type"); -const Identifier DrawableShape::FillAndStrokeState::colour ("colour"); -const Identifier DrawableShape::FillAndStrokeState::colours ("colours"); -const Identifier DrawableShape::FillAndStrokeState::fill ("Fill"); -const Identifier DrawableShape::FillAndStrokeState::stroke ("Stroke"); -const Identifier DrawableShape::FillAndStrokeState::path ("Path"); -const Identifier DrawableShape::FillAndStrokeState::jointStyle ("jointStyle"); -const Identifier DrawableShape::FillAndStrokeState::capStyle ("capStyle"); -const Identifier DrawableShape::FillAndStrokeState::strokeWidth ("strokeWidth"); -const Identifier DrawableShape::FillAndStrokeState::gradientPoint1 ("point1"); -const Identifier DrawableShape::FillAndStrokeState::gradientPoint2 ("point2"); -const Identifier DrawableShape::FillAndStrokeState::gradientPoint3 ("point3"); -const Identifier DrawableShape::FillAndStrokeState::radial ("radial"); -const Identifier DrawableShape::FillAndStrokeState::imageId ("imageId"); -const Identifier DrawableShape::FillAndStrokeState::imageOpacity ("imageOpacity"); - -DrawableShape::FillAndStrokeState::FillAndStrokeState (const ValueTree& state_) - : Drawable::ValueTreeWrapperBase (state_) +DrawableShape::RelativeFillType::RelativeFillType() { } -const FillType DrawableShape::FillAndStrokeState::getMainFill (Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider) const +DrawableShape::RelativeFillType::RelativeFillType (const FillType& fill_) + : fill (fill_) { - return readFillType (state.getChildWithName (fill), 0, 0, 0, nameFinder, imageProvider); + if (fill.isGradient()) + { + const ColourGradient& g = *fill.gradient; + + gradientPoint1 = g.point1.transformedBy (fill.transform); + gradientPoint2 = g.point2.transformedBy (fill.transform); + gradientPoint3 = Point (g.point1.getX() + g.point2.getY() - g.point1.getY(), + g.point1.getY() + g.point1.getX() - g.point2.getX()) + .transformedBy (fill.transform); + fill.transform = AffineTransform::identity; + } } -ValueTree DrawableShape::FillAndStrokeState::getMainFillState() +DrawableShape::RelativeFillType::RelativeFillType (const RelativeFillType& other) + : fill (other.fill), + gradientPoint1 (other.gradientPoint1), + gradientPoint2 (other.gradientPoint2), + gradientPoint3 (other.gradientPoint3) { - ValueTree v (state.getChildWithName (fill)); - if (v.isValid()) - return v; +} - setMainFill (Colours::black, 0, 0, 0, 0, 0); - return getMainFillState(); +DrawableShape::RelativeFillType& DrawableShape::RelativeFillType::operator= (const RelativeFillType& other) +{ + fill = other.fill; + gradientPoint1 = other.gradientPoint1; + gradientPoint2 = other.gradientPoint2; + gradientPoint3 = other.gradientPoint3; + return *this; } -void DrawableShape::FillAndStrokeState::setMainFill (const FillType& newFill, const RelativePoint* gp1, const RelativePoint* gp2, - const RelativePoint* gp3, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) +bool DrawableShape::RelativeFillType::operator== (const RelativeFillType& other) const { - ValueTree v (state.getOrCreateChildWithName (fill, undoManager)); - writeFillType (v, newFill, gp1, gp2, gp3, imageProvider, undoManager); + return fill == other.fill + && ((! fill.isGradient()) + || (gradientPoint1 == other.gradientPoint1 + && gradientPoint2 == other.gradientPoint2 + && gradientPoint3 == other.gradientPoint3)); } -const FillType DrawableShape::FillAndStrokeState::getStrokeFill (Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider) const +bool DrawableShape::RelativeFillType::operator!= (const RelativeFillType& other) const { - return readFillType (state.getChildWithName (stroke), 0, 0, 0, nameFinder, imageProvider); + return ! operator== (other); } -ValueTree DrawableShape::FillAndStrokeState::getStrokeFillState() +bool DrawableShape::RelativeFillType::recalculateCoords (Expression::EvaluationContext* context) { - ValueTree v (state.getChildWithName (stroke)); - if (v.isValid()) - return v; + if (fill.isGradient()) + { + const Point g1 (gradientPoint1.resolve (context)); + const Point g2 (gradientPoint2.resolve (context)); + AffineTransform t; + + ColourGradient& g = *fill.gradient; + + if (g.isRadial) + { + const Point g3 (gradientPoint3.resolve (context)); + const Point g3Source (g1.getX() + g2.getY() - g1.getY(), + g1.getY() + g1.getX() - g2.getX()); + + t = AffineTransform::fromTargetPoints (g1.getX(), g1.getY(), g1.getX(), g1.getY(), + g2.getX(), g2.getY(), g2.getX(), g2.getY(), + g3Source.getX(), g3Source.getY(), g3.getX(), g3.getY()); + } - setStrokeFill (Colours::black, 0, 0, 0, 0, 0); - return getStrokeFillState(); + if (g.point1 != g1 || g.point2 != g2 || fill.transform != t) + { + g.point1 = g1; + g.point2 = g2; + fill.transform = t; + return true; + } + } + + return false; } -void DrawableShape::FillAndStrokeState::setStrokeFill (const FillType& newFill, const RelativePoint* gp1, const RelativePoint* gp2, - const RelativePoint* gp3, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) +bool DrawableShape::RelativeFillType::isDynamic() const { - ValueTree v (state.getOrCreateChildWithName (stroke, undoManager)); - writeFillType (v, newFill, gp1, gp2, gp3, imageProvider, undoManager); + return gradientPoint1.isDynamic() || gradientPoint2.isDynamic() || gradientPoint3.isDynamic(); } -const PathStrokeType DrawableShape::FillAndStrokeState::getStrokeType() const +void DrawableShape::RelativeFillType::writeTo (ValueTree& v, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const { - const String jointStyleString (state [jointStyle].toString()); - const String capStyleString (state [capStyle].toString()); + if (fill.isColour()) + { + v.setProperty (FillAndStrokeState::type, "solid", undoManager); + v.setProperty (FillAndStrokeState::colour, String::toHexString ((int) fill.colour.getARGB()), undoManager); + } + else if (fill.isGradient()) + { + v.setProperty (FillAndStrokeState::type, "gradient", undoManager); + v.setProperty (FillAndStrokeState::gradientPoint1, gradientPoint1.toString(), undoManager); + v.setProperty (FillAndStrokeState::gradientPoint2, gradientPoint2.toString(), undoManager); + v.setProperty (FillAndStrokeState::gradientPoint3, gradientPoint3.toString(), undoManager); - return PathStrokeType (state [strokeWidth], - jointStyleString == "curved" ? PathStrokeType::curved - : (jointStyleString == "bevel" ? PathStrokeType::beveled - : PathStrokeType::mitered), - capStyleString == "square" ? PathStrokeType::square - : (capStyleString == "round" ? PathStrokeType::rounded - : PathStrokeType::butt)); -} + const ColourGradient& cg = *fill.gradient; + v.setProperty (FillAndStrokeState::radial, cg.isRadial, undoManager); -void DrawableShape::FillAndStrokeState::setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager) -{ - state.setProperty (strokeWidth, (double) newStrokeType.getStrokeThickness(), undoManager); - state.setProperty (jointStyle, newStrokeType.getJointStyle() == PathStrokeType::mitered - ? "miter" : (newStrokeType.getJointStyle() == PathStrokeType::curved ? "curved" : "bevel"), undoManager); - state.setProperty (capStyle, newStrokeType.getEndStyle() == PathStrokeType::butt - ? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager); + String s; + for (int i = 0; i < cg.getNumColours(); ++i) + s << ' ' << cg.getColourPosition (i) + << ' ' << String::toHexString ((int) cg.getColour(i).getARGB()); + + v.setProperty (FillAndStrokeState::colours, s.trimStart(), undoManager); + } + else if (fill.isTiledImage()) + { + v.setProperty (FillAndStrokeState::type, "image", undoManager); + + if (imageProvider != 0) + v.setProperty (FillAndStrokeState::imageId, imageProvider->getIdentifierForImage (fill.image), undoManager); + + if (fill.getOpacity() < 1.0f) + v.setProperty (FillAndStrokeState::imageOpacity, fill.getOpacity(), undoManager); + else + v.removeProperty (FillAndStrokeState::imageOpacity, undoManager); + } + else + { + jassertfalse; + } } -const FillType DrawableShape::FillAndStrokeState::readFillType (const ValueTree& v, RelativePoint* const gp1, RelativePoint* const gp2, RelativePoint* const gp3, - Expression::EvaluationContext* const nameFinder, ComponentBuilder::ImageProvider* imageProvider) +bool DrawableShape::RelativeFillType::readFrom (const ValueTree& v, ComponentBuilder::ImageProvider* imageProvider) { - const String newType (v[type].toString()); + const String newType (v [FillAndStrokeState::type].toString()); if (newType == "solid") { - const String colourString (v [colour].toString()); - return FillType (Colour (colourString.isEmpty() ? (uint32) 0xff000000 - : (uint32) colourString.getHexValue32())); + const String colourString (v [FillAndStrokeState::colour].toString()); + fill.setColour (Colour (colourString.isEmpty() ? (uint32) 0xff000000 + : (uint32) colourString.getHexValue32())); + return true; } else if (newType == "gradient") { - RelativePoint p1 (v [gradientPoint1]), p2 (v [gradientPoint2]), p3 (v [gradientPoint3]); - ColourGradient g; - - if (gp1 != 0) *gp1 = p1; - if (gp2 != 0) *gp2 = p2; - if (gp3 != 0) *gp3 = p3; - - g.point1 = p1.resolve (nameFinder); - g.point2 = p2.resolve (nameFinder); - g.isRadial = v[radial]; + g.isRadial = v [FillAndStrokeState::radial]; StringArray colourSteps; - colourSteps.addTokens (v[colours].toString(), false); + colourSteps.addTokens (v [FillAndStrokeState::colours].toString(), false); for (int i = 0; i < colourSteps.size() / 2; ++i) g.addColour (colourSteps[i * 2].getDoubleValue(), Colour ((uint32) colourSteps[i * 2 + 1].getHexValue32())); - FillType fillType (g); - - if (g.isRadial) - { - const Point point3 (p3.resolve (nameFinder)); - const Point point3Source (g.point1.getX() + g.point2.getY() - g.point1.getY(), - g.point1.getY() + g.point1.getX() - g.point2.getX()); - - fillType.transform = AffineTransform::fromTargetPoints (g.point1.getX(), g.point1.getY(), g.point1.getX(), g.point1.getY(), - g.point2.getX(), g.point2.getY(), g.point2.getX(), g.point2.getY(), - point3Source.getX(), point3Source.getY(), point3.getX(), point3.getY()); - } + fill.setGradient (g); - return fillType; + gradientPoint1 = RelativePoint (v [FillAndStrokeState::gradientPoint1]); + gradientPoint2 = RelativePoint (v [FillAndStrokeState::gradientPoint2]); + gradientPoint3 = RelativePoint (v [FillAndStrokeState::gradientPoint3]); + return true; } else if (newType == "image") { Image im; if (imageProvider != 0) - im = imageProvider->getImageForIdentifier (v[imageId]); + im = imageProvider->getImageForIdentifier (v [FillAndStrokeState::imageId]); - FillType f (im, AffineTransform::identity); - f.setOpacity ((float) v.getProperty (imageOpacity, 1.0f)); - return f; + fill.setTiledImage (im, AffineTransform::identity); + fill.setOpacity ((float) v.getProperty (FillAndStrokeState::imageOpacity, 1.0f)); + return true; } - jassert (! v.isValid()); - return FillType(); + jassertfalse; + return false; } -namespace DrawableShapeHelpers +//============================================================================== +const Identifier DrawableShape::FillAndStrokeState::type ("type"); +const Identifier DrawableShape::FillAndStrokeState::colour ("colour"); +const Identifier DrawableShape::FillAndStrokeState::colours ("colours"); +const Identifier DrawableShape::FillAndStrokeState::fill ("Fill"); +const Identifier DrawableShape::FillAndStrokeState::stroke ("Stroke"); +const Identifier DrawableShape::FillAndStrokeState::path ("Path"); +const Identifier DrawableShape::FillAndStrokeState::jointStyle ("jointStyle"); +const Identifier DrawableShape::FillAndStrokeState::capStyle ("capStyle"); +const Identifier DrawableShape::FillAndStrokeState::strokeWidth ("strokeWidth"); +const Identifier DrawableShape::FillAndStrokeState::gradientPoint1 ("point1"); +const Identifier DrawableShape::FillAndStrokeState::gradientPoint2 ("point2"); +const Identifier DrawableShape::FillAndStrokeState::gradientPoint3 ("point3"); +const Identifier DrawableShape::FillAndStrokeState::radial ("radial"); +const Identifier DrawableShape::FillAndStrokeState::imageId ("imageId"); +const Identifier DrawableShape::FillAndStrokeState::imageOpacity ("imageOpacity"); + +DrawableShape::FillAndStrokeState::FillAndStrokeState (const ValueTree& state_) + : Drawable::ValueTreeWrapperBase (state_) { - const Point calcThirdGradientPoint (const FillType& fillType) - { - const ColourGradient& g = *fillType.gradient; - const Point point3Source (g.point1.getX() + g.point2.getY() - g.point1.getY(), - g.point1.getY() + g.point1.getX() - g.point2.getX()); +} - return point3Source.transformedBy (fillType.transform); - } +const DrawableShape::RelativeFillType DrawableShape::FillAndStrokeState::getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider* imageProvider) const +{ + DrawableShape::RelativeFillType f; + f.readFrom (state.getChildWithName (fillOrStrokeType), imageProvider); + return f; } -void DrawableShape::FillAndStrokeState::writeFillType (ValueTree& v, const FillType& fillType, - const RelativePoint* const gp1, const RelativePoint* const gp2, const RelativePoint* gp3, - ComponentBuilder::ImageProvider* imageProvider, UndoManager* const undoManager) +ValueTree DrawableShape::FillAndStrokeState::getFillState (const Identifier& fillOrStrokeType) { - if (fillType.isColour()) - { - v.setProperty (type, "solid", undoManager); - v.setProperty (colour, String::toHexString ((int) fillType.colour.getARGB()), undoManager); - } - else if (fillType.isGradient()) - { - v.setProperty (type, "gradient", undoManager); - v.setProperty (gradientPoint1, gp1 != 0 ? gp1->toString() : fillType.gradient->point1.toString(), undoManager); - v.setProperty (gradientPoint2, gp2 != 0 ? gp2->toString() : fillType.gradient->point2.toString(), undoManager); - v.setProperty (gradientPoint3, gp3 != 0 ? gp3->toString() : DrawableShapeHelpers::calcThirdGradientPoint (fillType).toString(), undoManager); + ValueTree v (state.getChildWithName (fillOrStrokeType)); + if (v.isValid()) + return v; - v.setProperty (radial, fillType.gradient->isRadial, undoManager); + setFill (fillOrStrokeType, FillType (Colours::black), 0, 0); + return getFillState (fillOrStrokeType); +} - String s; - for (int i = 0; i < fillType.gradient->getNumColours(); ++i) - s << ' ' << fillType.gradient->getColourPosition (i) - << ' ' << String::toHexString ((int) fillType.gradient->getColour(i).getARGB()); +void DrawableShape::FillAndStrokeState::setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill, + ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) +{ + ValueTree v (state.getOrCreateChildWithName (fillOrStrokeType, undoManager)); + newFill.writeTo (v, imageProvider, undoManager); +} - v.setProperty (colours, s.trimStart(), undoManager); - } - else if (fillType.isTiledImage()) - { - v.setProperty (type, "image", undoManager); +const PathStrokeType DrawableShape::FillAndStrokeState::getStrokeType() const +{ + const String jointStyleString (state [jointStyle].toString()); + const String capStyleString (state [capStyle].toString()); - if (imageProvider != 0) - v.setProperty (imageId, imageProvider->getIdentifierForImage (fillType.image), undoManager); + return PathStrokeType (state [strokeWidth], + jointStyleString == "curved" ? PathStrokeType::curved + : (jointStyleString == "bevel" ? PathStrokeType::beveled + : PathStrokeType::mitered), + capStyleString == "square" ? PathStrokeType::square + : (capStyleString == "round" ? PathStrokeType::rounded + : PathStrokeType::butt)); +} - if (fillType.getOpacity() < 1.0f) - v.setProperty (imageOpacity, fillType.getOpacity(), undoManager); - else - v.removeProperty (imageOpacity, undoManager); - } - else - { - jassertfalse; - } +void DrawableShape::FillAndStrokeState::setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager) +{ + state.setProperty (strokeWidth, (double) newStrokeType.getStrokeThickness(), undoManager); + state.setProperty (jointStyle, newStrokeType.getJointStyle() == PathStrokeType::mitered + ? "miter" : (newStrokeType.getJointStyle() == PathStrokeType::curved ? "curved" : "bevel"), undoManager); + state.setProperty (capStyle, newStrokeType.getEndStyle() == PathStrokeType::butt + ? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager); } END_JUCE_NAMESPACE diff --git a/src/gui/graphics/drawables/juce_DrawableShape.h b/src/gui/graphics/drawables/juce_DrawableShape.h index f155ae76c6..89193b199a 100644 --- a/src/gui/graphics/drawables/juce_DrawableShape.h +++ b/src/gui/graphics/drawables/juce_DrawableShape.h @@ -29,7 +29,7 @@ #include "juce_Drawable.h" #include "../contexts/juce_FillType.h" #include "../colour/juce_ColourGradient.h" -#include "../../components/positioning/juce_RelativePoint.h" +#include "../../components/positioning/juce_RelativeCoordinatePositioner.h" //============================================================================== @@ -50,6 +50,31 @@ public: /** Destructor. */ ~DrawableShape(); + //============================================================================== + /** A FillType wrapper that allows the gradient coordinates to be implemented using RelativePoint. + */ + class RelativeFillType + { + public: + RelativeFillType(); + RelativeFillType (const FillType& fill); + RelativeFillType (const RelativeFillType&); + RelativeFillType& operator= (const RelativeFillType&); + + bool operator== (const RelativeFillType&) const; + bool operator!= (const RelativeFillType&) const; + + bool isDynamic() const; + bool recalculateCoords (Expression::EvaluationContext* context); + + void writeTo (ValueTree& v, ComponentBuilder::ImageProvider*, UndoManager*) const; + bool readFrom (const ValueTree& v, ComponentBuilder::ImageProvider*); + + //============================================================================== + FillType fill; + RelativePoint gradientPoint1, gradientPoint2, gradientPoint3; + }; + //============================================================================== /** Sets a fill type for the path. This colour is used to fill the path - if you don't want the path to be @@ -60,20 +85,34 @@ public: */ void setFill (const FillType& newFill); + /** Sets a fill type for the path. + This colour is used to fill the path - if you don't want the path to be + filled (e.g. if you're just drawing an outline), set this to a transparent + colour. + + @see setPath, setStrokeFill + */ + void setFill (const RelativeFillType& newFill); + /** Returns the current fill type. @see setFill */ - const FillType& getFill() const throw() { return mainFill; } + const RelativeFillType& getFill() const throw() { return mainFill; } /** Sets the fill type with which the outline will be drawn. @see setFill */ void setStrokeFill (const FillType& newStrokeFill); + /** Sets the fill type with which the outline will be drawn. + @see setFill + */ + void setStrokeFill (const RelativeFillType& newStrokeFill); + /** Returns the current stroke fill. @see setStrokeFill */ - const FillType& getStrokeFill() const throw() { return strokeFill; } + const RelativeFillType& getStrokeFill() const throw() { return strokeFill; } /** Changes the properties of the outline that will be drawn around the path. If the stroke has 0 thickness, no stroke will be drawn. @@ -87,7 +126,7 @@ public: void setStrokeThickness (float newThickness); /** Returns the current outline style. */ - const PathStrokeType& getStrokeType() const throw() { return strokeType; } + const PathStrokeType& getStrokeType() const throw() { return strokeType; } //============================================================================== /** @internal */ @@ -96,32 +135,13 @@ public: public: FillAndStrokeState (const ValueTree& state); - const FillType getMainFill (Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider) const; - ValueTree getMainFillState(); - void setMainFill (const FillType& newFill, const RelativePoint* gradientPoint1, - const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3, - ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager); - - const FillType getStrokeFill (Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider) const; - ValueTree getStrokeFillState(); - void setStrokeFill (const FillType& newFill, const RelativePoint* gradientPoint1, - const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3, - ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager); + ValueTree getFillState (const Identifier& fillOrStrokeType); + const RelativeFillType getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider*) const; + void setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill, + ComponentBuilder::ImageProvider*, UndoManager*); const PathStrokeType getStrokeType() const; - void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager); - - static const FillType readFillType (const ValueTree& v, RelativePoint* gradientPoint1, - RelativePoint* gradientPoint2, RelativePoint* gradientPoint3, - Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider); - - static void writeFillType (ValueTree& v, const FillType& fillType, - const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2, - const RelativePoint* gradientPoint3, ComponentBuilder::ImageProvider* imageProvider, - UndoManager* undoManager); + void setStrokeType (const PathStrokeType& newStrokeType, UndoManager*); static const Identifier type, colour, colours, fill, stroke, path, jointStyle, capStyle, strokeWidth, gradientPoint1, gradientPoint2, gradientPoint3, radial, imageId, imageOpacity; @@ -140,28 +160,24 @@ protected: void pathChanged(); /** Called when the cached stroke should be updated. */ void strokeChanged(); - - /** Implemented by subclasses to regenerate the path. */ - virtual bool rebuildPath (Path& path) const = 0; - /** True if there's a stroke with a non-zero thickness and non-transparent colour. */ bool isStrokeVisible() const throw(); - /** Updates the details from a FillAndStrokeState object, returning true if something changed. */ - bool refreshFillTypes (const FillAndStrokeState& newState, - Expression::EvaluationContext* nameFinder, - ComponentBuilder::ImageProvider* imageProvider); - + void refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider*); /** Writes the stroke and fill details to a FillAndStrokeState object. */ - void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const; - + void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider*, UndoManager*) const; //============================================================================== PathStrokeType strokeType; Path path, strokePath; private: - FillType mainFill, strokeFill; + class RelativePositioner; + RelativeFillType mainFill, strokeFill; + ScopedPointer mainFillPositioner, strokeFillPositioner; + + void setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill, + ScopedPointer& positioner); DrawableShape& operator= (const DrawableShape&); }; diff --git a/src/gui/graphics/drawables/juce_DrawableText.cpp b/src/gui/graphics/drawables/juce_DrawableText.cpp index 658d5048dc..3b3ba6fbf9 100644 --- a/src/gui/graphics/drawables/juce_DrawableText.cpp +++ b/src/gui/graphics/drawables/juce_DrawableText.cpp @@ -57,38 +57,38 @@ DrawableText::~DrawableText() } //============================================================================== -void DrawableText::refreshBounds() -{ - setBoundsToEnclose (getDrawableBounds()); - repaint(); -} - void DrawableText::setText (const String& newText) { - text = newText; - refreshBounds(); + if (text != newText) + { + text = newText; + refreshBounds(); + } } void DrawableText::setColour (const Colour& newColour) { - colour = newColour; - repaint(); + if (colour != newColour) + { + colour = newColour; + repaint(); + } } void DrawableText::setFont (const Font& newFont, bool applySizeAndScale) { - font = newFont; - - if (applySizeAndScale) + if (font != newFont) { - Point corners[3]; - bounds.resolveThreePoints (corners, getParent()); + font = newFont; - setFontSizeControlPoint (RelativePoint (RelativeParallelogram::getPointForInternalCoord (corners, - Point (font.getHorizontalScale() * font.getHeight(), font.getHeight())))); - } + if (applySizeAndScale) + { + setFontSizeControlPoint (RelativePoint (RelativeParallelogram::getPointForInternalCoord (resolvedPoints, + Point (font.getHorizontalScale() * font.getHeight(), font.getHeight())))); + } - refreshBounds(); + refreshBounds(); + } } void DrawableText::setJustification (const Justification& newJustification) @@ -99,47 +99,91 @@ void DrawableText::setJustification (const Justification& newJustification) void DrawableText::setBoundingBox (const RelativeParallelogram& newBounds) { - bounds = newBounds; - refreshBounds(); + if (bounds != newBounds) + { + bounds = newBounds; + refreshBounds(); + } } void DrawableText::setFontSizeControlPoint (const RelativePoint& newPoint) { - fontSizeControlPoint = newPoint; - refreshBounds(); + if (fontSizeControlPoint != newPoint) + { + fontSizeControlPoint = newPoint; + refreshBounds(); + } } -//============================================================================== -void DrawableText::paint (Graphics& g) +void DrawableText::refreshBounds() { - transformContextToCorrectOrigin (g); + if (bounds.isDynamic() || fontSizeControlPoint.isDynamic()) + { + Drawable::Positioner* const p = new Drawable::Positioner (*this); + setPositioner (p); + p->apply(); + } + else + { + setPositioner (0); + recalculateCoordinates (0); + } +} + +bool DrawableText::registerCoordinates (RelativeCoordinatePositionerBase& positioner) +{ + bool ok = positioner.addPoint (bounds.topLeft); + ok = positioner.addPoint (bounds.topRight) && ok; + ok = positioner.addPoint (bounds.bottomLeft) && ok; + return positioner.addPoint (fontSizeControlPoint) && ok; +} - Point points[3]; - bounds.resolveThreePoints (points, getParent()); +void DrawableText::recalculateCoordinates (Expression::EvaluationContext* context) +{ + bounds.resolveThreePoints (resolvedPoints, context); - const float w = Line (points[0], points[1]).getLength(); - const float h = Line (points[0], points[2]).getLength(); + const float w = Line (resolvedPoints[0], resolvedPoints[1]).getLength(); + const float h = Line (resolvedPoints[0], resolvedPoints[2]).getLength(); - const Point fontCoords (bounds.getInternalCoordForPoint (points, fontSizeControlPoint.resolve (getParent()))); + const Point fontCoords (RelativeParallelogram::getInternalCoordForPoint (resolvedPoints, fontSizeControlPoint.resolve (context))); const float fontHeight = jlimit (0.01f, jmax (0.01f, h), fontCoords.getY()); const float fontWidth = jlimit (0.01f, jmax (0.01f, w), fontCoords.getX()); - Font f (font); - f.setHeight (fontHeight); - f.setHorizontalScale (fontWidth / fontHeight); + scaledFont = font; + scaledFont.setHeight (fontHeight); + scaledFont.setHorizontalScale (fontWidth / fontHeight); + + setBoundsToEnclose (getDrawableBounds()); + repaint(); +} + +const AffineTransform DrawableText::getArrangementAndTransform (GlyphArrangement& glyphs) const +{ + const float w = Line (resolvedPoints[0], resolvedPoints[1]).getLength(); + const float h = Line (resolvedPoints[0], resolvedPoints[2]).getLength(); + + glyphs.addFittedText (scaledFont, text, 0, 0, w, h, justification, 0x100000); + + return AffineTransform::fromTargetPoints (0, 0, resolvedPoints[0].getX(), resolvedPoints[0].getY(), + w, 0, resolvedPoints[1].getX(), resolvedPoints[1].getY(), + 0, h, resolvedPoints[2].getX(), resolvedPoints[2].getY()); +} + +//============================================================================== +void DrawableText::paint (Graphics& g) +{ + transformContextToCorrectOrigin (g); g.setColour (colour); GlyphArrangement ga; - ga.addFittedText (f, text, 0, 0, w, h, justification, 0x100000); - ga.draw (g, AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(), - w, 0, points[1].getX(), points[1].getY(), - 0, h, points[2].getX(), points[2].getY())); + const AffineTransform transform (getArrangementAndTransform (ga)); + ga.draw (g, transform); } const Rectangle DrawableText::getDrawableBounds() const { - return bounds.getBounds (getParent()); + return RelativeParallelogram::getBoundingBox (resolvedPoints); } Drawable* DrawableText::createCopy() const @@ -254,7 +298,6 @@ void DrawableText::refreshFromValueTree (const ValueTree& tree, ComponentBuilder if (text != newText || font != newFont || justification != newJustification || colour != newColour || bounds != newBounds || newFontPoint != fontSizeControlPoint) { - repaint(); setBoundingBox (newBounds); setFontSizeControlPoint (newFontPoint); setColour (newColour); diff --git a/src/gui/graphics/drawables/juce_DrawableText.h b/src/gui/graphics/drawables/juce_DrawableText.h index fee6dd477a..0d8e0112c2 100644 --- a/src/gui/graphics/drawables/juce_DrawableText.h +++ b/src/gui/graphics/drawables/juce_DrawableText.h @@ -134,12 +134,17 @@ private: //============================================================================== RelativeParallelogram bounds; RelativePoint fontSizeControlPoint; - Font font; + Point resolvedPoints[3]; + Font font, scaledFont; String text; Colour colour; Justification justification; + friend class Drawable::Positioner; + bool registerCoordinates (RelativeCoordinatePositionerBase&); + void recalculateCoordinates (Expression::EvaluationContext*); void refreshBounds(); + const AffineTransform getArrangementAndTransform (GlyphArrangement& glyphs) const; DrawableText& operator= (const DrawableText&); JUCE_LEAK_DETECTOR (DrawableText); diff --git a/src/gui/graphics/fonts/juce_Font.cpp b/src/gui/graphics/fonts/juce_Font.cpp index 88c72c695b..ff574002e9 100644 --- a/src/gui/graphics/fonts/juce_Font.cpp +++ b/src/gui/graphics/fonts/juce_Font.cpp @@ -72,10 +72,6 @@ public: const Typeface::Ptr findTypefaceFor (const Font& font) { - // (can't initialise defaultFace in the constructor or in getDefaultTypeface() because of recursion). - if (defaultFace == 0) - defaultFace = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (Font()); - const int flags = font.getStyleFlags() & (Font::bold | Font::italic); const String faceName (font.getTypefaceName()); @@ -114,6 +110,9 @@ public: face.typeface = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (font); jassert (face.typeface != 0); // the look and feel must return a typeface! + if (defaultFace == 0 && font == Font()) + defaultFace = face.typeface; + return face.typeface; } diff --git a/src/native/mac/juce_mac_CoreGraphicsContext.mm b/src/native/mac/juce_mac_CoreGraphicsContext.mm index c11c303840..4b42d78f7b 100644 --- a/src/native/mac/juce_mac_CoreGraphicsContext.mm +++ b/src/native/mac/juce_mac_CoreGraphicsContext.mm @@ -90,7 +90,7 @@ public: } } -#if JUCE_MAC + #if JUCE_MAC static NSImage* createNSImage (const Image& image) { const ScopedAutoReleasePool pool; @@ -111,7 +111,7 @@ public: return im; } -#endif + #endif //============================================================================== CGContextRef context; @@ -120,11 +120,11 @@ public: private: static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) { -#if JUCE_BIG_ENDIAN + #if JUCE_BIG_ENDIAN return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) : kCGBitmapByteOrderDefault; -#else + #else return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) : kCGBitmapByteOrderDefault; -#endif + #endif } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImage); @@ -132,11 +132,11 @@ private: Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage) { -#if USE_COREGRAPHICS_RENDERING + #if USE_COREGRAPHICS_RENDERING return new CoreGraphicsImage (format == RGB ? ARGB : format, width, height, clearImage); -#else + #else return createSoftwareImage (format, width, height, clearImage); -#endif + #endif } //============================================================================== @@ -382,16 +382,16 @@ public: { if (replaceExistingContents) { -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 + #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 CGContextClearRect (context, cgRect); -#else - #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + #else + #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 if (CGContextDrawLinearGradient == 0) // (just a way of checking whether we're running in 10.5 or later) CGContextClearRect (context, cgRect); else - #endif + #endif CGContextSetBlendMode (context, kCGBlendModeCopy); -#endif + #endif fillCGRect (cgRect, false); CGContextSetBlendMode (context, kCGBlendModeNormal); @@ -467,16 +467,16 @@ public: if (fillEntireClipAsTiles) { -#if JUCE_IOS + #if JUCE_IOS CGContextDrawTiledImage (context, imageRect, image); -#else - #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + #else + #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 // There's a bug in CGContextDrawTiledImage that makes it incredibly slow // if it's doing a transformation - it's quicker to just draw lots of images manually if (CGContextDrawTiledImage != 0 && transform.isOnlyTranslation()) CGContextDrawTiledImage (context, imageRect, image); else - #endif + #endif { // Fallback to manually doing a tiled fill on 10.4 CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context)); @@ -496,7 +496,7 @@ public: y += ih; } } -#endif + #endif } else { @@ -681,8 +681,7 @@ private: CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient) { - numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable); - --numGradientLookupEntries; + numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable) - 1; CGShadingRef result = 0; CGFunctionRef function = CGFunctionCreate (this, 1, 0, 4, 0, &gradientCallbacks); @@ -803,7 +802,7 @@ const Image juce_loadWithCoreImage (InputStream& input) MemoryBlock data; input.readIntoMemoryBlock (data, -1); -#if JUCE_IOS + #if JUCE_IOS JUCE_AUTORELEASEPOOL UIImage* image = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() length: data.getSize() @@ -813,7 +812,7 @@ const Image juce_loadWithCoreImage (InputStream& input) { CGImageRef loadedImage = image.CGImage; -#else + #else CGDataProviderRef provider = CGDataProviderCreateWithData (0, data.getData(), data.getSize(), 0); CGImageSourceRef imageSource = CGImageSourceCreateWithDataProvider (provider, 0); CGDataProviderRelease (provider); @@ -822,7 +821,7 @@ const Image juce_loadWithCoreImage (InputStream& input) { CGImageRef loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, 0); CFRelease (imageSource); -#endif + #endif if (loadedImage != 0) { @@ -841,9 +840,9 @@ const Image juce_loadWithCoreImage (InputStream& input) CGContextDrawImage (cgImage->context, CGRectMake (0, 0, image.getWidth(), image.getHeight()), loadedImage); CGContextFlush (cgImage->context); -#if ! JUCE_IOS + #if ! JUCE_IOS CFRelease (loadedImage); -#endif + #endif // Because it's impossible to create a truly 24-bit CG image, this flag allows a user // to find out whether the file they just loaded the image from had an alpha channel or not.