@@ -94,6 +94,7 @@ OBJECTS := \ | |||
$(OBJDIR)/juce_Synthesiser_2bffa1dd.o \ | |||
$(OBJDIR)/juce_BigInteger_63589133.o \ | |||
$(OBJDIR)/juce_DynamicObject_69d02ab3.o \ | |||
$(OBJDIR)/juce_Expression_1e9a5aad.o \ | |||
$(OBJDIR)/juce_Identifier_89fa043e.o \ | |||
$(OBJDIR)/juce_MemoryBlock_edd65761.o \ | |||
$(OBJDIR)/juce_NamedValueSet_6b0793df.o \ | |||
@@ -631,6 +632,11 @@ $(OBJDIR)/juce_DynamicObject_69d02ab3.o: ../../src/containers/juce_DynamicObject | |||
@echo "Compiling juce_DynamicObject.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/juce_Expression_1e9a5aad.o: ../../src/containers/juce_Expression.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo "Compiling juce_Expression.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/juce_Identifier_89fa043e.o: ../../src/containers/juce_Identifier.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo "Compiling juce_Identifier.cpp" | |||
@@ -63,6 +63,7 @@ | |||
E8DFABC1603D55B97429A8E4 = { isa = PBXBuildFile; fileRef = 35668D8EEA19957C6C9AC83A; }; | |||
BE25871C34D79FEFFD1B94B6 = { isa = PBXBuildFile; fileRef = 895D742F49DA9F100990879C; }; | |||
4AB5E55BDF79028F82F83D8E = { isa = PBXBuildFile; fileRef = F77C9170829579FABA5679AD; }; | |||
25018C91F79D918FEA084630 = { isa = PBXBuildFile; fileRef = 199DFD1C5A282FE13A585FEA; }; | |||
95577AE91AA6CBA7FE9434F3 = { isa = PBXBuildFile; fileRef = 1CF7CC0EB057F995BBBEFC90; }; | |||
21BA256CBCC9C15265928A23 = { isa = PBXBuildFile; fileRef = FF40DA899AE16A5E1D8AA54A; }; | |||
9D2D1BA65C27BDA1F7C44769 = { isa = PBXBuildFile; fileRef = 70E5409425A76782B6188B31; }; | |||
@@ -481,6 +482,8 @@ | |||
F77C9170829579FABA5679AD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_DynamicObject.cpp; path = ../../src/containers/juce_DynamicObject.cpp; sourceTree = SOURCE_ROOT; }; | |||
34C402EF9ADCAD34FB657D43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_DynamicObject.h; path = ../../src/containers/juce_DynamicObject.h; sourceTree = SOURCE_ROOT; }; | |||
7DA9AC75A4D9227C8FC4B2F7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ElementComparator.h; path = ../../src/containers/juce_ElementComparator.h; sourceTree = SOURCE_ROOT; }; | |||
199DFD1C5A282FE13A585FEA = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Expression.cpp; path = ../../src/containers/juce_Expression.cpp; sourceTree = SOURCE_ROOT; }; | |||
3C12A5E0EBBB0916C01CFC58 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Expression.h; path = ../../src/containers/juce_Expression.h; sourceTree = SOURCE_ROOT; }; | |||
F364AA2637B7CB89D3657DFF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_HeapBlock.h; path = ../../src/containers/juce_HeapBlock.h; sourceTree = SOURCE_ROOT; }; | |||
1CF7CC0EB057F995BBBEFC90 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Identifier.cpp; path = ../../src/containers/juce_Identifier.cpp; sourceTree = SOURCE_ROOT; }; | |||
C16848F86DF014F1CBECE248 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Identifier.h; path = ../../src/containers/juce_Identifier.h; sourceTree = SOURCE_ROOT; }; | |||
@@ -1195,6 +1198,8 @@ | |||
F77C9170829579FABA5679AD, | |||
34C402EF9ADCAD34FB657D43, | |||
7DA9AC75A4D9227C8FC4B2F7, | |||
199DFD1C5A282FE13A585FEA, | |||
3C12A5E0EBBB0916C01CFC58, | |||
F364AA2637B7CB89D3657DFF, | |||
1CF7CC0EB057F995BBBEFC90, | |||
C16848F86DF014F1CBECE248, | |||
@@ -1952,6 +1957,7 @@ | |||
E8DFABC1603D55B97429A8E4, | |||
BE25871C34D79FEFFD1B94B6, | |||
4AB5E55BDF79028F82F83D8E, | |||
25018C91F79D918FEA084630, | |||
95577AE91AA6CBA7FE9434F3, | |||
21BA256CBCC9C15265928A23, | |||
9D2D1BA65C27BDA1F7C44769, | |||
@@ -350,6 +350,8 @@ | |||
<File RelativePath="..\..\src\containers\juce_DynamicObject.cpp"/> | |||
<File RelativePath="..\..\src\containers\juce_DynamicObject.h"/> | |||
<File RelativePath="..\..\src\containers\juce_ElementComparator.h"/> | |||
<File RelativePath="..\..\src\containers\juce_Expression.cpp"/> | |||
<File RelativePath="..\..\src\containers\juce_Expression.h"/> | |||
<File RelativePath="..\..\src\containers\juce_HeapBlock.h"/> | |||
<File RelativePath="..\..\src\containers\juce_Identifier.cpp"/> | |||
<File RelativePath="..\..\src\containers\juce_Identifier.h"/> | |||
@@ -350,6 +350,8 @@ | |||
<File RelativePath="..\..\src\containers\juce_DynamicObject.cpp"/> | |||
<File RelativePath="..\..\src\containers\juce_DynamicObject.h"/> | |||
<File RelativePath="..\..\src\containers\juce_ElementComparator.h"/> | |||
<File RelativePath="..\..\src\containers\juce_Expression.cpp"/> | |||
<File RelativePath="..\..\src\containers\juce_Expression.h"/> | |||
<File RelativePath="..\..\src\containers\juce_HeapBlock.h"/> | |||
<File RelativePath="..\..\src\containers\juce_Identifier.cpp"/> | |||
<File RelativePath="..\..\src\containers\juce_Identifier.h"/> | |||
@@ -352,6 +352,8 @@ | |||
<File RelativePath="..\..\src\containers\juce_DynamicObject.cpp"/> | |||
<File RelativePath="..\..\src\containers\juce_DynamicObject.h"/> | |||
<File RelativePath="..\..\src\containers\juce_ElementComparator.h"/> | |||
<File RelativePath="..\..\src\containers\juce_Expression.cpp"/> | |||
<File RelativePath="..\..\src\containers\juce_Expression.h"/> | |||
<File RelativePath="..\..\src\containers\juce_HeapBlock.h"/> | |||
<File RelativePath="..\..\src\containers\juce_Identifier.cpp"/> | |||
<File RelativePath="..\..\src\containers\juce_Identifier.h"/> | |||
@@ -177,6 +177,7 @@ | |||
<ClCompile Include="..\..\src\audio\synthesisers\juce_Synthesiser.cpp"/> | |||
<ClCompile Include="..\..\src\containers\juce_BigInteger.cpp"/> | |||
<ClCompile Include="..\..\src\containers\juce_DynamicObject.cpp"/> | |||
<ClCompile Include="..\..\src\containers\juce_Expression.cpp"/> | |||
<ClCompile Include="..\..\src\containers\juce_Identifier.cpp"/> | |||
<ClCompile Include="..\..\src\containers\juce_MemoryBlock.cpp"/> | |||
<ClCompile Include="..\..\src\containers\juce_NamedValueSet.cpp"/> | |||
@@ -502,6 +503,7 @@ | |||
<ClInclude Include="..\..\src\containers\juce_BigInteger.h"/> | |||
<ClInclude Include="..\..\src\containers\juce_DynamicObject.h"/> | |||
<ClInclude Include="..\..\src\containers\juce_ElementComparator.h"/> | |||
<ClInclude Include="..\..\src\containers\juce_Expression.h"/> | |||
<ClInclude Include="..\..\src\containers\juce_HeapBlock.h"/> | |||
<ClInclude Include="..\..\src\containers\juce_Identifier.h"/> | |||
<ClInclude Include="..\..\src\containers\juce_MemoryBlock.h"/> | |||
@@ -379,6 +379,9 @@ | |||
<ClCompile Include="..\..\src\containers\juce_DynamicObject.cpp"> | |||
<Filter>Juce\Source\containers</Filter> | |||
</ClCompile> | |||
<ClCompile Include="..\..\src\containers\juce_Expression.cpp"> | |||
<Filter>Juce\Source\containers</Filter> | |||
</ClCompile> | |||
<ClCompile Include="..\..\src\containers\juce_Identifier.cpp"> | |||
<Filter>Juce\Source\containers</Filter> | |||
</ClCompile> | |||
@@ -1428,6 +1431,9 @@ | |||
<ClInclude Include="..\..\src\containers\juce_ElementComparator.h"> | |||
<Filter>Juce\Source\containers</Filter> | |||
</ClInclude> | |||
<ClInclude Include="..\..\src\containers\juce_Expression.h"> | |||
<Filter>Juce\Source\containers</Filter> | |||
</ClInclude> | |||
<ClInclude Include="..\..\src\containers\juce_HeapBlock.h"> | |||
<Filter>Juce\Source\containers</Filter> | |||
</ClInclude> | |||
@@ -63,6 +63,7 @@ | |||
E8DFABC1603D55B97429A8E4 = { isa = PBXBuildFile; fileRef = 35668D8EEA19957C6C9AC83A; }; | |||
BE25871C34D79FEFFD1B94B6 = { isa = PBXBuildFile; fileRef = 895D742F49DA9F100990879C; }; | |||
4AB5E55BDF79028F82F83D8E = { isa = PBXBuildFile; fileRef = F77C9170829579FABA5679AD; }; | |||
25018C91F79D918FEA084630 = { isa = PBXBuildFile; fileRef = 199DFD1C5A282FE13A585FEA; }; | |||
95577AE91AA6CBA7FE9434F3 = { isa = PBXBuildFile; fileRef = 1CF7CC0EB057F995BBBEFC90; }; | |||
21BA256CBCC9C15265928A23 = { isa = PBXBuildFile; fileRef = FF40DA899AE16A5E1D8AA54A; }; | |||
9D2D1BA65C27BDA1F7C44769 = { isa = PBXBuildFile; fileRef = 70E5409425A76782B6188B31; }; | |||
@@ -481,6 +482,8 @@ | |||
F77C9170829579FABA5679AD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_DynamicObject.cpp; path = ../../src/containers/juce_DynamicObject.cpp; sourceTree = SOURCE_ROOT; }; | |||
34C402EF9ADCAD34FB657D43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_DynamicObject.h; path = ../../src/containers/juce_DynamicObject.h; sourceTree = SOURCE_ROOT; }; | |||
7DA9AC75A4D9227C8FC4B2F7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ElementComparator.h; path = ../../src/containers/juce_ElementComparator.h; sourceTree = SOURCE_ROOT; }; | |||
199DFD1C5A282FE13A585FEA = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Expression.cpp; path = ../../src/containers/juce_Expression.cpp; sourceTree = SOURCE_ROOT; }; | |||
3C12A5E0EBBB0916C01CFC58 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Expression.h; path = ../../src/containers/juce_Expression.h; sourceTree = SOURCE_ROOT; }; | |||
F364AA2637B7CB89D3657DFF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_HeapBlock.h; path = ../../src/containers/juce_HeapBlock.h; sourceTree = SOURCE_ROOT; }; | |||
1CF7CC0EB057F995BBBEFC90 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Identifier.cpp; path = ../../src/containers/juce_Identifier.cpp; sourceTree = SOURCE_ROOT; }; | |||
C16848F86DF014F1CBECE248 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Identifier.h; path = ../../src/containers/juce_Identifier.h; sourceTree = SOURCE_ROOT; }; | |||
@@ -1195,6 +1198,8 @@ | |||
F77C9170829579FABA5679AD, | |||
34C402EF9ADCAD34FB657D43, | |||
7DA9AC75A4D9227C8FC4B2F7, | |||
199DFD1C5A282FE13A585FEA, | |||
3C12A5E0EBBB0916C01CFC58, | |||
F364AA2637B7CB89D3657DFF, | |||
1CF7CC0EB057F995BBBEFC90, | |||
C16848F86DF014F1CBECE248, | |||
@@ -1952,6 +1957,7 @@ | |||
E8DFABC1603D55B97429A8E4, | |||
BE25871C34D79FEFFD1B94B6, | |||
4AB5E55BDF79028F82F83D8E, | |||
25018C91F79D918FEA084630, | |||
95577AE91AA6CBA7FE9434F3, | |||
21BA256CBCC9C15265928A23, | |||
9D2D1BA65C27BDA1F7C44769, | |||
@@ -359,6 +359,10 @@ | |||
file="src/containers/juce_DynamicObject.h"/> | |||
<FILE id="RNHQjBFmS" name="juce_ElementComparator.h" compile="0" resource="0" | |||
file="src/containers/juce_ElementComparator.h"/> | |||
<FILE id="01ekjVT" name="juce_Expression.cpp" compile="1" resource="0" | |||
file="src/containers/juce_Expression.cpp"/> | |||
<FILE id="MpE62KG" name="juce_Expression.h" compile="0" resource="0" | |||
file="src/containers/juce_Expression.h"/> | |||
<FILE id="ssHjnrvya" name="juce_HeapBlock.h" compile="0" resource="0" | |||
file="src/containers/juce_HeapBlock.h"/> | |||
<FILE id="3Wo76GZwg" name="juce_Identifier.cpp" compile="1" resource="0" | |||
@@ -110,6 +110,7 @@ | |||
#include "../src/containers/juce_Variant.cpp" | |||
#include "../src/containers/juce_NamedValueSet.cpp" | |||
#include "../src/containers/juce_DynamicObject.cpp" | |||
#include "../src/containers/juce_Expression.cpp" | |||
#include "../src/cryptography/juce_BlowFish.cpp" | |||
#include "../src/cryptography/juce_MD5.cpp" | |||
#include "../src/cryptography/juce_Primes.cpp" | |||
@@ -333,12 +333,15 @@ void RelativeRectangleLayoutManager::applyLayout() | |||
} | |||
} | |||
const RelativeCoordinate RelativeRectangleLayoutManager::findNamedCoordinate (const String& objectName, const String& edge) const | |||
const Expression RelativeRectangleLayoutManager::getSymbolValue (const String& symbol) const | |||
{ | |||
const String objectName (symbol.upToFirstOccurrenceOf (".", false, false).trim()); | |||
const String edge (symbol.fromFirstOccurrenceOf (".", false, false).trim()); | |||
if (objectName == RelativeCoordinate::Strings::parent) | |||
{ | |||
if (edge == RelativeCoordinate::Strings::right) return RelativeCoordinate ((double) parent->getWidth()); | |||
if (edge == RelativeCoordinate::Strings::bottom) return RelativeCoordinate ((double) parent->getHeight()); | |||
if (edge == RelativeCoordinate::Strings::right) return Expression ((double) parent->getWidth()); | |||
if (edge == RelativeCoordinate::Strings::bottom) return Expression ((double) parent->getHeight()); | |||
} | |||
if (objectName.isNotEmpty() && edge.isNotEmpty()) | |||
@@ -349,10 +352,10 @@ const RelativeCoordinate RelativeRectangleLayoutManager::findNamedCoordinate (co | |||
if (c->name == objectName) | |||
{ | |||
if (edge == RelativeCoordinate::Strings::left) return c->coords.left; | |||
if (edge == RelativeCoordinate::Strings::right) return c->coords.right; | |||
if (edge == RelativeCoordinate::Strings::top) return c->coords.top; | |||
if (edge == RelativeCoordinate::Strings::bottom) return c->coords.bottom; | |||
if (edge == RelativeCoordinate::Strings::left) return c->coords.left.getTerm(); | |||
if (edge == RelativeCoordinate::Strings::right) return c->coords.right.getTerm(); | |||
if (edge == RelativeCoordinate::Strings::top) return c->coords.top.getTerm(); | |||
if (edge == RelativeCoordinate::Strings::bottom) return c->coords.bottom.getTerm(); | |||
} | |||
} | |||
} | |||
@@ -362,10 +365,10 @@ const RelativeCoordinate RelativeRectangleLayoutManager::findNamedCoordinate (co | |||
MarkerPosition* m = markers.getUnchecked(i); | |||
if (m->markerName == objectName) | |||
return m->position; | |||
return m->position.getTerm(); | |||
} | |||
return RelativeCoordinate(); | |||
return Expression(); | |||
} | |||
void RelativeRectangleLayoutManager::componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) | |||
@@ -142,7 +142,7 @@ private: | |||
/** | |||
*/ | |||
class RelativeRectangleLayoutManager : public ComponentListener, | |||
public RelativeCoordinate::NamedCoordinateFinder, | |||
public Expression::EvaluationContext, | |||
public AsyncUpdater | |||
{ | |||
public: | |||
@@ -169,7 +169,7 @@ public: | |||
//============================================================================== | |||
/** @internal */ | |||
const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const; | |||
const Expression getSymbolValue (const String& symbol) const; | |||
/** @internal */ | |||
void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); | |||
/** @internal */ | |||
@@ -20,7 +20,7 @@ | |||
/** This is the editor component that our filter will display. | |||
*/ | |||
class JuceDemoPluginAudioProcessorEditor : public AudioProcessorEditor, | |||
public Slider::Listener, | |||
public SliderListener, | |||
public Timer | |||
{ | |||
public: | |||
@@ -64,7 +64,7 @@ | |||
*/ | |||
#define JUCE_MAJOR_VERSION 1 | |||
#define JUCE_MINOR_VERSION 52 | |||
#define JUCE_BUILDNUMBER 49 | |||
#define JUCE_BUILDNUMBER 50 | |||
/** Current Juce version number. | |||
@@ -536,7 +536,7 @@ | |||
@see Logger::outputDebugString | |||
*/ | |||
#define DBG(dbgtext) { String tempDbgBuf; tempDbgBuf << dbgtext; JUCE_NAMESPACE::Logger::outputDebugString (tempDbgBuf); } | |||
#define DBG(dbgtext) { JUCE_NAMESPACE::String tempDbgBuf; tempDbgBuf << dbgtext; JUCE_NAMESPACE::Logger::outputDebugString (tempDbgBuf); } | |||
// Assertions.. | |||
@@ -6370,23 +6370,11 @@ private: | |||
#ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ | |||
#endif | |||
#ifndef __JUCE_HEAPBLOCK_JUCEHEADER__ | |||
#endif | |||
#ifndef __JUCE_IDENTIFIER_JUCEHEADER__ | |||
#endif | |||
#ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ | |||
#endif | |||
#ifndef __JUCE_NAMEDVALUESET_JUCEHEADER__ | |||
#ifndef __JUCE_EXPRESSION_JUCEHEADER__ | |||
#endif | |||
#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ | |||
/*** Start of inlined file: juce_OwnedArray.h ***/ | |||
#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ | |||
#define __JUCE_OWNEDARRAY_JUCEHEADER__ | |||
/*** Start of inlined file: juce_Expression.h ***/ | |||
#ifndef __JUCE_EXPRESSION_JUCEHEADER__ | |||
#define __JUCE_EXPRESSION_JUCEHEADER__ | |||
/*** Start of inlined file: juce_ScopedPointer.h ***/ | |||
@@ -6562,6 +6550,206 @@ inline bool operator!= (const ScopedPointer<ObjectType>& pointer1, const ObjectT | |||
#endif // __JUCE_SCOPEDPOINTER_JUCEHEADER__ | |||
/*** End of inlined file: juce_ScopedPointer.h ***/ | |||
/** | |||
A class for dynamically evaluating simple numeric expressions. | |||
This class can parse a simple C-style string expression involving floating point | |||
numbers, named symbols and functions. The basic arithmetic operations of +, -, *, / | |||
are supported, as well as parentheses, and any alphanumeric identifiers are | |||
assumed to be named symbols which will be resolved when the expression is | |||
evaluated. | |||
Expressions which use identifiers and functions require a subclass of | |||
Expression::EvaluationContext 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. | |||
*/ | |||
class JUCE_API Expression | |||
{ | |||
public: | |||
/** Creates a simple expression with a value of 0. */ | |||
Expression(); | |||
/** Destructor. */ | |||
~Expression(); | |||
/** Creates a simple expression with a specified constant value. */ | |||
explicit Expression (const double constant); | |||
/** Creates a copy of an expression. */ | |||
Expression (const Expression& other); | |||
/** Copies another expression. */ | |||
Expression& operator= (const Expression& other); | |||
/** Creates an expression by parsing a string. | |||
If there's a syntax error in the string, this will throw a ParseError exception. | |||
@throws ParseError | |||
*/ | |||
explicit Expression (const String& stringToParse); | |||
/** Returns a string version of the expression. */ | |||
const String toString() const; | |||
/** Returns an expression which is an addtion operation of two existing expressions. */ | |||
const Expression operator+ (const Expression& other) const; | |||
/** Returns an expression which is a subtraction operation of two existing expressions. */ | |||
const Expression operator- (const Expression& other) const; | |||
/** Returns an expression which is a multiplication operation of two existing expressions. */ | |||
const Expression operator* (const Expression& other) const; | |||
/** Returns an expression which is a division operation of two existing expressions. */ | |||
const Expression operator/ (const Expression& other) const; | |||
/** Returns an expression which is a negation operation of two existing expressions. */ | |||
const Expression operator-() const; | |||
/** Returns an Expression which is an identifier reference. */ | |||
static const Expression symbol (const String& symbol); | |||
/** Returns an Expression which is a function call. */ | |||
static const Expression function (const String& functionName, const Array<Expression>& parameters); | |||
/** Returns an Expression which parses a string from a specified character index. | |||
The index value is incremented so that on return, it indicates the character that follows | |||
the end of the expression that was parsed. | |||
If there's a syntax error in the string, this will throw a ParseError exception. | |||
@throws ParseError | |||
*/ | |||
static const Expression parse (const String& stringToParse, int& textIndexToStartFrom); | |||
/** When evaluating an Expression object, this class is used to resolve symbols and | |||
perform functions that the expression uses. | |||
*/ | |||
class EvaluationContext | |||
{ | |||
public: | |||
EvaluationContext(); | |||
virtual ~EvaluationContext(); | |||
/** Returns the value of a symbol. | |||
If the symbol is unknown, this can throw an Expression::EvaluationError exception. | |||
@throws Expression::EvaluationError | |||
*/ | |||
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; | |||
}; | |||
/** Evaluates this expression, without using an EvaluationContext. | |||
Without an EvaluationContext, no symbols can be used, and only basic functions such as sin, cos, tan, | |||
min, max are available. | |||
*/ | |||
double evaluate() const; | |||
/** Evaluates this expression, providing a context that should be able to evaluate any symbols | |||
or functions that it uses. | |||
*/ | |||
double evaluate (const EvaluationContext& context) 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. | |||
*/ | |||
const Expression adjustedToGiveNewResult (double targetValue, const EvaluationContext& context) const; | |||
/** 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; | |||
/** Returns true if this expression makes use of the specified symbol. | |||
If a suitable context 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. | |||
*/ | |||
bool referencesSymbol (const String& symbol, const EvaluationContext& context) const; | |||
/** Returns true if this expression contains any symbols. */ | |||
bool usesAnySymbols() const; | |||
/** An exception that can be thrown by Expression::parse(). */ | |||
class ParseError : public std::exception | |||
{ | |||
public: | |||
ParseError (const String& message); | |||
String description; | |||
}; | |||
/** An exception that can be thrown by Expression::evaluate(). */ | |||
class EvaluationError : public std::exception | |||
{ | |||
public: | |||
EvaluationError (const String& message); | |||
String description; | |||
}; | |||
juce_UseDebuggingNewOperator | |||
private: | |||
class Helpers; | |||
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<Term> createTermToEvaluateInput (const EvaluationContext&, Term* inputTerm, | |||
double overallTarget, Term* topLevelTerm) const; | |||
juce_UseDebuggingNewOperator | |||
private: | |||
Term (const Term& other); | |||
Term& operator= (const Term&); | |||
}; | |||
friend class ScopedPointer<Term>; | |||
ReferenceCountedObjectPtr<Term> term; | |||
explicit Expression (Term* term); | |||
}; | |||
#endif // __JUCE_EXPRESSION_JUCEHEADER__ | |||
/*** End of inlined file: juce_Expression.h ***/ | |||
#endif | |||
#ifndef __JUCE_HEAPBLOCK_JUCEHEADER__ | |||
#endif | |||
#ifndef __JUCE_IDENTIFIER_JUCEHEADER__ | |||
#endif | |||
#ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ | |||
#endif | |||
#ifndef __JUCE_NAMEDVALUESET_JUCEHEADER__ | |||
#endif | |||
#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ | |||
/*** Start of inlined file: juce_OwnedArray.h ***/ | |||
#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ | |||
#define __JUCE_OWNEDARRAY_JUCEHEADER__ | |||
/** An array designed for holding objects. | |||
This holds a list of pointers to objects, and will automatically | |||
@@ -29868,6 +30056,15 @@ struct JUCE_API AudioSourceChannelInfo | |||
/** | |||
Base class for objects that can produce a continuous stream of audio. | |||
An AudioSource has two states: 'prepared' and 'unprepared'. | |||
When a source needs to be played, it is first put into a 'prepared' state by a call to | |||
prepareToPlay(), and then repeated calls will be made to its getNextAudioBlock() method to | |||
process the audio data. | |||
Once playback has finished, the releaseResources() method is called to put the stream | |||
back into an 'unprepared' state. | |||
@see AudioFormatReaderSource, ResamplingAudioSource | |||
*/ | |||
class JUCE_API AudioSource | |||
@@ -29883,7 +30080,14 @@ public: | |||
/** Tells the source to prepare for playing. | |||
The source can use this opportunity to initialise anything it needs to. | |||
An AudioSource has two states: prepared and unprepared. | |||
The prepareToPlay() method is guaranteed to be called at least once on an 'unpreprared' | |||
source to put it into a 'prepared' state before any calls will be made to getNextAudioBlock(). | |||
This callback allows the source to initialise any resources it might need when playing. | |||
Once playback has finished, the releaseResources() method is called to put the stream | |||
back into an 'unprepared' state. | |||
Note that this method could be called more than once in succession without | |||
a matching call to releaseResources(), so make sure your code is robust and | |||
@@ -31295,6 +31499,9 @@ public: | |||
/** Returns true if this source is actually playing in a loop. */ | |||
virtual bool isLooping() const = 0; | |||
/** Tells the source whether you'd like it to play in a loop. */ | |||
virtual void setLooping (bool shouldLoop) { (void) shouldLoop; } | |||
}; | |||
#endif // __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ | |||
@@ -31329,7 +31536,7 @@ public: | |||
@see isLooping | |||
*/ | |||
void setLooping (const bool shouldLoop) throw(); | |||
void setLooping (bool shouldLoop); | |||
/** Returns whether loop-mode is turned on or not. */ | |||
bool isLooping() const { return looping; } | |||
@@ -36616,7 +36823,8 @@ public: | |||
@param newItemText the text of the item to show in the list | |||
@param newItemId an associated ID number that can be set or retrieved - see | |||
getSelectedId() and setSelectedId() | |||
getSelectedId() and setSelectedId(). Note that this value can not | |||
be 0! | |||
@see setItemEnabled, addSeparator, addSectionHeading, removeItem, getNumItems, getItemText, getItemId | |||
*/ | |||
void addItem (const String& newItemText, | |||
@@ -42813,21 +43021,7 @@ private: | |||
#define __JUCE_RELATIVECOORDINATE_JUCEHEADER__ | |||
/** | |||
Expresses a coordinate as an absolute or proportional distance from other | |||
named coordinates. | |||
A RelativeCoordinate represents a position as either: | |||
- an absolute distance from the origin | |||
- an absolute distance from another named RelativeCoordinate | |||
- a proportion of the distance between two other named RelativeCoordinates | |||
Of course, the coordinates that this one is relative to may themselves be relative | |||
to other coordinates, so complex arrangements can be built up (as long as you're careful | |||
not to create recursive loops!) | |||
Rather than keeping pointers to the coordinates that this one is dependent on, it | |||
stores their names, and when resolving this coordinate to an absolute value, a | |||
NamedCoordinateFinder class is required to retrieve these coordinates by name. | |||
Expresses a coordinate as a dynamically evaluated expression. | |||
@see RelativePoint, RelativeRectangle | |||
*/ | |||
@@ -42837,6 +43031,9 @@ public: | |||
/** Creates a zero coordinate. */ | |||
RelativeCoordinate(); | |||
RelativeCoordinate (const Expression& expression); | |||
RelativeCoordinate (const RelativeCoordinate& other); | |||
RelativeCoordinate& operator= (const RelativeCoordinate& other); | |||
/** Creates an absolute position from the parent origin on either the X or Y axis. | |||
@@ -42844,52 +43041,16 @@ public: | |||
*/ | |||
RelativeCoordinate (double absoluteDistanceFromOrigin); | |||
/** Creates an absolute position relative to a named coordinate. | |||
@param absoluteDistanceFromAnchor the distance to add to the named anchor point | |||
@param anchorPoint the name of the coordinate from which this one will be relative. See the constructor | |||
notes for a description of the syntax for coordinate names. | |||
*/ | |||
RelativeCoordinate (double absoluteDistanceFromAnchor, const String& anchorPoint); | |||
/** Creates a relative position between two named points. | |||
@param relativeProportionBetweenAnchors a value between 0 and 1 indicating this coordinate's relative position | |||
between anchorPoint1 and anchorPoint2. | |||
@param anchorPoint1 the name of the first coordinate from which this one will be relative. See the constructor | |||
notes for a description of the syntax for coordinate names. | |||
@param anchorPoint2 the name of the first coordinate from which this one will be relative. See the constructor | |||
notes for a description of the syntax for coordinate names. | |||
*/ | |||
RelativeCoordinate (double relativeProportionBetweenAnchors, const String& anchorPoint1, const String& anchorPoint2); | |||
/** Recreates a coordinate from a string description. | |||
The string can be in one of the following formats: | |||
- "123" = 123 pixels from parent origin (this is equivalent to "parent.left + 123" | |||
or "parent.top + 123", depending on which axis the coordinate is using) | |||
- "anchor" = the same position as the coordinate named "anchor" | |||
- "anchor + 123" = the coordinate named "anchor" + 123 pixels | |||
- "anchor - 123" = the coordinate named "anchor" - 123 pixels | |||
- "50%" = 50% of the distance between the coordinate space's top-left origin and its extent | |||
(this is equivalent to "50% * parent.left -> parent.right" or "50% * parent.top -> parent.bottom") | |||
- "50% * anchor" = 50% of the distance between the coordinate space's origin and the coordinate named "anchor" | |||
(this is equivalent to "50% * parent.left -> anchor" or "50% * parent.top -> anchor") | |||
- "50% * anchor1 -> anchor2" = 50% of the distance between the coordinate "anchor1" and the coordinate "anchor2" | |||
An anchor name can either be just a single identifier (letters, digits and underscores only - no spaces), | |||
e.g. "marker1", or it can be a two-part name in the form "objectName.edge". For example "parent.left" is | |||
the origin, or "myComponent.top" is the top edge of a component called "myComponent". The exact names that | |||
will be recognised are dependent on the NamedCoordinateFinder that you provide for looking them up, but | |||
"parent.left" and "parent.top" are always available, meaning the origin. "parent.right" and "parent.bottom" | |||
may also be available if the coordinate space has a fixed size. | |||
@param stringVersion the string to parse | |||
The string will be parsed by ExpressionParser::parse(). | |||
@param stringVersion the expression to use | |||
@param isHorizontal this must be true if this is an X coordinate, or false if it's on the Y axis. | |||
@see toString | |||
*/ | |||
RelativeCoordinate (const String& stringVersion, bool isHorizontal); | |||
RelativeCoordinate (const String& stringVersion); | |||
/** Destructor. */ | |||
~RelativeCoordinate(); | |||
@@ -42897,44 +43058,20 @@ public: | |||
bool operator== (const RelativeCoordinate& other) const throw(); | |||
bool operator!= (const RelativeCoordinate& other) const throw(); | |||
/** | |||
Provides an interface for looking up the position of a named anchor when resolving a RelativeCoordinate. | |||
When using RelativeCoordinates, to resolve their names you need to provide a subclass of this which | |||
can retrieve a coordinate by name. | |||
*/ | |||
class JUCE_API NamedCoordinateFinder | |||
{ | |||
public: | |||
/** Destructor. */ | |||
virtual ~NamedCoordinateFinder() {} | |||
/** Returns the coordinate for a given name. | |||
The objectName parameter will be the first section of the name, and the edge the name of the second part. | |||
E.g. for "parent.right", objectName would be "parent" and edge would be "right". If the name | |||
has no dot, the edge parameter will be an empty string. | |||
This method must be able to resolve "parent.left", "parent.top", "parent.right" and "parent.bottom", as | |||
well as any other objects that your application uses. | |||
*/ | |||
virtual const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const = 0; | |||
}; | |||
/** Calculates the absolute position of this coordinate. | |||
You'll need to provide a suitable NamedCoordinateFinder for looking up any coordinates that may | |||
You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may | |||
be needed to calculate the result. | |||
*/ | |||
double resolve (const NamedCoordinateFinder* nameFinder) const; | |||
double resolve (const Expression::EvaluationContext* evaluationContext) 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 NamedCoordinateFinder* nameFinder) const; | |||
bool references (const String& coordName, const Expression::EvaluationContext* evaluationContext) const; | |||
/** Returns true if there's a recursive loop when trying to resolve this coordinate's position. */ | |||
bool isRecursive (const NamedCoordinateFinder* nameFinder) const; | |||
bool isRecursive (const Expression::EvaluationContext* evaluationContext) const; | |||
/** Returns true if this coordinate depends on any other coordinates for its position. */ | |||
bool isDynamic() const; | |||
@@ -42945,62 +43082,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 NamedCoordinateFinder* nameFinder); | |||
/** Returns true if the coordinate is calculated as a proportion of the distance between two other points. | |||
@see toggleProportionality | |||
*/ | |||
bool isProportional() const throw() { return anchor2.isNotEmpty(); } | |||
/** Toggles the coordinate between using a proportional or absolute position. | |||
Note that calling this will reset the names of any anchor points, and just make the | |||
coordinate relative to the parent origin and parent size. | |||
*/ | |||
void toggleProportionality (const NamedCoordinateFinder* nameFinder, | |||
const String& proportionalAnchor1, const String& proportionalAnchor2); | |||
/** Returns a value that can be edited to set this coordinate's position. | |||
The meaning of this number depends on the coordinate's mode. If the coordinate is | |||
proportional, the number will be a percentage between 0 and 100. If the | |||
coordinate is absolute, then it will be the number of pixels from its anchor point. | |||
@see setEditableNumber | |||
*/ | |||
const double getEditableNumber() const; | |||
/** Sets the value that controls this coordinate's position. | |||
The meaning of this number depends on the coordinate's mode. If the coordinate is | |||
proportional, the number must be a percentage between 0 and 100. If the | |||
coordinate is absolute, then it indicates the number of pixels from its anchor point. | |||
@see setEditableNumber | |||
*/ | |||
void setEditableNumber (const double newValue); | |||
/** Returns the name of the first anchor point from which this coordinate is relative. | |||
*/ | |||
const String getAnchorName1 (const String& returnValueIfOrigin) const; | |||
/** Returns the name of the second anchor point from which this coordinate is relative. | |||
The second anchor is only valid if the coordinate is in proportional mode. | |||
*/ | |||
const String getAnchorName2 (const String& returnValueIfOrigin) const; | |||
/** Returns the first anchor point as a coordinate. */ | |||
const RelativeCoordinate getAnchorCoordinate1() const; | |||
/** Returns the first anchor point as a coordinate. | |||
The second anchor is only valid if the coordinate is in proportional mode. | |||
*/ | |||
const RelativeCoordinate getAnchorCoordinate2() const; | |||
/** Changes the first anchor point, keeping the resultant position of this coordinate in | |||
the same place it was previously. | |||
*/ | |||
void changeAnchor1 (const String& newAnchor, const NamedCoordinateFinder* nameFinder); | |||
/** Changes the second anchor point, keeping the resultant position of this coordinate in | |||
the same place it was previously. | |||
*/ | |||
void changeAnchor2 (const String& newAnchor, const NamedCoordinateFinder* nameFinder); | |||
void moveToAbsolute (double absoluteTargetPosition, const Expression::EvaluationContext* evaluationContext); | |||
/** Tells the coordinate that an object is changing its name or being deleted. | |||
@@ -43009,8 +43091,11 @@ public: | |||
this coordinate was using it, the coordinate is changed to be relative to the origin | |||
instead. | |||
*/ | |||
void renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const NamedCoordinateFinder* nameFinder); | |||
void renameSymbolIfUsed (const String& oldName, const String& newName, | |||
const Expression::EvaluationContext* evaluationContext); | |||
/** Returns the expression that defines this coordinate. */ | |||
const Expression& getExpression() const { return term; } | |||
/** Returns a string which represents this coordinate. | |||
For details of the string syntax, see the constructor notes. | |||
@@ -43039,11 +43124,10 @@ public: | |||
private: | |||
String anchor1, anchor2; | |||
double value; | |||
Expression term; | |||
double resolve (const NamedCoordinateFinder* nameFinder, int recursionCounter) const; | |||
static double resolveAnchor (const String& anchorName, const NamedCoordinateFinder* nameFinder, int recursionCounter); | |||
// double resolve (const Expression::EvaluationContext* evaluationContext, int recursionCounter) const; | |||
// static double resolveAnchor (const String& anchorName, const Expression::EvaluationContext* evaluationContext, int recursionCounter); | |||
}; | |||
/** | |||
@@ -43078,10 +43162,10 @@ public: | |||
/** Calculates the absolute position of this point. | |||
You'll need to provide a suitable NamedCoordinateFinder for looking up any coordinates that may | |||
You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may | |||
be needed to calculate the result. | |||
*/ | |||
const Point<float> resolve (const RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
const Point<float> resolve (const Expression::EvaluationContext* evaluationContext) const; | |||
/** Changes the values of this point's coordinates to make it resolve to the specified position. | |||
@@ -43089,7 +43173,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<float>& newPos, const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
void moveToAbsolute (const Point<float>& newPos, const Expression::EvaluationContext* evaluationContext); | |||
/** Returns a string which represents this point. | |||
This returns a comma-separated pair of coordinates. For details of the string syntax used by the | |||
@@ -43101,8 +43185,8 @@ public: | |||
/** Tells the point that an object is changing its name or being deleted. | |||
This calls RelativeCoordinate::renameAnchorIfUsed() on its X and Y coordinates. | |||
*/ | |||
void renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
void renameSymbolIfUsed (const String& oldName, const String& newName, | |||
const Expression::EvaluationContext* evaluationContext); | |||
/** Returns true if this point depends on any other coordinates for its position. */ | |||
bool isDynamic() const; | |||
@@ -43145,10 +43229,10 @@ public: | |||
/** Calculates the absolute position of this rectangle. | |||
You'll need to provide a suitable NamedCoordinateFinder for looking up any coordinates that may | |||
You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may | |||
be needed to calculate the result. | |||
*/ | |||
const Rectangle<float> resolve (const RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
const Rectangle<float> resolve (const Expression::EvaluationContext* evaluationContext) const; | |||
/** Changes the values of this rectangle's coordinates to make it resolve to the specified position. | |||
@@ -43156,7 +43240,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<float>& newPos, const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
void moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* evaluationContext); | |||
/** Returns a string which represents this point. | |||
This returns a comma-separated list of coordinates, in the order left, top, right, bottom. For details of | |||
@@ -43166,10 +43250,10 @@ public: | |||
const String toString() const; | |||
/** Tells the rectangle that an object is changing its name or being deleted. | |||
This calls RelativeCoordinate::renameAnchorIfUsed() on the rectangle's coordinates. | |||
This calls RelativeCoordinate::renameSymbolIfUsed() on the rectangle's coordinates. | |||
*/ | |||
void renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
void renameSymbolIfUsed (const String& oldName, const String& newName, | |||
const Expression::EvaluationContext* evaluationContext); | |||
// The actual rectangle coords... | |||
RelativeCoordinate left, right, top, bottom; | |||
@@ -43194,7 +43278,7 @@ public: | |||
~RelativePointPath(); | |||
/** Resolves this points in this path and adds them to a normal Path object. */ | |||
void createPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder); | |||
void createPath (Path& path, Expression::EvaluationContext* coordFinder); | |||
/** Returns true if the path contains any non-fixed points. */ | |||
bool containsAnyDynamicPoints() const; | |||
@@ -43226,7 +43310,7 @@ public: | |||
ElementBase (ElementType type); | |||
virtual ~ElementBase() {} | |||
virtual const ValueTree createTree() const = 0; | |||
virtual void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const = 0; | |||
virtual void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const = 0; | |||
virtual RelativePoint* getControlPoints (int& numPoints) = 0; | |||
const ElementType type; | |||
@@ -43242,7 +43326,7 @@ public: | |||
StartSubPath (const RelativePoint& pos); | |||
~StartSubPath() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
RelativePoint startPos; | |||
@@ -43258,7 +43342,7 @@ public: | |||
CloseSubPath(); | |||
~CloseSubPath() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
private: | |||
@@ -43272,7 +43356,7 @@ public: | |||
LineTo (const RelativePoint& endPoint); | |||
~LineTo() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
RelativePoint endPoint; | |||
@@ -43288,7 +43372,7 @@ public: | |||
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint); | |||
~QuadraticTo() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
RelativePoint controlPoints[2]; | |||
@@ -43304,7 +43388,7 @@ public: | |||
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint); | |||
~CubicTo() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
RelativePoint controlPoints[3]; | |||
@@ -43339,11 +43423,11 @@ public: | |||
RelativeParallelogram (const String& topLeft, const String& topRight, const String& bottomLeft); | |||
~RelativeParallelogram(); | |||
void resolveThreePoints (Point<float>* points, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void resolveFourCorners (Point<float>* points, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
const Rectangle<float> getBounds (RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void getPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
const AffineTransform resetToPerpendicular (RelativeCoordinate::NamedCoordinateFinder* coordFinder); | |||
void resolveThreePoints (Point<float>* points, Expression::EvaluationContext* coordFinder) const; | |||
void resolveFourCorners (Point<float>* points, Expression::EvaluationContext* coordFinder) const; | |||
const Rectangle<float> getBounds (Expression::EvaluationContext* coordFinder) const; | |||
void getPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
const AffineTransform resetToPerpendicular (Expression::EvaluationContext* coordFinder); | |||
bool operator== (const RelativeParallelogram& other) const throw(); | |||
bool operator!= (const RelativeParallelogram& other) const throw(); | |||
@@ -43566,7 +43650,7 @@ public: | |||
static const FillType readFillType (const ValueTree& v, RelativePoint* gradientPoint1, | |||
RelativePoint* gradientPoint2, RelativePoint* gradientPoint3, | |||
RelativeCoordinate::NamedCoordinateFinder* nameFinder, | |||
Expression::EvaluationContext* nameFinder, | |||
ImageProvider* imageProvider); | |||
static void writeFillType (ValueTree& v, const FillType& fillType, | |||
@@ -59069,7 +59153,7 @@ protected: | |||
@see Drawable | |||
*/ | |||
class JUCE_API DrawableComposite : public Drawable, | |||
public RelativeCoordinate::NamedCoordinateFinder | |||
public Expression::EvaluationContext | |||
{ | |||
public: | |||
@@ -59230,7 +59314,7 @@ public: | |||
/** @internal */ | |||
const Identifier getValueTreeType() const { return valueTreeType; } | |||
/** @internal */ | |||
const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const; | |||
const Expression getSymbolValue (const String& symbol) const; | |||
/** Internally-used class for wrapping a DrawableComposite's state into a ValueTree. */ | |||
class ValueTreeWrapper : public ValueTreeWrapperBase | |||
@@ -59506,14 +59590,14 @@ public: | |||
public: | |||
ValueTreeWrapper (const ValueTree& state); | |||
const FillType getMainFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder, | |||
const FillType getMainFill (Expression::EvaluationContext* nameFinder, | |||
ImageProvider* imageProvider) const; | |||
ValueTree getMainFillState(); | |||
void setMainFill (const FillType& newFill, const RelativePoint* gradientPoint1, | |||
const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3, | |||
ImageProvider* imageProvider, UndoManager* undoManager); | |||
const FillType getStrokeFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder, | |||
const FillType getStrokeFill (Expression::EvaluationContext* nameFinder, | |||
ImageProvider* imageProvider) const; | |||
ValueTree getStrokeFillState(); | |||
void setStrokeFill (const FillType& newFill, const RelativePoint* gradientPoint1, | |||
@@ -59540,7 +59624,7 @@ public: | |||
const RelativePoint getStartPoint() const; | |||
const RelativePoint getEndPoint() const; | |||
void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager); | |||
float getLength (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
float getLength (Expression::EvaluationContext* nameFinder) const; | |||
ValueTreeWrapper getParent() const; | |||
Element getPreviousElement() const; | |||
@@ -59549,11 +59633,11 @@ public: | |||
void setModeOfEndPoint (const String& newMode, UndoManager* undoManager); | |||
void convertToLine (UndoManager* undoManager); | |||
void convertToCubic (RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); | |||
void convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager); | |||
void convertToPathBreak (UndoManager* undoManager); | |||
ValueTree insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); | |||
ValueTree insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager); | |||
void removePoint (UndoManager* undoManager); | |||
float findProportionAlongLine (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
float findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder) const; | |||
static const Identifier mode, startSubPathElement, closeSubPathElement, | |||
lineToElement, quadraticToElement, cubicToElement; | |||
@@ -55,7 +55,7 @@ void AudioFormatReaderSource::setNextReadPosition (int newPosition) | |||
nextPlayPos = newPosition; | |||
} | |||
void AudioFormatReaderSource::setLooping (const bool shouldLoop) throw() | |||
void AudioFormatReaderSource::setLooping (bool shouldLoop) | |||
{ | |||
looping = shouldLoop; | |||
} | |||
@@ -63,7 +63,7 @@ public: | |||
@see isLooping | |||
*/ | |||
void setLooping (const bool shouldLoop) throw(); | |||
void setLooping (bool shouldLoop); | |||
/** Returns whether loop-mode is turned on or not. */ | |||
bool isLooping() const { return looping; } | |||
@@ -74,6 +74,15 @@ struct JUCE_API AudioSourceChannelInfo | |||
/** | |||
Base class for objects that can produce a continuous stream of audio. | |||
An AudioSource has two states: 'prepared' and 'unprepared'. | |||
When a source needs to be played, it is first put into a 'prepared' state by a call to | |||
prepareToPlay(), and then repeated calls will be made to its getNextAudioBlock() method to | |||
process the audio data. | |||
Once playback has finished, the releaseResources() method is called to put the stream | |||
back into an 'unprepared' state. | |||
@see AudioFormatReaderSource, ResamplingAudioSource | |||
*/ | |||
class JUCE_API AudioSource | |||
@@ -90,7 +99,14 @@ public: | |||
//============================================================================== | |||
/** Tells the source to prepare for playing. | |||
The source can use this opportunity to initialise anything it needs to. | |||
An AudioSource has two states: prepared and unprepared. | |||
The prepareToPlay() method is guaranteed to be called at least once on an 'unpreprared' | |||
source to put it into a 'prepared' state before any calls will be made to getNextAudioBlock(). | |||
This callback allows the source to initialise any resources it might need when playing. | |||
Once playback has finished, the releaseResources() method is called to put the stream | |||
back into an 'unprepared' state. | |||
Note that this method could be called more than once in succession without | |||
a matching call to releaseResources(), so make sure your code is robust and | |||
@@ -72,6 +72,9 @@ public: | |||
/** Returns true if this source is actually playing in a loop. */ | |||
virtual bool isLooping() const = 0; | |||
/** Tells the source whether you'd like it to play in a loop. */ | |||
virtual void setLooping (bool shouldLoop) { (void) shouldLoop; } | |||
}; | |||
@@ -0,0 +1,949 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
Copyright 2004-10 by Raw Material Software Ltd. | |||
------------------------------------------------------------------------------ | |||
JUCE can be redistributed and/or modified under the terms of the GNU General | |||
Public License (Version 2), as published by the Free Software Foundation. | |||
A copy of the license is included in the JUCE distribution, or can be found | |||
online at www.gnu.org/licenses. | |||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
------------------------------------------------------------------------------ | |||
To release a closed-source product which uses JUCE, commercial licenses are | |||
available: visit www.rawmaterialsoftware.com/juce for more information. | |||
============================================================================== | |||
*/ | |||
#include "../core/juce_StandardHeader.h" | |||
BEGIN_JUCE_NAMESPACE | |||
#include "juce_Expression.h" | |||
#include "juce_ReferenceCountedArray.h" | |||
//============================================================================== | |||
class Expression::Helpers | |||
{ | |||
public: | |||
//============================================================================== | |||
class Constant : public Term | |||
{ | |||
public: | |||
Constant (const double value_) : value (value_), isResolutionTarget (false) {} | |||
Term* clone() const { return new Constant (value); } | |||
double evaluate (const EvaluationContext&, int) const { return value; } | |||
int getNumInputs() const { return 0; } | |||
Term* getInput (int) const { return 0; } | |||
const String toString() const | |||
{ | |||
if (isResolutionTarget) | |||
return "@" + String (value); | |||
return String (value); | |||
} | |||
double value; | |||
bool isResolutionTarget; | |||
}; | |||
//============================================================================== | |||
class Symbol : public Term | |||
{ | |||
public: | |||
Symbol (const String& symbol_) : symbol (symbol_) {} | |||
double evaluate (const EvaluationContext& c, int recursionDepth) const | |||
{ | |||
if (++recursionDepth > 256) | |||
throw EvaluationError ("Recursive symbol references"); | |||
return c.getSymbolValue (symbol).term->evaluate (c, recursionDepth); | |||
} | |||
Term* clone() const { return new Symbol (symbol); } | |||
int getNumInputs() const { return 0; } | |||
Term* getInput (int) const { return 0; } | |||
const String toString() const { return symbol; } | |||
bool referencesSymbol (const String& s, const EvaluationContext& c, int recursionDepth) const | |||
{ | |||
if (s == symbol) | |||
return true; | |||
if (++recursionDepth > 256) | |||
throw EvaluationError ("Recursive symbol references"); | |||
return c.getSymbolValue (symbol).term->referencesSymbol (s, c, recursionDepth); | |||
} | |||
String symbol; | |||
}; | |||
//============================================================================== | |||
class Function : public Term | |||
{ | |||
public: | |||
Function (const String& functionName_, const ReferenceCountedArray<Term>& parameters_) | |||
: functionName (functionName_), parameters (parameters_) | |||
{} | |||
Term* clone() const { return new Function (functionName, parameters); } | |||
double evaluate (const EvaluationContext& c, int recursionDepth) const | |||
{ | |||
HeapBlock <double> params (parameters.size()); | |||
for (int i = 0; i < parameters.size(); ++i) | |||
params[i] = parameters.getUnchecked(i)->evaluate (c, recursionDepth); | |||
return c.evaluateFunction (functionName, params, parameters.size()); | |||
} | |||
int getInputIndexFor (const Term* possibleInput) const { return parameters.indexOf (possibleInput); } | |||
int getNumInputs() const { return parameters.size(); } | |||
Term* getInput (int i) const { return parameters [i]; } | |||
bool referencesSymbol (const String& s, const EvaluationContext& c, int recursionDepth) const | |||
{ | |||
for (int i = 0; i < parameters.size(); ++i) | |||
if (parameters.getUnchecked(i)->referencesSymbol (s, c, recursionDepth)) | |||
return true; | |||
return false; | |||
} | |||
const String toString() const | |||
{ | |||
if (parameters.size() == 0) | |||
return functionName + "()"; | |||
String s (functionName + " ("); | |||
for (int i = 0; i < parameters.size(); ++i) | |||
{ | |||
s << parameters.getUnchecked(i)->toString(); | |||
if (i < parameters.size() - 1) | |||
s << ", "; | |||
} | |||
s << ')'; | |||
return s; | |||
} | |||
const String functionName; | |||
ReferenceCountedArray<Term> parameters; | |||
}; | |||
//============================================================================== | |||
class Negate : public Term | |||
{ | |||
public: | |||
Negate (Term* const input_) : input (input_) | |||
{ | |||
jassert (input_ != 0); | |||
} | |||
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<Term*> (input) : 0; } | |||
Term* clone() const { return new Negate (input->clone()); } | |||
double evaluate (const EvaluationContext& c, int recursionDepth) const { return -input->evaluate (c, recursionDepth); } | |||
const ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const EvaluationContext&, Term* input_, double overallTarget, Term* topLevelTerm) const | |||
{ | |||
jassert (input_ == input); | |||
const Term* const dest = findDestinationFor (topLevelTerm, this); | |||
Term* newDest; | |||
if (dest == 0) | |||
newDest = new Constant (overallTarget); | |||
else | |||
newDest = dest->clone(); | |||
return new Negate (newDest); | |||
} | |||
const String toString() const | |||
{ | |||
if (input->getOperatorPrecedence() > 0) | |||
return "-(" + input->toString() + ")"; | |||
else | |||
return "-" + input->toString(); | |||
} | |||
bool referencesSymbol (const String& s, const EvaluationContext& c, int recursionDepth) const | |||
{ | |||
return input->referencesSymbol (s, c, recursionDepth); | |||
} | |||
private: | |||
const ReferenceCountedObjectPtr<Term> input; | |||
}; | |||
//============================================================================== | |||
class BinaryTerm : public Term | |||
{ | |||
public: | |||
BinaryTerm (Term* const left_, Term* const right_) : left (left_), right (right_) | |||
{ | |||
jassert (left_ != 0 && right_ != 0); | |||
} | |||
int getInputIndexFor (const Term* possibleInput) const | |||
{ | |||
return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1); | |||
} | |||
int getNumInputs() const { return 2; } | |||
Term* getInput (int index) const { return index == 0 ? static_cast<Term*> (left) : (index == 1 ? static_cast<Term*> (right) : 0); } | |||
bool referencesSymbol (const String& s, const EvaluationContext& c, int recursionDepth) const | |||
{ | |||
return left->referencesSymbol (s, c, recursionDepth) | |||
|| right->referencesSymbol (s, c, recursionDepth); | |||
} | |||
protected: | |||
const ReferenceCountedObjectPtr<Term> left, right; | |||
const String createString (const String& op) const | |||
{ | |||
String s; | |||
const int ourPrecendence = getOperatorPrecedence(); | |||
if (left->getOperatorPrecedence() > ourPrecendence) | |||
s << '(' << left->toString() << ')'; | |||
else | |||
s = left->toString(); | |||
s << ' ' << op << ' '; | |||
if (right->getOperatorPrecedence() >= ourPrecendence) | |||
s << '(' << right->toString() << ')'; | |||
else | |||
s << right->toString(); | |||
return s; | |||
} | |||
Term* createDestinationTerm (const EvaluationContext&, 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); | |||
return dest->clone(); | |||
} | |||
}; | |||
//============================================================================== | |||
class Add : public BinaryTerm | |||
{ | |||
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); } | |||
const String toString() const { return createString ("+"); } | |||
int getOperatorPrecedence() const { return 2; } | |||
const ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const EvaluationContext& c, Term* input, double overallTarget, Term* topLevelTerm) const | |||
{ | |||
Term* const newDest = createDestinationTerm (c, input, overallTarget, topLevelTerm); | |||
if (newDest == 0) | |||
return 0; | |||
return new Subtract (newDest, (input == left ? right : left)->clone()); | |||
} | |||
}; | |||
//============================================================================== | |||
class Subtract : public BinaryTerm | |||
{ | |||
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); } | |||
const String toString() const { return createString ("-"); } | |||
int getOperatorPrecedence() const { return 2; } | |||
const ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const EvaluationContext& c, Term* input, double overallTarget, Term* topLevelTerm) const | |||
{ | |||
Term* const newDest = createDestinationTerm (c, input, overallTarget, topLevelTerm); | |||
if (newDest == 0) | |||
return 0; | |||
if (input == left) | |||
return new Add (newDest, right->clone()); | |||
else | |||
return new Subtract (left->clone(), newDest); | |||
} | |||
}; | |||
//============================================================================== | |||
class Multiply : public BinaryTerm | |||
{ | |||
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 toString() const { return createString ("*"); } | |||
int getOperatorPrecedence() const { return 1; } | |||
const ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const EvaluationContext& c, Term* input, double overallTarget, Term* topLevelTerm) const | |||
{ | |||
Term* const newDest = createDestinationTerm (c, input, overallTarget, topLevelTerm); | |||
if (newDest == 0) | |||
return 0; | |||
return new Divide (newDest, (input == left ? right : left)->clone()); | |||
} | |||
}; | |||
//============================================================================== | |||
class Divide : public BinaryTerm | |||
{ | |||
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 toString() const { return createString ("/"); } | |||
int getOperatorPrecedence() const { return 1; } | |||
const ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const EvaluationContext& c, Term* input, double overallTarget, Term* topLevelTerm) const | |||
{ | |||
Term* const newDest = createDestinationTerm (c, input, overallTarget, topLevelTerm); | |||
if (newDest == 0) | |||
return 0; | |||
if (input == left) | |||
return new Multiply (newDest, right->clone()); | |||
else | |||
return new Divide (left->clone(), newDest); | |||
} | |||
}; | |||
//============================================================================== | |||
static Term* findDestinationFor (Term* const topLevel, const Term* const inputTerm) | |||
{ | |||
const int inputIndex = topLevel->getInputIndexFor (inputTerm); | |||
if (inputIndex >= 0) | |||
return topLevel; | |||
for (int i = topLevel->getNumInputs(); --i >= 0;) | |||
{ | |||
Term* t = findDestinationFor (topLevel->getInput (i), inputTerm); | |||
if (t != 0) | |||
return t; | |||
} | |||
return 0; | |||
} | |||
static Constant* findTermToAdjust (Term* const term, const bool mustBeFlagged) | |||
{ | |||
Constant* c = dynamic_cast<Constant*> (term); | |||
if (c != 0 && (c->isResolutionTarget || ! mustBeFlagged)) | |||
return c; | |||
int i; | |||
for (i = term->getNumInputs(); --i >= 0;) | |||
{ | |||
Constant* c = dynamic_cast<Constant*> (term->getInput (i)); | |||
if (c != 0 && (c->isResolutionTarget || ! mustBeFlagged)) | |||
return c; | |||
} | |||
for (i = term->getNumInputs(); --i >= 0;) | |||
{ | |||
Constant* c = findTermToAdjust (term->getInput (i), mustBeFlagged); | |||
if (c != 0) | |||
return c; | |||
} | |||
return 0; | |||
} | |||
static bool containsAnySymbols (const Term* const t) | |||
{ | |||
if (dynamic_cast <const Symbol*> (t) != 0) | |||
return true; | |||
for (int i = t->getNumInputs(); --i >= 0;) | |||
if (containsAnySymbols (t->getInput (i))) | |||
return true; | |||
return false; | |||
} | |||
static bool renameSymbol (Term* const t, const String& oldName, const String& newName) | |||
{ | |||
Symbol* sym = dynamic_cast <Symbol*> (t); | |||
if (sym != 0) | |||
{ | |||
if (sym->symbol == oldName) | |||
{ | |||
sym->symbol = newName; | |||
return true; | |||
} | |||
else if (sym->symbol.startsWith (oldName + ".")) | |||
{ | |||
sym->symbol = newName + "." + sym->symbol.substring (0, oldName.length() + 1); | |||
return true; | |||
} | |||
} | |||
bool anyChanged = false; | |||
for (int i = t->getNumInputs(); --i >= 0;) | |||
if (renameSymbol (t->getInput (i), oldName, newName)) | |||
anyChanged = true; | |||
return anyChanged; | |||
} | |||
//============================================================================== | |||
class Parser | |||
{ | |||
public: | |||
//============================================================================== | |||
Parser (const String& stringToParse, int& textIndex_) | |||
: textString (stringToParse), textIndex (textIndex_) | |||
{ | |||
text = textString; | |||
} | |||
Term* readExpression() | |||
{ | |||
ScopedPointer<Term> lhs (readMultiplyOrDivideExpression()); | |||
char opType; | |||
while (lhs != 0 && readOperator ("+-", &opType)) | |||
{ | |||
Term* rhs = readMultiplyOrDivideExpression(); | |||
if (rhs == 0) | |||
throw ParseError ("Expected expression after \"" + String::charToString (opType) + "\""); | |||
if (opType == '+') | |||
lhs = new Add (lhs.release(), rhs); | |||
else | |||
lhs = new Subtract (lhs.release(), rhs); | |||
} | |||
return lhs.release(); | |||
} | |||
private: | |||
const String textString; | |||
const juce_wchar* text; | |||
int& textIndex; | |||
//============================================================================== | |||
static inline bool isDecimalDigit (const juce_wchar c) throw() | |||
{ | |||
return c >= '0' && c <= '9'; | |||
} | |||
void skipWhitespace (int& i) | |||
{ | |||
while (CharacterFunctions::isWhitespace (text [i])) | |||
++i; | |||
} | |||
bool readChar (const juce_wchar required) | |||
{ | |||
if (text[textIndex] == required) | |||
{ | |||
++textIndex; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool readOperator (const char* ops, char* const opType = 0) | |||
{ | |||
skipWhitespace (textIndex); | |||
while (*ops != 0) | |||
{ | |||
if (readChar (*ops)) | |||
{ | |||
if (opType != 0) | |||
*opType = *ops; | |||
return true; | |||
} | |||
++ops; | |||
} | |||
return false; | |||
} | |||
bool readIdentifier (String& identifier) | |||
{ | |||
skipWhitespace (textIndex); | |||
int i = textIndex; | |||
if (CharacterFunctions::isLetter (text[i]) || text[i] == '_') | |||
{ | |||
++i; | |||
while (CharacterFunctions::isLetterOrDigit (text[i]) || text[i] == '_' || text[i] == '.') | |||
++i; | |||
} | |||
if (i > textIndex) | |||
{ | |||
identifier = String (text + textIndex, i - textIndex); | |||
textIndex = i; | |||
return true; | |||
} | |||
return false; | |||
} | |||
Term* readNumber() | |||
{ | |||
skipWhitespace (textIndex); | |||
int i = textIndex; | |||
const bool isResolutionTarget = (text[i] == '@'); | |||
if (isResolutionTarget) | |||
{ | |||
++i; | |||
skipWhitespace (i); | |||
} | |||
int numDigits = 0; | |||
while (isDecimalDigit (text[i])) | |||
{ | |||
++i; | |||
++numDigits; | |||
} | |||
const bool hasPoint = (text[i] == '.'); | |||
if (hasPoint) | |||
{ | |||
++i; | |||
while (isDecimalDigit (text[i])) | |||
{ | |||
++i; | |||
++numDigits; | |||
} | |||
} | |||
if (numDigits == 0) | |||
return 0; | |||
juce_wchar c = text[i]; | |||
const bool hasExponent = (c == 'e' || c == 'E'); | |||
if (hasExponent) | |||
{ | |||
++i; | |||
c = text[i]; | |||
if (c == '+' || c == '-') | |||
++i; | |||
int numExpDigits = 0; | |||
while (isDecimalDigit (text[i])) | |||
{ | |||
++i; | |||
++numExpDigits; | |||
} | |||
if (numExpDigits == 0) | |||
return 0; | |||
} | |||
Constant* t = new Constant (String (text + textIndex, i - textIndex).getDoubleValue()); | |||
t->isResolutionTarget = isResolutionTarget; | |||
textIndex = i; | |||
return t; | |||
} | |||
Term* readMultiplyOrDivideExpression() | |||
{ | |||
ScopedPointer<Term> lhs (readUnaryExpression()); | |||
char opType; | |||
while (lhs != 0 && readOperator ("*/", &opType)) | |||
{ | |||
Term* rhs = readUnaryExpression(); | |||
if (rhs == 0) | |||
throw ParseError ("Expected expression after \"" + String::charToString (opType) + "\""); | |||
if (opType == '*') | |||
lhs = new Multiply (lhs.release(), rhs); | |||
else | |||
lhs = new Divide (lhs.release(), rhs); | |||
} | |||
return lhs.release(); | |||
} | |||
Term* readUnaryExpression() | |||
{ | |||
char opType; | |||
if (readOperator ("+-", &opType)) | |||
{ | |||
Term* term = readUnaryExpression(); | |||
if (term == 0) | |||
throw ParseError ("Expected expression after \"" + String::charToString (opType) + "\""); | |||
if (opType == '-') | |||
term = new Negate (term); | |||
return term; | |||
} | |||
return readPrimaryExpression(); | |||
} | |||
Term* readPrimaryExpression() | |||
{ | |||
Term* e = readParenthesisedExpression(); | |||
if (e != 0) | |||
return e; | |||
e = readNumber(); | |||
if (e != 0) | |||
return e; | |||
String identifier; | |||
if (readIdentifier (identifier)) | |||
{ | |||
if (readOperator ("(")) // method call... | |||
{ | |||
Function* f = new Function (identifier, ReferenceCountedArray<Term>()); | |||
ScopedPointer<Term> func (f); // (can't use ScopedPointer<Function> in MSVC) | |||
Term* param = readExpression(); | |||
if (param == 0) | |||
{ | |||
if (readOperator (")")) | |||
return func.release(); | |||
throw ParseError ("Expected parameters after \"" + identifier + " (\""); | |||
} | |||
f->parameters.add (param); | |||
while (readOperator (",")) | |||
{ | |||
param = readExpression(); | |||
if (param == 0) | |||
throw ParseError ("Expected expression after \",\""); | |||
f->parameters.add (param); | |||
} | |||
if (readOperator (")")) | |||
return func.release(); | |||
throw ParseError ("Expected \")\""); | |||
} | |||
else // just a symbol.. | |||
{ | |||
return new Symbol (identifier); | |||
} | |||
} | |||
return 0; | |||
} | |||
Term* readParenthesisedExpression() | |||
{ | |||
if (! readOperator ("(")) | |||
return 0; | |||
ScopedPointer<Term> e (readExpression()); | |||
if (e == 0) | |||
return 0; | |||
if (! readOperator (")")) | |||
e = 0; | |||
return e.release(); | |||
} | |||
Parser (const Parser&); | |||
Parser& operator= (const Parser&); | |||
}; | |||
}; | |||
//============================================================================== | |||
Expression::Expression() | |||
: term (new Expression::Helpers::Constant (0)) | |||
{ | |||
} | |||
Expression::~Expression() | |||
{ | |||
} | |||
Expression::Expression (Term* const term_) | |||
: term (term_) | |||
{ | |||
jassert (term != 0); | |||
} | |||
Expression::Expression (const double constant) | |||
: term (new Expression::Helpers::Constant (constant)) | |||
{ | |||
} | |||
Expression::Expression (const Expression& other) | |||
: term (other.term) | |||
{ | |||
} | |||
Expression& Expression::operator= (const Expression& other) | |||
{ | |||
term = other.term; | |||
return *this; | |||
} | |||
Expression::Expression (const String& stringToParse) | |||
{ | |||
int i = 0; | |||
Helpers::Parser parser (stringToParse, i); | |||
term = parser.readExpression(); | |||
if (term == 0) | |||
term = new Helpers::Constant (0); | |||
} | |||
const Expression Expression::parse (const String& stringToParse, int& textIndexToStartFrom) | |||
{ | |||
Helpers::Parser parser (stringToParse, textIndexToStartFrom); | |||
Term* term = parser.readExpression(); | |||
if (term != 0) | |||
return Expression (term); | |||
return Expression(); | |||
} | |||
double Expression::evaluate() const | |||
{ | |||
return evaluate (Expression::EvaluationContext()); | |||
} | |||
double Expression::evaluate (const Expression::EvaluationContext& context) const | |||
{ | |||
return term->evaluate (context, 0); | |||
} | |||
const Expression Expression::operator+ (const Expression& other) const | |||
{ | |||
return Expression (new Helpers::Add (term, other.term)); | |||
} | |||
const Expression Expression::operator- (const Expression& other) const | |||
{ | |||
return Expression (new Helpers::Subtract (term, other.term)); | |||
} | |||
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 (new Helpers::Negate (term)); | |||
} | |||
const String Expression::toString() const | |||
{ | |||
return term->toString(); | |||
} | |||
const Expression Expression::symbol (const String& symbol) | |||
{ | |||
return Expression (new Helpers::Symbol (symbol)); | |||
} | |||
const Expression Expression::function (const String& functionName, const Array<Expression>& parameters) | |||
{ | |||
ReferenceCountedArray<Term> params; | |||
for (int i = 0; i < parameters.size(); ++i) | |||
params.add (parameters.getReference(i).term); | |||
return Expression (new Helpers::Function (functionName, params)); | |||
} | |||
const Expression Expression::adjustedToGiveNewResult (const double targetValue, | |||
const Expression::EvaluationContext& context) const | |||
{ | |||
ScopedPointer<Term> newTerm (term->clone()); | |||
Helpers::Constant* termToAdjust = Helpers::findTermToAdjust (newTerm, true); | |||
if (termToAdjust == 0) | |||
termToAdjust = Helpers::findTermToAdjust (newTerm, false); | |||
if (termToAdjust == 0) | |||
{ | |||
newTerm = new Helpers::Add (newTerm.release(), new Helpers::Constant (0)); | |||
termToAdjust = Helpers::findTermToAdjust (newTerm, false); | |||
} | |||
jassert (termToAdjust != 0); | |||
const Term* parent = Helpers::findDestinationFor (newTerm, termToAdjust); | |||
if (parent == 0) | |||
{ | |||
termToAdjust->value = targetValue; | |||
} | |||
else | |||
{ | |||
const ReferenceCountedObjectPtr<Term> reverseTerm (parent->createTermToEvaluateInput (context, termToAdjust, targetValue, newTerm)); | |||
if (reverseTerm == 0) | |||
return Expression(); | |||
termToAdjust->value = reverseTerm->evaluate (context, 0); | |||
} | |||
return Expression (newTerm.release()); | |||
} | |||
const Expression Expression::withRenamedSymbol (const String& oldSymbol, const String& newSymbol) const | |||
{ | |||
jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
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); | |||
} | |||
//============================================================================== | |||
int Expression::Term::getOperatorPrecedence() const | |||
{ | |||
return 0; | |||
} | |||
bool Expression::Term::referencesSymbol (const String&, const EvaluationContext&, int) const | |||
{ | |||
return false; | |||
} | |||
int Expression::Term::getInputIndexFor (const Term*) const | |||
{ | |||
return -1; | |||
} | |||
const ReferenceCountedObjectPtr<Expression::Term> Expression::Term::createTermToEvaluateInput (const EvaluationContext&, Term*, double, Term*) const | |||
{ | |||
jassertfalse; | |||
return 0; | |||
} | |||
//============================================================================== | |||
Expression::ParseError::ParseError (const String& message) | |||
: description (message) | |||
{ | |||
} | |||
Expression::EvaluationError::EvaluationError (const String& message) | |||
: description (message) | |||
{ | |||
} | |||
//============================================================================== | |||
Expression::EvaluationContext::EvaluationContext() {} | |||
Expression::EvaluationContext::~EvaluationContext() {} | |||
const Expression Expression::EvaluationContext::getSymbolValue (const String& symbol) const | |||
{ | |||
throw EvaluationError ("Unknown symbol: \"" + symbol + "\""); | |||
} | |||
double Expression::EvaluationContext::evaluateFunction (const String& functionName, const double* parameters, int numParams) const | |||
{ | |||
if (numParams > 0) | |||
{ | |||
if (functionName == "min") | |||
{ | |||
double v = parameters[0]; | |||
for (int i = 1; i < numParams; ++i) | |||
v = jmin (v, parameters[i]); | |||
return v; | |||
} | |||
else if (functionName == "max") | |||
{ | |||
double v = parameters[0]; | |||
for (int i = 1; i < numParams; ++i) | |||
v = jmax (v, parameters[i]); | |||
return v; | |||
} | |||
else if (numParams == 1) | |||
{ | |||
if (functionName == "sin") | |||
return sin (parameters[0]); | |||
else if (functionName == "cos") | |||
return cos (parameters[0]); | |||
else if (functionName == "tan") | |||
return tan (parameters[0]); | |||
else if (functionName == "abs") | |||
return std::abs (parameters[0]); | |||
} | |||
} | |||
throw EvaluationError ("Unknown function: \"" + functionName + "\""); | |||
} | |||
END_JUCE_NAMESPACE |
@@ -0,0 +1,216 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
Copyright 2004-10 by Raw Material Software Ltd. | |||
------------------------------------------------------------------------------ | |||
JUCE can be redistributed and/or modified under the terms of the GNU General | |||
Public License (Version 2), as published by the Free Software Foundation. | |||
A copy of the license is included in the JUCE distribution, or can be found | |||
online at www.gnu.org/licenses. | |||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
------------------------------------------------------------------------------ | |||
To release a closed-source product which uses JUCE, commercial licenses are | |||
available: visit www.rawmaterialsoftware.com/juce for more information. | |||
============================================================================== | |||
*/ | |||
#ifndef __JUCE_EXPRESSION_JUCEHEADER__ | |||
#define __JUCE_EXPRESSION_JUCEHEADER__ | |||
#include "juce_ReferenceCountedObject.h" | |||
#include "juce_Array.h" | |||
#include "juce_ScopedPointer.h" | |||
//============================================================================== | |||
/** | |||
A class for dynamically evaluating simple numeric expressions. | |||
This class can parse a simple C-style string expression involving floating point | |||
numbers, named symbols and functions. The basic arithmetic operations of +, -, *, / | |||
are supported, as well as parentheses, and any alphanumeric identifiers are | |||
assumed to be named symbols which will be resolved when the expression is | |||
evaluated. | |||
Expressions which use identifiers and functions require a subclass of | |||
Expression::EvaluationContext 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. | |||
*/ | |||
class JUCE_API Expression | |||
{ | |||
public: | |||
//============================================================================== | |||
/** Creates a simple expression with a value of 0. */ | |||
Expression(); | |||
/** Destructor. */ | |||
~Expression(); | |||
/** Creates a simple expression with a specified constant value. */ | |||
explicit Expression (const double constant); | |||
/** Creates a copy of an expression. */ | |||
Expression (const Expression& other); | |||
/** Copies another expression. */ | |||
Expression& operator= (const Expression& other); | |||
/** Creates an expression by parsing a string. | |||
If there's a syntax error in the string, this will throw a ParseError exception. | |||
@throws ParseError | |||
*/ | |||
explicit Expression (const String& stringToParse); | |||
/** Returns a string version of the expression. */ | |||
const String toString() const; | |||
/** Returns an expression which is an addtion operation of two existing expressions. */ | |||
const Expression operator+ (const Expression& other) const; | |||
/** Returns an expression which is a subtraction operation of two existing expressions. */ | |||
const Expression operator- (const Expression& other) const; | |||
/** Returns an expression which is a multiplication operation of two existing expressions. */ | |||
const Expression operator* (const Expression& other) const; | |||
/** Returns an expression which is a division operation of two existing expressions. */ | |||
const Expression operator/ (const Expression& other) const; | |||
/** Returns an expression which is a negation operation of two existing expressions. */ | |||
const Expression operator-() const; | |||
/** Returns an Expression which is an identifier reference. */ | |||
static const Expression symbol (const String& symbol); | |||
/** Returns an Expression which is a function call. */ | |||
static const Expression function (const String& functionName, const Array<Expression>& parameters); | |||
/** Returns an Expression which parses a string from a specified character index. | |||
The index value is incremented so that on return, it indicates the character that follows | |||
the end of the expression that was parsed. | |||
If there's a syntax error in the string, this will throw a ParseError exception. | |||
@throws ParseError | |||
*/ | |||
static const Expression parse (const String& stringToParse, int& textIndexToStartFrom); | |||
//============================================================================== | |||
/** When evaluating an Expression object, this class is used to resolve symbols and | |||
perform functions that the expression uses. | |||
*/ | |||
class EvaluationContext | |||
{ | |||
public: | |||
EvaluationContext(); | |||
virtual ~EvaluationContext(); | |||
/** Returns the value of a symbol. | |||
If the symbol is unknown, this can throw an Expression::EvaluationError exception. | |||
@throws Expression::EvaluationError | |||
*/ | |||
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; | |||
}; | |||
/** Evaluates this expression, without using an EvaluationContext. | |||
Without an EvaluationContext, no symbols can be used, and only basic functions such as sin, cos, tan, | |||
min, max are available. | |||
*/ | |||
double evaluate() const; | |||
/** Evaluates this expression, providing a context that should be able to evaluate any symbols | |||
or functions that it uses. | |||
*/ | |||
double evaluate (const EvaluationContext& context) 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. | |||
*/ | |||
const Expression adjustedToGiveNewResult (double targetValue, const EvaluationContext& context) const; | |||
/** 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; | |||
/** Returns true if this expression makes use of the specified symbol. | |||
If a suitable context 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. | |||
*/ | |||
bool referencesSymbol (const String& symbol, const EvaluationContext& context) const; | |||
/** Returns true if this expression contains any symbols. */ | |||
bool usesAnySymbols() const; | |||
//============================================================================== | |||
/** An exception that can be thrown by Expression::parse(). */ | |||
class ParseError : public std::exception | |||
{ | |||
public: | |||
ParseError (const String& message); | |||
String description; | |||
}; | |||
//============================================================================== | |||
/** An exception that can be thrown by Expression::evaluate(). */ | |||
class EvaluationError : public std::exception | |||
{ | |||
public: | |||
EvaluationError (const String& message); | |||
String description; | |||
}; | |||
//============================================================================== | |||
juce_UseDebuggingNewOperator | |||
private: | |||
class Helpers; | |||
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<Term> createTermToEvaluateInput (const EvaluationContext&, Term* inputTerm, | |||
double overallTarget, Term* topLevelTerm) const; | |||
juce_UseDebuggingNewOperator | |||
private: | |||
Term (const Term& other); | |||
Term& operator= (const Term&); | |||
}; | |||
friend class ScopedPointer<Term>; | |||
ReferenceCountedObjectPtr<Term> term; | |||
explicit Expression (Term* term); | |||
}; | |||
#endif // __JUCE_EXPRESSION_JUCEHEADER__ |
@@ -68,7 +68,7 @@ | |||
@see Logger::outputDebugString | |||
*/ | |||
#define DBG(dbgtext) { String tempDbgBuf; tempDbgBuf << dbgtext; JUCE_NAMESPACE::Logger::outputDebugString (tempDbgBuf); } | |||
#define DBG(dbgtext) { JUCE_NAMESPACE::String tempDbgBuf; tempDbgBuf << dbgtext; JUCE_NAMESPACE::Logger::outputDebugString (tempDbgBuf); } | |||
//============================================================================== | |||
// Assertions.. | |||
@@ -33,7 +33,7 @@ | |||
*/ | |||
#define JUCE_MAJOR_VERSION 1 | |||
#define JUCE_MINOR_VERSION 52 | |||
#define JUCE_BUILDNUMBER 49 | |||
#define JUCE_BUILDNUMBER 50 | |||
/** Current Juce version number. | |||
@@ -97,7 +97,8 @@ public: | |||
@param newItemText the text of the item to show in the list | |||
@param newItemId an associated ID number that can be set or retrieved - see | |||
getSelectedId() and setSelectedId() | |||
getSelectedId() and setSelectedId(). Note that this value can not | |||
be 0! | |||
@see setItemEnabled, addSeparator, addSectionHeading, removeItem, getNumItems, getItemText, getItemId | |||
*/ | |||
void addItem (const String& newItemText, | |||
@@ -94,6 +94,7 @@ public: | |||
row = newRow; | |||
isSelected = isNowSelected; | |||
repaint(); | |||
deleteAllChildren(); | |||
} | |||
if (row < owner.getNumRows()) | |||
@@ -105,13 +106,12 @@ public: | |||
const TableHeaderComponent* const header = owner.getHeader(); | |||
const int numColumns = header->getNumColumns (true); | |||
int i; | |||
columnsWithComponents.clear(); | |||
if (owner.getModel() != 0) | |||
{ | |||
for (i = 0; i < numColumns; ++i) | |||
for (int i = 0; i < numColumns; ++i) | |||
{ | |||
const int columnId = header->getColumnIdOfIndex (i, true); | |||
@@ -133,7 +133,7 @@ public: | |||
} | |||
} | |||
for (i = getNumChildComponents(); --i >= 0;) | |||
for (int i = getNumChildComponents(); --i >= 0;) | |||
{ | |||
Component* const c = getChildComponent (i); | |||
@@ -30,6 +30,7 @@ BEGIN_JUCE_NAMESPACE | |||
#include "juce_CallOutBox.h" | |||
#include "juce_ComponentPeer.h" | |||
#include "../lookandfeel/juce_LookAndFeel.h" | |||
#include "../../../application/juce_Application.h" | |||
//============================================================================== | |||
@@ -50,6 +51,9 @@ CallOutBox::CallOutBox (Component& contentComponent, | |||
} | |||
else | |||
{ | |||
if (! JUCEApplication::isStandaloneApp()) | |||
setAlwaysOnTop (true); // for a plugin, make it always-on-top because the host windows are often top-level | |||
updatePosition (componentToPointTo.getScreenBounds(), | |||
componentToPointTo.getParentMonitorArea()); | |||
@@ -199,7 +199,7 @@ void Drawable::ValueTreeWrapperBase::setID (const String& newID, UndoManager* co | |||
} | |||
const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v, RelativePoint* const gp1, RelativePoint* const gp2, RelativePoint* const gp3, | |||
RelativeCoordinate::NamedCoordinateFinder* const nameFinder, ImageProvider* imageProvider) | |||
Expression::EvaluationContext* const nameFinder, ImageProvider* imageProvider) | |||
{ | |||
const String newType (v[type].toString()); | |||
@@ -250,7 +250,7 @@ public: | |||
static const FillType readFillType (const ValueTree& v, RelativePoint* gradientPoint1, | |||
RelativePoint* gradientPoint2, RelativePoint* gradientPoint3, | |||
RelativeCoordinate::NamedCoordinateFinder* nameFinder, | |||
Expression::EvaluationContext* nameFinder, | |||
ImageProvider* imageProvider); | |||
static void writeFillType (ValueTree& v, const FillType& fillType, | |||
@@ -247,33 +247,26 @@ void DrawableComposite::render (const Drawable::RenderingContext& context) const | |||
} | |||
} | |||
const RelativeCoordinate DrawableComposite::findNamedCoordinate (const String& objectName, const String& edge) const | |||
const Expression DrawableComposite::getSymbolValue (const String& symbol) const | |||
{ | |||
if (objectName == RelativeCoordinate::Strings::parent) | |||
{ | |||
if (edge == RelativeCoordinate::Strings::right || edge == RelativeCoordinate::Strings::bottom) | |||
{ | |||
jassertfalse; // a Drawable doesn't have a fixed right-hand or bottom edge - use a marker instead if you need a point of reference. | |||
return RelativeCoordinate (100.0); | |||
} | |||
} | |||
jassert (! symbol.containsChar ('.')) // the only symbols available in a Drawable are markers. | |||
int i; | |||
for (i = 0; i < markersX.size(); ++i) | |||
{ | |||
Marker* const m = markersX.getUnchecked(i); | |||
if (m->name == objectName) | |||
return m->position; | |||
if (m->name == symbol) | |||
return m->position.getExpression(); | |||
} | |||
for (i = 0; i < markersY.size(); ++i) | |||
{ | |||
Marker* const m = markersY.getUnchecked(i); | |||
if (m->name == objectName) | |||
return m->position; | |||
if (m->name == symbol) | |||
return m->position.getExpression(); | |||
} | |||
return RelativeCoordinate(); | |||
return Expression::EvaluationContext::getSymbolValue (symbol); | |||
} | |||
const Rectangle<float> DrawableComposite::getUntransformedBounds (const bool includeMarkers) const | |||
@@ -535,7 +528,7 @@ const DrawableComposite::Marker DrawableComposite::ValueTreeWrapper::getMarker ( | |||
{ | |||
jassert (containsMarker (xAxis, state)); | |||
return Marker (state [nameProperty], RelativeCoordinate (state [posProperty].toString(), xAxis)); | |||
return Marker (state [nameProperty], RelativeCoordinate (state [posProperty].toString())); | |||
} | |||
void DrawableComposite::ValueTreeWrapper::setMarker (bool xAxis, const Marker& m, UndoManager* undoManager) | |||
@@ -36,7 +36,7 @@ | |||
@see Drawable | |||
*/ | |||
class JUCE_API DrawableComposite : public Drawable, | |||
public RelativeCoordinate::NamedCoordinateFinder | |||
public Expression::EvaluationContext | |||
{ | |||
public: | |||
//============================================================================== | |||
@@ -201,7 +201,7 @@ public: | |||
/** @internal */ | |||
const Identifier getValueTreeType() const { return valueTreeType; } | |||
/** @internal */ | |||
const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const; | |||
const Expression getSymbolValue (const String& symbol) const; | |||
//============================================================================== | |||
/** Internally-used class for wrapping a DrawableComposite's state into a ValueTree. */ | |||
@@ -143,6 +143,8 @@ void DrawablePath::render (const Drawable::RenderingContext& context) const | |||
FillType f (mainFill); | |||
if (f.isGradient()) | |||
f.gradient->multiplyOpacity (context.opacity); | |||
else | |||
f.setOpacity (f.getOpacity() * context.opacity); | |||
f.transform = f.transform.followedBy (context.transform); | |||
context.g.setFillType (f); | |||
@@ -154,6 +156,8 @@ void DrawablePath::render (const Drawable::RenderingContext& context) const | |||
FillType f (strokeFill); | |||
if (f.isGradient()) | |||
f.gradient->multiplyOpacity (context.opacity); | |||
else | |||
f.setOpacity (f.getOpacity() * context.opacity); | |||
f.transform = f.transform.followedBy (context.transform); | |||
context.g.setFillType (f); | |||
@@ -226,7 +230,7 @@ ValueTree DrawablePath::ValueTreeWrapper::getStrokeFillState() | |||
return getStrokeFillState(); | |||
} | |||
const FillType DrawablePath::ValueTreeWrapper::getMainFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder, | |||
const FillType DrawablePath::ValueTreeWrapper::getMainFill (Expression::EvaluationContext* nameFinder, | |||
ImageProvider* imageProvider) const | |||
{ | |||
return readFillType (state.getChildWithName (fill), 0, 0, 0, nameFinder, imageProvider); | |||
@@ -240,7 +244,7 @@ void DrawablePath::ValueTreeWrapper::setMainFill (const FillType& newFill, const | |||
writeFillType (v, newFill, gp1, gp2, gp3, imageProvider, undoManager); | |||
} | |||
const FillType DrawablePath::ValueTreeWrapper::getStrokeFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder, | |||
const FillType DrawablePath::ValueTreeWrapper::getStrokeFill (Expression::EvaluationContext* nameFinder, | |||
ImageProvider* imageProvider) const | |||
{ | |||
return readFillType (state.getChildWithName (stroke), 0, 0, 0, nameFinder, imageProvider); | |||
@@ -368,7 +372,7 @@ const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const | |||
return RelativePoint(); | |||
} | |||
float DrawablePath::ValueTreeWrapper::Element::getLength (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const | |||
float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::EvaluationContext* nameFinder) const | |||
{ | |||
const Identifier i (state.getType()); | |||
@@ -419,7 +423,7 @@ void DrawablePath::ValueTreeWrapper::Element::convertToLine (UndoManager* undoMa | |||
} | |||
} | |||
void DrawablePath::ValueTreeWrapper::Element::convertToCubic (RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager) | |||
void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager) | |||
{ | |||
const Identifier i (state.getType()); | |||
@@ -473,7 +477,7 @@ static const Point<float> findQuadraticSubdivisionPoint (float proportion, const | |||
return mid1 + (mid2 - mid1) * proportion; | |||
} | |||
float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder) const | |||
float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder) const | |||
{ | |||
const Identifier i (state.getType()); | |||
float bestProp = 0; | |||
@@ -529,7 +533,7 @@ float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (const Po | |||
return bestProp; | |||
} | |||
ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager) | |||
ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager) | |||
{ | |||
ValueTree newTree; | |||
const Identifier i (state.getType()); | |||
@@ -129,14 +129,14 @@ public: | |||
public: | |||
ValueTreeWrapper (const ValueTree& state); | |||
const FillType getMainFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder, | |||
const FillType getMainFill (Expression::EvaluationContext* nameFinder, | |||
ImageProvider* imageProvider) const; | |||
ValueTree getMainFillState(); | |||
void setMainFill (const FillType& newFill, const RelativePoint* gradientPoint1, | |||
const RelativePoint* gradientPoint2, const RelativePoint* gradientPoint3, | |||
ImageProvider* imageProvider, UndoManager* undoManager); | |||
const FillType getStrokeFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder, | |||
const FillType getStrokeFill (Expression::EvaluationContext* nameFinder, | |||
ImageProvider* imageProvider) const; | |||
ValueTree getStrokeFillState(); | |||
void setStrokeFill (const FillType& newFill, const RelativePoint* gradientPoint1, | |||
@@ -163,7 +163,7 @@ public: | |||
const RelativePoint getStartPoint() const; | |||
const RelativePoint getEndPoint() const; | |||
void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager); | |||
float getLength (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
float getLength (Expression::EvaluationContext* nameFinder) const; | |||
ValueTreeWrapper getParent() const; | |||
Element getPreviousElement() const; | |||
@@ -172,11 +172,11 @@ public: | |||
void setModeOfEndPoint (const String& newMode, UndoManager* undoManager); | |||
void convertToLine (UndoManager* undoManager); | |||
void convertToCubic (RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); | |||
void convertToCubic (Expression::EvaluationContext* nameFinder, UndoManager* undoManager); | |||
void convertToPathBreak (UndoManager* undoManager); | |||
ValueTree insertPoint (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); | |||
ValueTree insertPoint (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder, UndoManager* undoManager); | |||
void removePoint (UndoManager* undoManager); | |||
float findProportionAlongLine (const Point<float>& targetPoint, RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
float findProportionAlongLine (const Point<float>& targetPoint, Expression::EvaluationContext* nameFinder) const; | |||
static const Identifier mode, startSubPathElement, closeSubPathElement, | |||
lineToElement, quadraticToElement, cubicToElement; | |||
@@ -35,166 +35,14 @@ BEGIN_JUCE_NAMESPACE | |||
//============================================================================== | |||
namespace RelativeCoordinateHelpers | |||
{ | |||
static bool isOrigin (const String& name) | |||
{ | |||
return name.isEmpty() | |||
|| name == RelativeCoordinate::Strings::parentLeft | |||
|| name == RelativeCoordinate::Strings::parentTop; | |||
} | |||
static const String getExtentAnchorName (const bool isHorizontal) throw() | |||
{ | |||
return isHorizontal ? RelativeCoordinate::Strings::parentRight | |||
: RelativeCoordinate::Strings::parentBottom; | |||
} | |||
static const String getObjectName (const String& fullName) | |||
{ | |||
return fullName.upToFirstOccurrenceOf (".", false, false); | |||
} | |||
static const String getEdgeName (const String& fullName) | |||
{ | |||
return fullName.fromFirstOccurrenceOf (".", false, false); | |||
} | |||
static const RelativeCoordinate findCoordinate (const String& name, const RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
{ | |||
return nameFinder != 0 ? nameFinder->findNamedCoordinate (getObjectName (name), getEdgeName (name)) | |||
: RelativeCoordinate(); | |||
} | |||
//============================================================================== | |||
struct RecursionException : public std::runtime_error | |||
{ | |||
RecursionException() : std::runtime_error ("Recursive RelativeCoordinate expression") | |||
{ | |||
} | |||
}; | |||
//============================================================================== | |||
static void skipWhitespace (const juce_wchar* const s, int& i) | |||
static void skipComma (const juce_wchar* const s, int& i) | |||
{ | |||
while (CharacterFunctions::isWhitespace (s[i])) | |||
++i; | |||
} | |||
static void skipComma (const juce_wchar* const s, int& i) | |||
{ | |||
skipWhitespace (s, i); | |||
if (s[i] == ',') | |||
++i; | |||
} | |||
static const String readAnchorName (const juce_wchar* const s, int& i) | |||
{ | |||
skipWhitespace (s, i); | |||
if (CharacterFunctions::isLetter (s[i]) || s[i] == '_') | |||
{ | |||
int start = i; | |||
while (CharacterFunctions::isLetterOrDigit (s[i]) || s[i] == '_' || s[i] == '.') | |||
++i; | |||
return String (s + start, i - start); | |||
} | |||
return String::empty; | |||
} | |||
static double readNumber (const juce_wchar* const s, int& i) | |||
{ | |||
skipWhitespace (s, i); | |||
int start = i; | |||
if (CharacterFunctions::isDigit (s[i]) || s[i] == '.' || s[i] == '-') | |||
++i; | |||
while (CharacterFunctions::isDigit (s[i]) || s[i] == '.') | |||
++i; | |||
if ((s[i] == 'e' || s[i] == 'E') | |||
&& (CharacterFunctions::isDigit (s[i + 1]) | |||
|| s[i + 1] == '-' | |||
|| s[i + 1] == '+')) | |||
{ | |||
i += 2; | |||
while (CharacterFunctions::isDigit (s[i])) | |||
++i; | |||
} | |||
const double value = String (s + start, i - start).getDoubleValue(); | |||
while (CharacterFunctions::isWhitespace (s[i]) || s[i] == ',') | |||
++i; | |||
return value; | |||
} | |||
static const RelativeCoordinate readNextCoordinate (const juce_wchar* const s, int& i, const bool isHorizontal) | |||
{ | |||
String anchor1 (readAnchorName (s, i)); | |||
double value = 0; | |||
if (anchor1.isNotEmpty()) | |||
{ | |||
skipWhitespace (s, i); | |||
if (s[i] == '+') | |||
value = readNumber (s, ++i); | |||
else if (s[i] == '-') | |||
value = -readNumber (s, ++i); | |||
return RelativeCoordinate (value, anchor1); | |||
} | |||
else | |||
{ | |||
value = readNumber (s, i); | |||
skipWhitespace (s, i); | |||
if (s[i] == '%') | |||
{ | |||
value /= 100.0; | |||
skipWhitespace (s, ++i); | |||
String anchor2; | |||
if (s[i] == '*') | |||
{ | |||
anchor1 = readAnchorName (s, ++i); | |||
skipWhitespace (s, i); | |||
if (s[i] == '-' && s[i + 1] == '>') | |||
{ | |||
i += 2; | |||
anchor2 = readAnchorName (s, i); | |||
} | |||
else | |||
{ | |||
anchor2 = anchor1; | |||
anchor1 = String::empty; | |||
} | |||
} | |||
else | |||
{ | |||
anchor1 = String::empty; | |||
anchor2 = getExtentAnchorName (isHorizontal); | |||
} | |||
return RelativeCoordinate (value, anchor1, anchor2); | |||
} | |||
return RelativeCoordinate (value); | |||
} | |||
} | |||
static const String limitedAccuracyString (const double n) | |||
{ | |||
if (! (n < -0.001 || n > 0.001)) // to detect NaN and inf as well as for rounding | |||
return "0"; | |||
return String (n, 3).trimCharactersAtEnd ("0").trimCharactersAtEnd ("."); | |||
} | |||
} | |||
//============================================================================== | |||
@@ -210,33 +58,38 @@ const String RelativeCoordinate::Strings::parentBottom ("parent.bottom"); | |||
//============================================================================== | |||
RelativeCoordinate::RelativeCoordinate() | |||
: value (0) | |||
{ | |||
} | |||
RelativeCoordinate::RelativeCoordinate (const double absoluteDistanceFromOrigin) | |||
: value (absoluteDistanceFromOrigin) | |||
RelativeCoordinate::RelativeCoordinate (const Expression& term_) | |||
: term (term_) | |||
{ | |||
} | |||
RelativeCoordinate::RelativeCoordinate (const double absoluteDistance, const String& source) | |||
: anchor1 (source.trim()), | |||
value (absoluteDistance) | |||
RelativeCoordinate::RelativeCoordinate (const RelativeCoordinate& other) | |||
: term (other.term) | |||
{ | |||
} | |||
RelativeCoordinate::RelativeCoordinate (const double relativeProportion, const String& pos1, const String& pos2) | |||
: anchor1 (pos1.trim()), | |||
anchor2 (pos2.trim()), | |||
value (relativeProportion) | |||
RelativeCoordinate& RelativeCoordinate::operator= (const RelativeCoordinate& other) | |||
{ | |||
term = other.term; | |||
return *this; | |||
} | |||
RelativeCoordinate::RelativeCoordinate (const String& s, const bool isHorizontal) | |||
: value (0) | |||
RelativeCoordinate::RelativeCoordinate (const double absoluteDistanceFromOrigin) | |||
: term (absoluteDistanceFromOrigin) | |||
{ | |||
int i = 0; | |||
*this = RelativeCoordinateHelpers::readNextCoordinate (s, i, isHorizontal); | |||
} | |||
RelativeCoordinate::RelativeCoordinate (const String& s) | |||
{ | |||
try | |||
{ | |||
term = Expression (s); | |||
} | |||
catch (...) | |||
{} | |||
} | |||
RelativeCoordinate::~RelativeCoordinate() | |||
@@ -245,7 +98,7 @@ RelativeCoordinate::~RelativeCoordinate() | |||
bool RelativeCoordinate::operator== (const RelativeCoordinate& other) const throw() | |||
{ | |||
return value == other.value && anchor1 == other.anchor1 && anchor2 == other.anchor2; | |||
return term.toString() == other.term.toString(); | |||
} | |||
bool RelativeCoordinate::operator!= (const RelativeCoordinate& other) const throw() | |||
@@ -253,58 +106,31 @@ bool RelativeCoordinate::operator!= (const RelativeCoordinate& other) const thro | |||
return ! operator== (other); | |||
} | |||
//============================================================================== | |||
const RelativeCoordinate RelativeCoordinate::getAnchorCoordinate1() const | |||
{ | |||
return RelativeCoordinate (0.0, anchor1); | |||
} | |||
const RelativeCoordinate RelativeCoordinate::getAnchorCoordinate2() const | |||
{ | |||
return RelativeCoordinate (0.0, anchor2); | |||
} | |||
double RelativeCoordinate::resolveAnchor (const String& anchorName, const NamedCoordinateFinder* nameFinder, int recursionCounter) | |||
{ | |||
if (RelativeCoordinateHelpers::isOrigin (anchorName)) | |||
return 0.0; | |||
return RelativeCoordinateHelpers::findCoordinate (anchorName, nameFinder).resolve (nameFinder, recursionCounter + 1); | |||
} | |||
double RelativeCoordinate::resolve (const NamedCoordinateFinder* nameFinder, int recursionCounter) const | |||
{ | |||
if (recursionCounter > 150) | |||
{ | |||
jassertfalse | |||
throw RelativeCoordinateHelpers::RecursionException(); | |||
} | |||
const double pos1 = resolveAnchor (anchor1, nameFinder, recursionCounter); | |||
return isProportional() ? pos1 + (resolveAnchor (anchor2, nameFinder, recursionCounter) - pos1) * value | |||
: pos1 + value; | |||
} | |||
double RelativeCoordinate::resolve (const NamedCoordinateFinder* nameFinder) const | |||
double RelativeCoordinate::resolve (const Expression::EvaluationContext* context) const | |||
{ | |||
try | |||
{ | |||
return resolve (nameFinder, 0); | |||
if (context != 0) | |||
return term.evaluate (*context); | |||
else | |||
return term.evaluate(); | |||
} | |||
catch (RelativeCoordinateHelpers::RecursionException&) | |||
catch (...) | |||
{} | |||
return 0.0; | |||
} | |||
bool RelativeCoordinate::isRecursive (const NamedCoordinateFinder* nameFinder) const | |||
bool RelativeCoordinate::isRecursive (const Expression::EvaluationContext* context) const | |||
{ | |||
try | |||
{ | |||
(void) resolve (nameFinder, 0); | |||
if (context != 0) | |||
term.evaluate (*context); | |||
else | |||
term.evaluate(); | |||
} | |||
catch (RelativeCoordinateHelpers::RecursionException&) | |||
catch (...) | |||
{ | |||
return true; | |||
} | |||
@@ -312,153 +138,61 @@ bool RelativeCoordinate::isRecursive (const NamedCoordinateFinder* nameFinder) c | |||
return false; | |||
} | |||
void RelativeCoordinate::moveToAbsolute (double newPos, const NamedCoordinateFinder* nameFinder) | |||
void RelativeCoordinate::moveToAbsolute (double newPos, const Expression::EvaluationContext* context) | |||
{ | |||
try | |||
{ | |||
const double pos1 = resolveAnchor (anchor1, nameFinder, 0); | |||
if (isProportional()) | |||
if (context != 0) | |||
{ | |||
const double size = resolveAnchor (anchor2, nameFinder, 0) - pos1; | |||
if (size != 0) | |||
value = (newPos - pos1) / size; | |||
term = term.adjustedToGiveNewResult (newPos, *context); | |||
} | |||
else | |||
{ | |||
value = newPos - pos1; | |||
Expression::EvaluationContext defaultContext; | |||
term = term.adjustedToGiveNewResult (newPos, defaultContext); | |||
} | |||
} | |||
catch (RelativeCoordinateHelpers::RecursionException&) | |||
catch (...) | |||
{} | |||
} | |||
void RelativeCoordinate::toggleProportionality (const NamedCoordinateFinder* nameFinder, | |||
const String& proportionalAnchor1, const String& proportionalAnchor2) | |||
{ | |||
const double oldValue = resolve (nameFinder); | |||
anchor1 = proportionalAnchor1; | |||
anchor2 = isProportional() ? String::empty : proportionalAnchor2; | |||
moveToAbsolute (oldValue, nameFinder); | |||
} | |||
bool RelativeCoordinate::references (const String& coordName, const NamedCoordinateFinder* nameFinder) const | |||
bool RelativeCoordinate::references (const String& coordName, const Expression::EvaluationContext* context) const | |||
{ | |||
using namespace RelativeCoordinateHelpers; | |||
if (isOrigin (anchor1) && ! isProportional()) | |||
return isOrigin (coordName); | |||
return anchor1 == coordName | |||
|| anchor2 == coordName | |||
|| findCoordinate (anchor1, nameFinder).references (coordName, nameFinder) | |||
|| (isProportional() && findCoordinate (anchor2, nameFinder).references (coordName, nameFinder)); | |||
} | |||
bool RelativeCoordinate::isDynamic() const | |||
{ | |||
return anchor2.isNotEmpty() || ! RelativeCoordinateHelpers::isOrigin (anchor1); | |||
} | |||
//============================================================================== | |||
const String RelativeCoordinate::toString() const | |||
{ | |||
using namespace RelativeCoordinateHelpers; | |||
if (isProportional()) | |||
try | |||
{ | |||
const String percent (limitedAccuracyString (value * 100.0)); | |||
if (context != 0) | |||
return term.referencesSymbol (coordName, *context); | |||
if (isOrigin (anchor1)) | |||
{ | |||
if (anchor2 == Strings::parentRight || anchor2 == Strings::parentBottom) | |||
return percent + "%"; | |||
else | |||
return percent + "% * " + anchor2; | |||
} | |||
else | |||
return percent + "% * " + anchor1 + " -> " + anchor2; | |||
Expression::EvaluationContext defaultContext; | |||
return term.referencesSymbol (coordName, defaultContext); | |||
} | |||
else | |||
{ | |||
if (isOrigin (anchor1)) | |||
return limitedAccuracyString (value); | |||
else if (value > 0) | |||
return anchor1 + " + " + limitedAccuracyString (value); | |||
else if (value < 0) | |||
return anchor1 + " - " + limitedAccuracyString (-value); | |||
else | |||
return anchor1; | |||
} | |||
} | |||
//============================================================================== | |||
const double RelativeCoordinate::getEditableNumber() const | |||
{ | |||
return isProportional() ? value * 100.0 : value; | |||
} | |||
void RelativeCoordinate::setEditableNumber (const double newValue) | |||
{ | |||
value = isProportional() ? newValue / 100.0 : newValue; | |||
} | |||
//============================================================================== | |||
const String RelativeCoordinate::getAnchorName1 (const String& returnValueIfOrigin) const | |||
{ | |||
return RelativeCoordinateHelpers::isOrigin (anchor1) ? returnValueIfOrigin : anchor1; | |||
} | |||
catch (...) | |||
{} | |||
const String RelativeCoordinate::getAnchorName2 (const String& returnValueIfOrigin) const | |||
{ | |||
return RelativeCoordinateHelpers::isOrigin (anchor2) ? returnValueIfOrigin : anchor2; | |||
return false; | |||
} | |||
void RelativeCoordinate::changeAnchor1 (const String& newAnchorName, const NamedCoordinateFinder* nameFinder) | |||
bool RelativeCoordinate::isDynamic() const | |||
{ | |||
jassert (newAnchorName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
const double oldValue = resolve (nameFinder); | |||
anchor1 = RelativeCoordinateHelpers::isOrigin (newAnchorName) ? String::empty : newAnchorName; | |||
moveToAbsolute (oldValue, nameFinder); | |||
return term.usesAnySymbols(); | |||
} | |||
void RelativeCoordinate::changeAnchor2 (const String& newAnchorName, const NamedCoordinateFinder* nameFinder) | |||
const String RelativeCoordinate::toString() const | |||
{ | |||
jassert (isProportional()); | |||
jassert (newAnchorName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
const double oldValue = resolve (nameFinder); | |||
anchor2 = RelativeCoordinateHelpers::isOrigin (newAnchorName) ? String::empty : newAnchorName; | |||
moveToAbsolute (oldValue, nameFinder); | |||
return term.toString(); | |||
} | |||
void RelativeCoordinate::renameAnchorIfUsed (const String& oldName, const String& newName, const NamedCoordinateFinder* nameFinder) | |||
void RelativeCoordinate::renameSymbolIfUsed (const String& oldName, const String& newName, | |||
const Expression::EvaluationContext* context) | |||
{ | |||
using namespace RelativeCoordinateHelpers; | |||
jassert (oldName.isNotEmpty()); | |||
jassert (newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_")); | |||
jassert (newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
if (newName.isEmpty()) | |||
{ | |||
if (getObjectName (anchor1) == oldName | |||
|| getObjectName (anchor2) == oldName) | |||
{ | |||
value = resolve (nameFinder); | |||
anchor1 = String::empty; | |||
anchor2 = String::empty; | |||
} | |||
} | |||
else | |||
if (term.referencesSymbol (oldName, *context)) | |||
{ | |||
if (getObjectName (anchor1) == oldName) | |||
anchor1 = newName + "." + getEdgeName (anchor1); | |||
const double oldValue = resolve (context); | |||
if (getObjectName (anchor2) == oldName) | |||
anchor2 = newName + "." + getEdgeName (anchor2); | |||
term = term.withRenamedSymbol (oldName, newName); | |||
moveToAbsolute (oldValue, context); | |||
} | |||
} | |||
@@ -485,9 +219,9 @@ RelativePoint::RelativePoint (const RelativeCoordinate& x_, const RelativeCoordi | |||
RelativePoint::RelativePoint (const String& s) | |||
{ | |||
int i = 0; | |||
x = RelativeCoordinateHelpers::readNextCoordinate (s, i, true); | |||
x = RelativeCoordinate (Expression::parse (s, i)); | |||
RelativeCoordinateHelpers::skipComma (s, i); | |||
y = RelativeCoordinateHelpers::readNextCoordinate (s, i, false); | |||
y = RelativeCoordinate (Expression::parse (s, i)); | |||
} | |||
bool RelativePoint::operator== (const RelativePoint& other) const throw() | |||
@@ -500,16 +234,16 @@ bool RelativePoint::operator!= (const RelativePoint& other) const throw() | |||
return ! operator== (other); | |||
} | |||
const Point<float> RelativePoint::resolve (const RelativeCoordinate::NamedCoordinateFinder* nameFinder) const | |||
const Point<float> RelativePoint::resolve (const Expression::EvaluationContext* context) const | |||
{ | |||
return Point<float> ((float) x.resolve (nameFinder), | |||
(float) y.resolve (nameFinder)); | |||
return Point<float> ((float) x.resolve (context), | |||
(float) y.resolve (context)); | |||
} | |||
void RelativePoint::moveToAbsolute (const Point<float>& newPos, const RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
void RelativePoint::moveToAbsolute (const Point<float>& newPos, const Expression::EvaluationContext* context) | |||
{ | |||
x.moveToAbsolute (newPos.getX(), nameFinder); | |||
y.moveToAbsolute (newPos.getY(), nameFinder); | |||
x.moveToAbsolute (newPos.getX(), context); | |||
y.moveToAbsolute (newPos.getY(), context); | |||
} | |||
const String RelativePoint::toString() const | |||
@@ -517,10 +251,10 @@ const String RelativePoint::toString() const | |||
return x.toString() + ", " + y.toString(); | |||
} | |||
void RelativePoint::renameAnchorIfUsed (const String& oldName, const String& newName, const RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
void RelativePoint::renameSymbolIfUsed (const String& oldName, const String& newName, const Expression::EvaluationContext* context) | |||
{ | |||
x.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
y.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
x.renameSymbolIfUsed (oldName, newName, context); | |||
y.renameSymbolIfUsed (oldName, newName, context); | |||
} | |||
bool RelativePoint::isDynamic() const | |||
@@ -542,22 +276,22 @@ RelativeRectangle::RelativeRectangle (const RelativeCoordinate& left_, const Rel | |||
RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect, const String& componentName) | |||
: left (rect.getX()), | |||
right (rect.getWidth(), componentName + "." + RelativeCoordinate::Strings::left), | |||
right (componentName + "." + RelativeCoordinate::Strings::left + " + " + String (rect.getWidth())), | |||
top (rect.getY()), | |||
bottom (rect.getHeight(), componentName + "." + RelativeCoordinate::Strings::top) | |||
bottom (componentName + "." + RelativeCoordinate::Strings::top + " + " + String (rect.getHeight())) | |||
{ | |||
} | |||
RelativeRectangle::RelativeRectangle (const String& s) | |||
{ | |||
int i = 0; | |||
left = RelativeCoordinateHelpers::readNextCoordinate (s, i, true); | |||
left = RelativeCoordinate (Expression::parse (s, i)); | |||
RelativeCoordinateHelpers::skipComma (s, i); | |||
top = RelativeCoordinateHelpers::readNextCoordinate (s, i, false); | |||
top = RelativeCoordinate (Expression::parse (s, i)); | |||
RelativeCoordinateHelpers::skipComma (s, i); | |||
right = RelativeCoordinateHelpers::readNextCoordinate (s, i, true); | |||
right = RelativeCoordinate (Expression::parse (s, i)); | |||
RelativeCoordinateHelpers::skipComma (s, i); | |||
bottom = RelativeCoordinateHelpers::readNextCoordinate (s, i, false); | |||
bottom = RelativeCoordinate (Expression::parse (s, i)); | |||
} | |||
bool RelativeRectangle::operator== (const RelativeRectangle& other) const throw() | |||
@@ -570,22 +304,22 @@ bool RelativeRectangle::operator!= (const RelativeRectangle& other) const throw( | |||
return ! operator== (other); | |||
} | |||
const Rectangle<float> RelativeRectangle::resolve (const RelativeCoordinate::NamedCoordinateFinder* nameFinder) const | |||
const Rectangle<float> RelativeRectangle::resolve (const Expression::EvaluationContext* context) const | |||
{ | |||
const double l = left.resolve (nameFinder); | |||
const double r = right.resolve (nameFinder); | |||
const double t = top.resolve (nameFinder); | |||
const double b = bottom.resolve (nameFinder); | |||
const double l = left.resolve (context); | |||
const double r = right.resolve (context); | |||
const double t = top.resolve (context); | |||
const double b = bottom.resolve (context); | |||
return Rectangle<float> ((float) l, (float) t, (float) (r - l), (float) (b - t)); | |||
} | |||
void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* context) | |||
{ | |||
left.moveToAbsolute (newPos.getX(), nameFinder); | |||
right.moveToAbsolute (newPos.getRight(), nameFinder); | |||
top.moveToAbsolute (newPos.getY(), nameFinder); | |||
bottom.moveToAbsolute (newPos.getBottom(), nameFinder); | |||
left.moveToAbsolute (newPos.getX(), context); | |||
right.moveToAbsolute (newPos.getRight(), context); | |||
top.moveToAbsolute (newPos.getY(), context); | |||
bottom.moveToAbsolute (newPos.getBottom(), context); | |||
} | |||
const String RelativeRectangle::toString() const | |||
@@ -593,13 +327,13 @@ const String RelativeRectangle::toString() const | |||
return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString(); | |||
} | |||
void RelativeRectangle::renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
void RelativeRectangle::renameSymbolIfUsed (const String& oldName, const String& newName, | |||
const Expression::EvaluationContext* context) | |||
{ | |||
left.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
right.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
top.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
bottom.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
left.renameSymbolIfUsed (oldName, newName, context); | |||
right.renameSymbolIfUsed (oldName, newName, context); | |||
top.renameSymbolIfUsed (oldName, newName, context); | |||
bottom.renameSymbolIfUsed (oldName, newName, context); | |||
} | |||
@@ -704,7 +438,7 @@ void RelativePointPath::swapWith (RelativePointPath& other) throw() | |||
swapVariables (usesNonZeroWinding, other.usesNonZeroWinding); | |||
} | |||
void RelativePointPath::createPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) | |||
void RelativePointPath::createPath (Path& path, Expression::EvaluationContext* coordFinder) | |||
{ | |||
for (int i = 0; i < elements.size(); ++i) | |||
elements.getUnchecked(i)->addToPath (path, coordFinder); | |||
@@ -733,7 +467,7 @@ const ValueTree RelativePointPath::StartSubPath::createTree() const | |||
return v; | |||
} | |||
void RelativePointPath::StartSubPath::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const | |||
void RelativePointPath::StartSubPath::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const | |||
{ | |||
path.startNewSubPath (startPos.resolve (coordFinder)); | |||
} | |||
@@ -755,7 +489,7 @@ const ValueTree RelativePointPath::CloseSubPath::createTree() const | |||
return ValueTree (DrawablePath::ValueTreeWrapper::Element::closeSubPathElement); | |||
} | |||
void RelativePointPath::CloseSubPath::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder*) const | |||
void RelativePointPath::CloseSubPath::addToPath (Path& path, Expression::EvaluationContext*) const | |||
{ | |||
path.closeSubPath(); | |||
} | |||
@@ -779,7 +513,7 @@ const ValueTree RelativePointPath::LineTo::createTree() const | |||
return v; | |||
} | |||
void RelativePointPath::LineTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const | |||
void RelativePointPath::LineTo::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const | |||
{ | |||
path.lineTo (endPoint.resolve (coordFinder)); | |||
} | |||
@@ -806,7 +540,7 @@ const ValueTree RelativePointPath::QuadraticTo::createTree() const | |||
return v; | |||
} | |||
void RelativePointPath::QuadraticTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const | |||
void RelativePointPath::QuadraticTo::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const | |||
{ | |||
path.quadraticTo (controlPoints[0].resolve (coordFinder), | |||
controlPoints[1].resolve (coordFinder)); | |||
@@ -836,7 +570,7 @@ const ValueTree RelativePointPath::CubicTo::createTree() const | |||
return v; | |||
} | |||
void RelativePointPath::CubicTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const | |||
void RelativePointPath::CubicTo::addToPath (Path& path, Expression::EvaluationContext* coordFinder) const | |||
{ | |||
path.cubicTo (controlPoints[0].resolve (coordFinder), | |||
controlPoints[1].resolve (coordFinder), | |||
@@ -869,27 +603,27 @@ RelativeParallelogram::~RelativeParallelogram() | |||
{ | |||
} | |||
void RelativeParallelogram::resolveThreePoints (Point<float>* points, RelativeCoordinate::NamedCoordinateFinder* const coordFinder) const | |||
void RelativeParallelogram::resolveThreePoints (Point<float>* points, Expression::EvaluationContext* const coordFinder) const | |||
{ | |||
points[0] = topLeft.resolve (coordFinder); | |||
points[1] = topRight.resolve (coordFinder); | |||
points[2] = bottomLeft.resolve (coordFinder); | |||
} | |||
void RelativeParallelogram::resolveFourCorners (Point<float>* points, RelativeCoordinate::NamedCoordinateFinder* const coordFinder) const | |||
void RelativeParallelogram::resolveFourCorners (Point<float>* points, Expression::EvaluationContext* const coordFinder) const | |||
{ | |||
resolveThreePoints (points, coordFinder); | |||
points[3] = points[1] + (points[2] - points[0]); | |||
} | |||
const Rectangle<float> RelativeParallelogram::getBounds (RelativeCoordinate::NamedCoordinateFinder* const coordFinder) const | |||
const Rectangle<float> RelativeParallelogram::getBounds (Expression::EvaluationContext* const coordFinder) const | |||
{ | |||
Point<float> points[4]; | |||
resolveFourCorners (points, coordFinder); | |||
return Rectangle<float>::findAreaContainingPoints (points, 4); | |||
} | |||
void RelativeParallelogram::getPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* const coordFinder) const | |||
void RelativeParallelogram::getPath (Path& path, Expression::EvaluationContext* const coordFinder) const | |||
{ | |||
Point<float> points[4]; | |||
resolveFourCorners (points, coordFinder); | |||
@@ -901,7 +635,7 @@ void RelativeParallelogram::getPath (Path& path, RelativeCoordinate::NamedCoordi | |||
path.closeSubPath(); | |||
} | |||
const AffineTransform RelativeParallelogram::resetToPerpendicular (RelativeCoordinate::NamedCoordinateFinder* const coordFinder) | |||
const AffineTransform RelativeParallelogram::resetToPerpendicular (Expression::EvaluationContext* const coordFinder) | |||
{ | |||
Point<float> corners[3]; | |||
resolveThreePoints (corners, coordFinder); | |||
@@ -28,27 +28,14 @@ | |||
#include "juce_Path.h" | |||
#include "juce_Rectangle.h" | |||
#include "../../../containers/juce_Expression.h" | |||
#include "../../../containers/juce_OwnedArray.h" | |||
#include "../../../containers/juce_ValueTree.h" | |||
//============================================================================== | |||
/** | |||
Expresses a coordinate as an absolute or proportional distance from other | |||
named coordinates. | |||
A RelativeCoordinate represents a position as either: | |||
- an absolute distance from the origin | |||
- an absolute distance from another named RelativeCoordinate | |||
- a proportion of the distance between two other named RelativeCoordinates | |||
Of course, the coordinates that this one is relative to may themselves be relative | |||
to other coordinates, so complex arrangements can be built up (as long as you're careful | |||
not to create recursive loops!) | |||
Rather than keeping pointers to the coordinates that this one is dependent on, it | |||
stores their names, and when resolving this coordinate to an absolute value, a | |||
NamedCoordinateFinder class is required to retrieve these coordinates by name. | |||
Expresses a coordinate as a dynamically evaluated expression. | |||
@see RelativePoint, RelativeRectangle | |||
*/ | |||
@@ -58,6 +45,9 @@ public: | |||
//============================================================================== | |||
/** Creates a zero coordinate. */ | |||
RelativeCoordinate(); | |||
RelativeCoordinate (const Expression& expression); | |||
RelativeCoordinate (const RelativeCoordinate& other); | |||
RelativeCoordinate& operator= (const RelativeCoordinate& other); | |||
/** Creates an absolute position from the parent origin on either the X or Y axis. | |||
@@ -65,53 +55,16 @@ public: | |||
*/ | |||
RelativeCoordinate (double absoluteDistanceFromOrigin); | |||
/** Creates an absolute position relative to a named coordinate. | |||
@param absoluteDistanceFromAnchor the distance to add to the named anchor point | |||
@param anchorPoint the name of the coordinate from which this one will be relative. See the constructor | |||
notes for a description of the syntax for coordinate names. | |||
*/ | |||
RelativeCoordinate (double absoluteDistanceFromAnchor, const String& anchorPoint); | |||
/** Creates a relative position between two named points. | |||
@param relativeProportionBetweenAnchors a value between 0 and 1 indicating this coordinate's relative position | |||
between anchorPoint1 and anchorPoint2. | |||
@param anchorPoint1 the name of the first coordinate from which this one will be relative. See the constructor | |||
notes for a description of the syntax for coordinate names. | |||
@param anchorPoint2 the name of the first coordinate from which this one will be relative. See the constructor | |||
notes for a description of the syntax for coordinate names. | |||
*/ | |||
RelativeCoordinate (double relativeProportionBetweenAnchors, const String& anchorPoint1, const String& anchorPoint2); | |||
/** Recreates a coordinate from a string description. | |||
The string can be in one of the following formats: | |||
- "123" = 123 pixels from parent origin (this is equivalent to "parent.left + 123" | |||
or "parent.top + 123", depending on which axis the coordinate is using) | |||
- "anchor" = the same position as the coordinate named "anchor" | |||
- "anchor + 123" = the coordinate named "anchor" + 123 pixels | |||
- "anchor - 123" = the coordinate named "anchor" - 123 pixels | |||
- "50%" = 50% of the distance between the coordinate space's top-left origin and its extent | |||
(this is equivalent to "50% * parent.left -> parent.right" or "50% * parent.top -> parent.bottom") | |||
- "50% * anchor" = 50% of the distance between the coordinate space's origin and the coordinate named "anchor" | |||
(this is equivalent to "50% * parent.left -> anchor" or "50% * parent.top -> anchor") | |||
- "50% * anchor1 -> anchor2" = 50% of the distance between the coordinate "anchor1" and the coordinate "anchor2" | |||
An anchor name can either be just a single identifier (letters, digits and underscores only - no spaces), | |||
e.g. "marker1", or it can be a two-part name in the form "objectName.edge". For example "parent.left" is | |||
the origin, or "myComponent.top" is the top edge of a component called "myComponent". The exact names that | |||
will be recognised are dependent on the NamedCoordinateFinder that you provide for looking them up, but | |||
"parent.left" and "parent.top" are always available, meaning the origin. "parent.right" and "parent.bottom" | |||
may also be available if the coordinate space has a fixed size. | |||
@param stringVersion the string to parse | |||
The string will be parsed by ExpressionParser::parse(). | |||
@param stringVersion the expression to use | |||
@param isHorizontal this must be true if this is an X coordinate, or false if it's on the Y axis. | |||
@see toString | |||
*/ | |||
RelativeCoordinate (const String& stringVersion, bool isHorizontal); | |||
RelativeCoordinate (const String& stringVersion); | |||
/** Destructor. */ | |||
~RelativeCoordinate(); | |||
@@ -119,46 +72,21 @@ public: | |||
bool operator== (const RelativeCoordinate& other) const throw(); | |||
bool operator!= (const RelativeCoordinate& other) const throw(); | |||
//============================================================================== | |||
/** | |||
Provides an interface for looking up the position of a named anchor when resolving a RelativeCoordinate. | |||
When using RelativeCoordinates, to resolve their names you need to provide a subclass of this which | |||
can retrieve a coordinate by name. | |||
*/ | |||
class JUCE_API NamedCoordinateFinder | |||
{ | |||
public: | |||
/** Destructor. */ | |||
virtual ~NamedCoordinateFinder() {} | |||
/** Returns the coordinate for a given name. | |||
The objectName parameter will be the first section of the name, and the edge the name of the second part. | |||
E.g. for "parent.right", objectName would be "parent" and edge would be "right". If the name | |||
has no dot, the edge parameter will be an empty string. | |||
This method must be able to resolve "parent.left", "parent.top", "parent.right" and "parent.bottom", as | |||
well as any other objects that your application uses. | |||
*/ | |||
virtual const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const = 0; | |||
}; | |||
//============================================================================== | |||
/** Calculates the absolute position of this coordinate. | |||
You'll need to provide a suitable NamedCoordinateFinder for looking up any coordinates that may | |||
You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may | |||
be needed to calculate the result. | |||
*/ | |||
double resolve (const NamedCoordinateFinder* nameFinder) const; | |||
double resolve (const Expression::EvaluationContext* evaluationContext) 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 NamedCoordinateFinder* nameFinder) const; | |||
bool references (const String& coordName, const Expression::EvaluationContext* evaluationContext) const; | |||
/** Returns true if there's a recursive loop when trying to resolve this coordinate's position. */ | |||
bool isRecursive (const NamedCoordinateFinder* nameFinder) const; | |||
bool isRecursive (const Expression::EvaluationContext* evaluationContext) const; | |||
/** Returns true if this coordinate depends on any other coordinates for its position. */ | |||
bool isDynamic() const; | |||
@@ -170,63 +98,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 NamedCoordinateFinder* nameFinder); | |||
/** Returns true if the coordinate is calculated as a proportion of the distance between two other points. | |||
@see toggleProportionality | |||
*/ | |||
bool isProportional() const throw() { return anchor2.isNotEmpty(); } | |||
/** Toggles the coordinate between using a proportional or absolute position. | |||
Note that calling this will reset the names of any anchor points, and just make the | |||
coordinate relative to the parent origin and parent size. | |||
*/ | |||
void toggleProportionality (const NamedCoordinateFinder* nameFinder, | |||
const String& proportionalAnchor1, const String& proportionalAnchor2); | |||
/** Returns a value that can be edited to set this coordinate's position. | |||
The meaning of this number depends on the coordinate's mode. If the coordinate is | |||
proportional, the number will be a percentage between 0 and 100. If the | |||
coordinate is absolute, then it will be the number of pixels from its anchor point. | |||
@see setEditableNumber | |||
*/ | |||
const double getEditableNumber() const; | |||
/** Sets the value that controls this coordinate's position. | |||
The meaning of this number depends on the coordinate's mode. If the coordinate is | |||
proportional, the number must be a percentage between 0 and 100. If the | |||
coordinate is absolute, then it indicates the number of pixels from its anchor point. | |||
@see setEditableNumber | |||
*/ | |||
void setEditableNumber (const double newValue); | |||
//============================================================================== | |||
/** Returns the name of the first anchor point from which this coordinate is relative. | |||
*/ | |||
const String getAnchorName1 (const String& returnValueIfOrigin) const; | |||
/** Returns the name of the second anchor point from which this coordinate is relative. | |||
The second anchor is only valid if the coordinate is in proportional mode. | |||
*/ | |||
const String getAnchorName2 (const String& returnValueIfOrigin) const; | |||
/** Returns the first anchor point as a coordinate. */ | |||
const RelativeCoordinate getAnchorCoordinate1() const; | |||
/** Returns the first anchor point as a coordinate. | |||
The second anchor is only valid if the coordinate is in proportional mode. | |||
*/ | |||
const RelativeCoordinate getAnchorCoordinate2() const; | |||
/** Changes the first anchor point, keeping the resultant position of this coordinate in | |||
the same place it was previously. | |||
*/ | |||
void changeAnchor1 (const String& newAnchor, const NamedCoordinateFinder* nameFinder); | |||
/** Changes the second anchor point, keeping the resultant position of this coordinate in | |||
the same place it was previously. | |||
*/ | |||
void changeAnchor2 (const String& newAnchor, const NamedCoordinateFinder* nameFinder); | |||
void moveToAbsolute (double absoluteTargetPosition, const Expression::EvaluationContext* evaluationContext); | |||
/** Tells the coordinate that an object is changing its name or being deleted. | |||
@@ -235,8 +107,12 @@ public: | |||
this coordinate was using it, the coordinate is changed to be relative to the origin | |||
instead. | |||
*/ | |||
void renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const NamedCoordinateFinder* nameFinder); | |||
void renameSymbolIfUsed (const String& oldName, const String& newName, | |||
const Expression::EvaluationContext* evaluationContext); | |||
/** Returns the expression that defines this coordinate. */ | |||
const Expression& getExpression() const { return term; } | |||
//============================================================================== | |||
/** Returns a string which represents this coordinate. | |||
@@ -267,11 +143,10 @@ public: | |||
private: | |||
//============================================================================== | |||
String anchor1, anchor2; | |||
double value; | |||
Expression term; | |||
double resolve (const NamedCoordinateFinder* nameFinder, int recursionCounter) const; | |||
static double resolveAnchor (const String& anchorName, const NamedCoordinateFinder* nameFinder, int recursionCounter); | |||
// double resolve (const Expression::EvaluationContext* evaluationContext, int recursionCounter) const; | |||
// static double resolveAnchor (const String& anchorName, const Expression::EvaluationContext* evaluationContext, int recursionCounter); | |||
}; | |||
@@ -308,10 +183,10 @@ public: | |||
/** Calculates the absolute position of this point. | |||
You'll need to provide a suitable NamedCoordinateFinder for looking up any coordinates that may | |||
You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may | |||
be needed to calculate the result. | |||
*/ | |||
const Point<float> resolve (const RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
const Point<float> resolve (const Expression::EvaluationContext* evaluationContext) const; | |||
/** Changes the values of this point's coordinates to make it resolve to the specified position. | |||
@@ -319,7 +194,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<float>& newPos, const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
void moveToAbsolute (const Point<float>& newPos, const Expression::EvaluationContext* evaluationContext); | |||
/** Returns a string which represents this point. | |||
This returns a comma-separated pair of coordinates. For details of the string syntax used by the | |||
@@ -331,8 +206,8 @@ public: | |||
/** Tells the point that an object is changing its name or being deleted. | |||
This calls RelativeCoordinate::renameAnchorIfUsed() on its X and Y coordinates. | |||
*/ | |||
void renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
void renameSymbolIfUsed (const String& oldName, const String& newName, | |||
const Expression::EvaluationContext* evaluationContext); | |||
/** Returns true if this point depends on any other coordinates for its position. */ | |||
bool isDynamic() const; | |||
@@ -378,10 +253,10 @@ public: | |||
//============================================================================== | |||
/** Calculates the absolute position of this rectangle. | |||
You'll need to provide a suitable NamedCoordinateFinder for looking up any coordinates that may | |||
You'll need to provide a suitable Expression::EvaluationContext for looking up any coordinates that may | |||
be needed to calculate the result. | |||
*/ | |||
const Rectangle<float> resolve (const RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
const Rectangle<float> resolve (const Expression::EvaluationContext* evaluationContext) const; | |||
/** Changes the values of this rectangle's coordinates to make it resolve to the specified position. | |||
@@ -389,7 +264,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<float>& newPos, const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
void moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* evaluationContext); | |||
/** Returns a string which represents this point. | |||
This returns a comma-separated list of coordinates, in the order left, top, right, bottom. For details of | |||
@@ -399,10 +274,10 @@ public: | |||
const String toString() const; | |||
/** Tells the rectangle that an object is changing its name or being deleted. | |||
This calls RelativeCoordinate::renameAnchorIfUsed() on the rectangle's coordinates. | |||
This calls RelativeCoordinate::renameSymbolIfUsed() on the rectangle's coordinates. | |||
*/ | |||
void renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
void renameSymbolIfUsed (const String& oldName, const String& newName, | |||
const Expression::EvaluationContext* evaluationContext); | |||
// The actual rectangle coords... | |||
RelativeCoordinate left, right, top, bottom; | |||
@@ -430,7 +305,7 @@ public: | |||
//============================================================================== | |||
/** Resolves this points in this path and adds them to a normal Path object. */ | |||
void createPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder); | |||
void createPath (Path& path, Expression::EvaluationContext* coordFinder); | |||
/** Returns true if the path contains any non-fixed points. */ | |||
bool containsAnyDynamicPoints() const; | |||
@@ -464,7 +339,7 @@ public: | |||
ElementBase (ElementType type); | |||
virtual ~ElementBase() {} | |||
virtual const ValueTree createTree() const = 0; | |||
virtual void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const = 0; | |||
virtual void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const = 0; | |||
virtual RelativePoint* getControlPoints (int& numPoints) = 0; | |||
const ElementType type; | |||
@@ -480,7 +355,7 @@ public: | |||
StartSubPath (const RelativePoint& pos); | |||
~StartSubPath() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
RelativePoint startPos; | |||
@@ -496,7 +371,7 @@ public: | |||
CloseSubPath(); | |||
~CloseSubPath() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
private: | |||
@@ -510,7 +385,7 @@ public: | |||
LineTo (const RelativePoint& endPoint); | |||
~LineTo() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
RelativePoint endPoint; | |||
@@ -526,7 +401,7 @@ public: | |||
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint); | |||
~QuadraticTo() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
RelativePoint controlPoints[2]; | |||
@@ -542,7 +417,7 @@ public: | |||
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint); | |||
~CubicTo() {} | |||
const ValueTree createTree() const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void addToPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
RelativePoint* getControlPoints (int& numPoints); | |||
RelativePoint controlPoints[3]; | |||
@@ -580,11 +455,11 @@ public: | |||
~RelativeParallelogram(); | |||
//============================================================================== | |||
void resolveThreePoints (Point<float>* points, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void resolveFourCorners (Point<float>* points, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
const Rectangle<float> getBounds (RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
void getPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
const AffineTransform resetToPerpendicular (RelativeCoordinate::NamedCoordinateFinder* coordFinder); | |||
void resolveThreePoints (Point<float>* points, Expression::EvaluationContext* coordFinder) const; | |||
void resolveFourCorners (Point<float>* points, Expression::EvaluationContext* coordFinder) const; | |||
const Rectangle<float> getBounds (Expression::EvaluationContext* coordFinder) const; | |||
void getPath (Path& path, Expression::EvaluationContext* coordFinder) const; | |||
const AffineTransform resetToPerpendicular (Expression::EvaluationContext* coordFinder); | |||
bool operator== (const RelativeParallelogram& other) const throw(); | |||
bool operator!= (const RelativeParallelogram& other) const throw(); | |||
@@ -41,6 +41,9 @@ | |||
#ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ | |||
#include "containers/juce_ElementComparator.h" | |||
#endif | |||
#ifndef __JUCE_EXPRESSION_JUCEHEADER__ | |||
#include "containers/juce_Expression.h" | |||
#endif | |||
#ifndef __JUCE_HEAPBLOCK_JUCEHEADER__ | |||
#include "containers/juce_HeapBlock.h" | |||
#endif | |||
@@ -167,8 +167,6 @@ public: | |||
[renderContext setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; | |||
[view setOpenGLContext: renderContext]; | |||
[renderContext setView: view]; | |||
[format release]; | |||
viewHolder = new NSViewComponentInternal (view, component); | |||
@@ -192,6 +190,10 @@ public: | |||
bool makeActive() const throw() | |||
{ | |||
jassert (renderContext != 0); | |||
if ([renderContext view] != view) | |||
[renderContext setView: view]; | |||
[view makeActive]; | |||
return isActive(); | |||
} | |||
@@ -479,8 +479,7 @@ void XmlDocument::readChildElements (XmlElement* parent) | |||
++len; | |||
} | |||
XmlElement* const e = new XmlElement ((int) 0); | |||
e->setText (String (inputStart, len)); | |||
XmlElement* const e = XmlElement::createTextElement (String (inputStart, len)); | |||
if (lastChildNode != 0) | |||
lastChildNode->nextElement = e; | |||