| @@ -333,11 +333,8 @@ void RelativeRectangleLayoutManager::applyLayout() | |||
| } | |||
| } | |||
| const Expression RelativeRectangleLayoutManager::getSymbolValue (const String& symbol) const | |||
| const Expression RelativeRectangleLayoutManager::getSymbolValue (const String& objectName, const String& edge) const | |||
| { | |||
| const String objectName (symbol.upToFirstOccurrenceOf (".", false, false).trim()); | |||
| const String edge (symbol.fromFirstOccurrenceOf (".", false, false).trim()); | |||
| if (objectName == RelativeCoordinate::Strings::parent) | |||
| { | |||
| if (edge == RelativeCoordinate::Strings::right) return Expression ((double) parent->getWidth()); | |||
| @@ -169,7 +169,7 @@ public: | |||
| //============================================================================== | |||
| /** @internal */ | |||
| const Expression getSymbolValue (const String& symbol) const; | |||
| const Expression getSymbolValue (const String& symbol, const String& member) const; | |||
| /** @internal */ | |||
| void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); | |||
| /** @internal */ | |||
| @@ -4632,7 +4632,15 @@ public: | |||
| class Symbol : public Term | |||
| { | |||
| public: | |||
| Symbol (const String& symbol_) : symbol (symbol_) {} | |||
| explicit Symbol (const String& symbol_) | |||
| : mainSymbol (symbol_.upToFirstOccurrenceOf (".", false, false).trim()), | |||
| member (symbol_.fromFirstOccurrenceOf (".", false, false).trim()) | |||
| {} | |||
| Symbol (const String& symbol_, const String& member_) | |||
| : mainSymbol (symbol_), | |||
| member (member_) | |||
| {} | |||
| double evaluate (const EvaluationContext& c, int recursionDepth) const | |||
| { | |||
| @@ -4641,7 +4649,7 @@ public: | |||
| try | |||
| { | |||
| return c.getSymbolValue (symbol).term->evaluate (c, recursionDepth); | |||
| return c.getSymbolValue (mainSymbol, member).term->evaluate (c, recursionDepth); | |||
| } | |||
| catch (...) | |||
| {} | |||
| @@ -4649,23 +4657,35 @@ public: | |||
| return 0; | |||
| } | |||
| Term* clone() const { return new Symbol (symbol); } | |||
| Term* clone() const { return new Symbol (mainSymbol, member); } | |||
| int getNumInputs() const { return 0; } | |||
| Term* getInput (int) const { return 0; } | |||
| const String toString() const { return symbol; } | |||
| const String toString() const | |||
| { | |||
| return member.isEmpty() ? mainSymbol | |||
| : mainSymbol + "." + member; | |||
| } | |||
| bool referencesSymbol (const String& s, const EvaluationContext& c, int recursionDepth) const | |||
| { | |||
| if (s == symbol) | |||
| if (s == mainSymbol) | |||
| return true; | |||
| if (++recursionDepth > 256) | |||
| throw EvaluationError ("Recursive symbol references"); | |||
| return c.getSymbolValue (symbol).term->referencesSymbol (s, c, recursionDepth); | |||
| try | |||
| { | |||
| return c.getSymbolValue (mainSymbol, member).term->referencesSymbol (s, c, recursionDepth); | |||
| } | |||
| catch (EvaluationError&) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| String symbol; | |||
| String mainSymbol, member; | |||
| }; | |||
| class Function : public Term | |||
| @@ -4937,6 +4957,9 @@ public: | |||
| if (c != 0 && (c->isResolutionTarget || ! mustBeFlagged)) | |||
| return c; | |||
| if (dynamic_cast<Function*> (term) != 0) | |||
| return 0; | |||
| int i; | |||
| const int numIns = term->getNumInputs(); | |||
| for (i = 0; i < numIns; ++i) | |||
| @@ -4970,20 +4993,12 @@ public: | |||
| static bool renameSymbol (Term* const t, const String& oldName, const String& newName) | |||
| { | |||
| Symbol* sym = dynamic_cast <Symbol*> (t); | |||
| Symbol* const sym = dynamic_cast <Symbol*> (t); | |||
| if (sym != 0) | |||
| if (sym != 0 && sym->mainSymbol == oldName) | |||
| { | |||
| if (sym->symbol == oldName) | |||
| { | |||
| sym->symbol = newName; | |||
| return true; | |||
| } | |||
| else if (sym->symbol.startsWith (oldName + ".")) | |||
| { | |||
| sym->symbol = newName + "." + sym->symbol.substring (0, oldName.length() + 1); | |||
| return true; | |||
| } | |||
| sym->mainSymbol = newName; | |||
| return true; | |||
| } | |||
| bool anyChanged = false; | |||
| @@ -5109,6 +5124,12 @@ public: | |||
| textIndex = i; | |||
| } | |||
| if (text[i] == '-') | |||
| { | |||
| ++i; | |||
| skipWhitespace (i); | |||
| } | |||
| int numDigits = 0; | |||
| while (isDecimalDigit (text[i])) | |||
| @@ -5154,9 +5175,9 @@ public: | |||
| return 0; | |||
| } | |||
| Constant* t = new Constant (String (text + textIndex, i - textIndex).getDoubleValue(), isResolutionTarget); | |||
| const int start = textIndex; | |||
| textIndex = i; | |||
| return t; | |||
| return new Constant (String (text + start, i - start).getDoubleValue(), isResolutionTarget); | |||
| } | |||
| const TermPtr readMultiplyOrDivideExpression() | |||
| @@ -5386,7 +5407,7 @@ const Expression Expression::adjustedToGiveNewResult (const double targetValue, | |||
| const Helpers::TermPtr reverseTerm (parent->createTermToEvaluateInput (context, termToAdjust, targetValue, newTerm)); | |||
| if (reverseTerm == 0) | |||
| return Expression(); | |||
| return Expression (targetValue); | |||
| termToAdjust->value = reverseTerm->evaluate (context, 0); | |||
| } | |||
| @@ -5396,7 +5417,7 @@ const Expression Expression::adjustedToGiveNewResult (const double targetValue, | |||
| const Expression Expression::withRenamedSymbol (const String& oldSymbol, const String& newSymbol) const | |||
| { | |||
| jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
| jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_")); | |||
| Expression newExpression (term->clone()); | |||
| Helpers::renameSymbol (newExpression.term, oldSymbol, newSymbol); | |||
| @@ -5454,9 +5475,9 @@ Expression::EvaluationError::EvaluationError (const String& message) | |||
| Expression::EvaluationContext::EvaluationContext() {} | |||
| Expression::EvaluationContext::~EvaluationContext() {} | |||
| const Expression Expression::EvaluationContext::getSymbolValue (const String& symbol) const | |||
| const Expression Expression::EvaluationContext::getSymbolValue (const String& symbol, const String& member) const | |||
| { | |||
| throw EvaluationError ("Unknown symbol: \"" + symbol + "\""); | |||
| throw EvaluationError ("Unknown symbol: \"" + symbol + (member.isEmpty() ? "\"" : ("." + member + "\""))); | |||
| } | |||
| double Expression::EvaluationContext::evaluateFunction (const String& functionName, const double* parameters, int numParams) const | |||
| @@ -19550,8 +19571,6 @@ FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool w | |||
| if (fc.browseForFileToSave (warnAboutOverwritingExistingFiles)) | |||
| { | |||
| setLastDocumentOpened (fc.getResult()); | |||
| File chosen (fc.getResult()); | |||
| if (chosen.getFileExtension().isEmpty()) | |||
| { | |||
| @@ -19572,6 +19591,7 @@ FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool w | |||
| } | |||
| } | |||
| setLastDocumentOpened (chosen); | |||
| return saveAs (chosen, false, false, true); | |||
| } | |||
| @@ -57322,6 +57342,17 @@ void TreeViewItem::paintRecursively (Graphics& g, int width) | |||
| const int indent = getIndentX(); | |||
| const int itemW = itemWidth < 0 ? width - indent : itemWidth; | |||
| { | |||
| g.saveState(); | |||
| g.setOrigin (indent, 0); | |||
| if (g.reduceClipRegion (drawsInLeftMargin ? -indent : 0, 0, | |||
| drawsInLeftMargin ? itemW + indent : itemW, itemHeight)) | |||
| paintItem (g, itemW, itemHeight); | |||
| g.restoreState(); | |||
| } | |||
| g.setColour (ownerView->findColour (TreeView::linesColourId)); | |||
| const float halfH = itemHeight * 0.5f; | |||
| @@ -57383,17 +57414,6 @@ void TreeViewItem::paintRecursively (Graphics& g, int width) | |||
| } | |||
| } | |||
| { | |||
| g.saveState(); | |||
| g.setOrigin (indent, 0); | |||
| if (g.reduceClipRegion (drawsInLeftMargin ? -indent : 0, 0, | |||
| drawsInLeftMargin ? itemW + indent : itemW, itemHeight)) | |||
| paintItem (g, itemW, itemHeight); | |||
| g.restoreState(); | |||
| } | |||
| if (isOpen()) | |||
| { | |||
| const Rectangle<int> clip (g.getClipBounds()); | |||
| @@ -79785,7 +79805,7 @@ const String RelativeCoordinate::toString() const | |||
| void RelativeCoordinate::renameSymbolIfUsed (const String& oldName, const String& newName, | |||
| const Expression::EvaluationContext* context) | |||
| { | |||
| jassert (newName.isNotEmpty() && newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
| jassert (newName.isNotEmpty() && newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_")); | |||
| if (term.referencesSymbol (oldName, *context)) | |||
| { | |||
| @@ -86144,9 +86164,9 @@ void DrawableComposite::render (const Drawable::RenderingContext& context) const | |||
| } | |||
| } | |||
| const Expression DrawableComposite::getSymbolValue (const String& symbol) const | |||
| const Expression DrawableComposite::getSymbolValue (const String& symbol, const String& member) const | |||
| { | |||
| jassert (! symbol.containsChar ('.')) // the only symbols available in a Drawable are markers. | |||
| jassert (member.isEmpty()) // the only symbols available in a Drawable are markers. | |||
| int i; | |||
| for (i = 0; i < markersX.size(); ++i) | |||
| @@ -86163,7 +86183,7 @@ const Expression DrawableComposite::getSymbolValue (const String& symbol) const | |||
| return m->position.getExpression(); | |||
| } | |||
| return Expression::EvaluationContext::getSymbolValue (symbol); | |||
| return Expression::EvaluationContext::getSymbolValue (symbol, member); | |||
| } | |||
| const Rectangle<float> DrawableComposite::getUntransformedBounds (const bool includeMarkers) const | |||
| @@ -64,7 +64,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 52 | |||
| #define JUCE_BUILDNUMBER 53 | |||
| #define JUCE_BUILDNUMBER 54 | |||
| /** Current Juce version number. | |||
| @@ -6630,9 +6630,11 @@ public: | |||
| /** Returns the value of a symbol. | |||
| If the symbol is unknown, this can throw an Expression::EvaluationError exception. | |||
| The member value is set to the part of the symbol that followed the dot, if there is | |||
| one, e.g. for "foo.bar", symbol = "foo" and member = "bar". | |||
| @throws Expression::EvaluationError | |||
| */ | |||
| virtual const Expression getSymbolValue (const String& symbol) const; | |||
| virtual const Expression getSymbolValue (const String& symbol, const String& member) const; | |||
| /** Executes a named function. | |||
| If the function name is unknown, this can throw an Expression::EvaluationError exception. | |||
| @@ -59306,7 +59308,7 @@ public: | |||
| /** @internal */ | |||
| const Identifier getValueTreeType() const { return valueTreeType; } | |||
| /** @internal */ | |||
| const Expression getSymbolValue (const String& symbol) const; | |||
| const Expression getSymbolValue (const String& symbol, const String& member) const; | |||
| /** Internally-used class for wrapping a DrawableComposite's state into a ValueTree. */ | |||
| class ValueTreeWrapper : public ValueTreeWrapperBase | |||
| @@ -70,7 +70,15 @@ public: | |||
| class Symbol : public Term | |||
| { | |||
| public: | |||
| Symbol (const String& symbol_) : symbol (symbol_) {} | |||
| explicit Symbol (const String& symbol_) | |||
| : mainSymbol (symbol_.upToFirstOccurrenceOf (".", false, false).trim()), | |||
| member (symbol_.fromFirstOccurrenceOf (".", false, false).trim()) | |||
| {} | |||
| Symbol (const String& symbol_, const String& member_) | |||
| : mainSymbol (symbol_), | |||
| member (member_) | |||
| {} | |||
| double evaluate (const EvaluationContext& c, int recursionDepth) const | |||
| { | |||
| @@ -79,7 +87,7 @@ public: | |||
| try | |||
| { | |||
| return c.getSymbolValue (symbol).term->evaluate (c, recursionDepth); | |||
| return c.getSymbolValue (mainSymbol, member).term->evaluate (c, recursionDepth); | |||
| } | |||
| catch (...) | |||
| {} | |||
| @@ -87,23 +95,35 @@ public: | |||
| return 0; | |||
| } | |||
| Term* clone() const { return new Symbol (symbol); } | |||
| Term* clone() const { return new Symbol (mainSymbol, member); } | |||
| int getNumInputs() const { return 0; } | |||
| Term* getInput (int) const { return 0; } | |||
| const String toString() const { return symbol; } | |||
| const String toString() const | |||
| { | |||
| return member.isEmpty() ? mainSymbol | |||
| : mainSymbol + "." + member; | |||
| } | |||
| bool referencesSymbol (const String& s, const EvaluationContext& c, int recursionDepth) const | |||
| { | |||
| if (s == symbol) | |||
| if (s == mainSymbol) | |||
| return true; | |||
| if (++recursionDepth > 256) | |||
| throw EvaluationError ("Recursive symbol references"); | |||
| return c.getSymbolValue (symbol).term->referencesSymbol (s, c, recursionDepth); | |||
| try | |||
| { | |||
| return c.getSymbolValue (mainSymbol, member).term->referencesSymbol (s, c, recursionDepth); | |||
| } | |||
| catch (EvaluationError&) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| String symbol; | |||
| String mainSymbol, member; | |||
| }; | |||
| //============================================================================== | |||
| @@ -383,6 +403,9 @@ public: | |||
| if (c != 0 && (c->isResolutionTarget || ! mustBeFlagged)) | |||
| return c; | |||
| if (dynamic_cast<Function*> (term) != 0) | |||
| return 0; | |||
| int i; | |||
| const int numIns = term->getNumInputs(); | |||
| for (i = 0; i < numIns; ++i) | |||
| @@ -416,20 +439,12 @@ public: | |||
| static bool renameSymbol (Term* const t, const String& oldName, const String& newName) | |||
| { | |||
| Symbol* sym = dynamic_cast <Symbol*> (t); | |||
| Symbol* const sym = dynamic_cast <Symbol*> (t); | |||
| if (sym != 0) | |||
| if (sym != 0 && sym->mainSymbol == oldName) | |||
| { | |||
| if (sym->symbol == oldName) | |||
| { | |||
| sym->symbol = newName; | |||
| return true; | |||
| } | |||
| else if (sym->symbol.startsWith (oldName + ".")) | |||
| { | |||
| sym->symbol = newName + "." + sym->symbol.substring (0, oldName.length() + 1); | |||
| return true; | |||
| } | |||
| sym->mainSymbol = newName; | |||
| return true; | |||
| } | |||
| bool anyChanged = false; | |||
| @@ -557,6 +572,12 @@ public: | |||
| textIndex = i; | |||
| } | |||
| if (text[i] == '-') | |||
| { | |||
| ++i; | |||
| skipWhitespace (i); | |||
| } | |||
| int numDigits = 0; | |||
| while (isDecimalDigit (text[i])) | |||
| @@ -602,9 +623,9 @@ public: | |||
| return 0; | |||
| } | |||
| Constant* t = new Constant (String (text + textIndex, i - textIndex).getDoubleValue(), isResolutionTarget); | |||
| const int start = textIndex; | |||
| textIndex = i; | |||
| return t; | |||
| return new Constant (String (text + start, i - start).getDoubleValue(), isResolutionTarget); | |||
| } | |||
| const TermPtr readMultiplyOrDivideExpression() | |||
| @@ -835,7 +856,7 @@ const Expression Expression::adjustedToGiveNewResult (const double targetValue, | |||
| const Helpers::TermPtr reverseTerm (parent->createTermToEvaluateInput (context, termToAdjust, targetValue, newTerm)); | |||
| if (reverseTerm == 0) | |||
| return Expression(); | |||
| return Expression (targetValue); | |||
| termToAdjust->value = reverseTerm->evaluate (context, 0); | |||
| } | |||
| @@ -845,7 +866,7 @@ const Expression Expression::adjustedToGiveNewResult (const double targetValue, | |||
| const Expression Expression::withRenamedSymbol (const String& oldSymbol, const String& newSymbol) const | |||
| { | |||
| jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
| jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_")); | |||
| Expression newExpression (term->clone()); | |||
| Helpers::renameSymbol (newExpression.term, oldSymbol, newSymbol); | |||
| @@ -906,9 +927,9 @@ Expression::EvaluationError::EvaluationError (const String& message) | |||
| Expression::EvaluationContext::EvaluationContext() {} | |||
| Expression::EvaluationContext::~EvaluationContext() {} | |||
| const Expression Expression::EvaluationContext::getSymbolValue (const String& symbol) const | |||
| const Expression Expression::EvaluationContext::getSymbolValue (const String& symbol, const String& member) const | |||
| { | |||
| throw EvaluationError ("Unknown symbol: \"" + symbol + "\""); | |||
| throw EvaluationError ("Unknown symbol: \"" + symbol + (member.isEmpty() ? "\"" : ("." + member + "\""))); | |||
| } | |||
| double Expression::EvaluationContext::evaluateFunction (const String& functionName, const double* parameters, int numParams) const | |||
| @@ -113,9 +113,11 @@ public: | |||
| /** Returns the value of a symbol. | |||
| If the symbol is unknown, this can throw an Expression::EvaluationError exception. | |||
| The member value is set to the part of the symbol that followed the dot, if there is | |||
| one, e.g. for "foo.bar", symbol = "foo" and member = "bar". | |||
| @throws Expression::EvaluationError | |||
| */ | |||
| virtual const Expression getSymbolValue (const String& symbol) const; | |||
| virtual const Expression getSymbolValue (const String& symbol, const String& member) const; | |||
| /** Executes a named function. | |||
| If the function name is unknown, this can throw an Expression::EvaluationError exception. | |||
| @@ -33,7 +33,7 @@ | |||
| */ | |||
| #define JUCE_MAJOR_VERSION 1 | |||
| #define JUCE_MINOR_VERSION 52 | |||
| #define JUCE_BUILDNUMBER 53 | |||
| #define JUCE_BUILDNUMBER 54 | |||
| /** Current Juce version number. | |||
| @@ -1427,6 +1427,17 @@ void TreeViewItem::paintRecursively (Graphics& g, int width) | |||
| const int indent = getIndentX(); | |||
| const int itemW = itemWidth < 0 ? width - indent : itemWidth; | |||
| { | |||
| g.saveState(); | |||
| g.setOrigin (indent, 0); | |||
| if (g.reduceClipRegion (drawsInLeftMargin ? -indent : 0, 0, | |||
| drawsInLeftMargin ? itemW + indent : itemW, itemHeight)) | |||
| paintItem (g, itemW, itemHeight); | |||
| g.restoreState(); | |||
| } | |||
| g.setColour (ownerView->findColour (TreeView::linesColourId)); | |||
| const float halfH = itemHeight * 0.5f; | |||
| @@ -1489,17 +1500,6 @@ void TreeViewItem::paintRecursively (Graphics& g, int width) | |||
| } | |||
| } | |||
| { | |||
| g.saveState(); | |||
| g.setOrigin (indent, 0); | |||
| if (g.reduceClipRegion (drawsInLeftMargin ? -indent : 0, 0, | |||
| drawsInLeftMargin ? itemW + indent : itemW, itemHeight)) | |||
| paintItem (g, itemW, itemHeight); | |||
| g.restoreState(); | |||
| } | |||
| if (isOpen()) | |||
| { | |||
| const Rectangle<int> clip (g.getClipBounds()); | |||
| @@ -247,9 +247,9 @@ void DrawableComposite::render (const Drawable::RenderingContext& context) const | |||
| } | |||
| } | |||
| const Expression DrawableComposite::getSymbolValue (const String& symbol) const | |||
| const Expression DrawableComposite::getSymbolValue (const String& symbol, const String& member) const | |||
| { | |||
| jassert (! symbol.containsChar ('.')) // the only symbols available in a Drawable are markers. | |||
| jassert (member.isEmpty()) // the only symbols available in a Drawable are markers. | |||
| int i; | |||
| for (i = 0; i < markersX.size(); ++i) | |||
| @@ -266,7 +266,7 @@ const Expression DrawableComposite::getSymbolValue (const String& symbol) const | |||
| return m->position.getExpression(); | |||
| } | |||
| return Expression::EvaluationContext::getSymbolValue (symbol); | |||
| return Expression::EvaluationContext::getSymbolValue (symbol, member); | |||
| } | |||
| const Rectangle<float> DrawableComposite::getUntransformedBounds (const bool includeMarkers) const | |||
| @@ -201,7 +201,7 @@ public: | |||
| /** @internal */ | |||
| const Identifier getValueTreeType() const { return valueTreeType; } | |||
| /** @internal */ | |||
| const Expression getSymbolValue (const String& symbol) const; | |||
| const Expression getSymbolValue (const String& symbol, const String& member) const; | |||
| //============================================================================== | |||
| /** Internally-used class for wrapping a DrawableComposite's state into a ValueTree. */ | |||
| @@ -185,7 +185,7 @@ const String RelativeCoordinate::toString() const | |||
| void RelativeCoordinate::renameSymbolIfUsed (const String& oldName, const String& newName, | |||
| const Expression::EvaluationContext* context) | |||
| { | |||
| jassert (newName.isNotEmpty() && newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
| jassert (newName.isNotEmpty() && newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_")); | |||
| if (term.referencesSymbol (oldName, *context)) | |||
| { | |||
| @@ -263,8 +263,6 @@ FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool w | |||
| if (fc.browseForFileToSave (warnAboutOverwritingExistingFiles)) | |||
| { | |||
| setLastDocumentOpened (fc.getResult()); | |||
| File chosen (fc.getResult()); | |||
| if (chosen.getFileExtension().isEmpty()) | |||
| { | |||
| @@ -285,6 +283,7 @@ FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool w | |||
| } | |||
| } | |||
| setLastDocumentOpened (chosen); | |||
| return saveAs (chosen, false, false, true); | |||
| } | |||