diff --git a/extras/Jucer (experimental)/Source/Project/jucer_ProjectInformationComponent.cpp b/extras/Jucer (experimental)/Source/Project/jucer_ProjectInformationComponent.cpp
index 45da13c89f..a32e94be02 100644
--- a/extras/Jucer (experimental)/Source/Project/jucer_ProjectInformationComponent.cpp
+++ b/extras/Jucer (experimental)/Source/Project/jucer_ProjectInformationComponent.cpp
@@ -104,21 +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"));
+ configTabBox.setBounds (RelativeRectangle ("8, 0, this.left + parent.width - 16, this.top + parent.height - 36"));
addAndMakeVisible (&editConfigsButton);
- editConfigsButton.setBounds (RelativeRectangle ("8, parent.bottom - 30, this.left + 192, this.top + 22"));
+ editConfigsButton.setBounds (RelativeRectangle ("8, parent.height - 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.setBounds (RelativeRectangle ("608, parent.height - 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.setBounds (RelativeRectangle ("208, parent.height - 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.setBounds (RelativeRectangle ("391, parent.height - 30, this.left + 208, this.top + 22"));
saveAndOpenButton.setButtonText ("Save And Open in");
saveAndOpenButton.addListener (this);
@@ -354,22 +354,22 @@ JUCER_COMPONENT_METADATA_START
constructorParams="Project& project_" memberInitialisers="project (project_)">
+ position="8, 0, this.left + parent.width - 16, this.top + parent.height - 36"/>
+ position="8, parent.height - 30, this.left + 192, this.top + 22"/>
+ textColour="" backgroundColourOn="" textColourOn="" position="608, parent.height - 30, this.left + 208, this.top + 22"/>
-
+
diff --git a/extras/Jucer (experimental)/Source/Utility/jucer_PresetIDs.h b/extras/Jucer (experimental)/Source/Utility/jucer_PresetIDs.h
index c3786ac218..8976eac34c 100644
--- a/extras/Jucer (experimental)/Source/Utility/jucer_PresetIDs.h
+++ b/extras/Jucer (experimental)/Source/Utility/jucer_PresetIDs.h
@@ -112,6 +112,7 @@ namespace Ids
DECLARE_ID (tooltip);
DECLARE_ID (memberName);
DECLARE_ID (focusOrder);
+ DECLARE_ID (hidden);
const Identifier class_ ("class");
const Identifier id_ ("id");
diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp
index 1cb815bb0d..4611b70c17 100644
--- a/juce_amalgamated.cpp
+++ b/juce_amalgamated.cpp
@@ -4664,138 +4664,252 @@ END_JUCE_NAMESPACE
/*** Start of inlined file: juce_Expression.cpp ***/
BEGIN_JUCE_NAMESPACE
+class Expression::Term : public ReferenceCountedObject
+{
+public:
+ Term() {}
+ virtual ~Term() {}
+
+ virtual Type getType() const throw() = 0;
+ virtual Term* clone() const = 0;
+ virtual const ReferenceCountedObjectPtr resolve (const Scope&, int recursionDepth) = 0;
+ virtual const String toString() const = 0;
+ virtual double toDouble() const { return 0; }
+ virtual int getInputIndexFor (const Term*) const { return -1; }
+ virtual int getOperatorPrecedence() const { return 0; }
+ virtual int getNumInputs() const { return 0; }
+ virtual Term* getInput (int) const { return 0; }
+ virtual const ReferenceCountedObjectPtr negated();
+
+ virtual const ReferenceCountedObjectPtr createTermToEvaluateInput (const Scope&, const Term* /*inputTerm*/,
+ double /*overallTarget*/, Term* /*topLevelTerm*/) const
+ {
+ jassertfalse;
+ return 0;
+ }
+
+ virtual const String getName() const
+ {
+ jassertfalse; // You shouldn't call this for an expression that's not actually a function!
+ return String::empty;
+ }
+
+ virtual void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
+ {
+ for (int i = getNumInputs(); --i >= 0;)
+ getInput (i)->renameSymbol (oldSymbol, newName, scope, recursionDepth);
+ }
+
+ class SymbolVisitor
+ {
+ public:
+ virtual ~SymbolVisitor() {}
+ virtual void useSymbol (const Symbol&) = 0;
+ };
+
+ virtual void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
+ {
+ for (int i = getNumInputs(); --i >= 0;)
+ getInput(i)->visitAllSymbols (visitor, scope, recursionDepth);
+ }
+
+private:
+ JUCE_DECLARE_NON_COPYABLE (Term);
+};
+
class Expression::Helpers
{
public:
typedef ReferenceCountedObjectPtr TermPtr;
// This helper function is needed to work around VC6 scoping bugs
- static const TermPtr& getTermFor (const Expression& exp) throw() { return exp.term; }
+ static inline const TermPtr& getTermFor (const Expression& exp) throw() { return exp.term; }
+
+ static void checkRecursionDepth (const int depth)
+ {
+ if (depth > 256)
+ throw EvaluationError ("Recursive symbol references");
+ }
friend class Expression::Term; // (also only needed as a VC6 workaround)
+ /** An exception that can be thrown by Expression::evaluate(). */
+ class EvaluationError : public std::exception
+ {
+ public:
+ EvaluationError (const String& description_)
+ : description (description_)
+ {
+ DBG ("Expression::EvaluationError: " + description);
+ }
+
+ String description;
+ };
+
class Constant : public Term
{
public:
- Constant (const double value_, bool isResolutionTarget_)
+ Constant (const double value_, const bool isResolutionTarget_)
: value (value_), isResolutionTarget (isResolutionTarget_) {}
- Type getType() const throw() { return constantType; }
- Term* clone() const { return new Constant (value, isResolutionTarget); }
- double evaluate (const EvaluationContext&, int) const { return value; }
- int getNumInputs() const { return 0; }
- Term* getInput (int) const { return 0; }
-
- const TermPtr negated()
- {
- return new Constant (-value, isResolutionTarget);
- }
+ Type getType() const throw() { return constantType; }
+ Term* clone() const { return new Constant (value, isResolutionTarget); }
+ const TermPtr resolve (const Scope&, int) { return this; }
+ double toDouble() const { return value; }
+ const TermPtr negated() { return new Constant (-value, isResolutionTarget); }
const String toString() const
{
+ String s (value);
if (isResolutionTarget)
- return "@" + String (value);
+ s = "@" + s;
- return String (value);
+ return s;
}
double value;
bool isResolutionTarget;
};
- class Symbol : public Term
+ class BinaryTerm : public Term
{
public:
- explicit Symbol (const String& symbol_)
- : mainSymbol (symbol_.upToFirstOccurrenceOf (".", false, false).trim()),
- member (symbol_.fromFirstOccurrenceOf (".", false, false).trim())
- {}
+ BinaryTerm (Term* const left_, Term* const right_) : left (left_), right (right_)
+ {
+ jassert (left_ != 0 && right_ != 0);
+ }
- Symbol (const String& symbol_, const String& member_)
- : mainSymbol (symbol_),
- member (member_)
- {}
+ int getInputIndexFor (const Term* possibleInput) const
+ {
+ return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
+ }
+
+ Type getType() const throw() { return operatorType; }
+ int getNumInputs() const { return 2; }
+ Term* getInput (int index) const { return index == 0 ? left.getObject() : (index == 1 ? right.getObject() : 0); }
+
+ virtual double performFunction (double left, double right) const = 0;
+ virtual void writeOperator (String& dest) const = 0;
- double evaluate (const EvaluationContext& c, int recursionDepth) const
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- if (++recursionDepth > 256)
- throw EvaluationError ("Recursive symbol references");
+ return new Constant (performFunction (left->resolve (scope, recursionDepth)->toDouble(),
+ right->resolve (scope, recursionDepth)->toDouble()), false);
+ }
- try
- {
- return getTermFor (c.getSymbolValue (mainSymbol, member))->evaluate (c, recursionDepth);
- }
- catch (...)
- {}
+ const String toString() const
+ {
+ String s;
- return 0;
+ const int ourPrecendence = getOperatorPrecedence();
+ if (left->getOperatorPrecedence() > ourPrecendence)
+ s << '(' << left->toString() << ')';
+ else
+ s = left->toString();
+
+ writeOperator (s);
+
+ if (right->getOperatorPrecedence() >= ourPrecendence)
+ s << '(' << right->toString() << ')';
+ else
+ s << right->toString();
+
+ return s;
}
- Type getType() const throw() { return symbolType; }
- Term* clone() const { return new Symbol (mainSymbol, member); }
- int getNumInputs() const { return 0; }
- Term* getInput (int) const { return 0; }
- const String toString() const { return joinParts (mainSymbol, member); }
- void getSymbolParts (String& objectName, String& memberName) const { objectName = mainSymbol; memberName = member; }
+ protected:
+ const TermPtr left, right;
- static const String joinParts (const String& mainSymbol, const String& member)
+ const TermPtr createDestinationTerm (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- return member.isEmpty() ? mainSymbol
- : mainSymbol + "." + member;
+ jassert (input == left || input == right);
+ if (input != left && input != right)
+ return 0;
+
+ const Term* const dest = findDestinationFor (topLevelTerm, this);
+
+ if (dest == 0)
+ return new Constant (overallTarget, false);
+
+ return dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm);
}
+ };
- bool referencesSymbol (const String& s, const EvaluationContext* c, int recursionDepth) const
+ class SymbolTerm : public Term
+ {
+ public:
+ explicit SymbolTerm (const String& symbol_) : symbol (symbol_) {}
+
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- if (s == mainSymbol || (s.containsChar ('.') && s == toString()))
- return true;
+ checkRecursionDepth (recursionDepth);
+ return getTermFor (scope.getSymbolValue (symbol))->resolve (scope, recursionDepth + 1);
+ }
- if (++recursionDepth > 256)
- throw EvaluationError ("Recursive symbol references");
+ Type getType() const throw() { return symbolType; }
+ Term* clone() const { return new SymbolTerm (symbol); }
+ const String toString() const { return symbol; }
+ const String getName() const { return symbol; }
- try
- {
- return c != 0 && getTermFor (c->getSymbolValue (mainSymbol, member))->referencesSymbol (s, c, recursionDepth);
- }
- catch (EvaluationError&)
- {
- return false;
- }
+ void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
+ {
+ checkRecursionDepth (recursionDepth);
+ visitor.useSymbol (Symbol (scope.getScopeUID(), symbol));
+ getTermFor (scope.getSymbolValue (symbol))->visitAllSymbols (visitor, scope, recursionDepth + 1);
}
- String mainSymbol, member;
+ void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int /*recursionDepth*/)
+ {
+ if (oldSymbol.symbolName == symbol && scope.getScopeUID() == oldSymbol.scopeUID)
+ symbol = newName;
+ }
+
+ String symbol;
};
class Function : public Term
{
public:
- Function (const String& functionName_, const ReferenceCountedArray& parameters_)
+ explicit Function (const String& functionName_) : functionName (functionName_) {}
+
+ Function (const String& functionName_, const Array& parameters_)
: functionName (functionName_), parameters (parameters_)
{}
- Term* clone() const { return new Function (functionName, parameters); }
+ Type getType() const throw() { return functionType; }
+ Term* clone() const { return new Function (functionName, parameters); }
+ int getNumInputs() const { return parameters.size(); }
+ Term* getInput (int i) const { return getTermFor (parameters [i]); }
+ const String getName() const { return functionName; }
- double evaluate (const EvaluationContext& c, int recursionDepth) const
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- HeapBlock params (parameters.size());
- for (int i = 0; i < parameters.size(); ++i)
- params[i] = parameters.getUnchecked(i)->evaluate (c, recursionDepth);
+ checkRecursionDepth (recursionDepth);
+ double result = 0;
+ const int numParams = parameters.size();
+ if (numParams > 0)
+ {
+ HeapBlock params (numParams);
+ for (int i = 0; i < numParams; ++i)
+ params[i] = getTermFor (parameters.getReference(i))->resolve (scope, recursionDepth + 1)->toDouble();
- return c.evaluateFunction (functionName, params, parameters.size());
- }
+ result = scope.evaluateFunction (functionName, params, numParams);
+ }
+ else
+ {
+ result = scope.evaluateFunction (functionName, 0, 0);
+ }
- Type getType() const throw() { return functionType; }
- int getInputIndexFor (const Term* possibleInput) const { return parameters.indexOf (possibleInput); }
- int getNumInputs() const { return parameters.size(); }
- Term* getInput (int i) const { return parameters [i]; }
- const String getFunctionName() const { return functionName; }
+ return new Constant (result, false);
+ }
- bool referencesSymbol (const String& s, const EvaluationContext* c, int recursionDepth) const
+ int getInputIndexFor (const Term* possibleInput) const
{
for (int i = 0; i < parameters.size(); ++i)
- if (parameters.getUnchecked(i)->referencesSymbol (s, c, recursionDepth))
- return true;
+ if (getTermFor (parameters.getReference(i)) == possibleInput)
+ return i;
- return false;
+ return -1;
}
const String toString() const
@@ -4807,7 +4921,7 @@ public:
for (int i = 0; i < parameters.size(); ++i)
{
- s << parameters.getUnchecked(i)->toString();
+ s << getTermFor (parameters.getReference(i))->toString();
if (i < parameters.size() - 1)
s << ", ";
@@ -4818,117 +4932,146 @@ public:
}
const String functionName;
- ReferenceCountedArray parameters;
+ Array parameters;
};
- class Negate : public Term
+ class DotOperator : public BinaryTerm
{
public:
- explicit Negate (const TermPtr& input_) : input (input_)
- {
- jassert (input_ != 0);
- }
-
- Type getType() const throw() { return operatorType; }
- int getInputIndexFor (const Term* possibleInput) const { return possibleInput == input ? 0 : -1; }
- int getNumInputs() const { return 1; }
- Term* getInput (int index) const { return index == 0 ? static_cast (input) : 0; }
- Term* clone() const { return new Negate (input->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return -input->evaluate (c, recursionDepth); }
- const String getFunctionName() const { return "-"; }
+ DotOperator (SymbolTerm* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
- const TermPtr negated()
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- return input;
+ checkRecursionDepth (recursionDepth);
+
+ EvaluationVisitor visitor (right, recursionDepth + 1);
+ scope.visitRelativeScope (getSymbol()->symbol, visitor);
+ return visitor.output;
}
- const TermPtr createTermToEvaluateInput (const EvaluationContext& context, const Term* input_, double overallTarget, Term* topLevelTerm) const
- {
- (void) input_;
- jassert (input_ == input);
+ Term* clone() const { return new DotOperator (getSymbol(), right); }
+ const String getName() const { return "."; }
+ int getOperatorPrecedence() const { return 1; }
+ void writeOperator (String& dest) const { dest << '.'; }
+ double performFunction (double, double) const { return 0.0; }
- const Term* const dest = findDestinationFor (topLevelTerm, this);
+ void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
+ {
+ checkRecursionDepth (recursionDepth);
+ visitor.useSymbol (Symbol (scope.getScopeUID(), getSymbol()->symbol));
- return new Negate (dest == 0 ? new Constant (overallTarget, false)
- : dest->createTermToEvaluateInput (context, this, overallTarget, topLevelTerm));
+ SymbolVisitingVisitor v (right, visitor, recursionDepth + 1);
+ scope.visitRelativeScope (getSymbol()->symbol, v);
}
- const String toString() const
+ void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
{
- if (input->getOperatorPrecedence() > 0)
- return "-(" + input->toString() + ")";
- else
- return "-" + input->toString();
- }
+ checkRecursionDepth (recursionDepth);
+ getSymbol()->renameSymbol (oldSymbol, newName, scope, recursionDepth);
- bool referencesSymbol (const String& s, const EvaluationContext* c, int recursionDepth) const
- {
- return input->referencesSymbol (s, c, recursionDepth);
+ SymbolRenamingVisitor visitor (right, oldSymbol, newName, recursionDepth + 1);
+ scope.visitRelativeScope (getSymbol()->symbol, visitor);
}
private:
- const TermPtr input;
- };
- class BinaryTerm : public Term
- {
- public:
- BinaryTerm (Term* const left_, Term* const right_) : left (left_), right (right_)
+ class EvaluationVisitor : public Scope::Visitor
{
- jassert (left_ != 0 && right_ != 0);
- }
+ public:
+ EvaluationVisitor (const TermPtr& input_, const int recursionCount_)
+ : input (input_), output (input_), recursionCount (recursionCount_) {}
- int getInputIndexFor (const Term* possibleInput) const
- {
- return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
- }
+ void visit (const Scope& scope) { output = input->resolve (scope, recursionCount); }
- Type getType() const throw() { return operatorType; }
- int getNumInputs() const { return 2; }
- Term* getInput (int index) const { return index == 0 ? static_cast (left) : (index == 1 ? static_cast (right) : 0); }
+ const TermPtr input;
+ TermPtr output;
+ const int recursionCount;
- bool referencesSymbol (const String& s, const EvaluationContext* c, int recursionDepth) const
+ private:
+ JUCE_DECLARE_NON_COPYABLE (EvaluationVisitor);
+ };
+
+ class SymbolVisitingVisitor : public Scope::Visitor
{
- return left->referencesSymbol (s, c, recursionDepth)
- || right->referencesSymbol (s, c, recursionDepth);
- }
+ public:
+ SymbolVisitingVisitor (const TermPtr& input_, SymbolVisitor& visitor_, const int recursionCount_)
+ : input (input_), visitor (visitor_), recursionCount (recursionCount_) {}
- const String toString() const
+ void visit (const Scope& scope) { input->visitAllSymbols (visitor, scope, recursionCount); }
+
+ private:
+ const TermPtr input;
+ SymbolVisitor& visitor;
+ const int recursionCount;
+
+ JUCE_DECLARE_NON_COPYABLE (SymbolVisitingVisitor);
+ };
+
+ class SymbolRenamingVisitor : public Scope::Visitor
{
- String s;
+ public:
+ SymbolRenamingVisitor (const TermPtr& input_, const Expression::Symbol& symbol_, const String& newName_, const int recursionCount_)
+ : input (input_), symbol (symbol_), newName (newName_), recursionCount (recursionCount_) {}
- const int ourPrecendence = getOperatorPrecedence();
- if (left->getOperatorPrecedence() > ourPrecendence)
- s << '(' << left->toString() << ')';
- else
- s = left->toString();
+ void visit (const Scope& scope) { input->renameSymbol (symbol, newName, scope, recursionCount); }
- s << ' ' << getFunctionName() << ' ';
+ private:
+ const TermPtr input;
+ const Symbol& symbol;
+ const String newName;
+ const int recursionCount;
- if (right->getOperatorPrecedence() >= ourPrecendence)
- s << '(' << right->toString() << ')';
- else
- s << right->toString();
+ JUCE_DECLARE_NON_COPYABLE (SymbolRenamingVisitor);
+ };
- return s;
+ SymbolTerm* getSymbol() const { return static_cast (left.getObject()); }
+
+ JUCE_DECLARE_NON_COPYABLE (DotOperator);
+ };
+
+ class Negate : public Term
+ {
+ public:
+ explicit Negate (const TermPtr& input_) : input (input_)
+ {
+ jassert (input_ != 0);
}
- protected:
- const TermPtr left, right;
+ Type getType() const throw() { return operatorType; }
+ int getInputIndexFor (const Term* possibleInput) const { return possibleInput == input ? 0 : -1; }
+ int getNumInputs() const { return 1; }
+ Term* getInput (int index) const { return index == 0 ? input.getObject() : 0; }
+ Term* clone() const { return new Negate (input->clone()); }
- const TermPtr createDestinationTerm (const EvaluationContext& context, const Term* input, double overallTarget, Term* topLevelTerm) const
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- jassert (input == left || input == right);
- if (input != left && input != right)
- return 0;
+ return new Constant (-input->resolve (scope, recursionDepth)->toDouble(), false);
+ }
+
+ const String getName() const { return "-"; }
+ const TermPtr negated() { return input; }
+
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input_, double overallTarget, Term* topLevelTerm) const
+ {
+ (void) input_;
+ jassert (input_ == input);
const Term* const dest = findDestinationFor (topLevelTerm, this);
- if (dest == 0)
- return new Constant (overallTarget, false);
+ return new Negate (dest == 0 ? new Constant (overallTarget, false)
+ : dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm));
+ }
- return dest->createTermToEvaluateInput (context, this, overallTarget, topLevelTerm);
+ const String toString() const
+ {
+ if (input->getOperatorPrecedence() > 0)
+ return "-(" + input->toString() + ")";
+ else
+ return "-" + input->toString();
}
+
+ private:
+ const TermPtr input;
};
class Add : public BinaryTerm
@@ -4937,13 +5080,14 @@ public:
Add (Term* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
Term* clone() const { return new Add (left->clone(), right->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return left->evaluate (c, recursionDepth) + right->evaluate (c, recursionDepth); }
- int getOperatorPrecedence() const { return 2; }
- const String getFunctionName() const { return "+"; }
+ double performFunction (double lhs, double rhs) const { return lhs + rhs; }
+ int getOperatorPrecedence() const { return 3; }
+ const String getName() const { return "+"; }
+ void writeOperator (String& dest) const { dest << " + "; }
- const TermPtr createTermToEvaluateInput (const EvaluationContext& c, const Term* input, double overallTarget, Term* topLevelTerm) const
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- const TermPtr newDest (createDestinationTerm (c, input, overallTarget, topLevelTerm));
+ const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
if (newDest == 0)
return 0;
@@ -4960,13 +5104,14 @@ public:
Subtract (Term* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
Term* clone() const { return new Subtract (left->clone(), right->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return left->evaluate (c, recursionDepth) - right->evaluate (c, recursionDepth); }
- int getOperatorPrecedence() const { return 2; }
- const String getFunctionName() const { return "-"; }
+ double performFunction (double lhs, double rhs) const { return lhs - rhs; }
+ int getOperatorPrecedence() const { return 3; }
+ const String getName() const { return "-"; }
+ void writeOperator (String& dest) const { dest << " - "; }
- const TermPtr createTermToEvaluateInput (const EvaluationContext& c, const Term* input, double overallTarget, Term* topLevelTerm) const
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- const TermPtr newDest (createDestinationTerm (c, input, overallTarget, topLevelTerm));
+ const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
if (newDest == 0)
return 0;
@@ -4986,13 +5131,14 @@ public:
Multiply (Term* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
Term* clone() const { return new Multiply (left->clone(), right->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return left->evaluate (c, recursionDepth) * right->evaluate (c, recursionDepth); }
- const String getFunctionName() const { return "*"; }
- int getOperatorPrecedence() const { return 1; }
+ double performFunction (double lhs, double rhs) const { return lhs * rhs; }
+ const String getName() const { return "*"; }
+ void writeOperator (String& dest) const { dest << " * "; }
+ int getOperatorPrecedence() const { return 2; }
- const TermPtr createTermToEvaluateInput (const EvaluationContext& c, const Term* input, double overallTarget, Term* topLevelTerm) const
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- const TermPtr newDest (createDestinationTerm (c, input, overallTarget, topLevelTerm));
+ const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
if (newDest == 0)
return 0;
@@ -5009,13 +5155,14 @@ public:
Divide (Term* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
Term* clone() const { return new Divide (left->clone(), right->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return left->evaluate (c, recursionDepth) / right->evaluate (c, recursionDepth); }
- const String getFunctionName() const { return "/"; }
- int getOperatorPrecedence() const { return 1; }
+ double performFunction (double lhs, double rhs) const { return lhs / rhs; }
+ const String getName() const { return "/"; }
+ void writeOperator (String& dest) const { dest << " / "; }
+ int getOperatorPrecedence() const { return 2; }
- const TermPtr createTermToEvaluateInput (const EvaluationContext& c, const Term* input, double overallTarget, Term* topLevelTerm) const
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- const TermPtr newDest (createDestinationTerm (c, input, overallTarget, topLevelTerm));
+ const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
if (newDest == 0)
return 0;
@@ -5088,24 +5235,31 @@ public:
return false;
}
- static bool renameSymbol (Term* const t, const String& oldName, const String& newName)
+ class SymbolCheckVisitor : public Term::SymbolVisitor
{
- Symbol* const sym = dynamic_cast (t);
+ public:
+ SymbolCheckVisitor (const Symbol& symbol_) : wasFound (false), symbol (symbol_) {}
+ void useSymbol (const Symbol& s) { wasFound = wasFound || s == symbol; }
- if (sym != 0 && sym->mainSymbol == oldName)
- {
- sym->mainSymbol = newName;
- return true;
- }
+ bool wasFound;
- bool anyChanged = false;
+ private:
+ const Symbol& symbol;
- for (int i = t->getNumInputs(); --i >= 0;)
- if (renameSymbol (t->getInput (i), oldName, newName))
- anyChanged = true;
+ JUCE_DECLARE_NON_COPYABLE (SymbolCheckVisitor);
+ };
- return anyChanged;
- }
+ class SymbolListVisitor : public Term::SymbolVisitor
+ {
+ public:
+ SymbolListVisitor (Array& list_) : list (list_) {}
+ void useSymbol (const Symbol& s) { list.addIfNotAlreadyThere (s); }
+
+ private:
+ Array& list;
+
+ JUCE_DECLARE_NON_COPYABLE (SymbolListVisitor);
+ };
class Parser
{
@@ -5194,7 +5348,7 @@ public:
{
++i;
- while (CharacterFunctions::isLetterOrDigit (text[i]) || text[i] == '_' || text[i] == '.')
+ while (CharacterFunctions::isLetterOrDigit (text[i]) || text[i] == '_')
++i;
}
@@ -5327,12 +5481,17 @@ public:
if (e != 0)
return e;
+ return readSymbolOrFunction();
+ }
+
+ const TermPtr readSymbolOrFunction()
+ {
String identifier;
if (readIdentifier (identifier))
{
if (readOperator ("(")) // method call...
{
- Function* const f = new Function (identifier, ReferenceCountedArray());
+ Function* const f = new Function (identifier);
ScopedPointer func (f); // (can't use ScopedPointer in MSVC)
TermPtr param (readExpression());
@@ -5345,7 +5504,7 @@ public:
throw ParseError ("Expected parameters after \"" + identifier + " (\"");
}
- f->parameters.add (param);
+ f->parameters.add (Expression (param));
while (readOperator (","))
{
@@ -5354,7 +5513,7 @@ public:
if (param == 0)
throw ParseError ("Expected expression after \",\"");
- f->parameters.add (param);
+ f->parameters.add (Expression (param));
}
if (readOperator (")"))
@@ -5362,9 +5521,22 @@ public:
throw ParseError ("Expected \")\"");
}
+ else if (readOperator ("."))
+ {
+ TermPtr rhs (readSymbolOrFunction());
+
+ if (rhs == 0)
+ throw ParseError ("Expected symbol or function after \".\"");
+
+ if (identifier == "this")
+ return rhs;
+
+ return new DotOperator (new SymbolTerm (identifier), rhs);
+ }
else // just a symbol..
{
- return new Symbol (identifier);
+ jassert (identifier.trim() == identifier);
+ return new SymbolTerm (identifier);
}
}
@@ -5441,12 +5613,33 @@ const Expression Expression::parse (const String& stringToParse, int& textIndexT
double Expression::evaluate() const
{
- return evaluate (Expression::EvaluationContext());
+ return evaluate (Expression::Scope());
+}
+
+double Expression::evaluate (const Expression::Scope& scope) const
+{
+ try
+ {
+ return term->resolve (scope, 0)->toDouble();
+ }
+ catch (Helpers::EvaluationError&)
+ {}
+
+ return 0;
}
-double Expression::evaluate (const Expression::EvaluationContext& context) const
+double Expression::evaluate (const Scope& scope, String& evaluationError) const
{
- return term->evaluate (context, 0);
+ try
+ {
+ return term->resolve (scope, 0)->toDouble();
+ }
+ catch (Helpers::EvaluationError& e)
+ {
+ evaluationError = e.description;
+ }
+
+ return 0;
}
const Expression Expression::operator+ (const Expression& other) const { return Expression (new Helpers::Add (term, other.term)); }
@@ -5454,28 +5647,14 @@ const Expression Expression::operator- (const Expression& other) const { return
const Expression Expression::operator* (const Expression& other) const { return Expression (new Helpers::Multiply (term, other.term)); }
const Expression Expression::operator/ (const Expression& other) const { return Expression (new Helpers::Divide (term, other.term)); }
const Expression Expression::operator-() const { return Expression (term->negated()); }
-
-const String Expression::toString() const
-{
- return term->toString();
-}
-
-const Expression Expression::symbol (const String& symbol)
-{
- return Expression (new Helpers::Symbol (symbol));
-}
+const Expression Expression::symbol (const String& symbol) { return Expression (new Helpers::SymbolTerm (symbol)); }
const Expression Expression::function (const String& functionName, const Array& parameters)
{
- ReferenceCountedArray params;
- for (int i = 0; i < parameters.size(); ++i)
- params.add (parameters.getReference(i).term);
-
- return Expression (new Helpers::Function (functionName, params));
+ return Expression (new Helpers::Function (functionName, parameters));
}
-const Expression Expression::adjustedToGiveNewResult (const double targetValue,
- const Expression::EvaluationContext& context) const
+const Expression Expression::adjustedToGiveNewResult (const double targetValue, const Expression::Scope& scope) const
{
ScopedPointer newTerm (term->clone());
@@ -5500,140 +5679,96 @@ const Expression Expression::adjustedToGiveNewResult (const double targetValue,
}
else
{
- const Helpers::TermPtr reverseTerm (parent->createTermToEvaluateInput (context, termToAdjust, targetValue, newTerm));
+ const Helpers::TermPtr reverseTerm (parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm));
if (reverseTerm == 0)
return Expression (targetValue);
- termToAdjust->value = reverseTerm->evaluate (context, 0);
+ termToAdjust->value = reverseTerm->resolve (scope, 0)->toDouble();
}
return Expression (newTerm.release());
}
-const Expression Expression::withRenamedSymbol (const String& oldSymbol, const String& newSymbol) const
+const Expression Expression::withRenamedSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Scope& scope) const
{
- jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
+ jassert (newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
- if (oldSymbol == newSymbol)
+ if (oldSymbol.symbolName == newName)
return *this;
- Expression newExpression (term->clone());
- Helpers::renameSymbol (newExpression.term, oldSymbol, newSymbol);
- return newExpression;
-}
-
-bool Expression::referencesSymbol (const String& symbol, const EvaluationContext* context) const
-{
- return term->referencesSymbol (symbol, context, 0);
-}
-
-bool Expression::usesAnySymbols() const
-{
- return Helpers::containsAnySymbols (term);
-}
-
-Expression::Type Expression::getType() const throw()
-{
- return term->getType();
-}
-
-const String Expression::getSymbol() const
-{
- String objectName, memberName;
- term->getSymbolParts (objectName, memberName);
- return Expression::Helpers::Symbol::joinParts (objectName, memberName);
-}
-
-void Expression::getSymbolParts (String& objectName, String& memberName) const
-{
- term->getSymbolParts (objectName, memberName);
-}
-
-const String Expression::getFunction() const
-{
- return term->getFunctionName();
-}
-
-const String Expression::getOperator() const
-{
- return term->getFunctionName();
-}
-
-int Expression::getNumInputs() const
-{
- return term->getNumInputs();
+ Expression e (term->clone());
+ e.term->renameSymbol (oldSymbol, newName, scope, 0);
+ return e;
}
-const Expression Expression::getInput (int index) const
+bool Expression::referencesSymbol (const Expression::Symbol& symbol, const Scope& scope) const
{
- return Expression (term->getInput (index));
-}
+ Helpers::SymbolCheckVisitor visitor (symbol);
-int Expression::Term::getOperatorPrecedence() const
-{
- return 0;
-}
+ try
+ {
+ term->visitAllSymbols (visitor, scope, 0);
+ }
+ catch (Helpers::EvaluationError&)
+ {}
-bool Expression::Term::referencesSymbol (const String&, const EvaluationContext*, int) const
-{
- return false;
+ return visitor.wasFound;
}
-int Expression::Term::getInputIndexFor (const Term*) const
+void Expression::findReferencedSymbols (Array& results, const Scope& scope) const
{
- return -1;
+ try
+ {
+ Helpers::SymbolListVisitor visitor (results);
+ term->visitAllSymbols (visitor, scope, 0);
+ }
+ catch (Helpers::EvaluationError&)
+ {}
}
-const ReferenceCountedObjectPtr Expression::Term::createTermToEvaluateInput (const EvaluationContext&, const Term*, double, Term*) const
-{
- jassertfalse;
- return 0;
-}
+const String Expression::toString() const { return term->toString(); }
+bool Expression::usesAnySymbols() const { return Helpers::containsAnySymbols (term); }
+Expression::Type Expression::getType() const throw() { return term->getType(); }
+const String Expression::getSymbolOrFunction() const { return term->getName(); }
+int Expression::getNumInputs() const { return term->getNumInputs(); }
+const Expression Expression::getInput (int index) const { return Expression (term->getInput (index)); }
const ReferenceCountedObjectPtr Expression::Term::negated()
{
return new Helpers::Negate (this);
}
-void Expression::Term::getSymbolParts (String&, String&) const
-{
- jassertfalse; // You should only call getSymbol() on an expression that's actually a symbol!
-}
-
-const String Expression::Term::getFunctionName() const
-{
- jassertfalse; // You shouldn't call this for an expression that's not actually a function!
- return String::empty;
-}
-
Expression::ParseError::ParseError (const String& message)
: description (message)
{
DBG ("Expression::ParseError: " + message);
}
-Expression::EvaluationError::EvaluationError (const String& message)
- : description (message)
+Expression::Symbol::Symbol (const String& scopeUID_, const String& symbolName_)
+ : scopeUID (scopeUID_), symbolName (symbolName_)
{
- DBG ("Expression::EvaluationError: " + description);
}
-Expression::EvaluationError::EvaluationError (const String& symbol, const String& member)
- : description ("Unknown symbol: \"" + symbol + (member.isEmpty() ? "\"" : ("." + member + "\"")))
+bool Expression::Symbol::operator== (const Symbol& other) const throw()
{
- DBG ("Expression::EvaluationError: " + description);
+ return symbolName == other.symbolName && scopeUID == other.scopeUID;
}
-Expression::EvaluationContext::EvaluationContext() {}
-Expression::EvaluationContext::~EvaluationContext() {}
+bool Expression::Symbol::operator!= (const Symbol& other) const throw()
+{
+ return ! operator== (other);
+}
+
+Expression::Scope::Scope() {}
+Expression::Scope::~Scope() {}
-const Expression Expression::EvaluationContext::getSymbolValue (const String& symbol, const String& member) const
+const Expression Expression::Scope::getSymbolValue (const String& symbol) const
{
- throw EvaluationError (symbol, member);
+ throw Helpers::EvaluationError ("Unknown symbol: " + symbol);
}
-double Expression::EvaluationContext::evaluateFunction (const String& functionName, const double* parameters, int numParams) const
+double Expression::Scope::evaluateFunction (const String& functionName, const double* parameters, int numParams) const
{
if (numParams > 0)
{
@@ -5662,7 +5797,16 @@ double Expression::EvaluationContext::evaluateFunction (const String& functionNa
}
}
- throw EvaluationError ("Unknown function: \"" + functionName + "\"");
+ throw Helpers::EvaluationError ("Unknown function: \"" + functionName + "\"");
+}
+
+void Expression::Scope::visitRelativeScope (const String&, Visitor&) const
+{
+}
+
+const String Expression::Scope::getScopeUID() const
+{
+ return String::empty;
}
END_JUCE_NAMESPACE
@@ -23229,10 +23373,6 @@ public:
}
}
- ~WavAudioFormatReader()
- {
- }
-
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples)
{
@@ -23388,7 +23528,8 @@ private:
const int bytesPerFrame = numChannels * bitsPerSample / 8;
output->writeInt (chunkName ("RIFF"));
output->writeInt ((int) (lengthInSamples * bytesPerFrame
- + ((bwavChunk.getSize() > 0) ? (44 + bwavChunk.getSize()) : 36)));
+ + ((bwavChunk.getSize() > 0) ? (44 + bwavChunk.getSize()) : 36)
+ + (smplChunk.getSize() > 0 ? smplChunk.getSize() + 8 : 0)));
output->writeInt (chunkName ("WAVE"));
output->writeInt (chunkName ("fmt "));
@@ -35989,10 +36130,6 @@ AudioProcessorGraph::Node::Node (const uint32 id_, AudioProcessor* const process
jassert (processor_ != 0);
}
-AudioProcessorGraph::Node::~Node()
-{
-}
-
void AudioProcessorGraph::Node::prepare (const double sampleRate, const int blockSize,
AudioProcessorGraph* const graph)
{
@@ -42908,6 +43045,8 @@ public:
void componentBeingDeleted (Component& comp)
{
+ ComponentMovementWatcher::componentBeingDeleted (comp);
+
if (component == &comp || comp.isParentOf (component))
cancel();
}
@@ -43041,9 +43180,14 @@ void ModalComponentManager::handleAsyncUpdate()
if (! item->isActive)
{
for (int j = item->callbacks.size(); --j >= 0;)
+ {
item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue);
- stack.remove (i);
+ if (! stack.contains (item))
+ break;
+ }
+
+ stack.removeObject (item);
}
}
}
@@ -49185,8 +49329,13 @@ const Image ListBox::createSnapshotOfSelectedRows (int& imageX, int& imageY)
Graphics g (snapshot);
g.setOrigin (pos.getX() - imageX, pos.getY() - imageY);
+
if (g.reduceClipRegion (rowComp->getLocalBounds()))
+ {
+ g.beginTransparencyLayer (0.6f);
rowComp->paintEntireComponent (g, false);
+ g.endTransparencyLayer();
+ }
}
}
@@ -49202,7 +49351,6 @@ void ListBox::startDragAndDrop (const MouseEvent& e, const String& dragDescripti
{
int x, y;
Image dragImage (createSnapshotOfSelectedRows (x, y));
- dragImage.multiplyAllAlphas (0.6f);
MouseEvent e2 (e.getEventRelativeTo (this));
const Point p (x - e2.x, y - e2.y);
@@ -79205,43 +79353,17 @@ void MarkerList::ValueTreeWrapper::removeMarker (const ValueTree& marker, UndoMa
state.removeChild (marker, undoManager);
}
-class MarkerListEvaluator : public Expression::EvaluationContext
+double MarkerList::getMarkerPosition (const Marker& marker, Component* parentComponent) const
{
-public:
- MarkerListEvaluator (const MarkerList& markerList_, Component* const parentComponent_)
- : markerList (markerList_), parentComponent (parentComponent_)
+ if (parentComponent != 0)
{
+ RelativeCoordinatePositionerBase::ComponentScope scope (*parentComponent);
+ return marker.position.resolve (&scope);
}
-
- const Expression getSymbolValue (const String& objectName, const String& member) const
+ else
{
- if (member.isEmpty())
- {
- const MarkerList::Marker* const marker = markerList.getMarker (objectName);
-
- if (marker != 0)
- return Expression (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);
+ return marker.position.resolve (0);
}
-
-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)
@@ -79280,15 +79402,28 @@ END_JUCE_NAMESPACE
BEGIN_JUCE_NAMESPACE
const String RelativeCoordinate::Strings::parent ("parent");
-const String RelativeCoordinate::Strings::this_ ("this");
const String RelativeCoordinate::Strings::left ("left");
const String RelativeCoordinate::Strings::right ("right");
const String RelativeCoordinate::Strings::top ("top");
const String RelativeCoordinate::Strings::bottom ("bottom");
-const String RelativeCoordinate::Strings::parentLeft ("parent.left");
-const String RelativeCoordinate::Strings::parentTop ("parent.top");
-const String RelativeCoordinate::Strings::parentRight ("parent.right");
-const String RelativeCoordinate::Strings::parentBottom ("parent.bottom");
+const String RelativeCoordinate::Strings::x ("x");
+const String RelativeCoordinate::Strings::y ("y");
+const String RelativeCoordinate::Strings::width ("width");
+const String RelativeCoordinate::Strings::height ("height");
+
+RelativeCoordinate::StandardStrings::Type RelativeCoordinate::StandardStrings::getTypeOf (const String& s) throw()
+{
+ if (s == Strings::left) return left;
+ if (s == Strings::right) return right;
+ if (s == Strings::top) return top;
+ if (s == Strings::bottom) return bottom;
+ if (s == Strings::x) return x;
+ if (s == Strings::y) return y;
+ if (s == Strings::width) return width;
+ if (s == Strings::height) return height;
+ if (s == Strings::parent) return parent;
+ return unknown;
+}
RelativeCoordinate::RelativeCoordinate()
{
@@ -79339,12 +79474,12 @@ bool RelativeCoordinate::operator!= (const RelativeCoordinate& other) const thro
return ! operator== (other);
}
-double RelativeCoordinate::resolve (const Expression::EvaluationContext* context) const
+double RelativeCoordinate::resolve (const Expression::Scope* scope) const
{
try
{
- if (context != 0)
- return term.evaluate (*context);
+ if (scope != 0)
+ return term.evaluate (*scope);
else
return term.evaluate();
}
@@ -79354,12 +79489,12 @@ double RelativeCoordinate::resolve (const Expression::EvaluationContext* context
return 0.0;
}
-bool RelativeCoordinate::isRecursive (const Expression::EvaluationContext* context) const
+bool RelativeCoordinate::isRecursive (const Expression::Scope* scope) const
{
try
{
- if (context != 0)
- term.evaluate (*context);
+ if (scope != 0)
+ term.evaluate (*scope);
else
term.evaluate();
}
@@ -79371,36 +79506,24 @@ bool RelativeCoordinate::isRecursive (const Expression::EvaluationContext* conte
return false;
}
-void RelativeCoordinate::moveToAbsolute (double newPos, const Expression::EvaluationContext* context)
+void RelativeCoordinate::moveToAbsolute (double newPos, const Expression::Scope* scope)
{
try
{
- if (context != 0)
+ if (scope != 0)
{
- term = term.adjustedToGiveNewResult (newPos, *context);
+ term = term.adjustedToGiveNewResult (newPos, *scope);
}
else
{
- Expression::EvaluationContext defaultContext;
- term = term.adjustedToGiveNewResult (newPos, defaultContext);
+ Expression::Scope defaultScope;
+ term = term.adjustedToGiveNewResult (newPos, defaultScope);
}
}
catch (...)
{}
}
-bool RelativeCoordinate::references (const String& coordName, const Expression::EvaluationContext* context) const
-{
- try
- {
- return term.referencesSymbol (coordName, context);
- }
- catch (...)
- {}
-
- return false;
-}
-
bool RelativeCoordinate::isDynamic() const
{
return term.usesAnySymbols();
@@ -79411,14 +79534,6 @@ const String RelativeCoordinate::toString() const
return term.toString();
}
-void RelativeCoordinate::renameSymbolIfUsed (const String& oldName, const String& newName)
-{
- jassert (newName.isNotEmpty() && newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
-
- if (term.referencesSymbol (oldName, 0))
- term = term.withRenamedSymbol (oldName, newName);
-}
-
END_JUCE_NAMESPACE
/*** End of inlined file: juce_RelativeCoordinate.cpp ***/
@@ -79475,16 +79590,16 @@ bool RelativePoint::operator!= (const RelativePoint& other) const throw()
return ! operator== (other);
}
-const Point RelativePoint::resolve (const Expression::EvaluationContext* context) const
+const Point RelativePoint::resolve (const Expression::Scope* scope) const
{
- return Point ((float) x.resolve (context),
- (float) y.resolve (context));
+ return Point ((float) x.resolve (scope),
+ (float) y.resolve (scope));
}
-void RelativePoint::moveToAbsolute (const Point& newPos, const Expression::EvaluationContext* context)
+void RelativePoint::moveToAbsolute (const Point& newPos, const Expression::Scope* scope)
{
- x.moveToAbsolute (newPos.getX(), context);
- y.moveToAbsolute (newPos.getY(), context);
+ x.moveToAbsolute (newPos.getX(), scope);
+ y.moveToAbsolute (newPos.getY(), scope);
}
const String RelativePoint::toString() const
@@ -79492,12 +79607,6 @@ const String RelativePoint::toString() const
return x.toString() + ", " + y.toString();
}
-void RelativePoint::renameSymbolIfUsed (const String& oldName, const String& newName)
-{
- x.renameSymbolIfUsed (oldName, newName);
- y.renameSymbolIfUsed (oldName, newName);
-}
-
bool RelativePoint::isDynamic() const
{
return x.isDynamic() || y.isDynamic();
@@ -79523,13 +79632,23 @@ namespace RelativeRectangleHelpers
bool dependsOnSymbolsOtherThanThis (const Expression& e)
{
+ if (e.getType() == Expression::operatorType && e.getSymbolOrFunction() == ".")
+ return true;
+
if (e.getType() == Expression::symbolType)
{
- String objectName, memberName;
- e.getSymbolParts (objectName, memberName);
+ switch (RelativeCoordinate::StandardStrings::getTypeOf (e.getSymbolOrFunction()))
+ {
+ case RelativeCoordinate::StandardStrings::x:
+ case RelativeCoordinate::StandardStrings::y:
+ case RelativeCoordinate::StandardStrings::left:
+ case RelativeCoordinate::StandardStrings::right:
+ case RelativeCoordinate::StandardStrings::top:
+ case RelativeCoordinate::StandardStrings::bottom: return false;
+ default: break;
+ }
- if (objectName != RelativeCoordinate::Strings::this_)
- return true;
+ return true;
}
else
{
@@ -79554,11 +79673,9 @@ RelativeRectangle::RelativeRectangle (const RelativeCoordinate& left_, const Rel
RelativeRectangle::RelativeRectangle (const Rectangle& rect)
: left (rect.getX()),
- right (Expression::symbol (RelativeCoordinate::Strings::this_ + "." + RelativeCoordinate::Strings::left)
- + Expression ((double) rect.getWidth())),
+ right (Expression::symbol (RelativeCoordinate::Strings::left) + Expression ((double) rect.getWidth())),
top (rect.getY()),
- bottom (Expression::symbol (RelativeCoordinate::Strings::this_ + "." + RelativeCoordinate::Strings::top)
- + Expression ((double) rect.getHeight()))
+ bottom (Expression::symbol (RelativeCoordinate::Strings::top) + Expression ((double) rect.getHeight()))
{
}
@@ -79584,22 +79701,58 @@ bool RelativeRectangle::operator!= (const RelativeRectangle& other) const throw(
return ! operator== (other);
}
-const Rectangle RelativeRectangle::resolve (const Expression::EvaluationContext* context) const
+// An expression context that can evaluate expressions using "this"
+class RelativeRectangleLocalScope : public Expression::Scope
{
- const double l = left.resolve (context);
- const double r = right.resolve (context);
- const double t = top.resolve (context);
- const double b = bottom.resolve (context);
+public:
+ RelativeRectangleLocalScope (const RelativeRectangle& rect_) : rect (rect_) {}
+
+ const Expression getSymbolValue (const String& symbol) const
+ {
+ switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
+ {
+ case RelativeCoordinate::StandardStrings::x:
+ case RelativeCoordinate::StandardStrings::left: return rect.left.getExpression();
+ case RelativeCoordinate::StandardStrings::y:
+ case RelativeCoordinate::StandardStrings::top: return rect.top.getExpression();
+ case RelativeCoordinate::StandardStrings::right: return rect.right.getExpression();
+ case RelativeCoordinate::StandardStrings::bottom: return rect.bottom.getExpression();
+ default: break;
+ }
+
+ return Expression::Scope::getSymbolValue (symbol);
+ }
- return Rectangle ((float) l, (float) t, (float) jmax (0.0, r - l), (float) jmax (0.0, b - t));
+private:
+ const RelativeRectangle& rect;
+
+ JUCE_DECLARE_NON_COPYABLE (RelativeRectangleLocalScope);
+};
+
+const Rectangle RelativeRectangle::resolve (const Expression::Scope* scope) const
+{
+ if (scope == 0)
+ {
+ RelativeRectangleLocalScope scope (*this);
+ return resolve (&scope);
+ }
+ else
+ {
+ const double l = left.resolve (scope);
+ const double r = right.resolve (scope);
+ const double t = top.resolve (scope);
+ const double b = bottom.resolve (scope);
+
+ return Rectangle ((float) l, (float) t, (float) jmax (0.0, r - l), (float) jmax (0.0, b - t));
+ }
}
-void RelativeRectangle::moveToAbsolute (const Rectangle& newPos, const Expression::EvaluationContext* context)
+void RelativeRectangle::moveToAbsolute (const Rectangle& newPos, const Expression::Scope* scope)
{
- left.moveToAbsolute (newPos.getX(), context);
- right.moveToAbsolute (newPos.getRight(), context);
- top.moveToAbsolute (newPos.getY(), context);
- bottom.moveToAbsolute (newPos.getBottom(), context);
+ left.moveToAbsolute (newPos.getX(), scope);
+ right.moveToAbsolute (newPos.getRight(), scope);
+ top.moveToAbsolute (newPos.getY(), scope);
+ bottom.moveToAbsolute (newPos.getBottom(), scope);
}
bool RelativeRectangle::isDynamic() const
@@ -79617,12 +79770,12 @@ const String RelativeRectangle::toString() const
return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString();
}
-void RelativeRectangle::renameSymbolIfUsed (const String& oldName, const String& newName)
+void RelativeRectangle::renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope)
{
- left.renameSymbolIfUsed (oldName, newName);
- right.renameSymbolIfUsed (oldName, newName);
- top.renameSymbolIfUsed (oldName, newName);
- bottom.renameSymbolIfUsed (oldName, newName);
+ left = left.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
+ right = right.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
+ top = top.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
+ bottom = bottom.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
}
class RelativeRectangleComponentPositioner : public RelativeCoordinatePositionerBase
@@ -79652,7 +79805,8 @@ public:
{
for (int i = 4; --i >= 0;)
{
- const Rectangle newBounds (rectangle.resolve (this).getSmallestIntegerContainer());
+ ComponentScope scope (getComponent());
+ const Rectangle newBounds (rectangle.resolve (&scope).getSmallestIntegerContainer());
if (newBounds == getComponent().getBounds())
return;
@@ -79669,31 +79823,6 @@ 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())
@@ -79711,9 +79840,7 @@ void RelativeRectangle::applyToComponent (Component& component) const
else
{
component.setPositioner (0);
-
- TemporaryRectangleContext context (*this);
- component.setBounds (resolve (&context).getSmallestIntegerContainer());
+ component.setBounds (resolve (0).getSmallestIntegerContainer());
}
}
@@ -79801,10 +79928,10 @@ void RelativePointPath::swapWith (RelativePointPath& other) throw()
swapVariables (containsDynamicPoints, other.containsDynamicPoints);
}
-void RelativePointPath::createPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::createPath (Path& path, Expression::Scope* scope) const
{
for (int i = 0; i < elements.size(); ++i)
- elements.getUnchecked(i)->addToPath (path, coordFinder);
+ elements.getUnchecked(i)->addToPath (path, scope);
}
bool RelativePointPath::containsAnyDynamicPoints() const
@@ -79849,9 +79976,9 @@ const ValueTree RelativePointPath::StartSubPath::createTree() const
return v;
}
-void RelativePointPath::StartSubPath::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::StartSubPath::addToPath (Path& path, Expression::Scope* scope) const
{
- path.startNewSubPath (startPos.resolve (coordFinder));
+ path.startNewSubPath (startPos.resolve (scope));
}
RelativePoint* RelativePointPath::StartSubPath::getControlPoints (int& numPoints)
@@ -79875,7 +80002,7 @@ const ValueTree RelativePointPath::CloseSubPath::createTree() const
return ValueTree (DrawablePath::ValueTreeWrapper::Element::closeSubPathElement);
}
-void RelativePointPath::CloseSubPath::addToPath (Path& path, Expression::EvaluationContext*) const
+void RelativePointPath::CloseSubPath::addToPath (Path& path, Expression::Scope*) const
{
path.closeSubPath();
}
@@ -79903,9 +80030,9 @@ const ValueTree RelativePointPath::LineTo::createTree() const
return v;
}
-void RelativePointPath::LineTo::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::LineTo::addToPath (Path& path, Expression::Scope* scope) const
{
- path.lineTo (endPoint.resolve (coordFinder));
+ path.lineTo (endPoint.resolve (scope));
}
RelativePoint* RelativePointPath::LineTo::getControlPoints (int& numPoints)
@@ -79934,10 +80061,10 @@ const ValueTree RelativePointPath::QuadraticTo::createTree() const
return v;
}
-void RelativePointPath::QuadraticTo::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::QuadraticTo::addToPath (Path& path, Expression::Scope* scope) const
{
- path.quadraticTo (controlPoints[0].resolve (coordFinder),
- controlPoints[1].resolve (coordFinder));
+ path.quadraticTo (controlPoints[0].resolve (scope),
+ controlPoints[1].resolve (scope));
}
RelativePoint* RelativePointPath::QuadraticTo::getControlPoints (int& numPoints)
@@ -79968,11 +80095,11 @@ const ValueTree RelativePointPath::CubicTo::createTree() const
return v;
}
-void RelativePointPath::CubicTo::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::CubicTo::addToPath (Path& path, Expression::Scope* scope) const
{
- path.cubicTo (controlPoints[0].resolve (coordFinder),
- controlPoints[1].resolve (coordFinder),
- controlPoints[2].resolve (coordFinder));
+ path.cubicTo (controlPoints[0].resolve (scope),
+ controlPoints[1].resolve (scope),
+ controlPoints[2].resolve (scope));
}
RelativePoint* RelativePointPath::CubicTo::getControlPoints (int& numPoints)
@@ -80016,30 +80143,30 @@ RelativeParallelogram::~RelativeParallelogram()
{
}
-void RelativeParallelogram::resolveThreePoints (Point* points, Expression::EvaluationContext* const coordFinder) const
+void RelativeParallelogram::resolveThreePoints (Point* points, Expression::Scope* const scope) const
{
- points[0] = topLeft.resolve (coordFinder);
- points[1] = topRight.resolve (coordFinder);
- points[2] = bottomLeft.resolve (coordFinder);
+ points[0] = topLeft.resolve (scope);
+ points[1] = topRight.resolve (scope);
+ points[2] = bottomLeft.resolve (scope);
}
-void RelativeParallelogram::resolveFourCorners (Point* points, Expression::EvaluationContext* const coordFinder) const
+void RelativeParallelogram::resolveFourCorners (Point* points, Expression::Scope* const scope) const
{
- resolveThreePoints (points, coordFinder);
+ resolveThreePoints (points, scope);
points[3] = points[1] + (points[2] - points[0]);
}
-const Rectangle RelativeParallelogram::getBounds (Expression::EvaluationContext* const coordFinder) const
+const Rectangle RelativeParallelogram::getBounds (Expression::Scope* const scope) const
{
Point points[4];
- resolveFourCorners (points, coordFinder);
+ resolveFourCorners (points, scope);
return Rectangle::findAreaContainingPoints (points, 4);
}
-void RelativeParallelogram::getPath (Path& path, Expression::EvaluationContext* const coordFinder) const
+void RelativeParallelogram::getPath (Path& path, Expression::Scope* const scope) const
{
Point points[4];
- resolveFourCorners (points, coordFinder);
+ resolveFourCorners (points, scope);
path.startNewSubPath (points[0]);
path.lineTo (points[1]);
@@ -80048,18 +80175,18 @@ void RelativeParallelogram::getPath (Path& path, Expression::EvaluationContext*
path.closeSubPath();
}
-const AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::EvaluationContext* const coordFinder)
+const AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::Scope* const scope)
{
Point corners[3];
- resolveThreePoints (corners, coordFinder);
+ resolveThreePoints (corners, scope);
const Line top (corners[0], corners[1]);
const Line left (corners[0], corners[2]);
const Point newTopRight (corners[0] + Point (top.getLength(), 0.0f));
const Point newBottomLeft (corners[0] + Point (0.0f, left.getLength()));
- topRight.moveToAbsolute (newTopRight, coordFinder);
- bottomLeft.moveToAbsolute (newBottomLeft, coordFinder);
+ topRight.moveToAbsolute (newTopRight, scope);
+ bottomLeft.moveToAbsolute (newBottomLeft, scope);
return AffineTransform::fromTargetPoints (corners[0].getX(), corners[0].getY(), corners[0].getX(), corners[0].getY(),
corners[1].getX(), corners[1].getY(), newTopRight.getX(), newTopRight.getY(),
@@ -80111,51 +80238,169 @@ END_JUCE_NAMESPACE
/*** Start of inlined file: juce_RelativeCoordinatePositioner.cpp ***/
BEGIN_JUCE_NAMESPACE
-RelativeCoordinatePositionerBase::RelativeCoordinatePositionerBase (Component& component_)
- : Component::Positioner (component_), registeredOk (false)
+RelativeCoordinatePositionerBase::ComponentScope::ComponentScope (Component& component_)
+ : component (component_)
{
}
-RelativeCoordinatePositionerBase::~RelativeCoordinatePositionerBase()
+const Expression RelativeCoordinatePositionerBase::ComponentScope::getSymbolValue (const String& symbol) const
{
- unregisterListeners();
+ switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
+ {
+ case RelativeCoordinate::StandardStrings::x:
+ case RelativeCoordinate::StandardStrings::left: return Expression ((double) component.getX());
+ case RelativeCoordinate::StandardStrings::y:
+ case RelativeCoordinate::StandardStrings::top: return Expression ((double) component.getY());
+ case RelativeCoordinate::StandardStrings::width: return Expression ((double) component.getWidth());
+ case RelativeCoordinate::StandardStrings::height: return Expression ((double) component.getHeight());
+ case RelativeCoordinate::StandardStrings::right: return Expression ((double) component.getRight());
+ case RelativeCoordinate::StandardStrings::bottom: return Expression ((double) component.getBottom());
+ default: break;
+ }
+
+ MarkerList* list;
+ const MarkerList::Marker* const marker = findMarker (symbol, list);
+
+ if (marker != 0)
+ return marker->position.getExpression();
+
+ return Expression::Scope::getSymbolValue (symbol);
+}
+
+void RelativeCoordinatePositionerBase::ComponentScope::visitRelativeScope (const String& scopeName, Visitor& visitor) const
+{
+ Component* targetComp = 0;
+
+ if (scopeName == RelativeCoordinate::Strings::parent)
+ targetComp = component.getParentComponent();
+ else
+ targetComp = findSiblingComponent (scopeName);
+
+ if (targetComp != 0)
+ visitor.visit (ComponentScope (*targetComp));
+}
+
+const String RelativeCoordinatePositionerBase::ComponentScope::getScopeUID() const
+{
+ return String::toHexString ((pointer_sized_int) (void*) &component);
+}
+
+Component* RelativeCoordinatePositionerBase::ComponentScope::findSiblingComponent (const String& componentID) const
+{
+ Component* const parent = component.getParentComponent();
+
+ if (parent != 0)
+ {
+ for (int i = parent->getNumChildComponents(); --i >= 0;)
+ {
+ Component* const c = parent->getChildComponent(i);
+
+ if (c->getComponentID() == componentID)
+ return c;
+ }
+ }
+
+ return 0;
}
-const Expression RelativeCoordinatePositionerBase::getSymbolValue (const String& objectName, const String& member) const
+const MarkerList::Marker* RelativeCoordinatePositionerBase::ComponentScope::findMarker (const String& name, MarkerList*& list) const
{
- jassert (objectName.isNotEmpty());
+ const MarkerList::Marker* marker = 0;
- if (member.isNotEmpty())
+ Component* const parent = component.getParentComponent();
+
+ if (parent != 0)
{
- const Component* comp = getSourceComponent (objectName);
+ list = parent->getMarkers (true);
+ if (list != 0)
+ marker = list->getMarker (name);
- if (comp == 0)
+ if (marker == 0)
{
- if (objectName == RelativeCoordinate::Strings::parent)
- comp = getComponent().getParentComponent();
- else if (objectName == RelativeCoordinate::Strings::this_ || objectName == getComponent().getComponentID())
- comp = &getComponent();
+ list = parent->getMarkers (false);
+
+ if (list != 0)
+ marker = list->getMarker (name);
}
+ }
+
+ return marker;
+}
+
+class RelativeCoordinatePositionerBase::DependencyFinderScope : public ComponentScope
+{
+public:
+ DependencyFinderScope (Component& component_, RelativeCoordinatePositionerBase& positioner_, bool& ok_)
+ : ComponentScope (component_), positioner (positioner_), ok (ok_)
+ {
+ }
- if (comp != 0)
+ const Expression getSymbolValue (const String& symbol) const
+ {
+ if (symbol == RelativeCoordinate::Strings::left || symbol == RelativeCoordinate::Strings::x
+ || symbol == RelativeCoordinate::Strings::width || symbol == RelativeCoordinate::Strings::right
+ || symbol == RelativeCoordinate::Strings::top || symbol == RelativeCoordinate::Strings::y
+ || symbol == RelativeCoordinate::Strings::height || symbol == RelativeCoordinate::Strings::bottom)
+ {
+ positioner.registerComponentListener (component);
+ }
+ else
{
- if (member == RelativeCoordinate::Strings::left) return xToExpression (comp, 0);
- if (member == RelativeCoordinate::Strings::right) return xToExpression (comp, comp->getWidth());
- if (member == RelativeCoordinate::Strings::top) return yToExpression (comp, 0);
- if (member == RelativeCoordinate::Strings::bottom) return yToExpression (comp, comp->getHeight());
+ MarkerList* list;
+ const MarkerList::Marker* const marker = findMarker (symbol, list);
+
+ if (marker != 0)
+ {
+ positioner.registerMarkerListListener (list);
+ }
+ else
+ {
+ // The marker we want doesn't exist, so watch all lists in case they change and the marker appears later..
+ positioner.registerMarkerListListener (component.getMarkers (true));
+ positioner.registerMarkerListListener (component.getMarkers (false));
+ ok = false;
+ }
}
+
+ return ComponentScope::getSymbolValue (symbol);
}
- for (int i = sourceMarkerLists.size(); --i >= 0;)
+ void visitRelativeScope (const String& scopeName, Visitor& visitor) const
{
- MarkerList* const markerList = sourceMarkerLists.getUnchecked(i);
- const MarkerList::Marker* const marker = markerList->getMarker (objectName);
+ Component* targetComp = 0;
+
+ if (scopeName == RelativeCoordinate::Strings::parent)
+ targetComp = component.getParentComponent();
+ else
+ targetComp = findSiblingComponent (scopeName);
- if (marker != 0)
- return Expression (markerList->getMarkerPosition (*marker, getComponent().getParentComponent()));
+ if (targetComp != 0)
+ {
+ visitor.visit (DependencyFinderScope (*targetComp, positioner, ok));
+ }
+ else
+ {
+ // The named component doesn't exist, so we'll watch the parent for changes in case it appears later..
+ positioner.registerComponentListener (component);
+ ok = false;
+ }
}
- return Expression::EvaluationContext::getSymbolValue (objectName, member);
+private:
+ RelativeCoordinatePositionerBase& positioner;
+ bool& ok;
+
+ JUCE_DECLARE_NON_COPYABLE (DependencyFinderScope);
+};
+
+RelativeCoordinatePositionerBase::RelativeCoordinatePositionerBase (Component& component_)
+ : Component::Positioner (component_), registeredOk (false)
+{
+}
+
+RelativeCoordinatePositionerBase::~RelativeCoordinatePositionerBase()
+{
+ unregisterListeners();
}
void RelativeCoordinatePositionerBase::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
@@ -80198,7 +80443,10 @@ void RelativeCoordinatePositionerBase::apply()
bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate& coord)
{
- return registerListeners (coord.getExpression());
+ bool ok = true;
+ DependencyFinderScope finderScope (getComponent(), *this, ok);
+ coord.getExpression().evaluate (finderScope);
+ return ok;
}
bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
@@ -80207,95 +80455,12 @@ bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
return addCoordinate (point.y) && ok;
}
-bool RelativeCoordinatePositionerBase::registerListeners (const Expression& e)
-{
- bool ok = true;
-
- if (e.getType() == Expression::symbolType)
- {
- String objectName, memberName;
- e.getSymbolParts (objectName, memberName);
-
- if (memberName.isNotEmpty())
- ok = registerComponent (objectName) && ok;
- else
- ok = registerMarker (objectName) && ok;
- }
- else
- {
- for (int i = e.getNumInputs(); --i >= 0;)
- ok = registerListeners (e.getInput (i)) && ok;
- }
-
- return ok;
-}
-
-bool RelativeCoordinatePositionerBase::registerComponent (const String& componentID)
-{
- Component* comp = findComponent (componentID);
-
- if (comp == 0)
- {
- if (componentID == RelativeCoordinate::Strings::parent)
- comp = getComponent().getParentComponent();
- else if (componentID == RelativeCoordinate::Strings::this_ || componentID == getComponent().getComponentID())
- comp = &getComponent();
- }
-
- if (comp != 0)
- {
- if (comp != &getComponent())
- registerComponentListener (comp);
-
- return true;
- }
- else
- {
- // The component we want doesn't exist, so watch the parent in case the hierarchy changes and it appears later..
- Component* const parent = getComponent().getParentComponent();
-
- if (parent != 0)
- registerComponentListener (parent);
- else
- registerComponentListener (&getComponent());
-
- return false;
- }
-}
-
-bool RelativeCoordinatePositionerBase::registerMarker (const String markerName)
-{
- Component* const parent = getComponent().getParentComponent();
-
- if (parent != 0)
- {
- MarkerList* list = parent->getMarkers (true);
-
- if (list == 0 || list->getMarker (markerName) == 0)
- list = parent->getMarkers (false);
-
- if (list != 0 && list->getMarker (markerName) != 0)
- {
- registerMarkerListListener (list);
- return true;
- }
- else
- {
- // The marker we want doesn't exist, so watch all lists in case they change and the marker appears later..
- registerMarkerListListener (parent->getMarkers (true));
- registerMarkerListListener (parent->getMarkers (false));
- }
- }
-
- return false;
-}
-
-void RelativeCoordinatePositionerBase::registerComponentListener (Component* const comp)
+void RelativeCoordinatePositionerBase::registerComponentListener (Component& comp)
{
- if (comp != 0 && ! sourceComponents.contains (comp))
+ if (! sourceComponents.contains (&comp))
{
- comp->addComponentListener (this);
- sourceComponents.add (comp);
+ comp.addComponentListener (this);
+ sourceComponents.add (&comp);
}
}
@@ -80321,47 +80486,6 @@ void RelativeCoordinatePositionerBase::unregisterListeners()
sourceMarkerLists.clear();
}
-Component* RelativeCoordinatePositionerBase::findComponent (const String& componentID) const
-{
- Component* const parent = getComponent().getParentComponent();
-
- if (parent != 0)
- {
- for (int i = parent->getNumChildComponents(); --i >= 0;)
- {
- Component* const c = parent->getChildComponent(i);
-
- if (c->getComponentID() == componentID)
- return c;
- }
- }
-
- return 0;
-}
-
-Component* RelativeCoordinatePositionerBase::getSourceComponent (const String& objectName) const
-{
- for (int i = sourceComponents.size(); --i >= 0;)
- {
- Component* const comp = sourceComponents.getUnchecked(i);
-
- if (comp->getComponentID() == objectName)
- return comp;
- }
-
- return 0;
-}
-
-const Expression RelativeCoordinatePositionerBase::xToExpression (const Component* const source, const int x) const
-{
- return Expression ((double) (getComponent().getLocalPoint (source, Point (x, 0)).getX() + getComponent().getX()));
-}
-
-const Expression RelativeCoordinatePositionerBase::yToExpression (const Component* const source, const int y) const
-{
- return Expression ((double) (getComponent().getLocalPoint (source, Point (0, y)).getY() + getComponent().getY()));
-}
-
END_JUCE_NAMESPACE
/*** End of inlined file: juce_RelativeCoordinatePositioner.cpp ***/
@@ -86252,8 +86376,9 @@ public:
void applyToComponentBounds()
{
- if (isMainFill ? owner.mainFill.recalculateCoords (this)
- : owner.strokeFill.recalculateCoords (this))
+ ComponentScope scope (owner);
+ if (isMainFill ? owner.mainFill.recalculateCoords (&scope)
+ : owner.strokeFill.recalculateCoords (&scope))
owner.repaint();
}
@@ -86435,19 +86560,19 @@ bool DrawableShape::RelativeFillType::operator!= (const RelativeFillType& other)
return ! operator== (other);
}
-bool DrawableShape::RelativeFillType::recalculateCoords (Expression::EvaluationContext* context)
+bool DrawableShape::RelativeFillType::recalculateCoords (Expression::Scope* scope)
{
if (fill.isGradient())
{
- const Point g1 (gradientPoint1.resolve (context));
- const Point g2 (gradientPoint2.resolve (context));
+ const Point g1 (gradientPoint1.resolve (scope));
+ const Point g2 (gradientPoint2.resolve (scope));
AffineTransform t;
ColourGradient& g = *fill.gradient;
if (g.isRadial)
{
- const Point g3 (gradientPoint3.resolve (context));
+ const Point g3 (gradientPoint3.resolve (scope));
const Point g3Source (g1.getX() + g2.getY() - g1.getY(),
g1.getY() + g1.getX() - g2.getX());
@@ -86755,12 +86880,12 @@ bool DrawableComposite::registerCoordinates (RelativeCoordinatePositionerBase& p
return positioner.addPoint (bounds.bottomLeft) && ok;
}
-void DrawableComposite::recalculateCoordinates (Expression::EvaluationContext* context)
+void DrawableComposite::recalculateCoordinates (Expression::Scope* scope)
{
Point resolved[3];
- bounds.resolveThreePoints (resolved, context);
+ bounds.resolveThreePoints (resolved, scope);
- const Rectangle content (getContentArea().resolve (context));
+ const Rectangle content (getContentArea().resolve (scope));
AffineTransform t (AffineTransform::fromTargetPoints (content.getX(), content.getY(), resolved[0].getX(), resolved[0].getY(),
content.getRight(), content.getY(), resolved[1].getX(), resolved[1].getY(),
@@ -87023,12 +87148,12 @@ bool DrawableImage::registerCoordinates (RelativeCoordinatePositionerBase& posit
return positioner.addPoint (bounds.bottomLeft) && ok;
}
-void DrawableImage::recalculateCoordinates (Expression::EvaluationContext* context)
+void DrawableImage::recalculateCoordinates (Expression::Scope* scope)
{
if (image.isValid())
{
Point resolved[3];
- bounds.resolveThreePoints (resolved, context);
+ bounds.resolveThreePoints (resolved, scope);
const Point tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth());
const Point bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight());
@@ -87256,10 +87381,10 @@ const Path& DrawablePath::getStrokePath() const
return strokePath;
}
-void DrawablePath::applyRelativePath (const RelativePointPath& newRelativePath, Expression::EvaluationContext* context)
+void DrawablePath::applyRelativePath (const RelativePointPath& newRelativePath, Expression::Scope* scope)
{
Path newPath;
- newRelativePath.createPath (newPath, context);
+ newRelativePath.createPath (newPath, scope);
if (path != newPath)
{
@@ -87301,7 +87426,9 @@ public:
void applyToComponentBounds()
{
jassert (owner.relativePath != 0);
- owner.applyRelativePath (*owner.relativePath, this);
+
+ ComponentScope scope (getComponent());
+ owner.applyRelativePath (*owner.relativePath, &scope);
}
private:
@@ -87479,26 +87606,26 @@ const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const
return RelativePoint();
}
-float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::EvaluationContext* context) const
+float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::Scope* scope) const
{
const Identifier i (state.getType());
if (i == lineToElement || i == closeSubPathElement)
- return getEndPoint().resolve (context).getDistanceFrom (getStartPoint().resolve (context));
+ return getEndPoint().resolve (scope).getDistanceFrom (getStartPoint().resolve (scope));
if (i == cubicToElement)
{
Path p;
- p.startNewSubPath (getStartPoint().resolve (context));
- p.cubicTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context), getControlPoint (2).resolve (context));
+ p.startNewSubPath (getStartPoint().resolve (scope));
+ p.cubicTo (getControlPoint (0).resolve (scope), getControlPoint (1).resolve (scope), getControlPoint (2).resolve (scope));
return p.getLength();
}
if (i == quadraticToElement)
{
Path p;
- p.startNewSubPath (getStartPoint().resolve (context));
- p.quadraticTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context));
+ p.startNewSubPath (getStartPoint().resolve (scope));
+ p.quadraticTo (getControlPoint (0).resolve (scope), getControlPoint (1).resolve (scope));
return p.getLength();
}
@@ -87530,7 +87657,7 @@ void DrawablePath::ValueTreeWrapper::Element::convertToLine (UndoManager* undoMa
}
}
-void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::EvaluationContext* context, UndoManager* undoManager)
+void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::Scope* scope, UndoManager* undoManager)
{
const Identifier i (state.getType());
@@ -87541,8 +87668,8 @@ void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::Evalua
const RelativePoint start (getStartPoint());
const RelativePoint end (getEndPoint());
- const Point startResolved (start.resolve (context));
- const Point endResolved (end.resolve (context));
+ const Point startResolved (start.resolve (scope));
+ const Point endResolved (end.resolve (scope));
e.setControlPoint (0, startResolved + (endResolved - startResolved) * 0.3f, undoManager);
e.setControlPoint (1, startResolved + (endResolved - startResolved) * 0.7f, undoManager);
e.setControlPoint (2, end, undoManager);
@@ -87587,7 +87714,7 @@ namespace DrawablePathHelpers
}
}
-float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext* context) const
+float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point& targetPoint, Expression::Scope* scope) const
{
using namespace DrawablePathHelpers;
const Identifier type (state.getType());
@@ -87597,7 +87724,7 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po
{
RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint());
- const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) };
+ const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope), rp4.resolve (scope) };
float bestDistance = std::numeric_limits::max();
@@ -87617,7 +87744,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 (context), rp2.resolve (context), rp3.resolve (context) };
+ const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope) };
float bestDistance = std::numeric_limits::max();
@@ -87637,24 +87764,24 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po
else if (type == lineToElement)
{
RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint());
- const Line line (rp1.resolve (context), rp2.resolve (context));
+ const Line line (rp1.resolve (scope), rp2.resolve (scope));
bestProp = line.findNearestProportionalPositionTo (targetPoint);
}
return bestProp;
}
-ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& targetPoint, Expression::EvaluationContext* context, UndoManager* undoManager)
+ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& targetPoint, Expression::Scope* scope, UndoManager* undoManager)
{
ValueTree newTree;
const Identifier type (state.getType());
if (type == cubicToElement)
{
- float bestProp = findProportionAlongLine (targetPoint, context);
+ float bestProp = findProportionAlongLine (targetPoint, scope);
RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint());
- const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) };
+ const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope), rp4.resolve (scope) };
const Point mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * bestProp),
@@ -87679,10 +87806,10 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context) };
+ const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope) };
const Point mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * bestProp);
@@ -87702,7 +87829,7 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point line (rp1.resolve (context), rp2.resolve (context));
+ const Line line (rp1.resolve (scope), rp2.resolve (scope));
const Point newPoint (line.findNearestPointTo (targetPoint));
setControlPoint (0, newPoint, undoManager);
@@ -87821,13 +87948,13 @@ bool DrawableRectangle::registerCoordinates (RelativeCoordinatePositionerBase& p
return positioner.addPoint (cornerSize) && ok;
}
-void DrawableRectangle::recalculateCoordinates (Expression::EvaluationContext* context)
+void DrawableRectangle::recalculateCoordinates (Expression::Scope* scope)
{
Point points[3];
- bounds.resolveThreePoints (points, context);
+ bounds.resolveThreePoints (points, scope);
- const float cornerSizeX = (float) cornerSize.x.resolve (context);
- const float cornerSizeY = (float) cornerSize.y.resolve (context);
+ const float cornerSizeX = (float) cornerSize.x.resolve (scope);
+ const float cornerSizeY = (float) cornerSize.y.resolve (scope);
const float w = Line (points[0], points[1]).getLength();
const float h = Line (points[0], points[2]).getLength();
@@ -88027,14 +88154,14 @@ bool DrawableText::registerCoordinates (RelativeCoordinatePositionerBase& positi
return positioner.addPoint (fontSizeControlPoint) && ok;
}
-void DrawableText::recalculateCoordinates (Expression::EvaluationContext* context)
+void DrawableText::recalculateCoordinates (Expression::Scope* scope)
{
- bounds.resolveThreePoints (resolvedPoints, context);
+ bounds.resolveThreePoints (resolvedPoints, scope);
const float w = Line (resolvedPoints[0], resolvedPoints[1]).getLength();
const float h = Line (resolvedPoints[0], resolvedPoints[2]).getLength();
- const Point fontCoords (RelativeParallelogram::getInternalCoordForPoint (resolvedPoints, fontSizeControlPoint.resolve (context)));
+ const Point fontCoords (RelativeParallelogram::getInternalCoordForPoint (resolvedPoints, fontSizeControlPoint.resolve (scope)));
const float fontHeight = jlimit (0.01f, jmax (0.01f, h), fontCoords.getY());
const float fontWidth = jlimit (0.01f, jmax (0.01f, w), fontCoords.getX());
diff --git a/juce_amalgamated.h b/juce_amalgamated.h
index 47c84cadc6..97c02561b6 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 14
+#define JUCE_BUILDNUMBER 15
/** Current Juce version number.
@@ -17817,7 +17817,7 @@ private:
evaluated.
Expressions which use identifiers and functions require a subclass of
- Expression::EvaluationContext to be supplied when evaluating them, and this object
+ Expression::Scope to be supplied when evaluating them, and this object
is expected to be able to resolve the symbol names and perform the functions that
are used.
*/
@@ -17879,11 +17879,14 @@ public:
/** When evaluating an Expression object, this class is used to resolve symbols and
perform functions that the expression uses.
*/
- class JUCE_API EvaluationContext
+ class JUCE_API Scope
{
public:
- EvaluationContext();
- virtual ~EvaluationContext();
+ Scope();
+ virtual ~Scope();
+
+ /** Returns some kind of globally unique ID that identifies this scope. */
+ virtual const String getScopeUID() const;
/** Returns the value of a symbol.
If the symbol is unknown, this can throw an Expression::EvaluationError exception.
@@ -17891,55 +17894,97 @@ public:
one, e.g. for "foo.bar", symbol = "foo" and member = "bar".
@throws Expression::EvaluationError
*/
- virtual const Expression getSymbolValue (const String& symbol, const String& member) const;
+ virtual const Expression getSymbolValue (const String& symbol) const;
/** Executes a named function.
If the function name is unknown, this can throw an Expression::EvaluationError exception.
@throws Expression::EvaluationError
*/
- virtual double evaluateFunction (const String& functionName, const double* parameters, int numParams) const;
+ virtual double evaluateFunction (const String& functionName,
+ const double* parameters, int numParameters) const;
+
+ /** Used as a callback by the Scope::visitRelativeScope() method.
+ You should never create an instance of this class yourself, it's used by the
+ expression evaluation code.
+ */
+ class Visitor
+ {
+ public:
+ virtual ~Visitor() {}
+ virtual void visit (const Scope&) = 0;
+ };
+
+ /** Creates a Scope object for a named scope, and then calls a visitor
+ to do some kind of processing with this new scope.
+
+ If the name is valid, this method must create a suitable (temporary) Scope
+ object to represent it, and must call the Visitor::visit() method with this
+ new scope.
+ */
+ virtual void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
};
- /** Evaluates this expression, without using an EvaluationContext.
- Without an EvaluationContext, no symbols can be used, and only basic functions such as sin, cos, tan,
+ /** Evaluates this expression, without using a Scope.
+ Without a Scope, no symbols can be used, and only basic functions such as sin, cos, tan,
min, max are available.
- @throws Expression::EvaluationError
+ To find out about any errors during evaluation, use the other version of this method which
+ takes a String parameter.
*/
double evaluate() const;
- /** Evaluates this expression, providing a context that should be able to evaluate any symbols
+ /** Evaluates this expression, providing a scope that should be able to evaluate any symbols
+ or functions that it uses.
+ To find out about any errors during evaluation, use the other version of this method which
+ takes a String parameter.
+ */
+ double evaluate (const Scope& scope) const;
+
+ /** Evaluates this expression, providing a scope that should be able to evaluate any symbols
or functions that it uses.
- @throws Expression::EvaluationError
*/
- double evaluate (const EvaluationContext& context) const;
+ double evaluate (const Scope& scope, String& evaluationError) const;
/** Attempts to return an expression which is a copy of this one, but with a constant adjusted
to make the expression resolve to a target value.
E.g. if the expression is "x + 10" and x is 5, then asking for a target value of 8 will return
the expression "x + 3". Obviously some expressions can't be reversed in this way, in which
- case they might just be adjusted by adding a constant to them.
+ case they might just be adjusted by adding a constant to the original expression.
@throws Expression::EvaluationError
*/
- const Expression adjustedToGiveNewResult (double targetValue, const EvaluationContext& context) const;
+ const Expression adjustedToGiveNewResult (double targetValue, const Scope& scope) const;
+
+ /** Represents a symbol that is used in an Expression. */
+ struct Symbol
+ {
+ Symbol (const String& scopeUID, const String& symbolName);
+ bool operator== (const Symbol&) const throw();
+ bool operator!= (const Symbol&) const throw();
+
+ String scopeUID; /**< The unique ID of the Scope that contains this symbol. */
+ String symbolName; /**< The name of the symbol. */
+ };
/** Returns a copy of this expression in which all instances of a given symbol have been renamed. */
- const Expression withRenamedSymbol (const String& oldSymbol, const String& newSymbol) const;
+ const Expression withRenamedSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope) const;
/** Returns true if this expression makes use of the specified symbol.
- If a suitable context is supplied, the search will dereference and recursively check
+ If a suitable scope is supplied, the search will dereference and recursively check
all symbols, so that it can be determined whether this expression relies on the given
- symbol at any level in its evaluation. If the context parameter is null, this just checks
+ symbol at any level in its evaluation. If the scope parameter is null, this just checks
whether the expression contains any direct references to the symbol.
@throws Expression::EvaluationError
*/
- bool referencesSymbol (const String& symbol, const EvaluationContext* context) const;
+ bool referencesSymbol (const Symbol& symbol, const Scope& scope) const;
/** Returns true if this expression contains any symbols. */
bool usesAnySymbols() const;
+ /** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */
+ void findReferencedSymbols (Array& results, const Scope& scope) const;
+
/** An exception that can be thrown by Expression::parse(). */
class ParseError : public std::exception
{
@@ -17949,16 +17994,6 @@ public:
String description;
};
- /** An exception that can be thrown by Expression::evaluate(). */
- class EvaluationError : public std::exception
- {
- public:
- EvaluationError (const String& message);
- EvaluationError (const String& symbolName, const String& memberName);
-
- String description;
- };
-
/** Expression type.
@see Expression::getType()
*/
@@ -17973,19 +18008,8 @@ public:
/** Returns the type of this expression. */
Type getType() const throw();
- /** If this expression is a symbol, this returns its full name. */
- const String getSymbol() const;
-
- /** For a symbol that contains a dot, this returns the two */
- void getSymbolParts (String& objectName, String& memberName) const;
-
- /** If this expression is a function, this returns its name. */
- const String getFunction() const;
-
- /** If this expression is an operator, this returns its name.
- E.g. "+", "-", "*", "/", etc.
- */
- const String getOperator() const;
+ /** If this expression is a symbol, function or operator, this returns its identifier. */
+ const String getSymbolOrFunction() const;
/** Returns the number of inputs to this expression.
@see getInput
@@ -17999,35 +18023,12 @@ public:
private:
+ class Term;
class Helpers;
+ friend class Term;
friend class Helpers;
-
- class Term : public ReferenceCountedObject
- {
- public:
- Term() {}
- virtual ~Term() {}
-
- virtual Term* clone() const = 0;
- virtual double evaluate (const EvaluationContext&, int recursionDepth) const = 0;
- virtual int getNumInputs() const = 0;
- virtual Term* getInput (int index) const = 0;
- virtual int getInputIndexFor (const Term* possibleInput) const;
- virtual const String toString() const = 0;
- virtual int getOperatorPrecedence() const;
- virtual bool referencesSymbol (const String& symbol, const EvaluationContext*, int recursionDepth) const;
- virtual const ReferenceCountedObjectPtr createTermToEvaluateInput (const EvaluationContext&, const Term* inputTerm,
- double overallTarget, Term* topLevelTerm) const;
- virtual const ReferenceCountedObjectPtr negated();
- virtual Type getType() const throw() = 0;
- virtual void getSymbolParts (String& objectName, String& memberName) const;
- virtual const String getFunctionName() const;
-
- private:
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Term);
- };
-
friend class ScopedPointer;
+ friend class ReferenceCountedObjectPtr;
ReferenceCountedObjectPtr term;
explicit Expression (Term* term);
@@ -27477,35 +27478,35 @@ public:
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
+ - "left", "right", "top", "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 "left + 100".
+ - "[id].left", "[id].right", "[id].top", "[id].bottom", "[id].width", "[id].height", 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".
+ - Instead of an [id], you can use the name "parent" to refer to this component's parent. Like
+ any other component, these values are relative to their component's parent, so "parent.right" won't be
+ very useful for positioning a component because it refers to a position with the parent's parent.. but
+ "parent.width" can be used for setting positions relative to the parent's size. E.g. to make a 10x10
+ component which remains 1 pixel away from its parent's bottom-right, you could use
+ "right - 10, bottom - 10, parent.width - 1, parent.height - 1".
+ - The name of one of the parent component's markers can also be used as a symbol. 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"));
+ @code myComp.setBounds (RelativeBounds ("parent.width / 2 - 50, parent.height / 2 - 50, left + 100, 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"));
+ @code myComp.setBounds (RelativeBounds ("right - 100, bottom - 100, parent.width / 2 + 50, parent.height / 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"));
+ @code myComp.setBounds (RelativeBounds ("otherComp.right + 50, topMarker, left + 100, top + 100"));
@endcode
Be careful not to make your coordinate expressions recursive, though, or exceptions and assertions will
@@ -43481,7 +43482,6 @@ public:
AudioProcessorGraph();
/** Destructor.
-
Any processor objects that have been added to the graph will also be deleted.
*/
~AudioProcessorGraph();
@@ -43493,9 +43493,6 @@ public:
class JUCE_API Node : public ReferenceCountedObject
{
public:
- /** Destructor.
- */
- ~Node();
/** The ID number assigned to this node.
@@ -45643,18 +45640,18 @@ public:
/** Calculates the absolute position of this coordinate.
- You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
+ You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
- double resolve (const Expression::EvaluationContext* evaluationContext) const;
+ double resolve (const Expression::Scope* evaluationScope) const;
/** Returns true if this coordinate uses the specified coord name at any level in its evaluation.
This will recursively check any coordinates upon which this one depends.
*/
- bool references (const String& coordName, const Expression::EvaluationContext* evaluationContext) const;
+ bool references (const String& coordName, const Expression::Scope* evaluationScope) const;
/** Returns true if there's a recursive loop when trying to resolve this coordinate's position. */
- bool isRecursive (const Expression::EvaluationContext* evaluationContext) const;
+ bool isRecursive (const Expression::Scope* evaluationScope) const;
/** Returns true if this coordinate depends on any other coordinates for its position. */
bool isDynamic() const;
@@ -45665,10 +45662,7 @@ public:
or relative position to whatever value is necessary to make its resultant position
match the position that is provided.
*/
- void moveToAbsolute (double absoluteTargetPosition, const Expression::EvaluationContext* evaluationContext);
-
- /** Changes the name of a symbol if it is used as part of the coordinate's expression. */
- void renameSymbolIfUsed (const String& oldName, const String& newName);
+ void moveToAbsolute (double absoluteTargetPosition, const Expression::Scope* evaluationScope);
/** Returns the expression that defines this coordinate. */
const Expression& getExpression() const { return term; }
@@ -45688,15 +45682,27 @@ public:
struct Strings
{
static const String parent; /**< "parent" */
- static const String this_; /**< "this" */
static const String left; /**< "left" */
static const String right; /**< "right" */
static const String top; /**< "top" */
static const String bottom; /**< "bottom" */
- static const String parentLeft; /**< "parent.left" */
- static const String parentTop; /**< "parent.top" */
- static const String parentRight; /**< "parent.right" */
- static const String parentBottom; /**< "parent.bottom" */
+ static const String x; /**< "x" */
+ static const String y; /**< "y" */
+ static const String width; /**< "width" */
+ static const String height; /**< "height" */
+ };
+
+ struct StandardStrings
+ {
+ enum Type
+ {
+ left, right, top, bottom,
+ x, y, width, height,
+ parent,
+ unknown
+ };
+
+ static Type getTypeOf (const String& s) throw();
};
private:
@@ -45749,10 +45755,10 @@ public:
/** Calculates the absolute position of this point.
- You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
+ You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
- const Point resolve (const Expression::EvaluationContext* evaluationContext) const;
+ const Point resolve (const Expression::Scope* evaluationContext) const;
/** Changes the values of this point's coordinates to make it resolve to the specified position.
@@ -45760,7 +45766,7 @@ public:
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);
+ void moveToAbsolute (const Point& newPos, const Expression::Scope* 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
@@ -45769,11 +45775,6 @@ public:
*/
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;
@@ -45946,15 +45947,12 @@ private:
*/
class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner,
public ComponentListener,
- public MarkerList::Listener,
- public Expression::EvaluationContext
+ public MarkerList::Listener
{
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);
@@ -45966,25 +45964,40 @@ public:
bool addCoordinate (const RelativeCoordinate& coord);
bool addPoint (const RelativePoint& point);
+ /** Used for resolving a RelativeCoordinate expression in the context of a component. */
+ class ComponentScope : public Expression::Scope
+ {
+ public:
+ ComponentScope (Component& component_);
+
+ const Expression getSymbolValue (const String& symbol) const;
+ void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
+ const String getScopeUID() const;
+
+ protected:
+ Component& component;
+
+ Component* findSiblingComponent (const String& componentID) const;
+ const MarkerList::Marker* findMarker (const String& name, MarkerList*& list) const;
+
+ private:
+ JUCE_DECLARE_NON_COPYABLE (ComponentScope);
+ };
+
protected:
virtual bool registerCoordinates() = 0;
virtual void applyToComponentBounds() = 0;
private:
+ class DependencyFinderScope;
+ friend class DependencyFinderScope;
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 registerComponentListener (Component& 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);
};
@@ -46395,7 +46408,11 @@ protected:
{}
bool registerCoordinates() { return owner.registerCoordinates (*this); }
- void applyToComponentBounds() { owner.recalculateCoordinates (this); }
+ void applyToComponentBounds()
+ {
+ ComponentScope scope (getComponent());
+ owner.recalculateCoordinates (&scope);
+ }
private:
DrawableType& owner;
@@ -57857,11 +57874,11 @@ public:
RelativeParallelogram (const String& topLeft, const String& topRight, const String& bottomLeft);
~RelativeParallelogram();
- void resolveThreePoints (Point* points, Expression::EvaluationContext* coordFinder) const;
- void resolveFourCorners (Point* points, Expression::EvaluationContext* coordFinder) const;
- const Rectangle getBounds (Expression::EvaluationContext* coordFinder) const;
- void getPath (Path& path, Expression::EvaluationContext* coordFinder) const;
- const AffineTransform resetToPerpendicular (Expression::EvaluationContext* coordFinder);
+ void resolveThreePoints (Point* points, Expression::Scope* scope) const;
+ void resolveFourCorners (Point* points, Expression::Scope* scope) const;
+ const Rectangle getBounds (Expression::Scope* scope) const;
+ void getPath (Path& path, Expression::Scope* scope) const;
+ const AffineTransform resetToPerpendicular (Expression::Scope* scope);
bool isDynamic() const;
bool operator== (const RelativeParallelogram& other) const throw();
@@ -57911,7 +57928,7 @@ public:
bool operator!= (const RelativePointPath& other) const throw();
/** Resolves this points in this path and adds them to a normal Path object. */
- void createPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void createPath (Path& path, Expression::Scope* scope) const;
/** Returns true if the path contains any non-fixed points. */
bool containsAnyDynamicPoints() const;
@@ -57940,7 +57957,7 @@ public:
ElementBase (ElementType type);
virtual ~ElementBase() {}
virtual const ValueTree createTree() const = 0;
- virtual void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const = 0;
+ virtual void addToPath (Path& path, Expression::Scope*) const = 0;
virtual RelativePoint* getControlPoints (int& numPoints) = 0;
virtual ElementBase* clone() const = 0;
bool isDynamic();
@@ -57956,7 +57973,7 @@ public:
public:
StartSubPath (const RelativePoint& pos);
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
@@ -57971,7 +57988,7 @@ public:
public:
CloseSubPath();
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
@@ -57984,7 +58001,7 @@ public:
public:
LineTo (const RelativePoint& endPoint);
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
@@ -57999,7 +58016,7 @@ public:
public:
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint);
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
@@ -58014,7 +58031,7 @@ public:
public:
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint);
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
@@ -58087,10 +58104,10 @@ public:
/** Calculates the absolute position of this rectangle.
- You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
+ You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
- const Rectangle resolve (const Expression::EvaluationContext* evaluationContext) const;
+ const Rectangle resolve (const Expression::Scope* scope) const;
/** Changes the values of this rectangle's coordinates to make it resolve to the specified position.
@@ -58098,7 +58115,7 @@ public:
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
- void moveToAbsolute (const Rectangle& newPos, const Expression::EvaluationContext* evaluationContext);
+ void moveToAbsolute (const Rectangle& newPos, const Expression::Scope* scope);
/** 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.
@@ -58113,9 +58130,9 @@ public:
const String toString() const;
/** Renames a symbol if it is used by any of the coordinates.
- This calls RelativeCoordinate::renameSymbolIfUsed() on the rectangle's coordinates.
+ This calls Expression::withRenamedSymbol() on the rectangle's coordinates.
*/
- void renameSymbolIfUsed (const String& oldName, const String& newName);
+ void renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope);
/** Creates and sets an appropriate Component::Positioner object for the given component, which will
keep it positioned with this rectangle.
@@ -61907,7 +61924,7 @@ private:
friend class Drawable::Positioner;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
- void recalculateCoordinates (Expression::EvaluationContext*);
+ void recalculateCoordinates (Expression::Scope*);
void updateBoundsToFitChildren();
@@ -62024,7 +62041,7 @@ private:
friend class Drawable::Positioner;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
- void recalculateCoordinates (Expression::EvaluationContext*);
+ void recalculateCoordinates (Expression::Scope*);
DrawableImage& operator= (const DrawableImage&);
JUCE_LEAK_DETECTOR (DrawableImage);
@@ -62077,7 +62094,7 @@ public:
bool operator!= (const RelativeFillType&) const;
bool isDynamic() const;
- bool recalculateCoords (Expression::EvaluationContext* context);
+ bool recalculateCoords (Expression::Scope* scope);
void writeTo (ValueTree& v, ComponentBuilder::ImageProvider*, UndoManager*) const;
bool readFrom (const ValueTree& v, ComponentBuilder::ImageProvider*);
@@ -62260,7 +62277,7 @@ public:
const RelativePoint getStartPoint() const;
const RelativePoint getEndPoint() const;
void setControlPoint (int index, const RelativePoint& point, UndoManager*);
- float getLength (Expression::EvaluationContext*) const;
+ float getLength (Expression::Scope*) const;
ValueTreeWrapper getParent() const;
Element getPreviousElement() const;
@@ -62269,11 +62286,11 @@ public:
void setModeOfEndPoint (const String& newMode, UndoManager*);
void convertToLine (UndoManager*);
- void convertToCubic (Expression::EvaluationContext*, UndoManager*);
+ void convertToCubic (Expression::Scope*, UndoManager*);
void convertToPathBreak (UndoManager* undoManager);
- ValueTree insertPoint (const Point& targetPoint, Expression::EvaluationContext*, UndoManager*);
+ ValueTree insertPoint (const Point& targetPoint, Expression::Scope*, UndoManager*);
void removePoint (UndoManager* undoManager);
- float findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext*) const;
+ float findProportionAlongLine (const Point& targetPoint, Expression::Scope*) const;
static const Identifier mode, startSubPathElement, closeSubPathElement,
lineToElement, quadraticToElement, cubicToElement;
@@ -62298,7 +62315,7 @@ private:
class RelativePositioner;
friend class RelativePositioner;
- void applyRelativePath (const RelativePointPath&, Expression::EvaluationContext*);
+ void applyRelativePath (const RelativePointPath&, Expression::Scope*);
DrawablePath& operator= (const DrawablePath&);
JUCE_LEAK_DETECTOR (DrawablePath);
@@ -62377,7 +62394,7 @@ private:
void rebuildPath();
bool registerCoordinates (RelativeCoordinatePositionerBase&);
- void recalculateCoordinates (Expression::EvaluationContext*);
+ void recalculateCoordinates (Expression::Scope*);
DrawableRectangle& operator= (const DrawableRectangle&);
JUCE_LEAK_DETECTOR (DrawableRectangle);
@@ -62503,7 +62520,7 @@ private:
friend class Drawable::Positioner;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
- void recalculateCoordinates (Expression::EvaluationContext*);
+ void recalculateCoordinates (Expression::Scope*);
void refreshBounds();
const AffineTransform getArrangementAndTransform (GlyphArrangement& glyphs) const;
diff --git a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp
index d9d4d3da8f..f1aafce43a 100644
--- a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp
+++ b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp
@@ -370,10 +370,6 @@ public:
}
}
- ~WavAudioFormatReader()
- {
- }
-
//==============================================================================
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples)
@@ -532,7 +528,8 @@ private:
const int bytesPerFrame = numChannels * bitsPerSample / 8;
output->writeInt (chunkName ("RIFF"));
output->writeInt ((int) (lengthInSamples * bytesPerFrame
- + ((bwavChunk.getSize() > 0) ? (44 + bwavChunk.getSize()) : 36)));
+ + ((bwavChunk.getSize() > 0) ? (44 + bwavChunk.getSize()) : 36)
+ + (smplChunk.getSize() > 0 ? smplChunk.getSize() + 8 : 0)));
output->writeInt (chunkName ("WAVE"));
output->writeInt (chunkName ("fmt "));
diff --git a/src/audio/processors/juce_AudioProcessorGraph.cpp b/src/audio/processors/juce_AudioProcessorGraph.cpp
index 2199190cb8..95389a1589 100644
--- a/src/audio/processors/juce_AudioProcessorGraph.cpp
+++ b/src/audio/processors/juce_AudioProcessorGraph.cpp
@@ -42,10 +42,6 @@ AudioProcessorGraph::Node::Node (const uint32 id_, AudioProcessor* const process
jassert (processor_ != 0);
}
-AudioProcessorGraph::Node::~Node()
-{
-}
-
void AudioProcessorGraph::Node::prepare (const double sampleRate, const int blockSize,
AudioProcessorGraph* const graph)
{
diff --git a/src/audio/processors/juce_AudioProcessorGraph.h b/src/audio/processors/juce_AudioProcessorGraph.h
index 994bd901a7..ef60ac184d 100644
--- a/src/audio/processors/juce_AudioProcessorGraph.h
+++ b/src/audio/processors/juce_AudioProcessorGraph.h
@@ -57,7 +57,6 @@ public:
AudioProcessorGraph();
/** Destructor.
-
Any processor objects that have been added to the graph will also be deleted.
*/
~AudioProcessorGraph();
@@ -70,10 +69,6 @@ public:
class JUCE_API Node : public ReferenceCountedObject
{
public:
- /** Destructor.
- */
- ~Node();
-
//==============================================================================
/** The ID number assigned to this node.
diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h
index 132b4ea3f0..a65aaa57f2 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 14
+#define JUCE_BUILDNUMBER 15
/** Current Juce version number.
diff --git a/src/gui/components/controls/juce_ListBox.cpp b/src/gui/components/controls/juce_ListBox.cpp
index 94769be410..836710a462 100644
--- a/src/gui/components/controls/juce_ListBox.cpp
+++ b/src/gui/components/controls/juce_ListBox.cpp
@@ -888,8 +888,13 @@ const Image ListBox::createSnapshotOfSelectedRows (int& imageX, int& imageY)
Graphics g (snapshot);
g.setOrigin (pos.getX() - imageX, pos.getY() - imageY);
+
if (g.reduceClipRegion (rowComp->getLocalBounds()))
+ {
+ g.beginTransparencyLayer (0.6f);
rowComp->paintEntireComponent (g, false);
+ g.endTransparencyLayer();
+ }
}
}
@@ -905,7 +910,6 @@ void ListBox::startDragAndDrop (const MouseEvent& e, const String& dragDescripti
{
int x, y;
Image dragImage (createSnapshotOfSelectedRows (x, y));
- dragImage.multiplyAllAlphas (0.6f);
MouseEvent e2 (e.getEventRelativeTo (this));
const Point p (x - e2.x, y - e2.y);
diff --git a/src/gui/components/juce_Component.h b/src/gui/components/juce_Component.h
index 910f57c9c0..6b5e31c720 100644
--- a/src/gui/components/juce_Component.h
+++ b/src/gui/components/juce_Component.h
@@ -488,35 +488,35 @@ public:
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
+ - "left", "right", "top", "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 "left + 100".
+ - "[id].left", "[id].right", "[id].top", "[id].bottom", "[id].width", "[id].height", 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".
+ - Instead of an [id], you can use the name "parent" to refer to this component's parent. Like
+ any other component, these values are relative to their component's parent, so "parent.right" won't be
+ very useful for positioning a component because it refers to a position with the parent's parent.. but
+ "parent.width" can be used for setting positions relative to the parent's size. E.g. to make a 10x10
+ component which remains 1 pixel away from its parent's bottom-right, you could use
+ "right - 10, bottom - 10, parent.width - 1, parent.height - 1".
+ - The name of one of the parent component's markers can also be used as a symbol. 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"));
+ @code myComp.setBounds (RelativeBounds ("parent.width / 2 - 50, parent.height / 2 - 50, left + 100, 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"));
+ @code myComp.setBounds (RelativeBounds ("right - 100, bottom - 100, parent.width / 2 + 50, parent.height / 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"));
+ @code myComp.setBounds (RelativeBounds ("otherComp.right + 50, topMarker, left + 100, top + 100"));
@endcode
Be careful not to make your coordinate expressions recursive, though, or exceptions and assertions will
diff --git a/src/gui/components/juce_ModalComponentManager.cpp b/src/gui/components/juce_ModalComponentManager.cpp
index c5cf2b4c02..6d58bdd957 100644
--- a/src/gui/components/juce_ModalComponentManager.cpp
+++ b/src/gui/components/juce_ModalComponentManager.cpp
@@ -65,6 +65,8 @@ public:
void componentBeingDeleted (Component& comp)
{
+ ComponentMovementWatcher::componentBeingDeleted (comp);
+
if (component == &comp || comp.isParentOf (component))
cancel();
}
@@ -201,9 +203,14 @@ void ModalComponentManager::handleAsyncUpdate()
if (! item->isActive)
{
for (int j = item->callbacks.size(); --j >= 0;)
+ {
item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue);
- stack.remove (i);
+ if (! stack.contains (item))
+ break;
+ }
+
+ stack.removeObject (item);
}
}
}
diff --git a/src/gui/components/positioning/juce_MarkerList.cpp b/src/gui/components/positioning/juce_MarkerList.cpp
index 12cf0f2417..de82a67a59 100644
--- a/src/gui/components/positioning/juce_MarkerList.cpp
+++ b/src/gui/components/positioning/juce_MarkerList.cpp
@@ -28,8 +28,10 @@
BEGIN_JUCE_NAMESPACE
#include "juce_MarkerList.h"
+#include "juce_RelativeCoordinatePositioner.h"
#include "../juce_Component.h"
+
//==============================================================================
MarkerList::MarkerList()
{
@@ -246,44 +248,17 @@ void MarkerList::ValueTreeWrapper::removeMarker (const ValueTree& marker, UndoMa
state.removeChild (marker, undoManager);
}
-//==============================================================================
-class MarkerListEvaluator : public Expression::EvaluationContext
+double MarkerList::getMarkerPosition (const Marker& marker, Component* parentComponent) const
{
-public:
- MarkerListEvaluator (const MarkerList& markerList_, Component* const parentComponent_)
- : markerList (markerList_), parentComponent (parentComponent_)
+ if (parentComponent != 0)
{
+ RelativeCoordinatePositionerBase::ComponentScope scope (*parentComponent);
+ return marker.position.resolve (&scope);
}
-
- const Expression getSymbolValue (const String& objectName, const String& member) const
+ else
{
- if (member.isEmpty())
- {
- const MarkerList::Marker* const marker = markerList.getMarker (objectName);
-
- if (marker != 0)
- return Expression (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);
+ return marker.position.resolve (0);
}
-
-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);
}
//==============================================================================
diff --git a/src/gui/components/positioning/juce_RelativeCoordinate.cpp b/src/gui/components/positioning/juce_RelativeCoordinate.cpp
index 9861000402..6389d360d1 100644
--- a/src/gui/components/positioning/juce_RelativeCoordinate.cpp
+++ b/src/gui/components/positioning/juce_RelativeCoordinate.cpp
@@ -32,15 +32,28 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
const String RelativeCoordinate::Strings::parent ("parent");
-const String RelativeCoordinate::Strings::this_ ("this");
const String RelativeCoordinate::Strings::left ("left");
const String RelativeCoordinate::Strings::right ("right");
const String RelativeCoordinate::Strings::top ("top");
const String RelativeCoordinate::Strings::bottom ("bottom");
-const String RelativeCoordinate::Strings::parentLeft ("parent.left");
-const String RelativeCoordinate::Strings::parentTop ("parent.top");
-const String RelativeCoordinate::Strings::parentRight ("parent.right");
-const String RelativeCoordinate::Strings::parentBottom ("parent.bottom");
+const String RelativeCoordinate::Strings::x ("x");
+const String RelativeCoordinate::Strings::y ("y");
+const String RelativeCoordinate::Strings::width ("width");
+const String RelativeCoordinate::Strings::height ("height");
+
+RelativeCoordinate::StandardStrings::Type RelativeCoordinate::StandardStrings::getTypeOf (const String& s) throw()
+{
+ if (s == Strings::left) return left;
+ if (s == Strings::right) return right;
+ if (s == Strings::top) return top;
+ if (s == Strings::bottom) return bottom;
+ if (s == Strings::x) return x;
+ if (s == Strings::y) return y;
+ if (s == Strings::width) return width;
+ if (s == Strings::height) return height;
+ if (s == Strings::parent) return parent;
+ return unknown;
+}
//==============================================================================
RelativeCoordinate::RelativeCoordinate()
@@ -92,12 +105,12 @@ bool RelativeCoordinate::operator!= (const RelativeCoordinate& other) const thro
return ! operator== (other);
}
-double RelativeCoordinate::resolve (const Expression::EvaluationContext* context) const
+double RelativeCoordinate::resolve (const Expression::Scope* scope) const
{
try
{
- if (context != 0)
- return term.evaluate (*context);
+ if (scope != 0)
+ return term.evaluate (*scope);
else
return term.evaluate();
}
@@ -107,12 +120,12 @@ double RelativeCoordinate::resolve (const Expression::EvaluationContext* context
return 0.0;
}
-bool RelativeCoordinate::isRecursive (const Expression::EvaluationContext* context) const
+bool RelativeCoordinate::isRecursive (const Expression::Scope* scope) const
{
try
{
- if (context != 0)
- term.evaluate (*context);
+ if (scope != 0)
+ term.evaluate (*scope);
else
term.evaluate();
}
@@ -124,36 +137,24 @@ bool RelativeCoordinate::isRecursive (const Expression::EvaluationContext* conte
return false;
}
-void RelativeCoordinate::moveToAbsolute (double newPos, const Expression::EvaluationContext* context)
+void RelativeCoordinate::moveToAbsolute (double newPos, const Expression::Scope* scope)
{
try
{
- if (context != 0)
+ if (scope != 0)
{
- term = term.adjustedToGiveNewResult (newPos, *context);
+ term = term.adjustedToGiveNewResult (newPos, *scope);
}
else
{
- Expression::EvaluationContext defaultContext;
- term = term.adjustedToGiveNewResult (newPos, defaultContext);
+ Expression::Scope defaultScope;
+ term = term.adjustedToGiveNewResult (newPos, defaultScope);
}
}
catch (...)
{}
}
-bool RelativeCoordinate::references (const String& coordName, const Expression::EvaluationContext* context) const
-{
- try
- {
- return term.referencesSymbol (coordName, context);
- }
- catch (...)
- {}
-
- return false;
-}
-
bool RelativeCoordinate::isDynamic() const
{
return term.usesAnySymbols();
@@ -164,13 +165,6 @@ const String RelativeCoordinate::toString() const
return term.toString();
}
-void RelativeCoordinate::renameSymbolIfUsed (const String& oldName, const String& newName)
-{
- jassert (newName.isNotEmpty() && newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
-
- if (term.referencesSymbol (oldName, 0))
- term = term.withRenamedSymbol (oldName, newName);
-}
END_JUCE_NAMESPACE
diff --git a/src/gui/components/positioning/juce_RelativeCoordinate.h b/src/gui/components/positioning/juce_RelativeCoordinate.h
index d9dceb6e70..ce8d68cc83 100644
--- a/src/gui/components/positioning/juce_RelativeCoordinate.h
+++ b/src/gui/components/positioning/juce_RelativeCoordinate.h
@@ -69,18 +69,18 @@ public:
//==============================================================================
/** Calculates the absolute position of this coordinate.
- You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
+ You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
- double resolve (const Expression::EvaluationContext* evaluationContext) const;
+ double resolve (const Expression::Scope* evaluationScope) const;
/** Returns true if this coordinate uses the specified coord name at any level in its evaluation.
This will recursively check any coordinates upon which this one depends.
*/
- bool references (const String& coordName, const Expression::EvaluationContext* evaluationContext) const;
+ bool references (const String& coordName, const Expression::Scope* evaluationScope) const;
/** Returns true if there's a recursive loop when trying to resolve this coordinate's position. */
- bool isRecursive (const Expression::EvaluationContext* evaluationContext) const;
+ bool isRecursive (const Expression::Scope* evaluationScope) const;
/** Returns true if this coordinate depends on any other coordinates for its position. */
bool isDynamic() const;
@@ -92,10 +92,7 @@ public:
or relative position to whatever value is necessary to make its resultant position
match the position that is provided.
*/
- void moveToAbsolute (double absoluteTargetPosition, const Expression::EvaluationContext* evaluationContext);
-
- /** Changes the name of a symbol if it is used as part of the coordinate's expression. */
- void renameSymbolIfUsed (const String& oldName, const String& newName);
+ void moveToAbsolute (double absoluteTargetPosition, const Expression::Scope* evaluationScope);
/** Returns the expression that defines this coordinate. */
const Expression& getExpression() const { return term; }
@@ -118,15 +115,27 @@ public:
struct Strings
{
static const String parent; /**< "parent" */
- static const String this_; /**< "this" */
static const String left; /**< "left" */
static const String right; /**< "right" */
static const String top; /**< "top" */
static const String bottom; /**< "bottom" */
- static const String parentLeft; /**< "parent.left" */
- static const String parentTop; /**< "parent.top" */
- static const String parentRight; /**< "parent.right" */
- static const String parentBottom; /**< "parent.bottom" */
+ static const String x; /**< "x" */
+ static const String y; /**< "y" */
+ static const String width; /**< "width" */
+ static const String height; /**< "height" */
+ };
+
+ struct StandardStrings
+ {
+ enum Type
+ {
+ left, right, top, bottom,
+ x, y, width, height,
+ parent,
+ unknown
+ };
+
+ static Type getTypeOf (const String& s) throw();
};
private:
diff --git a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp
index bd87084daf..3de66a14eb 100644
--- a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp
+++ b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp
@@ -31,51 +31,171 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
-RelativeCoordinatePositionerBase::RelativeCoordinatePositionerBase (Component& component_)
- : Component::Positioner (component_), registeredOk (false)
+RelativeCoordinatePositionerBase::ComponentScope::ComponentScope (Component& component_)
+ : component (component_)
{
}
-RelativeCoordinatePositionerBase::~RelativeCoordinatePositionerBase()
+const Expression RelativeCoordinatePositionerBase::ComponentScope::getSymbolValue (const String& symbol) const
{
- unregisterListeners();
+ switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
+ {
+ case RelativeCoordinate::StandardStrings::x:
+ case RelativeCoordinate::StandardStrings::left: return Expression ((double) component.getX());
+ case RelativeCoordinate::StandardStrings::y:
+ case RelativeCoordinate::StandardStrings::top: return Expression ((double) component.getY());
+ case RelativeCoordinate::StandardStrings::width: return Expression ((double) component.getWidth());
+ case RelativeCoordinate::StandardStrings::height: return Expression ((double) component.getHeight());
+ case RelativeCoordinate::StandardStrings::right: return Expression ((double) component.getRight());
+ case RelativeCoordinate::StandardStrings::bottom: return Expression ((double) component.getBottom());
+ default: break;
+ }
+
+ MarkerList* list;
+ const MarkerList::Marker* const marker = findMarker (symbol, list);
+
+ if (marker != 0)
+ return marker->position.getExpression();
+
+ return Expression::Scope::getSymbolValue (symbol);
}
-const Expression RelativeCoordinatePositionerBase::getSymbolValue (const String& objectName, const String& member) const
+void RelativeCoordinatePositionerBase::ComponentScope::visitRelativeScope (const String& scopeName, Visitor& visitor) const
{
- jassert (objectName.isNotEmpty());
+ Component* targetComp = 0;
- if (member.isNotEmpty())
+ if (scopeName == RelativeCoordinate::Strings::parent)
+ targetComp = component.getParentComponent();
+ else
+ targetComp = findSiblingComponent (scopeName);
+
+ if (targetComp != 0)
+ visitor.visit (ComponentScope (*targetComp));
+}
+
+const String RelativeCoordinatePositionerBase::ComponentScope::getScopeUID() const
+{
+ return String::toHexString ((pointer_sized_int) (void*) &component);
+}
+
+Component* RelativeCoordinatePositionerBase::ComponentScope::findSiblingComponent (const String& componentID) const
+{
+ Component* const parent = component.getParentComponent();
+
+ if (parent != 0)
{
- const Component* comp = getSourceComponent (objectName);
+ for (int i = parent->getNumChildComponents(); --i >= 0;)
+ {
+ Component* const c = parent->getChildComponent(i);
+
+ if (c->getComponentID() == componentID)
+ return c;
+ }
+ }
+
+ return 0;
+}
+
+const MarkerList::Marker* RelativeCoordinatePositionerBase::ComponentScope::findMarker (const String& name, MarkerList*& list) const
+{
+ const MarkerList::Marker* marker = 0;
+
+ Component* const parent = component.getParentComponent();
- if (comp == 0)
+ if (parent != 0)
+ {
+ list = parent->getMarkers (true);
+ if (list != 0)
+ marker = list->getMarker (name);
+
+ if (marker == 0)
{
- if (objectName == RelativeCoordinate::Strings::parent)
- comp = getComponent().getParentComponent();
- else if (objectName == RelativeCoordinate::Strings::this_ || objectName == getComponent().getComponentID())
- comp = &getComponent();
+ list = parent->getMarkers (false);
+
+ if (list != 0)
+ marker = list->getMarker (name);
}
+ }
+
+ return marker;
+}
+
+//==============================================================================
+class RelativeCoordinatePositionerBase::DependencyFinderScope : public ComponentScope
+{
+public:
+ DependencyFinderScope (Component& component_, RelativeCoordinatePositionerBase& positioner_, bool& ok_)
+ : ComponentScope (component_), positioner (positioner_), ok (ok_)
+ {
+ }
- if (comp != 0)
+ const Expression getSymbolValue (const String& symbol) const
+ {
+ if (symbol == RelativeCoordinate::Strings::left || symbol == RelativeCoordinate::Strings::x
+ || symbol == RelativeCoordinate::Strings::width || symbol == RelativeCoordinate::Strings::right
+ || symbol == RelativeCoordinate::Strings::top || symbol == RelativeCoordinate::Strings::y
+ || symbol == RelativeCoordinate::Strings::height || symbol == RelativeCoordinate::Strings::bottom)
{
- if (member == RelativeCoordinate::Strings::left) return xToExpression (comp, 0);
- if (member == RelativeCoordinate::Strings::right) return xToExpression (comp, comp->getWidth());
- if (member == RelativeCoordinate::Strings::top) return yToExpression (comp, 0);
- if (member == RelativeCoordinate::Strings::bottom) return yToExpression (comp, comp->getHeight());
+ positioner.registerComponentListener (component);
}
+ else
+ {
+ MarkerList* list;
+ const MarkerList::Marker* const marker = findMarker (symbol, list);
+
+ if (marker != 0)
+ {
+ positioner.registerMarkerListListener (list);
+ }
+ else
+ {
+ // The marker we want doesn't exist, so watch all lists in case they change and the marker appears later..
+ positioner.registerMarkerListListener (component.getMarkers (true));
+ positioner.registerMarkerListListener (component.getMarkers (false));
+ ok = false;
+ }
+ }
+
+ return ComponentScope::getSymbolValue (symbol);
}
- for (int i = sourceMarkerLists.size(); --i >= 0;)
+ void visitRelativeScope (const String& scopeName, Visitor& visitor) const
{
- MarkerList* const markerList = sourceMarkerLists.getUnchecked(i);
- const MarkerList::Marker* const marker = markerList->getMarker (objectName);
+ Component* targetComp = 0;
- if (marker != 0)
- return Expression (markerList->getMarkerPosition (*marker, getComponent().getParentComponent()));
+ if (scopeName == RelativeCoordinate::Strings::parent)
+ targetComp = component.getParentComponent();
+ else
+ targetComp = findSiblingComponent (scopeName);
+
+ if (targetComp != 0)
+ {
+ visitor.visit (DependencyFinderScope (*targetComp, positioner, ok));
+ }
+ else
+ {
+ // The named component doesn't exist, so we'll watch the parent for changes in case it appears later..
+ positioner.registerComponentListener (component);
+ ok = false;
+ }
}
- return Expression::EvaluationContext::getSymbolValue (objectName, member);
+private:
+ RelativeCoordinatePositionerBase& positioner;
+ bool& ok;
+
+ JUCE_DECLARE_NON_COPYABLE (DependencyFinderScope);
+};
+
+//==============================================================================
+RelativeCoordinatePositionerBase::RelativeCoordinatePositionerBase (Component& component_)
+ : Component::Positioner (component_), registeredOk (false)
+{
+}
+
+RelativeCoordinatePositionerBase::~RelativeCoordinatePositionerBase()
+{
+ unregisterListeners();
}
void RelativeCoordinatePositionerBase::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
@@ -118,7 +238,10 @@ void RelativeCoordinatePositionerBase::apply()
bool RelativeCoordinatePositionerBase::addCoordinate (const RelativeCoordinate& coord)
{
- return registerListeners (coord.getExpression());
+ bool ok = true;
+ DependencyFinderScope finderScope (getComponent(), *this, ok);
+ coord.getExpression().evaluate (finderScope);
+ return ok;
}
bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
@@ -127,95 +250,12 @@ bool RelativeCoordinatePositionerBase::addPoint (const RelativePoint& point)
return addCoordinate (point.y) && ok;
}
-bool RelativeCoordinatePositionerBase::registerListeners (const Expression& e)
-{
- bool ok = true;
-
- if (e.getType() == Expression::symbolType)
- {
- String objectName, memberName;
- e.getSymbolParts (objectName, memberName);
-
- if (memberName.isNotEmpty())
- ok = registerComponent (objectName) && ok;
- else
- ok = registerMarker (objectName) && ok;
- }
- else
- {
- for (int i = e.getNumInputs(); --i >= 0;)
- ok = registerListeners (e.getInput (i)) && ok;
- }
-
- return ok;
-}
-
-bool RelativeCoordinatePositionerBase::registerComponent (const String& componentID)
+void RelativeCoordinatePositionerBase::registerComponentListener (Component& comp)
{
- Component* comp = findComponent (componentID);
-
- if (comp == 0)
+ if (! sourceComponents.contains (&comp))
{
- if (componentID == RelativeCoordinate::Strings::parent)
- comp = getComponent().getParentComponent();
- else if (componentID == RelativeCoordinate::Strings::this_ || componentID == getComponent().getComponentID())
- comp = &getComponent();
- }
-
- if (comp != 0)
- {
- if (comp != &getComponent())
- registerComponentListener (comp);
-
- return true;
- }
- else
- {
- // The component we want doesn't exist, so watch the parent in case the hierarchy changes and it appears later..
- Component* const parent = getComponent().getParentComponent();
-
- if (parent != 0)
- registerComponentListener (parent);
- else
- registerComponentListener (&getComponent());
-
- return false;
- }
-}
-
-bool RelativeCoordinatePositionerBase::registerMarker (const String markerName)
-{
- Component* const parent = getComponent().getParentComponent();
-
- if (parent != 0)
- {
- MarkerList* list = parent->getMarkers (true);
-
- if (list == 0 || list->getMarker (markerName) == 0)
- list = parent->getMarkers (false);
-
- if (list != 0 && list->getMarker (markerName) != 0)
- {
- registerMarkerListListener (list);
- return true;
- }
- else
- {
- // The marker we want doesn't exist, so watch all lists in case they change and the marker appears later..
- registerMarkerListListener (parent->getMarkers (true));
- registerMarkerListListener (parent->getMarkers (false));
- }
- }
-
- return false;
-}
-
-void RelativeCoordinatePositionerBase::registerComponentListener (Component* const comp)
-{
- if (comp != 0 && ! sourceComponents.contains (comp))
- {
- comp->addComponentListener (this);
- sourceComponents.add (comp);
+ comp.addComponentListener (this);
+ sourceComponents.add (&comp);
}
}
@@ -241,45 +281,5 @@ void RelativeCoordinatePositionerBase::unregisterListeners()
sourceMarkerLists.clear();
}
-Component* RelativeCoordinatePositionerBase::findComponent (const String& componentID) const
-{
- Component* const parent = getComponent().getParentComponent();
-
- if (parent != 0)
- {
- for (int i = parent->getNumChildComponents(); --i >= 0;)
- {
- Component* const c = parent->getChildComponent(i);
-
- if (c->getComponentID() == componentID)
- return c;
- }
- }
-
- return 0;
-}
-
-Component* RelativeCoordinatePositionerBase::getSourceComponent (const String& objectName) const
-{
- for (int i = sourceComponents.size(); --i >= 0;)
- {
- Component* const comp = sourceComponents.getUnchecked(i);
-
- if (comp->getComponentID() == objectName)
- return comp;
- }
-
- return 0;
-}
-
-const Expression RelativeCoordinatePositionerBase::xToExpression (const Component* const source, const int x) const
-{
- return Expression ((double) (getComponent().getLocalPoint (source, Point (x, 0)).getX() + getComponent().getX()));
-}
-
-const Expression RelativeCoordinatePositionerBase::yToExpression (const Component* const source, const int y) const
-{
- return Expression ((double) (getComponent().getLocalPoint (source, Point (0, y)).getY() + getComponent().getY()));
-}
END_JUCE_NAMESPACE
diff --git a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h
index 84a689467f..a7bc77f2f1 100644
--- a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h
+++ b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h
@@ -37,15 +37,12 @@
*/
class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner,
public ComponentListener,
- public MarkerList::Listener,
- public Expression::EvaluationContext
+ public MarkerList::Listener
{
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);
@@ -57,25 +54,41 @@ public:
bool addCoordinate (const RelativeCoordinate& coord);
bool addPoint (const RelativePoint& point);
+ //==============================================================================
+ /** Used for resolving a RelativeCoordinate expression in the context of a component. */
+ class ComponentScope : public Expression::Scope
+ {
+ public:
+ ComponentScope (Component& component_);
+
+ const Expression getSymbolValue (const String& symbol) const;
+ void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
+ const String getScopeUID() const;
+
+ protected:
+ Component& component;
+
+ Component* findSiblingComponent (const String& componentID) const;
+ const MarkerList::Marker* findMarker (const String& name, MarkerList*& list) const;
+
+ private:
+ JUCE_DECLARE_NON_COPYABLE (ComponentScope);
+ };
+
protected:
virtual bool registerCoordinates() = 0;
virtual void applyToComponentBounds() = 0;
private:
+ class DependencyFinderScope;
+ friend class DependencyFinderScope;
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 registerComponentListener (Component& 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);
};
diff --git a/src/gui/components/positioning/juce_RelativeParallelogram.cpp b/src/gui/components/positioning/juce_RelativeParallelogram.cpp
index d451b5a4f8..c24ae4ef45 100644
--- a/src/gui/components/positioning/juce_RelativeParallelogram.cpp
+++ b/src/gui/components/positioning/juce_RelativeParallelogram.cpp
@@ -53,30 +53,30 @@ RelativeParallelogram::~RelativeParallelogram()
{
}
-void RelativeParallelogram::resolveThreePoints (Point* points, Expression::EvaluationContext* const coordFinder) const
+void RelativeParallelogram::resolveThreePoints (Point* points, Expression::Scope* const scope) const
{
- points[0] = topLeft.resolve (coordFinder);
- points[1] = topRight.resolve (coordFinder);
- points[2] = bottomLeft.resolve (coordFinder);
+ points[0] = topLeft.resolve (scope);
+ points[1] = topRight.resolve (scope);
+ points[2] = bottomLeft.resolve (scope);
}
-void RelativeParallelogram::resolveFourCorners (Point* points, Expression::EvaluationContext* const coordFinder) const
+void RelativeParallelogram::resolveFourCorners (Point* points, Expression::Scope* const scope) const
{
- resolveThreePoints (points, coordFinder);
+ resolveThreePoints (points, scope);
points[3] = points[1] + (points[2] - points[0]);
}
-const Rectangle RelativeParallelogram::getBounds (Expression::EvaluationContext* const coordFinder) const
+const Rectangle RelativeParallelogram::getBounds (Expression::Scope* const scope) const
{
Point points[4];
- resolveFourCorners (points, coordFinder);
+ resolveFourCorners (points, scope);
return Rectangle::findAreaContainingPoints (points, 4);
}
-void RelativeParallelogram::getPath (Path& path, Expression::EvaluationContext* const coordFinder) const
+void RelativeParallelogram::getPath (Path& path, Expression::Scope* const scope) const
{
Point points[4];
- resolveFourCorners (points, coordFinder);
+ resolveFourCorners (points, scope);
path.startNewSubPath (points[0]);
path.lineTo (points[1]);
@@ -85,18 +85,18 @@ void RelativeParallelogram::getPath (Path& path, Expression::EvaluationContext*
path.closeSubPath();
}
-const AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::EvaluationContext* const coordFinder)
+const AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::Scope* const scope)
{
Point corners[3];
- resolveThreePoints (corners, coordFinder);
+ resolveThreePoints (corners, scope);
const Line top (corners[0], corners[1]);
const Line left (corners[0], corners[2]);
const Point newTopRight (corners[0] + Point (top.getLength(), 0.0f));
const Point newBottomLeft (corners[0] + Point (0.0f, left.getLength()));
- topRight.moveToAbsolute (newTopRight, coordFinder);
- bottomLeft.moveToAbsolute (newBottomLeft, coordFinder);
+ topRight.moveToAbsolute (newTopRight, scope);
+ bottomLeft.moveToAbsolute (newBottomLeft, scope);
return AffineTransform::fromTargetPoints (corners[0].getX(), corners[0].getY(), corners[0].getX(), corners[0].getY(),
corners[1].getX(), corners[1].getY(), newTopRight.getX(), newTopRight.getY(),
diff --git a/src/gui/components/positioning/juce_RelativeParallelogram.h b/src/gui/components/positioning/juce_RelativeParallelogram.h
index a0dbe94bff..e378882cce 100644
--- a/src/gui/components/positioning/juce_RelativeParallelogram.h
+++ b/src/gui/components/positioning/juce_RelativeParallelogram.h
@@ -46,11 +46,11 @@ public:
~RelativeParallelogram();
//==============================================================================
- void resolveThreePoints (Point* points, Expression::EvaluationContext* coordFinder) const;
- void resolveFourCorners (Point* points, Expression::EvaluationContext* coordFinder) const;
- const Rectangle getBounds (Expression::EvaluationContext* coordFinder) const;
- void getPath (Path& path, Expression::EvaluationContext* coordFinder) const;
- const AffineTransform resetToPerpendicular (Expression::EvaluationContext* coordFinder);
+ void resolveThreePoints (Point* points, Expression::Scope* scope) const;
+ void resolveFourCorners (Point* points, Expression::Scope* scope) const;
+ const Rectangle getBounds (Expression::Scope* scope) const;
+ void getPath (Path& path, Expression::Scope* scope) const;
+ const AffineTransform resetToPerpendicular (Expression::Scope* scope);
bool isDynamic() const;
bool operator== (const RelativeParallelogram& other) const throw();
diff --git a/src/gui/components/positioning/juce_RelativePoint.cpp b/src/gui/components/positioning/juce_RelativePoint.cpp
index 1b5ec9f36c..3458b9a592 100644
--- a/src/gui/components/positioning/juce_RelativePoint.cpp
+++ b/src/gui/components/positioning/juce_RelativePoint.cpp
@@ -79,16 +79,16 @@ bool RelativePoint::operator!= (const RelativePoint& other) const throw()
return ! operator== (other);
}
-const Point RelativePoint::resolve (const Expression::EvaluationContext* context) const
+const Point RelativePoint::resolve (const Expression::Scope* scope) const
{
- return Point ((float) x.resolve (context),
- (float) y.resolve (context));
+ return Point ((float) x.resolve (scope),
+ (float) y.resolve (scope));
}
-void RelativePoint::moveToAbsolute (const Point& newPos, const Expression::EvaluationContext* context)
+void RelativePoint::moveToAbsolute (const Point& newPos, const Expression::Scope* scope)
{
- x.moveToAbsolute (newPos.getX(), context);
- y.moveToAbsolute (newPos.getY(), context);
+ x.moveToAbsolute (newPos.getX(), scope);
+ y.moveToAbsolute (newPos.getY(), scope);
}
const String RelativePoint::toString() const
@@ -96,12 +96,6 @@ const String RelativePoint::toString() const
return x.toString() + ", " + y.toString();
}
-void RelativePoint::renameSymbolIfUsed (const String& oldName, const String& newName)
-{
- x.renameSymbolIfUsed (oldName, newName);
- y.renameSymbolIfUsed (oldName, newName);
-}
-
bool RelativePoint::isDynamic() const
{
return x.isDynamic() || y.isDynamic();
diff --git a/src/gui/components/positioning/juce_RelativePoint.h b/src/gui/components/positioning/juce_RelativePoint.h
index 1d614e7ce8..93f54f338c 100644
--- a/src/gui/components/positioning/juce_RelativePoint.h
+++ b/src/gui/components/positioning/juce_RelativePoint.h
@@ -62,10 +62,10 @@ public:
/** Calculates the absolute position of this point.
- You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
+ You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
- const Point resolve (const Expression::EvaluationContext* evaluationContext) const;
+ const Point resolve (const Expression::Scope* evaluationContext) const;
/** Changes the values of this point's coordinates to make it resolve to the specified position.
@@ -73,7 +73,7 @@ public:
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);
+ void moveToAbsolute (const Point& newPos, const Expression::Scope* 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
@@ -82,11 +82,6 @@ public:
*/
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;
diff --git a/src/gui/components/positioning/juce_RelativePointPath.cpp b/src/gui/components/positioning/juce_RelativePointPath.cpp
index 629fafc58b..b19b4da0ca 100644
--- a/src/gui/components/positioning/juce_RelativePointPath.cpp
+++ b/src/gui/components/positioning/juce_RelativePointPath.cpp
@@ -109,10 +109,10 @@ void RelativePointPath::swapWith (RelativePointPath& other) throw()
swapVariables (containsDynamicPoints, other.containsDynamicPoints);
}
-void RelativePointPath::createPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::createPath (Path& path, Expression::Scope* scope) const
{
for (int i = 0; i < elements.size(); ++i)
- elements.getUnchecked(i)->addToPath (path, coordFinder);
+ elements.getUnchecked(i)->addToPath (path, scope);
}
bool RelativePointPath::containsAnyDynamicPoints() const
@@ -159,9 +159,9 @@ const ValueTree RelativePointPath::StartSubPath::createTree() const
return v;
}
-void RelativePointPath::StartSubPath::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::StartSubPath::addToPath (Path& path, Expression::Scope* scope) const
{
- path.startNewSubPath (startPos.resolve (coordFinder));
+ path.startNewSubPath (startPos.resolve (scope));
}
RelativePoint* RelativePointPath::StartSubPath::getControlPoints (int& numPoints)
@@ -186,7 +186,7 @@ const ValueTree RelativePointPath::CloseSubPath::createTree() const
return ValueTree (DrawablePath::ValueTreeWrapper::Element::closeSubPathElement);
}
-void RelativePointPath::CloseSubPath::addToPath (Path& path, Expression::EvaluationContext*) const
+void RelativePointPath::CloseSubPath::addToPath (Path& path, Expression::Scope*) const
{
path.closeSubPath();
}
@@ -215,9 +215,9 @@ const ValueTree RelativePointPath::LineTo::createTree() const
return v;
}
-void RelativePointPath::LineTo::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::LineTo::addToPath (Path& path, Expression::Scope* scope) const
{
- path.lineTo (endPoint.resolve (coordFinder));
+ path.lineTo (endPoint.resolve (scope));
}
RelativePoint* RelativePointPath::LineTo::getControlPoints (int& numPoints)
@@ -247,10 +247,10 @@ const ValueTree RelativePointPath::QuadraticTo::createTree() const
return v;
}
-void RelativePointPath::QuadraticTo::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::QuadraticTo::addToPath (Path& path, Expression::Scope* scope) const
{
- path.quadraticTo (controlPoints[0].resolve (coordFinder),
- controlPoints[1].resolve (coordFinder));
+ path.quadraticTo (controlPoints[0].resolve (scope),
+ controlPoints[1].resolve (scope));
}
RelativePoint* RelativePointPath::QuadraticTo::getControlPoints (int& numPoints)
@@ -283,11 +283,11 @@ const ValueTree RelativePointPath::CubicTo::createTree() const
return v;
}
-void RelativePointPath::CubicTo::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const
+void RelativePointPath::CubicTo::addToPath (Path& path, Expression::Scope* scope) const
{
- path.cubicTo (controlPoints[0].resolve (coordFinder),
- controlPoints[1].resolve (coordFinder),
- controlPoints[2].resolve (coordFinder));
+ path.cubicTo (controlPoints[0].resolve (scope),
+ controlPoints[1].resolve (scope),
+ controlPoints[2].resolve (scope));
}
RelativePoint* RelativePointPath::CubicTo::getControlPoints (int& numPoints)
diff --git a/src/gui/components/positioning/juce_RelativePointPath.h b/src/gui/components/positioning/juce_RelativePointPath.h
index ff9ba1c8b9..c686dce4bb 100644
--- a/src/gui/components/positioning/juce_RelativePointPath.h
+++ b/src/gui/components/positioning/juce_RelativePointPath.h
@@ -54,7 +54,7 @@ public:
//==============================================================================
/** Resolves this points in this path and adds them to a normal Path object. */
- void createPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void createPath (Path& path, Expression::Scope* scope) const;
/** Returns true if the path contains any non-fixed points. */
bool containsAnyDynamicPoints() const;
@@ -85,7 +85,7 @@ public:
ElementBase (ElementType type);
virtual ~ElementBase() {}
virtual const ValueTree createTree() const = 0;
- virtual void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const = 0;
+ virtual void addToPath (Path& path, Expression::Scope*) const = 0;
virtual RelativePoint* getControlPoints (int& numPoints) = 0;
virtual ElementBase* clone() const = 0;
bool isDynamic();
@@ -102,7 +102,7 @@ public:
public:
StartSubPath (const RelativePoint& pos);
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
@@ -118,7 +118,7 @@ public:
public:
CloseSubPath();
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
@@ -132,7 +132,7 @@ public:
public:
LineTo (const RelativePoint& endPoint);
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
@@ -148,7 +148,7 @@ public:
public:
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint);
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
@@ -164,7 +164,7 @@ public:
public:
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint);
const ValueTree createTree() const;
- void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const;
+ void addToPath (Path& path, Expression::Scope*) const;
RelativePoint* getControlPoints (int& numPoints);
ElementBase* clone() const;
diff --git a/src/gui/components/positioning/juce_RelativeRectangle.cpp b/src/gui/components/positioning/juce_RelativeRectangle.cpp
index 6fc8aed9b6..308a6fb1ec 100644
--- a/src/gui/components/positioning/juce_RelativeRectangle.cpp
+++ b/src/gui/components/positioning/juce_RelativeRectangle.cpp
@@ -30,6 +30,8 @@ BEGIN_JUCE_NAMESPACE
#include "juce_RelativeRectangle.h"
#include "juce_RelativeCoordinatePositioner.h"
+
+//==============================================================================
namespace RelativeRectangleHelpers
{
inline void skipComma (const juce_wchar* const s, int& i)
@@ -43,13 +45,23 @@ namespace RelativeRectangleHelpers
bool dependsOnSymbolsOtherThanThis (const Expression& e)
{
+ if (e.getType() == Expression::operatorType && e.getSymbolOrFunction() == ".")
+ return true;
+
if (e.getType() == Expression::symbolType)
{
- String objectName, memberName;
- e.getSymbolParts (objectName, memberName);
-
- if (objectName != RelativeCoordinate::Strings::this_)
- return true;
+ switch (RelativeCoordinate::StandardStrings::getTypeOf (e.getSymbolOrFunction()))
+ {
+ case RelativeCoordinate::StandardStrings::x:
+ case RelativeCoordinate::StandardStrings::y:
+ case RelativeCoordinate::StandardStrings::left:
+ case RelativeCoordinate::StandardStrings::right:
+ case RelativeCoordinate::StandardStrings::top:
+ case RelativeCoordinate::StandardStrings::bottom: return false;
+ default: break;
+ }
+
+ return true;
}
else
{
@@ -75,11 +87,9 @@ RelativeRectangle::RelativeRectangle (const RelativeCoordinate& left_, const Rel
RelativeRectangle::RelativeRectangle (const Rectangle& rect)
: left (rect.getX()),
- right (Expression::symbol (RelativeCoordinate::Strings::this_ + "." + RelativeCoordinate::Strings::left)
- + Expression ((double) rect.getWidth())),
+ right (Expression::symbol (RelativeCoordinate::Strings::left) + Expression ((double) rect.getWidth())),
top (rect.getY()),
- bottom (Expression::symbol (RelativeCoordinate::Strings::this_ + "." + RelativeCoordinate::Strings::top)
- + Expression ((double) rect.getHeight()))
+ bottom (Expression::symbol (RelativeCoordinate::Strings::top) + Expression ((double) rect.getHeight()))
{
}
@@ -105,22 +115,59 @@ bool RelativeRectangle::operator!= (const RelativeRectangle& other) const throw(
return ! operator== (other);
}
-const Rectangle RelativeRectangle::resolve (const Expression::EvaluationContext* context) const
+//==============================================================================
+// An expression context that can evaluate expressions using "this"
+class RelativeRectangleLocalScope : public Expression::Scope
{
- const double l = left.resolve (context);
- const double r = right.resolve (context);
- const double t = top.resolve (context);
- const double b = bottom.resolve (context);
+public:
+ RelativeRectangleLocalScope (const RelativeRectangle& rect_) : rect (rect_) {}
+
+ const Expression getSymbolValue (const String& symbol) const
+ {
+ switch (RelativeCoordinate::StandardStrings::getTypeOf (symbol))
+ {
+ case RelativeCoordinate::StandardStrings::x:
+ case RelativeCoordinate::StandardStrings::left: return rect.left.getExpression();
+ case RelativeCoordinate::StandardStrings::y:
+ case RelativeCoordinate::StandardStrings::top: return rect.top.getExpression();
+ case RelativeCoordinate::StandardStrings::right: return rect.right.getExpression();
+ case RelativeCoordinate::StandardStrings::bottom: return rect.bottom.getExpression();
+ default: break;
+ }
- return Rectangle ((float) l, (float) t, (float) jmax (0.0, r - l), (float) jmax (0.0, b - t));
+ return Expression::Scope::getSymbolValue (symbol);
+ }
+
+private:
+ const RelativeRectangle& rect;
+
+ JUCE_DECLARE_NON_COPYABLE (RelativeRectangleLocalScope);
+};
+
+const Rectangle RelativeRectangle::resolve (const Expression::Scope* scope) const
+{
+ if (scope == 0)
+ {
+ RelativeRectangleLocalScope scope (*this);
+ return resolve (&scope);
+ }
+ else
+ {
+ const double l = left.resolve (scope);
+ const double r = right.resolve (scope);
+ const double t = top.resolve (scope);
+ const double b = bottom.resolve (scope);
+
+ return Rectangle ((float) l, (float) t, (float) jmax (0.0, r - l), (float) jmax (0.0, b - t));
+ }
}
-void RelativeRectangle::moveToAbsolute (const Rectangle& newPos, const Expression::EvaluationContext* context)
+void RelativeRectangle::moveToAbsolute (const Rectangle& newPos, const Expression::Scope* scope)
{
- left.moveToAbsolute (newPos.getX(), context);
- right.moveToAbsolute (newPos.getRight(), context);
- top.moveToAbsolute (newPos.getY(), context);
- bottom.moveToAbsolute (newPos.getBottom(), context);
+ left.moveToAbsolute (newPos.getX(), scope);
+ right.moveToAbsolute (newPos.getRight(), scope);
+ top.moveToAbsolute (newPos.getY(), scope);
+ bottom.moveToAbsolute (newPos.getBottom(), scope);
}
bool RelativeRectangle::isDynamic() const
@@ -138,12 +185,12 @@ const String RelativeRectangle::toString() const
return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString();
}
-void RelativeRectangle::renameSymbolIfUsed (const String& oldName, const String& newName)
+void RelativeRectangle::renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope)
{
- left.renameSymbolIfUsed (oldName, newName);
- right.renameSymbolIfUsed (oldName, newName);
- top.renameSymbolIfUsed (oldName, newName);
- bottom.renameSymbolIfUsed (oldName, newName);
+ left = left.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
+ right = right.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
+ top = top.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
+ bottom = bottom.getExpression().withRenamedSymbol (oldSymbol, newName, scope);
}
//==============================================================================
@@ -174,7 +221,8 @@ public:
{
for (int i = 4; --i >= 0;)
{
- const Rectangle newBounds (rectangle.resolve (this).getSmallestIntegerContainer());
+ ComponentScope scope (getComponent());
+ const Rectangle newBounds (rectangle.resolve (&scope).getSmallestIntegerContainer());
if (newBounds == getComponent().getBounds())
return;
@@ -191,31 +239,6 @@ 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())
@@ -233,9 +256,7 @@ void RelativeRectangle::applyToComponent (Component& component) const
else
{
component.setPositioner (0);
-
- TemporaryRectangleContext context (*this);
- component.setBounds (resolve (&context).getSmallestIntegerContainer());
+ component.setBounds (resolve (0).getSmallestIntegerContainer());
}
}
diff --git a/src/gui/components/positioning/juce_RelativeRectangle.h b/src/gui/components/positioning/juce_RelativeRectangle.h
index 7b77461c08..24f0775d02 100644
--- a/src/gui/components/positioning/juce_RelativeRectangle.h
+++ b/src/gui/components/positioning/juce_RelativeRectangle.h
@@ -65,10 +65,10 @@ public:
//==============================================================================
/** Calculates the absolute position of this rectangle.
- You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may
+ You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
be needed to calculate the result.
*/
- const Rectangle resolve (const Expression::EvaluationContext* evaluationContext) const;
+ const Rectangle resolve (const Expression::Scope* scope) const;
/** Changes the values of this rectangle's coordinates to make it resolve to the specified position.
@@ -76,7 +76,7 @@ public:
or relative positions to whatever values are necessary to make the resultant position
match the position that is provided.
*/
- void moveToAbsolute (const Rectangle& newPos, const Expression::EvaluationContext* evaluationContext);
+ void moveToAbsolute (const Rectangle& newPos, const Expression::Scope* scope);
/** 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.
@@ -91,9 +91,9 @@ public:
const String toString() const;
/** Renames a symbol if it is used by any of the coordinates.
- This calls RelativeCoordinate::renameSymbolIfUsed() on the rectangle's coordinates.
+ This calls Expression::withRenamedSymbol() on the rectangle's coordinates.
*/
- void renameSymbolIfUsed (const String& oldName, const String& newName);
+ void renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope);
/** Creates and sets an appropriate Component::Positioner object for the given component, which will
keep it positioned with this rectangle.
diff --git a/src/gui/graphics/drawables/juce_Drawable.h b/src/gui/graphics/drawables/juce_Drawable.h
index 883cd291ac..00644e28eb 100644
--- a/src/gui/graphics/drawables/juce_Drawable.h
+++ b/src/gui/graphics/drawables/juce_Drawable.h
@@ -228,7 +228,11 @@ protected:
{}
bool registerCoordinates() { return owner.registerCoordinates (*this); }
- void applyToComponentBounds() { owner.recalculateCoordinates (this); }
+ void applyToComponentBounds()
+ {
+ ComponentScope scope (getComponent());
+ owner.recalculateCoordinates (&scope);
+ }
private:
DrawableType& owner;
diff --git a/src/gui/graphics/drawables/juce_DrawableComposite.cpp b/src/gui/graphics/drawables/juce_DrawableComposite.cpp
index bf5d77c195..873074d62d 100644
--- a/src/gui/graphics/drawables/juce_DrawableComposite.cpp
+++ b/src/gui/graphics/drawables/juce_DrawableComposite.cpp
@@ -153,12 +153,12 @@ bool DrawableComposite::registerCoordinates (RelativeCoordinatePositionerBase& p
return positioner.addPoint (bounds.bottomLeft) && ok;
}
-void DrawableComposite::recalculateCoordinates (Expression::EvaluationContext* context)
+void DrawableComposite::recalculateCoordinates (Expression::Scope* scope)
{
Point resolved[3];
- bounds.resolveThreePoints (resolved, context);
+ bounds.resolveThreePoints (resolved, scope);
- const Rectangle content (getContentArea().resolve (context));
+ const Rectangle content (getContentArea().resolve (scope));
AffineTransform t (AffineTransform::fromTargetPoints (content.getX(), content.getY(), resolved[0].getX(), resolved[0].getY(),
content.getRight(), content.getY(), resolved[1].getX(), resolved[1].getY(),
diff --git a/src/gui/graphics/drawables/juce_DrawableComposite.h b/src/gui/graphics/drawables/juce_DrawableComposite.h
index 8421c33090..cf0273e3d1 100644
--- a/src/gui/graphics/drawables/juce_DrawableComposite.h
+++ b/src/gui/graphics/drawables/juce_DrawableComposite.h
@@ -150,7 +150,7 @@ private:
friend class Drawable::Positioner;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
- void recalculateCoordinates (Expression::EvaluationContext*);
+ void recalculateCoordinates (Expression::Scope*);
void updateBoundsToFitChildren();
diff --git a/src/gui/graphics/drawables/juce_DrawableImage.cpp b/src/gui/graphics/drawables/juce_DrawableImage.cpp
index 419b0e3f31..cef4dacdda 100644
--- a/src/gui/graphics/drawables/juce_DrawableImage.cpp
+++ b/src/gui/graphics/drawables/juce_DrawableImage.cpp
@@ -106,12 +106,12 @@ bool DrawableImage::registerCoordinates (RelativeCoordinatePositionerBase& posit
return positioner.addPoint (bounds.bottomLeft) && ok;
}
-void DrawableImage::recalculateCoordinates (Expression::EvaluationContext* context)
+void DrawableImage::recalculateCoordinates (Expression::Scope* scope)
{
if (image.isValid())
{
Point resolved[3];
- bounds.resolveThreePoints (resolved, context);
+ bounds.resolveThreePoints (resolved, scope);
const Point tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth());
const Point bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight());
diff --git a/src/gui/graphics/drawables/juce_DrawableImage.h b/src/gui/graphics/drawables/juce_DrawableImage.h
index 4537b90181..32251c772e 100644
--- a/src/gui/graphics/drawables/juce_DrawableImage.h
+++ b/src/gui/graphics/drawables/juce_DrawableImage.h
@@ -133,7 +133,7 @@ private:
friend class Drawable::Positioner;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
- void recalculateCoordinates (Expression::EvaluationContext*);
+ void recalculateCoordinates (Expression::Scope*);
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 477c6c4dff..ac803e2351 100644
--- a/src/gui/graphics/drawables/juce_DrawablePath.cpp
+++ b/src/gui/graphics/drawables/juce_DrawablePath.cpp
@@ -72,10 +72,10 @@ const Path& DrawablePath::getStrokePath() const
return strokePath;
}
-void DrawablePath::applyRelativePath (const RelativePointPath& newRelativePath, Expression::EvaluationContext* context)
+void DrawablePath::applyRelativePath (const RelativePointPath& newRelativePath, Expression::Scope* scope)
{
Path newPath;
- newRelativePath.createPath (newPath, context);
+ newRelativePath.createPath (newPath, scope);
if (path != newPath)
{
@@ -118,7 +118,9 @@ public:
void applyToComponentBounds()
{
jassert (owner.relativePath != 0);
- owner.applyRelativePath (*owner.relativePath, this);
+
+ ComponentScope scope (getComponent());
+ owner.applyRelativePath (*owner.relativePath, &scope);
}
private:
@@ -299,26 +301,26 @@ const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const
return RelativePoint();
}
-float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::EvaluationContext* context) const
+float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::Scope* scope) const
{
const Identifier i (state.getType());
if (i == lineToElement || i == closeSubPathElement)
- return getEndPoint().resolve (context).getDistanceFrom (getStartPoint().resolve (context));
+ return getEndPoint().resolve (scope).getDistanceFrom (getStartPoint().resolve (scope));
if (i == cubicToElement)
{
Path p;
- p.startNewSubPath (getStartPoint().resolve (context));
- p.cubicTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context), getControlPoint (2).resolve (context));
+ p.startNewSubPath (getStartPoint().resolve (scope));
+ p.cubicTo (getControlPoint (0).resolve (scope), getControlPoint (1).resolve (scope), getControlPoint (2).resolve (scope));
return p.getLength();
}
if (i == quadraticToElement)
{
Path p;
- p.startNewSubPath (getStartPoint().resolve (context));
- p.quadraticTo (getControlPoint (0).resolve (context), getControlPoint (1).resolve (context));
+ p.startNewSubPath (getStartPoint().resolve (scope));
+ p.quadraticTo (getControlPoint (0).resolve (scope), getControlPoint (1).resolve (scope));
return p.getLength();
}
@@ -350,7 +352,7 @@ void DrawablePath::ValueTreeWrapper::Element::convertToLine (UndoManager* undoMa
}
}
-void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::EvaluationContext* context, UndoManager* undoManager)
+void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::Scope* scope, UndoManager* undoManager)
{
const Identifier i (state.getType());
@@ -361,8 +363,8 @@ void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::Evalua
const RelativePoint start (getStartPoint());
const RelativePoint end (getEndPoint());
- const Point startResolved (start.resolve (context));
- const Point endResolved (end.resolve (context));
+ const Point startResolved (start.resolve (scope));
+ const Point endResolved (end.resolve (scope));
e.setControlPoint (0, startResolved + (endResolved - startResolved) * 0.3f, undoManager);
e.setControlPoint (1, startResolved + (endResolved - startResolved) * 0.7f, undoManager);
e.setControlPoint (2, end, undoManager);
@@ -407,7 +409,7 @@ namespace DrawablePathHelpers
}
}
-float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext* context) const
+float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point& targetPoint, Expression::Scope* scope) const
{
using namespace DrawablePathHelpers;
const Identifier type (state.getType());
@@ -417,7 +419,7 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po
{
RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint());
- const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) };
+ const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope), rp4.resolve (scope) };
float bestDistance = std::numeric_limits::max();
@@ -437,7 +439,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 (context), rp2.resolve (context), rp3.resolve (context) };
+ const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope) };
float bestDistance = std::numeric_limits::max();
@@ -457,24 +459,24 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po
else if (type == lineToElement)
{
RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint());
- const Line line (rp1.resolve (context), rp2.resolve (context));
+ const Line line (rp1.resolve (scope), rp2.resolve (scope));
bestProp = line.findNearestProportionalPositionTo (targetPoint);
}
return bestProp;
}
-ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& targetPoint, Expression::EvaluationContext* context, UndoManager* undoManager)
+ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point& targetPoint, Expression::Scope* scope, UndoManager* undoManager)
{
ValueTree newTree;
const Identifier type (state.getType());
if (type == cubicToElement)
{
- float bestProp = findProportionAlongLine (targetPoint, context);
+ float bestProp = findProportionAlongLine (targetPoint, scope);
RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint());
- const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context), rp4.resolve (context) };
+ const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope), rp4.resolve (scope) };
const Point mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * bestProp),
@@ -499,10 +501,10 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point points[] = { rp1.resolve (context), rp2.resolve (context), rp3.resolve (context) };
+ const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope) };
const Point mid1 (points[0] + (points[1] - points[0]) * bestProp),
mid2 (points[1] + (points[2] - points[1]) * bestProp);
@@ -522,7 +524,7 @@ ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point line (rp1.resolve (context), rp2.resolve (context));
+ const Line line (rp1.resolve (scope), rp2.resolve (scope));
const Point newPoint (line.findNearestPointTo (targetPoint));
setControlPoint (0, newPoint, undoManager);
diff --git a/src/gui/graphics/drawables/juce_DrawablePath.h b/src/gui/graphics/drawables/juce_DrawablePath.h
index b7a223709b..15bc04c484 100644
--- a/src/gui/graphics/drawables/juce_DrawablePath.h
+++ b/src/gui/graphics/drawables/juce_DrawablePath.h
@@ -101,7 +101,7 @@ public:
const RelativePoint getStartPoint() const;
const RelativePoint getEndPoint() const;
void setControlPoint (int index, const RelativePoint& point, UndoManager*);
- float getLength (Expression::EvaluationContext*) const;
+ float getLength (Expression::Scope*) const;
ValueTreeWrapper getParent() const;
Element getPreviousElement() const;
@@ -110,11 +110,11 @@ public:
void setModeOfEndPoint (const String& newMode, UndoManager*);
void convertToLine (UndoManager*);
- void convertToCubic (Expression::EvaluationContext*, UndoManager*);
+ void convertToCubic (Expression::Scope*, UndoManager*);
void convertToPathBreak (UndoManager* undoManager);
- ValueTree insertPoint (const Point& targetPoint, Expression::EvaluationContext*, UndoManager*);
+ ValueTree insertPoint (const Point& targetPoint, Expression::Scope*, UndoManager*);
void removePoint (UndoManager* undoManager);
- float findProportionAlongLine (const Point& targetPoint, Expression::EvaluationContext*) const;
+ float findProportionAlongLine (const Point& targetPoint, Expression::Scope*) const;
static const Identifier mode, startSubPathElement, closeSubPathElement,
lineToElement, quadraticToElement, cubicToElement;
@@ -139,7 +139,7 @@ private:
class RelativePositioner;
friend class RelativePositioner;
- void applyRelativePath (const RelativePointPath&, Expression::EvaluationContext*);
+ void applyRelativePath (const RelativePointPath&, Expression::Scope*);
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 3752ab5eea..29932606c5 100644
--- a/src/gui/graphics/drawables/juce_DrawableRectangle.cpp
+++ b/src/gui/graphics/drawables/juce_DrawableRectangle.cpp
@@ -95,13 +95,13 @@ bool DrawableRectangle::registerCoordinates (RelativeCoordinatePositionerBase& p
return positioner.addPoint (cornerSize) && ok;
}
-void DrawableRectangle::recalculateCoordinates (Expression::EvaluationContext* context)
+void DrawableRectangle::recalculateCoordinates (Expression::Scope* scope)
{
Point points[3];
- bounds.resolveThreePoints (points, context);
+ bounds.resolveThreePoints (points, scope);
- const float cornerSizeX = (float) cornerSize.x.resolve (context);
- const float cornerSizeY = (float) cornerSize.y.resolve (context);
+ const float cornerSizeX = (float) cornerSize.x.resolve (scope);
+ const float cornerSizeY = (float) cornerSize.y.resolve (scope);
const float w = Line (points[0], points[1]).getLength();
const float h = Line (points[0], points[2]).getLength();
diff --git a/src/gui/graphics/drawables/juce_DrawableRectangle.h b/src/gui/graphics/drawables/juce_DrawableRectangle.h
index 0b5a55869c..300308dc67 100644
--- a/src/gui/graphics/drawables/juce_DrawableRectangle.h
+++ b/src/gui/graphics/drawables/juce_DrawableRectangle.h
@@ -97,7 +97,7 @@ private:
void rebuildPath();
bool registerCoordinates (RelativeCoordinatePositionerBase&);
- void recalculateCoordinates (Expression::EvaluationContext*);
+ void recalculateCoordinates (Expression::Scope*);
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 82d8300ed7..0eed3fc833 100644
--- a/src/gui/graphics/drawables/juce_DrawableShape.cpp
+++ b/src/gui/graphics/drawables/juce_DrawableShape.cpp
@@ -71,8 +71,9 @@ public:
void applyToComponentBounds()
{
- if (isMainFill ? owner.mainFill.recalculateCoords (this)
- : owner.strokeFill.recalculateCoords (this))
+ ComponentScope scope (owner);
+ if (isMainFill ? owner.mainFill.recalculateCoords (&scope)
+ : owner.strokeFill.recalculateCoords (&scope))
owner.repaint();
}
@@ -256,19 +257,19 @@ bool DrawableShape::RelativeFillType::operator!= (const RelativeFillType& other)
return ! operator== (other);
}
-bool DrawableShape::RelativeFillType::recalculateCoords (Expression::EvaluationContext* context)
+bool DrawableShape::RelativeFillType::recalculateCoords (Expression::Scope* scope)
{
if (fill.isGradient())
{
- const Point g1 (gradientPoint1.resolve (context));
- const Point g2 (gradientPoint2.resolve (context));
+ const Point g1 (gradientPoint1.resolve (scope));
+ const Point g2 (gradientPoint2.resolve (scope));
AffineTransform t;
ColourGradient& g = *fill.gradient;
if (g.isRadial)
{
- const Point g3 (gradientPoint3.resolve (context));
+ const Point g3 (gradientPoint3.resolve (scope));
const Point g3Source (g1.getX() + g2.getY() - g1.getY(),
g1.getY() + g1.getX() - g2.getX());
diff --git a/src/gui/graphics/drawables/juce_DrawableShape.h b/src/gui/graphics/drawables/juce_DrawableShape.h
index 89193b199a..421e9dde52 100644
--- a/src/gui/graphics/drawables/juce_DrawableShape.h
+++ b/src/gui/graphics/drawables/juce_DrawableShape.h
@@ -65,7 +65,7 @@ public:
bool operator!= (const RelativeFillType&) const;
bool isDynamic() const;
- bool recalculateCoords (Expression::EvaluationContext* context);
+ bool recalculateCoords (Expression::Scope* scope);
void writeTo (ValueTree& v, ComponentBuilder::ImageProvider*, UndoManager*) const;
bool readFrom (const ValueTree& v, ComponentBuilder::ImageProvider*);
diff --git a/src/gui/graphics/drawables/juce_DrawableText.cpp b/src/gui/graphics/drawables/juce_DrawableText.cpp
index 3b3ba6fbf9..5674a9b2d0 100644
--- a/src/gui/graphics/drawables/juce_DrawableText.cpp
+++ b/src/gui/graphics/drawables/juce_DrawableText.cpp
@@ -138,14 +138,14 @@ bool DrawableText::registerCoordinates (RelativeCoordinatePositionerBase& positi
return positioner.addPoint (fontSizeControlPoint) && ok;
}
-void DrawableText::recalculateCoordinates (Expression::EvaluationContext* context)
+void DrawableText::recalculateCoordinates (Expression::Scope* scope)
{
- bounds.resolveThreePoints (resolvedPoints, context);
+ bounds.resolveThreePoints (resolvedPoints, scope);
const float w = Line (resolvedPoints[0], resolvedPoints[1]).getLength();
const float h = Line (resolvedPoints[0], resolvedPoints[2]).getLength();
- const Point fontCoords (RelativeParallelogram::getInternalCoordForPoint (resolvedPoints, fontSizeControlPoint.resolve (context)));
+ const Point fontCoords (RelativeParallelogram::getInternalCoordForPoint (resolvedPoints, fontSizeControlPoint.resolve (scope)));
const float fontHeight = jlimit (0.01f, jmax (0.01f, h), fontCoords.getY());
const float fontWidth = jlimit (0.01f, jmax (0.01f, w), fontCoords.getX());
diff --git a/src/gui/graphics/drawables/juce_DrawableText.h b/src/gui/graphics/drawables/juce_DrawableText.h
index 0d8e0112c2..704436ad2e 100644
--- a/src/gui/graphics/drawables/juce_DrawableText.h
+++ b/src/gui/graphics/drawables/juce_DrawableText.h
@@ -142,7 +142,7 @@ private:
friend class Drawable::Positioner;
bool registerCoordinates (RelativeCoordinatePositionerBase&);
- void recalculateCoordinates (Expression::EvaluationContext*);
+ void recalculateCoordinates (Expression::Scope*);
void refreshBounds();
const AffineTransform getArrangementAndTransform (GlyphArrangement& glyphs) const;
diff --git a/src/maths/juce_Expression.cpp b/src/maths/juce_Expression.cpp
index cf1fef9829..a294430ce8 100644
--- a/src/maths/juce_Expression.cpp
+++ b/src/maths/juce_Expression.cpp
@@ -31,6 +31,61 @@ BEGIN_JUCE_NAMESPACE
#include "../containers/juce_ReferenceCountedArray.h"
+//==============================================================================
+class Expression::Term : public ReferenceCountedObject
+{
+public:
+ Term() {}
+ virtual ~Term() {}
+
+ virtual Type getType() const throw() = 0;
+ virtual Term* clone() const = 0;
+ virtual const ReferenceCountedObjectPtr resolve (const Scope&, int recursionDepth) = 0;
+ virtual const String toString() const = 0;
+ virtual double toDouble() const { return 0; }
+ virtual int getInputIndexFor (const Term*) const { return -1; }
+ virtual int getOperatorPrecedence() const { return 0; }
+ virtual int getNumInputs() const { return 0; }
+ virtual Term* getInput (int) const { return 0; }
+ virtual const ReferenceCountedObjectPtr negated();
+
+ virtual const ReferenceCountedObjectPtr createTermToEvaluateInput (const Scope&, const Term* /*inputTerm*/,
+ double /*overallTarget*/, Term* /*topLevelTerm*/) const
+ {
+ jassertfalse;
+ return 0;
+ }
+
+ virtual const String getName() const
+ {
+ jassertfalse; // You shouldn't call this for an expression that's not actually a function!
+ return String::empty;
+ }
+
+ virtual void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
+ {
+ for (int i = getNumInputs(); --i >= 0;)
+ getInput (i)->renameSymbol (oldSymbol, newName, scope, recursionDepth);
+ }
+
+ class SymbolVisitor
+ {
+ public:
+ virtual ~SymbolVisitor() {}
+ virtual void useSymbol (const Symbol&) = 0;
+ };
+
+ virtual void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
+ {
+ for (int i = getNumInputs(); --i >= 0;)
+ getInput(i)->visitAllSymbols (visitor, scope, recursionDepth);
+ }
+
+private:
+ JUCE_DECLARE_NON_COPYABLE (Term);
+};
+
+
//==============================================================================
class Expression::Helpers
{
@@ -38,34 +93,50 @@ public:
typedef ReferenceCountedObjectPtr TermPtr;
// This helper function is needed to work around VC6 scoping bugs
- static const TermPtr& getTermFor (const Expression& exp) throw() { return exp.term; }
+ static inline const TermPtr& getTermFor (const Expression& exp) throw() { return exp.term; }
+
+ static void checkRecursionDepth (const int depth)
+ {
+ if (depth > 256)
+ throw EvaluationError ("Recursive symbol references");
+ }
friend class Expression::Term; // (also only needed as a VC6 workaround)
+ //==============================================================================
+ /** An exception that can be thrown by Expression::evaluate(). */
+ class EvaluationError : public std::exception
+ {
+ public:
+ EvaluationError (const String& description_)
+ : description (description_)
+ {
+ DBG ("Expression::EvaluationError: " + description);
+ }
+
+ String description;
+ };
+
//==============================================================================
class Constant : public Term
{
public:
- Constant (const double value_, bool isResolutionTarget_)
+ Constant (const double value_, const bool isResolutionTarget_)
: value (value_), isResolutionTarget (isResolutionTarget_) {}
- Type getType() const throw() { return constantType; }
- Term* clone() const { return new Constant (value, isResolutionTarget); }
- double evaluate (const EvaluationContext&, int) const { return value; }
- int getNumInputs() const { return 0; }
- Term* getInput (int) const { return 0; }
-
- const TermPtr negated()
- {
- return new Constant (-value, isResolutionTarget);
- }
+ Type getType() const throw() { return constantType; }
+ Term* clone() const { return new Constant (value, isResolutionTarget); }
+ const TermPtr resolve (const Scope&, int) { return this; }
+ double toDouble() const { return value; }
+ const TermPtr negated() { return new Constant (-value, isResolutionTarget); }
const String toString() const
{
+ String s (value);
if (isResolutionTarget)
- return "@" + String (value);
+ s = "@" + s;
- return String (value);
+ return s;
}
double value;
@@ -73,100 +144,147 @@ public:
};
//==============================================================================
- class Symbol : public Term
+ class BinaryTerm : public Term
{
public:
- explicit Symbol (const String& symbol_)
- : mainSymbol (symbol_.upToFirstOccurrenceOf (".", false, false).trim()),
- member (symbol_.fromFirstOccurrenceOf (".", false, false).trim())
- {}
+ BinaryTerm (Term* const left_, Term* const right_) : left (left_), right (right_)
+ {
+ jassert (left_ != 0 && right_ != 0);
+ }
- Symbol (const String& symbol_, const String& member_)
- : mainSymbol (symbol_),
- member (member_)
- {}
+ int getInputIndexFor (const Term* possibleInput) const
+ {
+ return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
+ }
- double evaluate (const EvaluationContext& c, int recursionDepth) const
+ Type getType() const throw() { return operatorType; }
+ int getNumInputs() const { return 2; }
+ Term* getInput (int index) const { return index == 0 ? left.getObject() : (index == 1 ? right.getObject() : 0); }
+
+ virtual double performFunction (double left, double right) const = 0;
+ virtual void writeOperator (String& dest) const = 0;
+
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- if (++recursionDepth > 256)
- throw EvaluationError ("Recursive symbol references");
+ return new Constant (performFunction (left->resolve (scope, recursionDepth)->toDouble(),
+ right->resolve (scope, recursionDepth)->toDouble()), false);
+ }
- try
- {
- return getTermFor (c.getSymbolValue (mainSymbol, member))->evaluate (c, recursionDepth);
- }
- catch (...)
- {}
+ const String toString() const
+ {
+ String s;
- return 0;
+ const int ourPrecendence = getOperatorPrecedence();
+ if (left->getOperatorPrecedence() > ourPrecendence)
+ s << '(' << left->toString() << ')';
+ else
+ s = left->toString();
+
+ writeOperator (s);
+
+ if (right->getOperatorPrecedence() >= ourPrecendence)
+ s << '(' << right->toString() << ')';
+ else
+ s << right->toString();
+
+ return s;
}
- Type getType() const throw() { return symbolType; }
- Term* clone() const { return new Symbol (mainSymbol, member); }
- int getNumInputs() const { return 0; }
- Term* getInput (int) const { return 0; }
- const String toString() const { return joinParts (mainSymbol, member); }
- void getSymbolParts (String& objectName, String& memberName) const { objectName = mainSymbol; memberName = member; }
+ protected:
+ const TermPtr left, right;
- static const String joinParts (const String& mainSymbol, const String& member)
+ const TermPtr createDestinationTerm (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- return member.isEmpty() ? mainSymbol
- : mainSymbol + "." + member;
+ jassert (input == left || input == right);
+ if (input != left && input != right)
+ return 0;
+
+ const Term* const dest = findDestinationFor (topLevelTerm, this);
+
+ if (dest == 0)
+ return new Constant (overallTarget, false);
+
+ return dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm);
}
+ };
- bool referencesSymbol (const String& s, const EvaluationContext* c, int recursionDepth) const
+ //==============================================================================
+ class SymbolTerm : public Term
+ {
+ public:
+ explicit SymbolTerm (const String& symbol_) : symbol (symbol_) {}
+
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- if (s == mainSymbol || (s.containsChar ('.') && s == toString()))
- return true;
+ checkRecursionDepth (recursionDepth);
+ return getTermFor (scope.getSymbolValue (symbol))->resolve (scope, recursionDepth + 1);
+ }
- if (++recursionDepth > 256)
- throw EvaluationError ("Recursive symbol references");
+ Type getType() const throw() { return symbolType; }
+ Term* clone() const { return new SymbolTerm (symbol); }
+ const String toString() const { return symbol; }
+ const String getName() const { return symbol; }
- try
- {
- return c != 0 && getTermFor (c->getSymbolValue (mainSymbol, member))->referencesSymbol (s, c, recursionDepth);
- }
- catch (EvaluationError&)
- {
- return false;
- }
+ void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
+ {
+ checkRecursionDepth (recursionDepth);
+ visitor.useSymbol (Symbol (scope.getScopeUID(), symbol));
+ getTermFor (scope.getSymbolValue (symbol))->visitAllSymbols (visitor, scope, recursionDepth + 1);
}
- String mainSymbol, member;
+ void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int /*recursionDepth*/)
+ {
+ if (oldSymbol.symbolName == symbol && scope.getScopeUID() == oldSymbol.scopeUID)
+ symbol = newName;
+ }
+
+ String symbol;
};
//==============================================================================
class Function : public Term
{
public:
- Function (const String& functionName_, const ReferenceCountedArray& parameters_)
+ explicit Function (const String& functionName_) : functionName (functionName_) {}
+
+ Function (const String& functionName_, const Array& parameters_)
: functionName (functionName_), parameters (parameters_)
{}
- Term* clone() const { return new Function (functionName, parameters); }
+ Type getType() const throw() { return functionType; }
+ Term* clone() const { return new Function (functionName, parameters); }
+ int getNumInputs() const { return parameters.size(); }
+ Term* getInput (int i) const { return getTermFor (parameters [i]); }
+ const String getName() const { return functionName; }
- double evaluate (const EvaluationContext& c, int recursionDepth) const
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- HeapBlock params (parameters.size());
- for (int i = 0; i < parameters.size(); ++i)
- params[i] = parameters.getUnchecked(i)->evaluate (c, recursionDepth);
+ checkRecursionDepth (recursionDepth);
+ double result = 0;
+ const int numParams = parameters.size();
+ if (numParams > 0)
+ {
+ HeapBlock params (numParams);
+ for (int i = 0; i < numParams; ++i)
+ params[i] = getTermFor (parameters.getReference(i))->resolve (scope, recursionDepth + 1)->toDouble();
- return c.evaluateFunction (functionName, params, parameters.size());
- }
+ result = scope.evaluateFunction (functionName, params, numParams);
+ }
+ else
+ {
+ result = scope.evaluateFunction (functionName, 0, 0);
+ }
- Type getType() const throw() { return functionType; }
- int getInputIndexFor (const Term* possibleInput) const { return parameters.indexOf (possibleInput); }
- int getNumInputs() const { return parameters.size(); }
- Term* getInput (int i) const { return parameters [i]; }
- const String getFunctionName() const { return functionName; }
+ return new Constant (result, false);
+ }
- bool referencesSymbol (const String& s, const EvaluationContext* c, int recursionDepth) const
+ int getInputIndexFor (const Term* possibleInput) const
{
for (int i = 0; i < parameters.size(); ++i)
- if (parameters.getUnchecked(i)->referencesSymbol (s, c, recursionDepth))
- return true;
+ if (getTermFor (parameters.getReference(i)) == possibleInput)
+ return i;
- return false;
+ return -1;
}
const String toString() const
@@ -178,7 +296,7 @@ public:
for (int i = 0; i < parameters.size(); ++i)
{
- s << parameters.getUnchecked(i)->toString();
+ s << getTermFor (parameters.getReference(i))->toString();
if (i < parameters.size() - 1)
s << ", ";
@@ -189,119 +307,148 @@ public:
}
const String functionName;
- ReferenceCountedArray parameters;
+ Array parameters;
};
//==============================================================================
- class Negate : public Term
+ class DotOperator : public BinaryTerm
{
public:
- explicit Negate (const TermPtr& input_) : input (input_)
+ DotOperator (SymbolTerm* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
+
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- jassert (input_ != 0);
+ checkRecursionDepth (recursionDepth);
+
+ EvaluationVisitor visitor (right, recursionDepth + 1);
+ scope.visitRelativeScope (getSymbol()->symbol, visitor);
+ return visitor.output;
}
- Type getType() const throw() { return operatorType; }
- int getInputIndexFor (const Term* possibleInput) const { return possibleInput == input ? 0 : -1; }
- int getNumInputs() const { return 1; }
- Term* getInput (int index) const { return index == 0 ? static_cast (input) : 0; }
- Term* clone() const { return new Negate (input->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return -input->evaluate (c, recursionDepth); }
- const String getFunctionName() const { return "-"; }
+ Term* clone() const { return new DotOperator (getSymbol(), right); }
+ const String getName() const { return "."; }
+ int getOperatorPrecedence() const { return 1; }
+ void writeOperator (String& dest) const { dest << '.'; }
+ double performFunction (double, double) const { return 0.0; }
- const TermPtr negated()
+ void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
{
- return input;
+ checkRecursionDepth (recursionDepth);
+ visitor.useSymbol (Symbol (scope.getScopeUID(), getSymbol()->symbol));
+
+ SymbolVisitingVisitor v (right, visitor, recursionDepth + 1);
+ scope.visitRelativeScope (getSymbol()->symbol, v);
}
- const TermPtr createTermToEvaluateInput (const EvaluationContext& context, const Term* input_, double overallTarget, Term* topLevelTerm) const
+ void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
{
- (void) input_;
- jassert (input_ == input);
-
- const Term* const dest = findDestinationFor (topLevelTerm, this);
+ checkRecursionDepth (recursionDepth);
+ getSymbol()->renameSymbol (oldSymbol, newName, scope, recursionDepth);
- return new Negate (dest == 0 ? new Constant (overallTarget, false)
- : dest->createTermToEvaluateInput (context, this, overallTarget, topLevelTerm));
+ SymbolRenamingVisitor visitor (right, oldSymbol, newName, recursionDepth + 1);
+ scope.visitRelativeScope (getSymbol()->symbol, visitor);
}
- const String toString() const
+ private:
+ //==============================================================================
+ class EvaluationVisitor : public Scope::Visitor
{
- if (input->getOperatorPrecedence() > 0)
- return "-(" + input->toString() + ")";
- else
- return "-" + input->toString();
- }
+ public:
+ EvaluationVisitor (const TermPtr& input_, const int recursionCount_)
+ : input (input_), output (input_), recursionCount (recursionCount_) {}
- bool referencesSymbol (const String& s, const EvaluationContext* c, int recursionDepth) const
+ void visit (const Scope& scope) { output = input->resolve (scope, recursionCount); }
+
+ const TermPtr input;
+ TermPtr output;
+ const int recursionCount;
+
+ private:
+ JUCE_DECLARE_NON_COPYABLE (EvaluationVisitor);
+ };
+
+ class SymbolVisitingVisitor : public Scope::Visitor
{
- return input->referencesSymbol (s, c, recursionDepth);
- }
+ public:
+ SymbolVisitingVisitor (const TermPtr& input_, SymbolVisitor& visitor_, const int recursionCount_)
+ : input (input_), visitor (visitor_), recursionCount (recursionCount_) {}
- private:
- const TermPtr input;
+ void visit (const Scope& scope) { input->visitAllSymbols (visitor, scope, recursionCount); }
+
+ private:
+ const TermPtr input;
+ SymbolVisitor& visitor;
+ const int recursionCount;
+
+ JUCE_DECLARE_NON_COPYABLE (SymbolVisitingVisitor);
+ };
+
+ class SymbolRenamingVisitor : public Scope::Visitor
+ {
+ public:
+ SymbolRenamingVisitor (const TermPtr& input_, const Expression::Symbol& symbol_, const String& newName_, const int recursionCount_)
+ : input (input_), symbol (symbol_), newName (newName_), recursionCount (recursionCount_) {}
+
+ void visit (const Scope& scope) { input->renameSymbol (symbol, newName, scope, recursionCount); }
+
+ private:
+ const TermPtr input;
+ const Symbol& symbol;
+ const String newName;
+ const int recursionCount;
+
+ JUCE_DECLARE_NON_COPYABLE (SymbolRenamingVisitor);
+ };
+
+ SymbolTerm* getSymbol() const { return static_cast (left.getObject()); }
+
+ JUCE_DECLARE_NON_COPYABLE (DotOperator);
};
//==============================================================================
- class BinaryTerm : public Term
+ class Negate : public Term
{
public:
- BinaryTerm (Term* const left_, Term* const right_) : left (left_), right (right_)
+ explicit Negate (const TermPtr& input_) : input (input_)
{
- jassert (left_ != 0 && right_ != 0);
+ jassert (input_ != 0);
}
- int getInputIndexFor (const Term* possibleInput) const
+ Type getType() const throw() { return operatorType; }
+ int getInputIndexFor (const Term* possibleInput) const { return possibleInput == input ? 0 : -1; }
+ int getNumInputs() const { return 1; }
+ Term* getInput (int index) const { return index == 0 ? input.getObject() : 0; }
+ Term* clone() const { return new Negate (input->clone()); }
+
+ const TermPtr resolve (const Scope& scope, int recursionDepth)
{
- return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
+ return new Constant (-input->resolve (scope, recursionDepth)->toDouble(), false);
}
- Type getType() const throw() { return operatorType; }
- int getNumInputs() const { return 2; }
- Term* getInput (int index) const { return index == 0 ? static_cast (left) : (index == 1 ? static_cast (right) : 0); }
+ const String getName() const { return "-"; }
+ const TermPtr negated() { return input; }
- bool referencesSymbol (const String& s, const EvaluationContext* c, int recursionDepth) const
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input_, double overallTarget, Term* topLevelTerm) const
{
- return left->referencesSymbol (s, c, recursionDepth)
- || right->referencesSymbol (s, c, recursionDepth);
+ (void) input_;
+ jassert (input_ == input);
+
+ const Term* const dest = findDestinationFor (topLevelTerm, this);
+
+ return new Negate (dest == 0 ? new Constant (overallTarget, false)
+ : dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm));
}
const String toString() const
{
- String s;
-
- const int ourPrecendence = getOperatorPrecedence();
- if (left->getOperatorPrecedence() > ourPrecendence)
- s << '(' << left->toString() << ')';
- else
- s = left->toString();
-
- s << ' ' << getFunctionName() << ' ';
-
- if (right->getOperatorPrecedence() >= ourPrecendence)
- s << '(' << right->toString() << ')';
+ if (input->getOperatorPrecedence() > 0)
+ return "-(" + input->toString() + ")";
else
- s << right->toString();
-
- return s;
+ return "-" + input->toString();
}
- protected:
- const TermPtr left, right;
-
- const TermPtr createDestinationTerm (const EvaluationContext& context, const Term* input, double overallTarget, Term* topLevelTerm) const
- {
- jassert (input == left || input == right);
- if (input != left && input != right)
- return 0;
-
- const Term* const dest = findDestinationFor (topLevelTerm, this);
-
- if (dest == 0)
- return new Constant (overallTarget, false);
-
- return dest->createTermToEvaluateInput (context, this, overallTarget, topLevelTerm);
- }
+ private:
+ const TermPtr input;
};
//==============================================================================
@@ -311,13 +458,14 @@ public:
Add (Term* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
Term* clone() const { return new Add (left->clone(), right->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return left->evaluate (c, recursionDepth) + right->evaluate (c, recursionDepth); }
- int getOperatorPrecedence() const { return 2; }
- const String getFunctionName() const { return "+"; }
+ double performFunction (double lhs, double rhs) const { return lhs + rhs; }
+ int getOperatorPrecedence() const { return 3; }
+ const String getName() const { return "+"; }
+ void writeOperator (String& dest) const { dest << " + "; }
- const TermPtr createTermToEvaluateInput (const EvaluationContext& c, const Term* input, double overallTarget, Term* topLevelTerm) const
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- const TermPtr newDest (createDestinationTerm (c, input, overallTarget, topLevelTerm));
+ const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
if (newDest == 0)
return 0;
@@ -335,13 +483,14 @@ public:
Subtract (Term* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
Term* clone() const { return new Subtract (left->clone(), right->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return left->evaluate (c, recursionDepth) - right->evaluate (c, recursionDepth); }
- int getOperatorPrecedence() const { return 2; }
- const String getFunctionName() const { return "-"; }
+ double performFunction (double lhs, double rhs) const { return lhs - rhs; }
+ int getOperatorPrecedence() const { return 3; }
+ const String getName() const { return "-"; }
+ void writeOperator (String& dest) const { dest << " - "; }
- const TermPtr createTermToEvaluateInput (const EvaluationContext& c, const Term* input, double overallTarget, Term* topLevelTerm) const
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- const TermPtr newDest (createDestinationTerm (c, input, overallTarget, topLevelTerm));
+ const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
if (newDest == 0)
return 0;
@@ -362,13 +511,14 @@ public:
Multiply (Term* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
Term* clone() const { return new Multiply (left->clone(), right->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return left->evaluate (c, recursionDepth) * right->evaluate (c, recursionDepth); }
- const String getFunctionName() const { return "*"; }
- int getOperatorPrecedence() const { return 1; }
+ double performFunction (double lhs, double rhs) const { return lhs * rhs; }
+ const String getName() const { return "*"; }
+ void writeOperator (String& dest) const { dest << " * "; }
+ int getOperatorPrecedence() const { return 2; }
- const TermPtr createTermToEvaluateInput (const EvaluationContext& c, const Term* input, double overallTarget, Term* topLevelTerm) const
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- const TermPtr newDest (createDestinationTerm (c, input, overallTarget, topLevelTerm));
+ const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
if (newDest == 0)
return 0;
@@ -386,13 +536,14 @@ public:
Divide (Term* const left_, Term* const right_) : BinaryTerm (left_, right_) {}
Term* clone() const { return new Divide (left->clone(), right->clone()); }
- double evaluate (const EvaluationContext& c, int recursionDepth) const { return left->evaluate (c, recursionDepth) / right->evaluate (c, recursionDepth); }
- const String getFunctionName() const { return "/"; }
- int getOperatorPrecedence() const { return 1; }
+ double performFunction (double lhs, double rhs) const { return lhs / rhs; }
+ const String getName() const { return "/"; }
+ void writeOperator (String& dest) const { dest << " / "; }
+ int getOperatorPrecedence() const { return 2; }
- const TermPtr createTermToEvaluateInput (const EvaluationContext& c, const Term* input, double overallTarget, Term* topLevelTerm) const
+ const TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
{
- const TermPtr newDest (createDestinationTerm (c, input, overallTarget, topLevelTerm));
+ const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
if (newDest == 0)
return 0;
@@ -466,24 +617,33 @@ public:
return false;
}
- static bool renameSymbol (Term* const t, const String& oldName, const String& newName)
+ //==============================================================================
+ class SymbolCheckVisitor : public Term::SymbolVisitor
{
- Symbol* const sym = dynamic_cast (t);
+ public:
+ SymbolCheckVisitor (const Symbol& symbol_) : wasFound (false), symbol (symbol_) {}
+ void useSymbol (const Symbol& s) { wasFound = wasFound || s == symbol; }
- if (sym != 0 && sym->mainSymbol == oldName)
- {
- sym->mainSymbol = newName;
- return true;
- }
+ bool wasFound;
- bool anyChanged = false;
+ private:
+ const Symbol& symbol;
- for (int i = t->getNumInputs(); --i >= 0;)
- if (renameSymbol (t->getInput (i), oldName, newName))
- anyChanged = true;
+ JUCE_DECLARE_NON_COPYABLE (SymbolCheckVisitor);
+ };
- return anyChanged;
- }
+ //==============================================================================
+ class SymbolListVisitor : public Term::SymbolVisitor
+ {
+ public:
+ SymbolListVisitor (Array& list_) : list (list_) {}
+ void useSymbol (const Symbol& s) { list.addIfNotAlreadyThere (s); }
+
+ private:
+ Array& list;
+
+ JUCE_DECLARE_NON_COPYABLE (SymbolListVisitor);
+ };
//==============================================================================
class Parser
@@ -574,7 +734,7 @@ public:
{
++i;
- while (CharacterFunctions::isLetterOrDigit (text[i]) || text[i] == '_' || text[i] == '.')
+ while (CharacterFunctions::isLetterOrDigit (text[i]) || text[i] == '_')
++i;
}
@@ -707,12 +867,17 @@ public:
if (e != 0)
return e;
+ return readSymbolOrFunction();
+ }
+
+ const TermPtr readSymbolOrFunction()
+ {
String identifier;
if (readIdentifier (identifier))
{
if (readOperator ("(")) // method call...
{
- Function* const f = new Function (identifier, ReferenceCountedArray());
+ Function* const f = new Function (identifier);
ScopedPointer