Added Justification::appliedToRectangle() and RectanglePlacement::appliedTo(). Removed a behavioural oddity from TopLevelWindow which brought them to the front when made visible. More RelativeRectangle development. AU wrapper now detects app shutdown and closes its UI.tags/2021-05-28
| @@ -7,7 +7,7 @@ | |||
| the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | |||
| and re-saved. | |||
| Created for JUCE version: JUCE v1.52.97 | |||
| Created for JUCE version: JUCE v1.53.8 | |||
| ------------------------------------------------------------------------------ | |||
| @@ -32,10 +32,6 @@ public: | |||
| { | |||
| } | |||
| ~PropertiesWithHelpComponent() | |||
| { | |||
| } | |||
| void rebuildProperties() | |||
| { | |||
| getPanel().clear(); | |||
| @@ -108,16 +104,21 @@ ProjectInformationComponent::ProjectInformationComponent (Project& project_) | |||
| configTabBox (TabbedButtonBar::TabsAtTop) | |||
| { | |||
| addAndMakeVisible (&configTabBox); | |||
| configTabBox.setBounds (RelativeRectangle ("8, 0, this.left + parent.right - 16, this.top + parent.bottom - 36")); | |||
| addAndMakeVisible (&editConfigsButton); | |||
| editConfigsButton.setBounds (RelativeRectangle ("8, parent.bottom - 30, this.left + 192, this.top + 22")); | |||
| editConfigsButton.setButtonText ("Add/Remove Configurations..."); | |||
| editConfigsButton.addListener (this); | |||
| addAndMakeVisible (&openProjectButton); | |||
| openProjectButton.setBounds (RelativeRectangle ("608, parent.bottom - 30, this.left + 208, this.top + 22")); | |||
| openProjectButton.setButtonText ("Open Project in "); | |||
| openProjectButton.addListener (this); | |||
| addAndMakeVisible (&editExportersButton); | |||
| editExportersButton.setBounds (RelativeRectangle ("208, parent.bottom - 30, this.left + 160, this.top + 22")); | |||
| editExportersButton.setButtonText ("Add/Remove Exporters..."); | |||
| editExportersButton.addListener (this); | |||
| addAndMakeVisible (&saveAndOpenButton); | |||
| saveAndOpenButton.setBounds (RelativeRectangle ("391, parent.bottom - 30, this.left + 208, this.top + 22")); | |||
| saveAndOpenButton.setButtonText ("Save And Open in"); | |||
| saveAndOpenButton.addListener (this); | |||
| @@ -136,7 +137,7 @@ ProjectInformationComponent::ProjectInformationComponent (Project& project_) | |||
| #endif | |||
| //[/UserPreSize] | |||
| setSize (859, 479); | |||
| setSize (836, 427); | |||
| //[Constructor] You can add your own custom stuff here.. | |||
| configTabBox.setOutline (1); | |||
| @@ -166,16 +167,7 @@ void ProjectInformationComponent::resized() | |||
| //[Userresized_Pre] | |||
| //[/Userresized_Pre] | |||
| configTabBox.setBounds (Rectangle<int>::leftTopRightBottom (8, 0, (int) ((8.0 + getWidth()) - 16.0), | |||
| (int) ((0.0 + getHeight()) - 36.0))); | |||
| editConfigsButton.setBounds (Rectangle<int>::leftTopRightBottom (8, (int) (getHeight() - 30.0), (int) (8.0 + 192.0), | |||
| (int) (getHeight() - 30.0 + 22.0))); | |||
| openProjectButton.setBounds (Rectangle<int>::leftTopRightBottom (608, (int) (getHeight() - 30.0), (int) (608.0 + 208.0), | |||
| (int) (getHeight() - 30.0 + 22.0))); | |||
| editExportersButton.setBounds (Rectangle<int>::leftTopRightBottom (208, (int) (getHeight() - 30.0), | |||
| (int) (208.0 + 160.0), (int) (getHeight() - 30.0 + 22.0))); | |||
| saveAndOpenButton.setBounds (Rectangle<int>::leftTopRightBottom (391, (int) (getHeight() - 30.0), (int) (391.0 + 208.0), | |||
| (int) (getHeight() - 30.0 + 22.0))); | |||
| //[Userresized_Post] | |||
| //[/Userresized_Post] | |||
| @@ -357,8 +349,8 @@ void ProjectInformationComponent::changeListenerCallback (ChangeBroadcaster*) | |||
| JUCER_COMPONENT_METADATA_START | |||
| <COMPONENT id="tO9EG1a" className="ProjectInformationComponent" width="859" | |||
| height="479" background="f6f9ff" parentClasses="public Component, public ChangeListener" | |||
| <COMPONENT id="tO9EG1a" className="ProjectInformationComponent" width="836" | |||
| height="427" background="f6f9ff" parentClasses="public Component, public ChangeListener" | |||
| constructorParams="Project& project_" memberInitialisers="project (project_)"> | |||
| <COMPONENTS> | |||
| <TABBEDCOMPONENT id="962c1575c4142253" memberName="configTabBox" focusOrder="0" | |||
| @@ -7,7 +7,7 @@ | |||
| the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | |||
| and re-saved. | |||
| Created for JUCE version: JUCE v1.52.97 | |||
| Created for JUCE version: JUCE v1.53.8 | |||
| ------------------------------------------------------------------------------ | |||
| @@ -195,6 +195,11 @@ namespace CodeHelpers | |||
| return CodeHelpers::addEscapeChars (text).quoted(); | |||
| } | |||
| const String stringLiteralIfNotEmpty (const String& text) | |||
| { | |||
| return text.isNotEmpty() ? stringLiteral (text) : String::empty; | |||
| } | |||
| const String boolLiteral (const bool b) | |||
| { | |||
| return b ? "true" : "false"; | |||
| @@ -37,6 +37,7 @@ namespace CodeHelpers | |||
| const String makeHeaderGuardName (const File& file); | |||
| const String stringLiteral (const String& text); | |||
| const String stringLiteralIfNotEmpty (const String& text); // if the string's empty, this returns an empty string | |||
| const String boolLiteral (bool b); | |||
| const String floatLiteral (float v); | |||
| const String doubleLiteral (double v); | |||
| @@ -84,52 +84,3 @@ private: | |||
| Colour colour; | |||
| GlyphArrangement glyphs; | |||
| }; | |||
| //============================================================================== | |||
| class JucerToolbarButton : public ToolbarItemComponent | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| JucerToolbarButton (int itemId_, const String& labelText) | |||
| : ToolbarItemComponent (itemId_, labelText, true) | |||
| { | |||
| setClickingTogglesState (false); | |||
| } | |||
| //============================================================================== | |||
| bool getToolbarItemSizes (int toolbarDepth, bool isToolbarVertical, int& preferredSize, int& minSize, int& maxSize) | |||
| { | |||
| preferredSize = minSize = maxSize = 50; | |||
| return true; | |||
| } | |||
| void paintButton (Graphics& g, bool over, bool down) | |||
| { | |||
| Path p; | |||
| p.addRoundedRectangle (1.5f, 2.5f, getWidth() - 3.0f, getHeight() - 5.0f, 3.0f); | |||
| if (getToggleState()) | |||
| { | |||
| g.setColour (Colours::grey.withAlpha (0.5f)); | |||
| g.fillPath (p); | |||
| } | |||
| g.setColour (Colours::darkgrey.withAlpha (0.3f)); | |||
| g.strokePath (p, PathStrokeType (1.0f)); | |||
| g.setFont (11.0f); | |||
| g.setColour (Colours::black.withAlpha ((over || down) ? 1.0f : 0.7f)); | |||
| g.drawFittedText (getButtonText(), 2, 2, getWidth() - 4, getHeight() - 4, Justification::centred, 2); | |||
| } | |||
| void paintButtonArea (Graphics& g, int width, int height, bool isMouseOver, bool isMouseDown) | |||
| { | |||
| } | |||
| void contentAreaChanged (const Rectangle<int>& newBounds) | |||
| { | |||
| } | |||
| private: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JucerToolbarButton); | |||
| }; | |||
| @@ -109,6 +109,8 @@ class EditorCompHolder; | |||
| withAU: (JuceAU*) au | |||
| withComponent: (AudioProcessorEditor*) editorComp; | |||
| - (void) dealloc; | |||
| - (void) shutdown; | |||
| - (void) applicationWillTerminate: (NSNotification*) aNotification; | |||
| - (void) viewDidMoveToWindow; | |||
| - (BOOL) mouseDownCanMoveWindow; | |||
| - (void) filterBeingDeleted: (JuceAU*) au_; | |||
| @@ -1010,6 +1012,10 @@ public: | |||
| [self setHidden: NO]; | |||
| [self setPostsFrameChangedNotifications: YES]; | |||
| [[NSNotificationCenter defaultCenter] addObserver: self | |||
| selector: @selector (applicationWillTerminate:) | |||
| name: NSApplicationWillTerminateNotification | |||
| object: nil]; | |||
| activeUIs.add (self); | |||
| editorComp->addToDesktop (0, (void*) self); | |||
| @@ -1019,6 +1025,20 @@ public: | |||
| } | |||
| - (void) dealloc | |||
| { | |||
| if (activeUIs.contains (self)) | |||
| [self shutdown]; | |||
| [super dealloc]; | |||
| } | |||
| - (void) applicationWillTerminate: (NSNotification*) aNotification | |||
| { | |||
| (void) aNotification; | |||
| [self shutdown]; | |||
| } | |||
| - (void) shutdown | |||
| { | |||
| // there's some kind of component currently modal, but the host | |||
| // is trying to delete our plugin.. | |||
| @@ -1030,8 +1050,6 @@ public: | |||
| activeUIs.removeValue (self); | |||
| if (activePlugins.size() + activeUIs.size() == 0) | |||
| shutdownJuce_GUI(); | |||
| [super dealloc]; | |||
| } | |||
| - (void) viewDidMoveToWindow | |||
| @@ -4812,7 +4812,7 @@ public: | |||
| class Negate : public Term | |||
| { | |||
| public: | |||
| Negate (const TermPtr& input_) : input (input_) | |||
| explicit Negate (const TermPtr& input_) : input (input_) | |||
| { | |||
| jassert (input_ != 0); | |||
| } | |||
| @@ -4872,7 +4872,6 @@ public: | |||
| } | |||
| Type getType() const throw() { return operatorType; } | |||
| int getNumInputs() const { return 2; } | |||
| Term* getInput (int index) const { return index == 0 ? static_cast<Term*> (left) : (index == 1 ? static_cast<Term*> (right) : 0); } | |||
| @@ -5026,7 +5025,7 @@ public: | |||
| for (int i = topLevel->getNumInputs(); --i >= 0;) | |||
| { | |||
| Term* t = findDestinationFor (topLevel->getInput (i), inputTerm); | |||
| Term* const t = findDestinationFor (topLevel->getInput (i), inputTerm); | |||
| if (t != 0) | |||
| return t; | |||
| @@ -5038,7 +5037,7 @@ public: | |||
| static Constant* findTermToAdjust (Term* const term, const bool mustBeFlagged) | |||
| { | |||
| { | |||
| Constant* c = dynamic_cast<Constant*> (term); | |||
| Constant* const c = dynamic_cast<Constant*> (term); | |||
| if (c != 0 && (c->isResolutionTarget || ! mustBeFlagged)) | |||
| return c; | |||
| } | |||
| @@ -5050,14 +5049,14 @@ public: | |||
| const int numIns = term->getNumInputs(); | |||
| for (i = 0; i < numIns; ++i) | |||
| { | |||
| Constant* c = dynamic_cast<Constant*> (term->getInput (i)); | |||
| Constant* const c = dynamic_cast<Constant*> (term->getInput (i)); | |||
| if (c != 0 && (c->isResolutionTarget || ! mustBeFlagged)) | |||
| return c; | |||
| } | |||
| for (i = 0; i < numIns; ++i) | |||
| { | |||
| Constant* c = findTermToAdjust (term->getInput (i), mustBeFlagged); | |||
| Constant* const c = findTermToAdjust (term->getInput (i), mustBeFlagged); | |||
| if (c != 0) | |||
| return c; | |||
| } | |||
| @@ -5067,7 +5066,7 @@ public: | |||
| static bool containsAnySymbols (const Term* const t) | |||
| { | |||
| if (dynamic_cast <const Symbol*> (t) != 0) | |||
| if (t->getType() == Expression::symbolType) | |||
| return true; | |||
| for (int i = t->getNumInputs(); --i >= 0;) | |||
| @@ -5079,7 +5078,7 @@ public: | |||
| static bool renameSymbol (Term* const t, const String& oldName, const String& newName) | |||
| { | |||
| Symbol* const sym = dynamic_cast <Symbol*> (t); | |||
| Symbol* const sym = dynamic_cast<Symbol*> (t); | |||
| if (sym != 0 && sym->mainSymbol == oldName) | |||
| { | |||
| @@ -5137,13 +5136,13 @@ public: | |||
| return c >= '0' && c <= '9'; | |||
| } | |||
| void skipWhitespace (int& i) | |||
| void skipWhitespace (int& i) throw() | |||
| { | |||
| while (CharacterFunctions::isWhitespace (text [i])) | |||
| ++i; | |||
| } | |||
| bool readChar (const juce_wchar required) | |||
| bool readChar (const juce_wchar required) throw() | |||
| { | |||
| if (text[textIndex] == required) | |||
| { | |||
| @@ -5154,7 +5153,7 @@ public: | |||
| return false; | |||
| } | |||
| bool readOperator (const char* ops, char* const opType = 0) | |||
| bool readOperator (const char* ops, char* const opType = 0) throw() | |||
| { | |||
| skipWhitespace (textIndex); | |||
| @@ -5174,7 +5173,7 @@ public: | |||
| return false; | |||
| } | |||
| bool readIdentifier (String& identifier) | |||
| bool readIdentifier (String& identifier) throw() | |||
| { | |||
| skipWhitespace (textIndex); | |||
| int i = textIndex; | |||
| @@ -5197,7 +5196,7 @@ public: | |||
| return false; | |||
| } | |||
| Term* readNumber() | |||
| Term* readNumber() throw() | |||
| { | |||
| skipWhitespace (textIndex); | |||
| int i = textIndex; | |||
| @@ -5321,7 +5320,7 @@ public: | |||
| { | |||
| if (readOperator ("(")) // method call... | |||
| { | |||
| Function* f = new Function (identifier, ReferenceCountedArray<Term>()); | |||
| Function* const f = new Function (identifier, ReferenceCountedArray<Term>()); | |||
| ScopedPointer<Term> func (f); // (can't use ScopedPointer<Function> in MSVC) | |||
| TermPtr param (readExpression()); | |||
| @@ -5481,7 +5480,7 @@ const Expression Expression::adjustedToGiveNewResult (const double targetValue, | |||
| jassert (termToAdjust != 0); | |||
| const Term* parent = Helpers::findDestinationFor (newTerm, termToAdjust); | |||
| const Term* const parent = Helpers::findDestinationFor (newTerm, termToAdjust); | |||
| if (parent == 0) | |||
| { | |||
| @@ -24896,7 +24895,7 @@ void ResamplingAudioSource::releaseResources() | |||
| void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | |||
| { | |||
| float localRatio; | |||
| double localRatio; | |||
| { | |||
| const ScopedLock sl (ratioLock); | |||
| @@ -40595,10 +40594,12 @@ void Component::setTopRightPosition (const int x, const int y) | |||
| void Component::setBounds (const Rectangle<int>& r) | |||
| { | |||
| setBounds (r.getX(), | |||
| r.getY(), | |||
| r.getWidth(), | |||
| r.getHeight()); | |||
| setBounds (r.getX(), r.getY(), r.getWidth(), r.getHeight()); | |||
| } | |||
| void Component::setBounds (const RelativeRectangle& newBounds) | |||
| { | |||
| newBounds.applyToComponent (*this); | |||
| } | |||
| void Component::setBoundsRelative (const float x, const float y, | |||
| @@ -40675,13 +40676,8 @@ void Component::setBoundsToFit (int x, int y, int width, int height, | |||
| } | |||
| if (newW > 0 && newH > 0) | |||
| { | |||
| int newX, newY; | |||
| justification.applyToRectangle (newX, newY, newW, newH, | |||
| x, y, width, height); | |||
| setBounds (newX, newY, newW, newH); | |||
| } | |||
| setBounds (justification.appliedToRectangle (Rectangle<int> (0, 0, newW, newH), | |||
| Rectangle<int> (x, y, width, height))); | |||
| } | |||
| } | |||
| @@ -79265,12 +79261,6 @@ void TopLevelWindow::parentHierarchyChanged() | |||
| setDropShadowEnabled (useDropShadow); | |||
| } | |||
| void TopLevelWindow::visibilityChanged() | |||
| { | |||
| if (isShowing()) | |||
| toFront (true); | |||
| } | |||
| int TopLevelWindow::getDesktopWindowStyleFlags() const | |||
| { | |||
| int styleFlags = ComponentPeer::windowAppearsOnTaskbar; | |||
| @@ -79642,6 +79632,45 @@ void MarkerList::ValueTreeWrapper::removeMarker (const ValueTree& marker, UndoMa | |||
| state.removeChild (marker, undoManager); | |||
| } | |||
| class MarkerListEvaluator : public Expression::EvaluationContext | |||
| { | |||
| public: | |||
| MarkerListEvaluator (const MarkerList& markerList_, Component* const parentComponent_) | |||
| : markerList (markerList_), parentComponent (parentComponent_) | |||
| { | |||
| } | |||
| const Expression getSymbolValue (const String& objectName, const String& member) const | |||
| { | |||
| if (member.isNotEmpty()) | |||
| { | |||
| const MarkerList::Marker* const marker = markerList.getMarker (objectName); | |||
| if (marker != 0) | |||
| return Expression ((double) marker->position.resolve (this)); | |||
| } | |||
| else if (parentComponent != 0 && objectName == RelativeCoordinate::Strings::parent) | |||
| { | |||
| if (member == RelativeCoordinate::Strings::right) return Expression ((double) parentComponent->getWidth()); | |||
| if (member == RelativeCoordinate::Strings::bottom) return Expression ((double) parentComponent->getHeight()); | |||
| } | |||
| return Expression::EvaluationContext::getSymbolValue (objectName, member); | |||
| } | |||
| private: | |||
| const MarkerList& markerList; | |||
| Component* parentComponent; | |||
| JUCE_DECLARE_NON_COPYABLE (MarkerListEvaluator); | |||
| }; | |||
| double MarkerList::getMarkerPosition (const Marker& marker, Component* const parentComponent) const | |||
| { | |||
| MarkerListEvaluator context (*this, parentComponent); | |||
| return marker.position.resolve (&context); | |||
| } | |||
| void MarkerList::ValueTreeWrapper::applyTo (MarkerList& markerList) | |||
| { | |||
| const int numMarkers = getNumMarkers(); | |||
| @@ -79918,6 +79947,26 @@ namespace RelativeRectangleHelpers | |||
| if (s[i] == ',') | |||
| ++i; | |||
| } | |||
| bool dependsOnSymbolsOtherThanThis (const Expression& e) | |||
| { | |||
| if (e.getType() == Expression::symbolType) | |||
| { | |||
| String objectName, memberName; | |||
| e.getSymbolParts (objectName, memberName); | |||
| if (objectName != RelativeCoordinate::Strings::this_) | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| for (int i = e.getNumInputs(); --i >= 0;) | |||
| if (dependsOnSymbolsOtherThanThis (e.getInput(i))) | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| } | |||
| RelativeRectangle::RelativeRectangle() | |||
| @@ -79930,11 +79979,13 @@ RelativeRectangle::RelativeRectangle (const RelativeCoordinate& left_, const Rel | |||
| { | |||
| } | |||
| RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect, const String& componentName) | |||
| RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect) | |||
| : left (rect.getX()), | |||
| right (Expression::symbol (componentName + "." + RelativeCoordinate::Strings::left) + Expression ((double) rect.getWidth())), | |||
| right (Expression::symbol (RelativeCoordinate::Strings::this_ + "." + RelativeCoordinate::Strings::left) | |||
| + Expression ((double) rect.getWidth())), | |||
| top (rect.getY()), | |||
| bottom (Expression::symbol (componentName + "." + RelativeCoordinate::Strings::top) + Expression ((double) rect.getHeight())) | |||
| bottom (Expression::symbol (RelativeCoordinate::Strings::this_ + "." + RelativeCoordinate::Strings::top) | |||
| + Expression ((double) rect.getHeight())) | |||
| { | |||
| } | |||
| @@ -79980,7 +80031,12 @@ void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Ex | |||
| bool RelativeRectangle::isDynamic() const | |||
| { | |||
| return left.isDynamic() || right.isDynamic() || top.isDynamic() || bottom.isDynamic(); | |||
| using namespace RelativeRectangleHelpers; | |||
| return dependsOnSymbolsOtherThanThis (left.getExpression()) | |||
| || dependsOnSymbolsOtherThanThis (right.getExpression()) | |||
| || dependsOnSymbolsOtherThanThis (top.getExpression()) | |||
| || dependsOnSymbolsOtherThanThis (bottom.getExpression()); | |||
| } | |||
| const String RelativeRectangle::toString() const | |||
| @@ -80040,6 +80096,31 @@ private: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeRectangleComponentPositioner); | |||
| }; | |||
| // An expression context that can evaluate expressions using "this" | |||
| class TemporaryRectangleContext : public Expression::EvaluationContext | |||
| { | |||
| public: | |||
| TemporaryRectangleContext (const RelativeRectangle& rect_) : rect (rect_) {} | |||
| const Expression getSymbolValue (const String& objectName, const String& edge) const | |||
| { | |||
| if (objectName == RelativeCoordinate::Strings::this_) | |||
| { | |||
| if (edge == RelativeCoordinate::Strings::left) return rect.left.getExpression(); | |||
| if (edge == RelativeCoordinate::Strings::right) return rect.right.getExpression(); | |||
| if (edge == RelativeCoordinate::Strings::top) return rect.top.getExpression(); | |||
| if (edge == RelativeCoordinate::Strings::bottom) return rect.bottom.getExpression(); | |||
| } | |||
| return Expression::EvaluationContext::getSymbolValue (objectName, edge); | |||
| } | |||
| private: | |||
| const RelativeRectangle& rect; | |||
| JUCE_DECLARE_NON_COPYABLE (TemporaryRectangleContext); | |||
| }; | |||
| void RelativeRectangle::applyToComponent (Component& component) const | |||
| { | |||
| if (isDynamic()) | |||
| @@ -80057,7 +80138,9 @@ void RelativeRectangle::applyToComponent (Component& component) const | |||
| else | |||
| { | |||
| component.setPositioner (0); | |||
| component.setBounds (resolve (0).getSmallestIntegerContainer()); | |||
| TemporaryRectangleContext context (*this); | |||
| component.setBounds (resolve (&context).getSmallestIntegerContainer()); | |||
| } | |||
| } | |||
| @@ -80496,7 +80579,7 @@ const Expression RelativeCoordinatePositionerBase::getSymbolValue (const String& | |||
| const MarkerList::Marker* const marker = markerList->getMarker (objectName); | |||
| if (marker != 0) | |||
| return marker->position.getExpression(); | |||
| return Expression (markerList->getMarkerPosition (*marker, getComponent().getParentComponent())); | |||
| } | |||
| return Expression::EvaluationContext::getSymbolValue (objectName, member); | |||
| @@ -83256,26 +83339,6 @@ int Justification::getOnlyHorizontalFlags() const throw() | |||
| return flags & (left | right | horizontallyCentred | horizontallyJustified); | |||
| } | |||
| void Justification::applyToRectangle (int& x, int& y, | |||
| const int w, const int h, | |||
| const int spaceX, const int spaceY, | |||
| const int spaceW, const int spaceH) const throw() | |||
| { | |||
| if ((flags & horizontallyCentred) != 0) | |||
| x = spaceX + ((spaceW - w) >> 1); | |||
| else if ((flags & right) != 0) | |||
| x = spaceX + spaceW - w; | |||
| else | |||
| x = spaceX; | |||
| if ((flags & verticallyCentred) != 0) | |||
| y = spaceY + ((spaceH - h) >> 1); | |||
| else if ((flags & bottom) != 0) | |||
| y = spaceY + spaceH - h; | |||
| else | |||
| y = spaceY; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| /*** End of inlined file: juce_Justification.cpp ***/ | |||
| @@ -246157,24 +246220,12 @@ void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle<i | |||
| int normalWidth, normalHeight; | |||
| getMovieNormalSize (normalWidth, normalHeight); | |||
| if (normalWidth > 0 && normalHeight > 0 && ! spaceToFitWithin.isEmpty()) | |||
| { | |||
| double x = 0.0, y = 0.0, w = normalWidth, h = normalHeight; | |||
| placement.applyTo (x, y, w, h, | |||
| spaceToFitWithin.getX(), spaceToFitWithin.getY(), | |||
| spaceToFitWithin.getWidth(), spaceToFitWithin.getHeight()); | |||
| const Rectangle<int> normalSize (0, 0, normalWidth, normalHeight); | |||
| if (w > 0 && h > 0) | |||
| { | |||
| setBounds (roundToInt (x), roundToInt (y), | |||
| roundToInt (w), roundToInt (h)); | |||
| } | |||
| } | |||
| if (! (spaceToFitWithin.isEmpty() || normalSize.isEmpty())) | |||
| setBounds (placement.appliedTo (normalSize, spaceToFitWithin)); | |||
| else | |||
| { | |||
| setBounds (spaceToFitWithin); | |||
| } | |||
| } | |||
| #endif | |||
| @@ -275569,24 +275620,12 @@ void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle<i | |||
| int normalWidth, normalHeight; | |||
| getMovieNormalSize (normalWidth, normalHeight); | |||
| if (normalWidth > 0 && normalHeight > 0 && ! spaceToFitWithin.isEmpty()) | |||
| { | |||
| double x = 0.0, y = 0.0, w = normalWidth, h = normalHeight; | |||
| const Rectangle<int> normalSize (0, 0, normalWidth, normalHeight); | |||
| placement.applyTo (x, y, w, h, | |||
| spaceToFitWithin.getX(), spaceToFitWithin.getY(), | |||
| spaceToFitWithin.getWidth(), spaceToFitWithin.getHeight()); | |||
| if (w > 0 && h > 0) | |||
| { | |||
| setBounds (roundToInt (x), roundToInt (y), | |||
| roundToInt (w), roundToInt (h)); | |||
| } | |||
| } | |||
| if (! (spaceToFitWithin.isEmpty() || normalSize.isEmpty())) | |||
| setBounds (placement.appliedTo (normalSize, spaceToFitWithin)); | |||
| else | |||
| { | |||
| setBounds (spaceToFitWithin); | |||
| } | |||
| } | |||
| #if ! (JUCE_MAC && JUCE_64BIT) | |||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 8 | |||
| #define JUCE_BUILDNUMBER 9 | |||
| /** Current Juce version number. | |||
| @@ -21954,6 +21954,9 @@ public: | |||
| /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ | |||
| void setPosition (const ValueType newX, const ValueType newY) throw() { x = newX; y = newY; } | |||
| /** Returns a rectangle with the same size as this one, but a new position. */ | |||
| const Rectangle withPosition (const ValueType newX, const ValueType newY) const throw() { return Rectangle (newX, newY, w, h); } | |||
| /** Returns a rectangle with the same size as this one, but a new position. */ | |||
| const Rectangle withPosition (const Point<ValueType>& newPos) const throw() { return Rectangle (newPos.getX(), newPos.getY(), w, h); } | |||
| @@ -22584,8 +22587,30 @@ public: | |||
| The (x, y) position of the rectangle will be updated to position it inside the | |||
| given space according to the justification flags. | |||
| */ | |||
| void applyToRectangle (int& x, int& y, int w, int h, | |||
| int spaceX, int spaceY, int spaceW, int spaceH) const throw(); | |||
| template <typename ValueType> | |||
| void applyToRectangle (ValueType& x, ValueType& y, ValueType w, ValueType h, | |||
| ValueType spaceX, ValueType spaceY, ValueType spaceW, ValueType spaceH) const throw() | |||
| { | |||
| x = spaceX; | |||
| if ((flags & horizontallyCentred) != 0) x += (spaceW - w) / (ValueType) 2; | |||
| else if ((flags & right) != 0) x += spaceW - w; | |||
| y = spaceY; | |||
| if ((flags & verticallyCentred) != 0) y += (spaceH - h) / (ValueType) 2; | |||
| else if ((flags & bottom) != 0) y += spaceH - h; | |||
| } | |||
| /** Returns the new position of a rectangle that has been justified to fit within a given space. | |||
| */ | |||
| template <typename ValueType> | |||
| const Rectangle<ValueType> appliedToRectangle (const Rectangle<ValueType>& areaToAdjust, | |||
| const Rectangle<ValueType>& targetSpace) const throw() | |||
| { | |||
| ValueType x = areaToAdjust.getX(), y = areaToAdjust.getY(); | |||
| applyToRectangle (x, y, areaToAdjust.getWidth(), areaToAdjust.getHeight(), | |||
| targetSpace.getX(), targetSpace.getY(), targetSpace.getWidth(), targetSpace.getHeight()); | |||
| return areaToAdjust.withPosition (x, y); | |||
| } | |||
| /** Flag values that can be combined and used in the constructor. */ | |||
| enum | |||
| @@ -25319,6 +25344,20 @@ public: | |||
| double destinationW, | |||
| double destinationH) const throw(); | |||
| /** Returns the transform that should be applied to these source co-ordinates to fit them | |||
| into the destination rectangle using the current flags. | |||
| */ | |||
| template <typename ValueType> | |||
| const Rectangle<ValueType> appliedTo (const Rectangle<ValueType>& source, | |||
| const Rectangle<ValueType>& destination) const throw() | |||
| { | |||
| double x = source.getX(), y = source.getY(), w = source.getWidth(), h = source.getHeight(); | |||
| applyTo (x, y, w, h, static_cast <double> (destination.getX()), static_cast <double> (destination.getY()), | |||
| static_cast <double> (destination.getWidth()), static_cast <double> (destination.getHeight())); | |||
| return Rectangle<ValueType> (static_cast <ValueType> (x), static_cast <ValueType> (y), | |||
| static_cast <ValueType> (w), static_cast <ValueType> (h)); | |||
| } | |||
| /** Returns the transform that should be applied to these source co-ordinates to fit them | |||
| into the destination rectangle using the current flags. | |||
| */ | |||
| @@ -26895,6 +26934,7 @@ class MouseInputSource; | |||
| class MouseInputSourceInternal; | |||
| class ComponentPeer; | |||
| class MarkerList; | |||
| class RelativeRectangle; | |||
| /** | |||
| The base class for all JUCE user-interface objects. | |||
| @@ -27317,6 +27357,53 @@ public: | |||
| */ | |||
| void setBounds (const Rectangle<int>& newBounds); | |||
| /** Changes the component's position and size. | |||
| This is similar to the other setBounds() methods, but uses RelativeRectangle::applyToComponent() | |||
| to set the position, This uses a Component::Positioner to make sure that any dynamic | |||
| expressions are used in the RelativeRectangle will be automatically re-applied to the | |||
| component's bounds when the source values change. See RelativeRectangle::applyToComponent() | |||
| for more details. | |||
| When using relative expressions, the following symbols are available: | |||
| - "this.left", "this.right", "this.top", "this.bottom" refer to the position of those | |||
| edges in this component, so e.g. for a component whose width is always 100, you might | |||
| set the right edge to the "this.left + 100". | |||
| - "parent.left", "parent.right", "parent.top", "parent.bottom" refer to the parent component's | |||
| positions, in its own coordinate space, so "parent.left", "parent.right" are always 0, and | |||
| "parent.top", "parent.bottom" will actually be the width and height of the parent. So | |||
| for example to make your component's right-hand edge always 10 pixels away from its parent's | |||
| right-hand edge, you could set it to "parent.right - 10" | |||
| - "[id].left", "[id].right", "[id].top", "[id].bottom", where [id] is the identifier of one of | |||
| this component's siblings. A component's identifier is set with Component::setComponentID(). | |||
| So for example if you want your component to always be 50 pixels to the right of the one | |||
| called "xyz", you could set your left edge to be "xyz.right + 50" | |||
| - The name of a marker that is defined in the parent component. For markers to be used, the parent | |||
| component must implement its Component::getMarkers() method, and return at least one | |||
| valid MarkerList. So if you want your component's top edge to be 10 pixels below the | |||
| marker called "foobar", you'd set it to "foobar + 10". | |||
| See the Expression class for details about the operators that are supported, but for example | |||
| if you wanted to make your component remain centred within its parent with a size of 100, 100, | |||
| you could express it as: | |||
| @code myComp.setBounds (RelativeBounds ("parent.right / 2 - 50, parent.bottom / 2 - 50, this.left + 100, this.top + 100")); | |||
| @endcode | |||
| ..or an alternative way to achieve the same thing: | |||
| @code myComp.setBounds (RelativeBounds ("this.right - 100, this.bottom - 100, parent.right / 2 + 50, parent.bottom / 2 + 50")); | |||
| @endcode | |||
| Or if you wanted a 100x100 component whose top edge is lined up to a marker called "topMarker" and | |||
| which is positioned 50 pixels to the right of another component called "otherComp", you could write: | |||
| @code myComp.setBounds (RelativeBounds ("otherComp.right + 50, topMarker, this.left + 100, this.top + 100")); | |||
| @endcode | |||
| Be careful not to make your coordinate expressions recursive, though, or exceptions and assertions will | |||
| be thrown! | |||
| @see setBounds, RelativeRectangle::applyToComponent(), Expression | |||
| */ | |||
| void setBounds (const RelativeRectangle& newBounds); | |||
| /** Changes the component's position and size in terms of fractions of its parent's size. | |||
| The values are factors of the parent's size, so for example | |||
| @@ -45533,6 +45620,8 @@ public: | |||
| #ifndef __JUCE_MARKERLIST_JUCEHEADER__ | |||
| #define __JUCE_MARKERLIST_JUCEHEADER__ | |||
| class Component; | |||
| /** | |||
| Holds a set of named marker points along a one-dimensional axis. | |||
| @@ -45564,7 +45653,17 @@ public: | |||
| /** The marker's name. */ | |||
| String name; | |||
| /** The marker's position. */ | |||
| /** The marker's position. | |||
| The expression used to define the coordinate may use the names of other | |||
| markers, so that markers can be linked in arbitrary ways, but be careful | |||
| not to create recursive loops of markers whose positions are based on each | |||
| other! It can also refer to "parent.right" and "parent.bottom" so that you | |||
| can set markers which are relative to the size of the component that contains | |||
| them. | |||
| To resolve the coordinate, you can use the MarkerList::getMarkerPosition() method. | |||
| */ | |||
| RelativeCoordinate position; | |||
| /** Returns true if both the names and positions of these two markers match. */ | |||
| @@ -45584,6 +45683,12 @@ public: | |||
| */ | |||
| const Marker* getMarker (const String& name) const throw(); | |||
| /** Evaluates the given marker and returns its absolute position. | |||
| The parent component must be supplied in case the marker's expression refers to | |||
| the size of its parent component. | |||
| */ | |||
| double getMarkerPosition (const Marker& marker, Component* parentComponent) const; | |||
| /** Sets the position of a marker. | |||
| If the name already exists, then the existing marker is moved; if it doesn't exist, then a | |||
| @@ -45659,7 +45764,7 @@ public: | |||
| private: | |||
| OwnedArray<Marker> markers; | |||
| ListenerList <Listener> listeners; | |||
| ListenerList<Listener> listeners; | |||
| JUCE_LEAK_DETECTOR (MarkerList); | |||
| }; | |||
| @@ -51738,8 +51843,6 @@ protected: | |||
| /** @internal */ | |||
| void parentHierarchyChanged(); | |||
| /** @internal */ | |||
| void visibilityChanged(); | |||
| /** @internal */ | |||
| virtual int getDesktopWindowStyleFlags() const; | |||
| /** @internal */ | |||
| void recreateDesktopWindow(); | |||
| @@ -57949,7 +58052,7 @@ public: | |||
| RelativeRectangle(); | |||
| /** Creates an absolute rectangle, relative to the origin. */ | |||
| explicit RelativeRectangle (const Rectangle<float>& rect, const String& componentName); | |||
| explicit RelativeRectangle (const Rectangle<float>& rect); | |||
| /** Creates a rectangle from four coordinates. */ | |||
| RelativeRectangle (const RelativeCoordinate& left, const RelativeCoordinate& right, | |||
| @@ -57981,7 +58084,9 @@ public: | |||
| */ | |||
| void moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* evaluationContext); | |||
| /** Returns true if this rectangle depends on any other coordinates for its position. */ | |||
| /** Returns true if this rectangle depends on any external symbols for its position. | |||
| Coordinates that refer to symbols based on "this" are assumed not to be dynamic. | |||
| */ | |||
| bool isDynamic() const; | |||
| /** Returns a string which represents this point. | |||
| @@ -88,7 +88,7 @@ void ResamplingAudioSource::releaseResources() | |||
| void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) | |||
| { | |||
| float localRatio; | |||
| double localRatio; | |||
| { | |||
| const ScopedLock sl (ratioLock); | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 53 | |||
| #define JUCE_BUILDNUMBER 8 | |||
| #define JUCE_BUILDNUMBER 9 | |||
| /** Current Juce version number. | |||
| @@ -41,6 +41,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../../core/juce_Time.h" | |||
| #include "../../core/juce_PlatformUtilities.h" | |||
| #include "mouse/juce_MouseInputSource.h" | |||
| #include "positioning/juce_RelativeRectangle.h" | |||
| //============================================================================== | |||
| @@ -1084,10 +1085,12 @@ void Component::setTopRightPosition (const int x, const int y) | |||
| void Component::setBounds (const Rectangle<int>& r) | |||
| { | |||
| setBounds (r.getX(), | |||
| r.getY(), | |||
| r.getWidth(), | |||
| r.getHeight()); | |||
| setBounds (r.getX(), r.getY(), r.getWidth(), r.getHeight()); | |||
| } | |||
| void Component::setBounds (const RelativeRectangle& newBounds) | |||
| { | |||
| newBounds.applyToComponent (*this); | |||
| } | |||
| void Component::setBoundsRelative (const float x, const float y, | |||
| @@ -1164,13 +1167,8 @@ void Component::setBoundsToFit (int x, int y, int width, int height, | |||
| } | |||
| if (newW > 0 && newH > 0) | |||
| { | |||
| int newX, newY; | |||
| justification.applyToRectangle (newX, newY, newW, newH, | |||
| x, y, width, height); | |||
| setBounds (newX, newY, newW, newH); | |||
| } | |||
| setBounds (justification.appliedToRectangle (Rectangle<int> (0, 0, newW, newH), | |||
| Rectangle<int> (x, y, width, height))); | |||
| } | |||
| } | |||
| @@ -48,7 +48,7 @@ class MouseInputSource; | |||
| class MouseInputSourceInternal; | |||
| class ComponentPeer; | |||
| class MarkerList; | |||
| class RelativeRectangle; | |||
| //============================================================================== | |||
| /** | |||
| @@ -479,6 +479,53 @@ public: | |||
| */ | |||
| void setBounds (const Rectangle<int>& newBounds); | |||
| /** Changes the component's position and size. | |||
| This is similar to the other setBounds() methods, but uses RelativeRectangle::applyToComponent() | |||
| to set the position, This uses a Component::Positioner to make sure that any dynamic | |||
| expressions are used in the RelativeRectangle will be automatically re-applied to the | |||
| component's bounds when the source values change. See RelativeRectangle::applyToComponent() | |||
| for more details. | |||
| When using relative expressions, the following symbols are available: | |||
| - "this.left", "this.right", "this.top", "this.bottom" refer to the position of those | |||
| edges in this component, so e.g. for a component whose width is always 100, you might | |||
| set the right edge to the "this.left + 100". | |||
| - "parent.left", "parent.right", "parent.top", "parent.bottom" refer to the parent component's | |||
| positions, in its own coordinate space, so "parent.left", "parent.right" are always 0, and | |||
| "parent.top", "parent.bottom" will actually be the width and height of the parent. So | |||
| for example to make your component's right-hand edge always 10 pixels away from its parent's | |||
| right-hand edge, you could set it to "parent.right - 10" | |||
| - "[id].left", "[id].right", "[id].top", "[id].bottom", where [id] is the identifier of one of | |||
| this component's siblings. A component's identifier is set with Component::setComponentID(). | |||
| So for example if you want your component to always be 50 pixels to the right of the one | |||
| called "xyz", you could set your left edge to be "xyz.right + 50" | |||
| - The name of a marker that is defined in the parent component. For markers to be used, the parent | |||
| component must implement its Component::getMarkers() method, and return at least one | |||
| valid MarkerList. So if you want your component's top edge to be 10 pixels below the | |||
| marker called "foobar", you'd set it to "foobar + 10". | |||
| See the Expression class for details about the operators that are supported, but for example | |||
| if you wanted to make your component remain centred within its parent with a size of 100, 100, | |||
| you could express it as: | |||
| @code myComp.setBounds (RelativeBounds ("parent.right / 2 - 50, parent.bottom / 2 - 50, this.left + 100, this.top + 100")); | |||
| @endcode | |||
| ..or an alternative way to achieve the same thing: | |||
| @code myComp.setBounds (RelativeBounds ("this.right - 100, this.bottom - 100, parent.right / 2 + 50, parent.bottom / 2 + 50")); | |||
| @endcode | |||
| Or if you wanted a 100x100 component whose top edge is lined up to a marker called "topMarker" and | |||
| which is positioned 50 pixels to the right of another component called "otherComp", you could write: | |||
| @code myComp.setBounds (RelativeBounds ("otherComp.right + 50, topMarker, this.left + 100, this.top + 100")); | |||
| @endcode | |||
| Be careful not to make your coordinate expressions recursive, though, or exceptions and assertions will | |||
| be thrown! | |||
| @see setBounds, RelativeRectangle::applyToComponent(), Expression | |||
| */ | |||
| void setBounds (const RelativeRectangle& newBounds); | |||
| /** Changes the component's position and size in terms of fractions of its parent's size. | |||
| The values are factors of the parent's size, so for example | |||
| @@ -28,7 +28,7 @@ | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_MarkerList.h" | |||
| #include "../juce_Component.h" | |||
| //============================================================================== | |||
| MarkerList::MarkerList() | |||
| @@ -246,6 +246,47 @@ void MarkerList::ValueTreeWrapper::removeMarker (const ValueTree& marker, UndoMa | |||
| state.removeChild (marker, undoManager); | |||
| } | |||
| //============================================================================== | |||
| class MarkerListEvaluator : public Expression::EvaluationContext | |||
| { | |||
| public: | |||
| MarkerListEvaluator (const MarkerList& markerList_, Component* const parentComponent_) | |||
| : markerList (markerList_), parentComponent (parentComponent_) | |||
| { | |||
| } | |||
| const Expression getSymbolValue (const String& objectName, const String& member) const | |||
| { | |||
| if (member.isNotEmpty()) | |||
| { | |||
| const MarkerList::Marker* const marker = markerList.getMarker (objectName); | |||
| if (marker != 0) | |||
| return Expression ((double) marker->position.resolve (this)); | |||
| } | |||
| else if (parentComponent != 0 && objectName == RelativeCoordinate::Strings::parent) | |||
| { | |||
| if (member == RelativeCoordinate::Strings::right) return Expression ((double) parentComponent->getWidth()); | |||
| if (member == RelativeCoordinate::Strings::bottom) return Expression ((double) parentComponent->getHeight()); | |||
| } | |||
| return Expression::EvaluationContext::getSymbolValue (objectName, member); | |||
| } | |||
| private: | |||
| const MarkerList& markerList; | |||
| Component* parentComponent; | |||
| JUCE_DECLARE_NON_COPYABLE (MarkerListEvaluator); | |||
| }; | |||
| double MarkerList::getMarkerPosition (const Marker& marker, Component* const parentComponent) const | |||
| { | |||
| MarkerListEvaluator context (*this, parentComponent); | |||
| return marker.position.resolve (&context); | |||
| } | |||
| //============================================================================== | |||
| void MarkerList::ValueTreeWrapper::applyTo (MarkerList& markerList) | |||
| { | |||
| const int numMarkers = getNumMarkers(); | |||
| @@ -28,6 +28,7 @@ | |||
| #include "../../../containers/juce_ValueTree.h" | |||
| #include "../positioning/juce_RelativeCoordinate.h" | |||
| class Component; | |||
| //============================================================================== | |||
| @@ -63,7 +64,17 @@ public: | |||
| /** The marker's name. */ | |||
| String name; | |||
| /** The marker's position. */ | |||
| /** The marker's position. | |||
| The expression used to define the coordinate may use the names of other | |||
| markers, so that markers can be linked in arbitrary ways, but be careful | |||
| not to create recursive loops of markers whose positions are based on each | |||
| other! It can also refer to "parent.right" and "parent.bottom" so that you | |||
| can set markers which are relative to the size of the component that contains | |||
| them. | |||
| To resolve the coordinate, you can use the MarkerList::getMarkerPosition() method. | |||
| */ | |||
| RelativeCoordinate position; | |||
| /** Returns true if both the names and positions of these two markers match. */ | |||
| @@ -84,6 +95,12 @@ public: | |||
| */ | |||
| const Marker* getMarker (const String& name) const throw(); | |||
| /** Evaluates the given marker and returns its absolute position. | |||
| The parent component must be supplied in case the marker's expression refers to | |||
| the size of its parent component. | |||
| */ | |||
| double getMarkerPosition (const Marker& marker, Component* parentComponent) const; | |||
| /** Sets the position of a marker. | |||
| If the name already exists, then the existing marker is moved; if it doesn't exist, then a | |||
| @@ -161,7 +178,7 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| OwnedArray<Marker> markers; | |||
| ListenerList <Listener> listeners; | |||
| ListenerList<Listener> listeners; | |||
| JUCE_LEAK_DETECTOR (MarkerList); | |||
| }; | |||
| @@ -72,7 +72,7 @@ const Expression RelativeCoordinatePositionerBase::getSymbolValue (const String& | |||
| const MarkerList::Marker* const marker = markerList->getMarker (objectName); | |||
| if (marker != 0) | |||
| return marker->position.getExpression(); | |||
| return Expression (markerList->getMarkerPosition (*marker, getComponent().getParentComponent())); | |||
| } | |||
| return Expression::EvaluationContext::getSymbolValue (objectName, member); | |||
| @@ -40,6 +40,26 @@ namespace RelativeRectangleHelpers | |||
| if (s[i] == ',') | |||
| ++i; | |||
| } | |||
| bool dependsOnSymbolsOtherThanThis (const Expression& e) | |||
| { | |||
| if (e.getType() == Expression::symbolType) | |||
| { | |||
| String objectName, memberName; | |||
| e.getSymbolParts (objectName, memberName); | |||
| if (objectName != RelativeCoordinate::Strings::this_) | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| for (int i = e.getNumInputs(); --i >= 0;) | |||
| if (dependsOnSymbolsOtherThanThis (e.getInput(i))) | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| } | |||
| //============================================================================== | |||
| @@ -53,11 +73,13 @@ RelativeRectangle::RelativeRectangle (const RelativeCoordinate& left_, const Rel | |||
| { | |||
| } | |||
| RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect, const String& componentName) | |||
| RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect) | |||
| : left (rect.getX()), | |||
| right (Expression::symbol (componentName + "." + RelativeCoordinate::Strings::left) + Expression ((double) rect.getWidth())), | |||
| right (Expression::symbol (RelativeCoordinate::Strings::this_ + "." + RelativeCoordinate::Strings::left) | |||
| + Expression ((double) rect.getWidth())), | |||
| top (rect.getY()), | |||
| bottom (Expression::symbol (componentName + "." + RelativeCoordinate::Strings::top) + Expression ((double) rect.getHeight())) | |||
| bottom (Expression::symbol (RelativeCoordinate::Strings::this_ + "." + RelativeCoordinate::Strings::top) | |||
| + Expression ((double) rect.getHeight())) | |||
| { | |||
| } | |||
| @@ -103,7 +125,12 @@ void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Ex | |||
| bool RelativeRectangle::isDynamic() const | |||
| { | |||
| return left.isDynamic() || right.isDynamic() || top.isDynamic() || bottom.isDynamic(); | |||
| using namespace RelativeRectangleHelpers; | |||
| return dependsOnSymbolsOtherThanThis (left.getExpression()) | |||
| || dependsOnSymbolsOtherThanThis (right.getExpression()) | |||
| || dependsOnSymbolsOtherThanThis (top.getExpression()) | |||
| || dependsOnSymbolsOtherThanThis (bottom.getExpression()); | |||
| } | |||
| const String RelativeRectangle::toString() const | |||
| @@ -164,6 +191,31 @@ private: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeRectangleComponentPositioner); | |||
| }; | |||
| // An expression context that can evaluate expressions using "this" | |||
| class TemporaryRectangleContext : public Expression::EvaluationContext | |||
| { | |||
| public: | |||
| TemporaryRectangleContext (const RelativeRectangle& rect_) : rect (rect_) {} | |||
| const Expression getSymbolValue (const String& objectName, const String& edge) const | |||
| { | |||
| if (objectName == RelativeCoordinate::Strings::this_) | |||
| { | |||
| if (edge == RelativeCoordinate::Strings::left) return rect.left.getExpression(); | |||
| if (edge == RelativeCoordinate::Strings::right) return rect.right.getExpression(); | |||
| if (edge == RelativeCoordinate::Strings::top) return rect.top.getExpression(); | |||
| if (edge == RelativeCoordinate::Strings::bottom) return rect.bottom.getExpression(); | |||
| } | |||
| return Expression::EvaluationContext::getSymbolValue (objectName, edge); | |||
| } | |||
| private: | |||
| const RelativeRectangle& rect; | |||
| JUCE_DECLARE_NON_COPYABLE (TemporaryRectangleContext); | |||
| }; | |||
| void RelativeRectangle::applyToComponent (Component& component) const | |||
| { | |||
| if (isDynamic()) | |||
| @@ -181,7 +233,9 @@ void RelativeRectangle::applyToComponent (Component& component) const | |||
| else | |||
| { | |||
| component.setPositioner (0); | |||
| component.setBounds (resolve (0).getSmallestIntegerContainer()); | |||
| TemporaryRectangleContext context (*this); | |||
| component.setBounds (resolve (&context).getSmallestIntegerContainer()); | |||
| } | |||
| } | |||
| @@ -45,7 +45,7 @@ public: | |||
| RelativeRectangle(); | |||
| /** Creates an absolute rectangle, relative to the origin. */ | |||
| explicit RelativeRectangle (const Rectangle<float>& rect, const String& componentName); | |||
| explicit RelativeRectangle (const Rectangle<float>& rect); | |||
| /** Creates a rectangle from four coordinates. */ | |||
| RelativeRectangle (const RelativeCoordinate& left, const RelativeCoordinate& right, | |||
| @@ -78,7 +78,9 @@ public: | |||
| */ | |||
| void moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* evaluationContext); | |||
| /** Returns true if this rectangle depends on any other coordinates for its position. */ | |||
| /** Returns true if this rectangle depends on any external symbols for its position. | |||
| Coordinates that refer to symbols based on "this" are assumed not to be dynamic. | |||
| */ | |||
| bool isDynamic() const; | |||
| /** Returns a string which represents this point. | |||
| @@ -192,12 +192,6 @@ void TopLevelWindow::parentHierarchyChanged() | |||
| setDropShadowEnabled (useDropShadow); | |||
| } | |||
| void TopLevelWindow::visibilityChanged() | |||
| { | |||
| if (isShowing()) | |||
| toFront (true); | |||
| } | |||
| int TopLevelWindow::getDesktopWindowStyleFlags() const | |||
| { | |||
| int styleFlags = ComponentPeer::windowAppearsOnTaskbar; | |||
| @@ -148,8 +148,6 @@ protected: | |||
| /** @internal */ | |||
| void parentHierarchyChanged(); | |||
| /** @internal */ | |||
| void visibilityChanged(); | |||
| /** @internal */ | |||
| virtual int getDesktopWindowStyleFlags() const; | |||
| /** @internal */ | |||
| void recreateDesktopWindow(); | |||
| @@ -52,24 +52,5 @@ int Justification::getOnlyHorizontalFlags() const throw() | |||
| return flags & (left | right | horizontallyCentred | horizontallyJustified); | |||
| } | |||
| void Justification::applyToRectangle (int& x, int& y, | |||
| const int w, const int h, | |||
| const int spaceX, const int spaceY, | |||
| const int spaceW, const int spaceH) const throw() | |||
| { | |||
| if ((flags & horizontallyCentred) != 0) | |||
| x = spaceX + ((spaceW - w) >> 1); | |||
| else if ((flags & right) != 0) | |||
| x = spaceX + spaceW - w; | |||
| else | |||
| x = spaceX; | |||
| if ((flags & verticallyCentred) != 0) | |||
| y = spaceY + ((spaceH - h) >> 1); | |||
| else if ((flags & bottom) != 0) | |||
| y = spaceY + spaceH - h; | |||
| else | |||
| y = spaceY; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -26,6 +26,8 @@ | |||
| #ifndef __JUCE_JUSTIFICATION_JUCEHEADER__ | |||
| #define __JUCE_JUSTIFICATION_JUCEHEADER__ | |||
| #include "../geometry/juce_Rectangle.h" | |||
| //============================================================================== | |||
| /** | |||
| @@ -74,9 +76,30 @@ public: | |||
| The (x, y) position of the rectangle will be updated to position it inside the | |||
| given space according to the justification flags. | |||
| */ | |||
| void applyToRectangle (int& x, int& y, int w, int h, | |||
| int spaceX, int spaceY, int spaceW, int spaceH) const throw(); | |||
| template <typename ValueType> | |||
| void applyToRectangle (ValueType& x, ValueType& y, ValueType w, ValueType h, | |||
| ValueType spaceX, ValueType spaceY, ValueType spaceW, ValueType spaceH) const throw() | |||
| { | |||
| x = spaceX; | |||
| if ((flags & horizontallyCentred) != 0) x += (spaceW - w) / (ValueType) 2; | |||
| else if ((flags & right) != 0) x += spaceW - w; | |||
| y = spaceY; | |||
| if ((flags & verticallyCentred) != 0) y += (spaceH - h) / (ValueType) 2; | |||
| else if ((flags & bottom) != 0) y += spaceH - h; | |||
| } | |||
| /** Returns the new position of a rectangle that has been justified to fit within a given space. | |||
| */ | |||
| template <typename ValueType> | |||
| const Rectangle<ValueType> appliedToRectangle (const Rectangle<ValueType>& areaToAdjust, | |||
| const Rectangle<ValueType>& targetSpace) const throw() | |||
| { | |||
| ValueType x = areaToAdjust.getX(), y = areaToAdjust.getY(); | |||
| applyToRectangle (x, y, areaToAdjust.getWidth(), areaToAdjust.getHeight(), | |||
| targetSpace.getX(), targetSpace.getY(), targetSpace.getWidth(), targetSpace.getHeight()); | |||
| return areaToAdjust.withPosition (x, y); | |||
| } | |||
| //============================================================================== | |||
| /** Flag values that can be combined and used in the constructor. */ | |||
| @@ -141,12 +141,27 @@ public: | |||
| double destinationW, | |||
| double destinationH) const throw(); | |||
| /** Returns the transform that should be applied to these source co-ordinates to fit them | |||
| into the destination rectangle using the current flags. | |||
| */ | |||
| template <typename ValueType> | |||
| const Rectangle<ValueType> appliedTo (const Rectangle<ValueType>& source, | |||
| const Rectangle<ValueType>& destination) const throw() | |||
| { | |||
| double x = source.getX(), y = source.getY(), w = source.getWidth(), h = source.getHeight(); | |||
| applyTo (x, y, w, h, static_cast <double> (destination.getX()), static_cast <double> (destination.getY()), | |||
| static_cast <double> (destination.getWidth()), static_cast <double> (destination.getHeight())); | |||
| return Rectangle<ValueType> (static_cast <ValueType> (x), static_cast <ValueType> (y), | |||
| static_cast <ValueType> (w), static_cast <ValueType> (h)); | |||
| } | |||
| /** Returns the transform that should be applied to these source co-ordinates to fit them | |||
| into the destination rectangle using the current flags. | |||
| */ | |||
| const AffineTransform getTransformToFit (const Rectangle<float>& source, | |||
| const Rectangle<float>& destination) const throw(); | |||
| private: | |||
| //============================================================================== | |||
| int flags; | |||
| @@ -149,6 +149,9 @@ public: | |||
| /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ | |||
| void setPosition (const ValueType newX, const ValueType newY) throw() { x = newX; y = newY; } | |||
| /** Returns a rectangle with the same size as this one, but a new position. */ | |||
| const Rectangle withPosition (const ValueType newX, const ValueType newY) const throw() { return Rectangle (newX, newY, w, h); } | |||
| /** Returns a rectangle with the same size as this one, but a new position. */ | |||
| const Rectangle withPosition (const Point<ValueType>& newPos) const throw() { return Rectangle (newPos.getX(), newPos.getY(), w, h); } | |||
| @@ -196,7 +196,7 @@ public: | |||
| class Negate : public Term | |||
| { | |||
| public: | |||
| Negate (const TermPtr& input_) : input (input_) | |||
| explicit Negate (const TermPtr& input_) : input (input_) | |||
| { | |||
| jassert (input_ != 0); | |||
| } | |||
| @@ -257,7 +257,6 @@ public: | |||
| } | |||
| Type getType() const throw() { return operatorType; } | |||
| int getNumInputs() const { return 2; } | |||
| Term* getInput (int index) const { return index == 0 ? static_cast<Term*> (left) : (index == 1 ? static_cast<Term*> (right) : 0); } | |||
| @@ -416,7 +415,7 @@ public: | |||
| for (int i = topLevel->getNumInputs(); --i >= 0;) | |||
| { | |||
| Term* t = findDestinationFor (topLevel->getInput (i), inputTerm); | |||
| Term* const t = findDestinationFor (topLevel->getInput (i), inputTerm); | |||
| if (t != 0) | |||
| return t; | |||
| @@ -428,7 +427,7 @@ public: | |||
| static Constant* findTermToAdjust (Term* const term, const bool mustBeFlagged) | |||
| { | |||
| { | |||
| Constant* c = dynamic_cast<Constant*> (term); | |||
| Constant* const c = dynamic_cast<Constant*> (term); | |||
| if (c != 0 && (c->isResolutionTarget || ! mustBeFlagged)) | |||
| return c; | |||
| } | |||
| @@ -440,14 +439,14 @@ public: | |||
| const int numIns = term->getNumInputs(); | |||
| for (i = 0; i < numIns; ++i) | |||
| { | |||
| Constant* c = dynamic_cast<Constant*> (term->getInput (i)); | |||
| Constant* const c = dynamic_cast<Constant*> (term->getInput (i)); | |||
| if (c != 0 && (c->isResolutionTarget || ! mustBeFlagged)) | |||
| return c; | |||
| } | |||
| for (i = 0; i < numIns; ++i) | |||
| { | |||
| Constant* c = findTermToAdjust (term->getInput (i), mustBeFlagged); | |||
| Constant* const c = findTermToAdjust (term->getInput (i), mustBeFlagged); | |||
| if (c != 0) | |||
| return c; | |||
| } | |||
| @@ -457,7 +456,7 @@ public: | |||
| static bool containsAnySymbols (const Term* const t) | |||
| { | |||
| if (dynamic_cast <const Symbol*> (t) != 0) | |||
| if (t->getType() == Expression::symbolType) | |||
| return true; | |||
| for (int i = t->getNumInputs(); --i >= 0;) | |||
| @@ -469,7 +468,7 @@ public: | |||
| static bool renameSymbol (Term* const t, const String& oldName, const String& newName) | |||
| { | |||
| Symbol* const sym = dynamic_cast <Symbol*> (t); | |||
| Symbol* const sym = dynamic_cast<Symbol*> (t); | |||
| if (sym != 0 && sym->mainSymbol == oldName) | |||
| { | |||
| @@ -529,13 +528,13 @@ public: | |||
| return c >= '0' && c <= '9'; | |||
| } | |||
| void skipWhitespace (int& i) | |||
| void skipWhitespace (int& i) throw() | |||
| { | |||
| while (CharacterFunctions::isWhitespace (text [i])) | |||
| ++i; | |||
| } | |||
| bool readChar (const juce_wchar required) | |||
| bool readChar (const juce_wchar required) throw() | |||
| { | |||
| if (text[textIndex] == required) | |||
| { | |||
| @@ -546,7 +545,7 @@ public: | |||
| return false; | |||
| } | |||
| bool readOperator (const char* ops, char* const opType = 0) | |||
| bool readOperator (const char* ops, char* const opType = 0) throw() | |||
| { | |||
| skipWhitespace (textIndex); | |||
| @@ -566,7 +565,7 @@ public: | |||
| return false; | |||
| } | |||
| bool readIdentifier (String& identifier) | |||
| bool readIdentifier (String& identifier) throw() | |||
| { | |||
| skipWhitespace (textIndex); | |||
| int i = textIndex; | |||
| @@ -589,7 +588,7 @@ public: | |||
| return false; | |||
| } | |||
| Term* readNumber() | |||
| Term* readNumber() throw() | |||
| { | |||
| skipWhitespace (textIndex); | |||
| int i = textIndex; | |||
| @@ -713,7 +712,7 @@ public: | |||
| { | |||
| if (readOperator ("(")) // method call... | |||
| { | |||
| Function* f = new Function (identifier, ReferenceCountedArray<Term>()); | |||
| Function* const f = new Function (identifier, ReferenceCountedArray<Term>()); | |||
| ScopedPointer<Term> func (f); // (can't use ScopedPointer<Function> in MSVC) | |||
| TermPtr param (readExpression()); | |||
| @@ -874,7 +873,7 @@ const Expression Expression::adjustedToGiveNewResult (const double targetValue, | |||
| jassert (termToAdjust != 0); | |||
| const Term* parent = Helpers::findDestinationFor (newTerm, termToAdjust); | |||
| const Term* const parent = Helpers::findDestinationFor (newTerm, termToAdjust); | |||
| if (parent == 0) | |||
| { | |||
| @@ -324,24 +324,12 @@ void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle<i | |||
| int normalWidth, normalHeight; | |||
| getMovieNormalSize (normalWidth, normalHeight); | |||
| if (normalWidth > 0 && normalHeight > 0 && ! spaceToFitWithin.isEmpty()) | |||
| { | |||
| double x = 0.0, y = 0.0, w = normalWidth, h = normalHeight; | |||
| placement.applyTo (x, y, w, h, | |||
| spaceToFitWithin.getX(), spaceToFitWithin.getY(), | |||
| spaceToFitWithin.getWidth(), spaceToFitWithin.getHeight()); | |||
| const Rectangle<int> normalSize (0, 0, normalWidth, normalHeight); | |||
| if (w > 0 && h > 0) | |||
| { | |||
| setBounds (roundToInt (x), roundToInt (y), | |||
| roundToInt (w), roundToInt (h)); | |||
| } | |||
| } | |||
| if (! (spaceToFitWithin.isEmpty() || normalSize.isEmpty())) | |||
| setBounds (placement.appliedTo (normalSize, spaceToFitWithin)); | |||
| else | |||
| { | |||
| setBounds (spaceToFitWithin); | |||
| } | |||
| } | |||
| @@ -478,24 +478,12 @@ void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle<i | |||
| int normalWidth, normalHeight; | |||
| getMovieNormalSize (normalWidth, normalHeight); | |||
| if (normalWidth > 0 && normalHeight > 0 && ! spaceToFitWithin.isEmpty()) | |||
| { | |||
| double x = 0.0, y = 0.0, w = normalWidth, h = normalHeight; | |||
| placement.applyTo (x, y, w, h, | |||
| spaceToFitWithin.getX(), spaceToFitWithin.getY(), | |||
| spaceToFitWithin.getWidth(), spaceToFitWithin.getHeight()); | |||
| const Rectangle<int> normalSize (0, 0, normalWidth, normalHeight); | |||
| if (w > 0 && h > 0) | |||
| { | |||
| setBounds (roundToInt (x), roundToInt (y), | |||
| roundToInt (w), roundToInt (h)); | |||
| } | |||
| } | |||
| if (! (spaceToFitWithin.isEmpty() || normalSize.isEmpty())) | |||
| setBounds (placement.appliedTo (normalSize, spaceToFitWithin)); | |||
| else | |||
| { | |||
| setBounds (spaceToFitWithin); | |||
| } | |||
| } | |||
| #endif | |||