Browse Source

Documentation fixes. Mac OpenGL fix. PositionableAudioSource tweak. Added new class: Expression, and changed RelativeCoordinate to use an Expression to store its position.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
3e30e09afa
38 changed files with 4287 additions and 2716 deletions
  1. +6
    -0
      Builds/Linux/Makefile
  2. +6
    -0
      Builds/MacOSX/Juce.xcodeproj/project.pbxproj
  3. +2
    -0
      Builds/VisualStudio2005/Juce.vcproj
  4. +2
    -0
      Builds/VisualStudio2008/Juce.vcproj
  5. +2
    -0
      Builds/VisualStudio2008_DLL/Juce.vcproj
  6. +2
    -0
      Builds/VisualStudio2010/Juce.vcxproj
  7. +6
    -0
      Builds/VisualStudio2010/Juce.vcxproj.filters
  8. +6
    -0
      Builds/iPhone/Juce.xcodeproj/project.pbxproj
  9. +4
    -0
      Juce.jucer
  10. +1
    -0
      amalgamation/juce_amalgamated_template.cpp
  11. +12
    -9
      extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.cpp
  12. +2
    -2
      extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.h
  13. +1
    -1
      extras/audio plugins/demo/Source/PluginEditor.h
  14. +1045
    -397
      juce_amalgamated.cpp
  15. +282
    -198
      juce_amalgamated.h
  16. +1
    -1
      src/audio/audio_sources/juce_AudioFormatReaderSource.cpp
  17. +1
    -1
      src/audio/audio_sources/juce_AudioFormatReaderSource.h
  18. +17
    -1
      src/audio/audio_sources/juce_AudioSource.h
  19. +3
    -0
      src/audio/audio_sources/juce_PositionableAudioSource.h
  20. +1525
    -1525
      src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm
  21. +949
    -0
      src/containers/juce_Expression.cpp
  22. +216
    -0
      src/containers/juce_Expression.h
  23. +1
    -1
      src/core/juce_PlatformDefs.h
  24. +1
    -1
      src/core/juce_StandardHeader.h
  25. +2
    -1
      src/gui/components/controls/juce_ComboBox.h
  26. +3
    -3
      src/gui/components/controls/juce_TableListBox.cpp
  27. +4
    -0
      src/gui/components/windows/juce_CallOutBox.cpp
  28. +1
    -1
      src/gui/graphics/drawables/juce_Drawable.cpp
  29. +1
    -1
      src/gui/graphics/drawables/juce_Drawable.h
  30. +8
    -15
      src/gui/graphics/drawables/juce_DrawableComposite.cpp
  31. +2
    -2
      src/gui/graphics/drawables/juce_DrawableComposite.h
  32. +10
    -6
      src/gui/graphics/drawables/juce_DrawablePath.cpp
  33. +6
    -6
      src/gui/graphics/drawables/juce_DrawablePath.h
  34. +103
    -369
      src/gui/graphics/geometry/juce_RelativeCoordinate.cpp
  35. +46
    -171
      src/gui/graphics/geometry/juce_RelativeCoordinate.h
  36. +3
    -0
      src/juce_core_includes.h
  37. +4
    -2
      src/native/mac/juce_mac_OpenGLComponent.mm
  38. +1
    -2
      src/text/juce_XmlDocument.cpp

+ 6
- 0
Builds/Linux/Makefile View File

@@ -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"


+ 6
- 0
Builds/MacOSX/Juce.xcodeproj/project.pbxproj View File

@@ -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,


+ 2
- 0
Builds/VisualStudio2005/Juce.vcproj View File

@@ -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"/>


+ 2
- 0
Builds/VisualStudio2008/Juce.vcproj View File

@@ -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"/>


+ 2
- 0
Builds/VisualStudio2008_DLL/Juce.vcproj View File

@@ -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"/>


+ 2
- 0
Builds/VisualStudio2010/Juce.vcxproj View File

@@ -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"/>


+ 6
- 0
Builds/VisualStudio2010/Juce.vcxproj.filters View File

@@ -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>


+ 6
- 0
Builds/iPhone/Juce.xcodeproj/project.pbxproj View File

@@ -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,


+ 4
- 0
Juce.jucer View File

@@ -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"


+ 1
- 0
amalgamation/juce_amalgamated_template.cpp View File

@@ -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"


+ 12
- 9
extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.cpp View File

@@ -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)


+ 2
- 2
extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.h View File

@@ -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 */


+ 1
- 1
extras/audio plugins/demo/Source/PluginEditor.h View File

@@ -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:


+ 1045
- 397
juce_amalgamated.cpp
File diff suppressed because it is too large
View File


+ 282
- 198
juce_amalgamated.h View File

@@ -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;


+ 1
- 1
src/audio/audio_sources/juce_AudioFormatReaderSource.cpp View File

@@ -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;
}


+ 1
- 1
src/audio/audio_sources/juce_AudioFormatReaderSource.h View File

@@ -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; }


+ 17
- 1
src/audio/audio_sources/juce_AudioSource.h View File

@@ -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


+ 3
- 0
src/audio/audio_sources/juce_PositionableAudioSource.h View File

@@ -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; }
};


+ 1525
- 1525
src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm
File diff suppressed because it is too large
View File


+ 949
- 0
src/containers/juce_Expression.cpp View File

@@ -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

+ 216
- 0
src/containers/juce_Expression.h View File

@@ -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__

+ 1
- 1
src/core/juce_PlatformDefs.h View File

@@ -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..


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -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.


+ 2
- 1
src/gui/components/controls/juce_ComboBox.h View File

@@ -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,


+ 3
- 3
src/gui/components/controls/juce_TableListBox.cpp View File

@@ -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);


+ 4
- 0
src/gui/components/windows/juce_CallOutBox.cpp View File

@@ -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());


+ 1
- 1
src/gui/graphics/drawables/juce_Drawable.cpp View File

@@ -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());


+ 1
- 1
src/gui/graphics/drawables/juce_Drawable.h View File

@@ -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,


+ 8
- 15
src/gui/graphics/drawables/juce_DrawableComposite.cpp View File

@@ -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)


+ 2
- 2
src/gui/graphics/drawables/juce_DrawableComposite.h View File

@@ -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. */


+ 10
- 6
src/gui/graphics/drawables/juce_DrawablePath.cpp View File

@@ -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());


+ 6
- 6
src/gui/graphics/drawables/juce_DrawablePath.h View File

@@ -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;


+ 103
- 369
src/gui/graphics/geometry/juce_RelativeCoordinate.cpp View File

@@ -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);


+ 46
- 171
src/gui/graphics/geometry/juce_RelativeCoordinate.h View File

@@ -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();


+ 3
- 0
src/juce_core_includes.h View File

@@ -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


+ 4
- 2
src/native/mac/juce_mac_OpenGLComponent.mm View File

@@ -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();
}


+ 1
- 2
src/text/juce_XmlDocument.cpp View File

@@ -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;


Loading…
Cancel
Save