@@ -68,7 +68,6 @@ OBJECTS := \ | |||
$(OBJDIR)/jucer_ProjectTreeViewBase.o \ | |||
$(OBJDIR)/jucer_TreeViewTypes.o \ | |||
$(OBJDIR)/jucer_CodeHelpers.o \ | |||
$(OBJDIR)/jucer_Coordinate.o \ | |||
$(OBJDIR)/jucer_FileHelpers.o \ | |||
$(OBJDIR)/jucer_StoredSettings.o \ | |||
$(OBJDIR)/jucer_MiscUtilities.o \ | |||
@@ -96,177 +95,172 @@ clean: | |||
$(OBJDIR)/jucer_CodeGenerator.o: ../../Source/model/Component/jucer_CodeGenerator.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_CodeGenerator.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ComponentDocument.o: ../../Source/model/Component/jucer_ComponentDocument.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ComponentDocument.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ComponentTypeManager.o: ../../Source/model/Component/Types/jucer_ComponentTypeManager.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ComponentTypeManager.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_DrawableDocument.o: ../../Source/model/Drawable/jucer_DrawableDocument.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_DrawableDocument.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_NewFileWizard.o: ../../Source/model/Project/jucer_NewFileWizard.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_NewFileWizard.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_Project.o: ../../Source/model/Project/jucer_Project.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_Project.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ProjectExporter.o: ../../Source/model/Project/jucer_ProjectExporter.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ProjectExporter.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ProjectWizard.o: ../../Source/model/Project/jucer_ProjectWizard.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ProjectWizard.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ResourceFile.o: ../../Source/model/Project/jucer_ResourceFile.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ResourceFile.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_SourceCodeEditor.o: ../../Source/ui/Code\ Editor/jucer_SourceCodeEditor.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_SourceCodeEditor.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ComponentEditor.o: ../../Source/ui/Component\ Editor/jucer_ComponentEditor.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ComponentEditor.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ComponentViewer.o: ../../Source/ui/Component\ Editor/jucer_ComponentViewer.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ComponentViewer.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_DrawableEditor.o: ../../Source/ui/Drawable\ Editor/jucer_DrawableEditor.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_DrawableEditor.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_EditorCanvas.o: ../../Source/ui/Editor\ Base/jucer_EditorCanvas.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_EditorCanvas.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_DocumentEditorComponent.o: ../../Source/ui/jucer_DocumentEditorComponent.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_DocumentEditorComponent.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_JucerTreeViewBase.o: ../../Source/ui/jucer_JucerTreeViewBase.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_JucerTreeViewBase.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_MainWindow.o: ../../Source/ui/jucer_MainWindow.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_MainWindow.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_OpenDocumentManager.o: ../../Source/ui/jucer_OpenDocumentManager.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_OpenDocumentManager.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_GroupInformationComponent.o: ../../Source/ui/Project\ Editor/jucer_GroupInformationComponent.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_GroupInformationComponent.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ItemPreviewComponent.o: ../../Source/ui/Project\ Editor/jucer_ItemPreviewComponent.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ItemPreviewComponent.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ProjectContentComponent.o: ../../Source/ui/Project\ Editor/jucer_ProjectContentComponent.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ProjectContentComponent.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ProjectInformationComponent.o: ../../Source/ui/Project\ Editor/jucer_ProjectInformationComponent.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ProjectInformationComponent.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_ProjectTreeViewBase.o: ../../Source/ui/Project\ Editor/jucer_ProjectTreeViewBase.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_ProjectTreeViewBase.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_TreeViewTypes.o: ../../Source/ui/Project\ Editor/jucer_TreeViewTypes.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_TreeViewTypes.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_CodeHelpers.o: ../../Source/utility/jucer_CodeHelpers.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_Coordinate.o: ../../Source/utility/jucer_Coordinate.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_CodeHelpers.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_FileHelpers.o: ../../Source/utility/jucer_FileHelpers.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_FileHelpers.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_StoredSettings.o: ../../Source/utility/jucer_StoredSettings.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_StoredSettings.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_MiscUtilities.o: ../../Source/utility/jucer_MiscUtilities.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_MiscUtilities.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/jucer_Main.o: ../../Source/jucer_Main.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling jucer_Main.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/BinaryData.o: ../../JuceLibraryCode/BinaryData.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling BinaryData.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode1.o: ../../JuceLibraryCode/JuceLibraryCode1.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode1.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode2.o: ../../JuceLibraryCode/JuceLibraryCode2.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode2.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode3.o: ../../JuceLibraryCode/JuceLibraryCode3.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode3.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode4.o: ../../JuceLibraryCode/JuceLibraryCode4.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode4.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
-include $(OBJECTS:%.o=%.d) |
@@ -42,7 +42,6 @@ | |||
984444E3B2947675DC7D65DA = { isa = PBXBuildFile; fileRef = 1FDE55685608689765ADC578; }; | |||
58BF60E87F9A8EDCACC5D1AE = { isa = PBXBuildFile; fileRef = 939E2A7946081DB4D21B89B6; }; | |||
28B94C4BB7B572E6F5419E5D = { isa = PBXBuildFile; fileRef = 78E0309CB6D5E7E80B5BED7D; }; | |||
5BF87265418D736250283182 = { isa = PBXBuildFile; fileRef = C7ADB43F83A83FFC08921A12; }; | |||
12C1D006503C664FF07F476F = { isa = PBXBuildFile; fileRef = 5533704F0D30A9C62058FEC7; }; | |||
DDAB225ABE572196882C3524 = { isa = PBXBuildFile; fileRef = 7A1CD936BD306A6E0BEFB046; }; | |||
92612DD3884793248F1EC45A = { isa = PBXBuildFile; fileRef = 49A1C43070A68985C25F34C7; }; | |||
@@ -85,6 +84,7 @@ | |||
E894E1F6D582678EE1F02763 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_Viewport.h; path = ../../Source/model/Component/Types/jucer_Viewport.h; sourceTree = SOURCE_ROOT; }; | |||
B1471E8698D193FBCF0DD13D = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_DrawableDocument.cpp; path = ../../Source/model/Drawable/jucer_DrawableDocument.cpp; sourceTree = SOURCE_ROOT; }; | |||
739F94CA6213B43D867AB0FD = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_DrawableDocument.h; path = ../../Source/model/Drawable/jucer_DrawableDocument.h; sourceTree = SOURCE_ROOT; }; | |||
BDE8CD9273E1B0D0E500D283 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_DrawableTypeHandler.h; path = ../../Source/model/Drawable/jucer_DrawableTypeHandler.h; sourceTree = SOURCE_ROOT; }; | |||
9DCB32BBD7053ACCB598CE79 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_NewFileWizard.cpp; path = ../../Source/model/Project/jucer_NewFileWizard.cpp; sourceTree = SOURCE_ROOT; }; | |||
201DF0B7B4AA3E03B1AA5144 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_NewFileWizard.h; path = ../../Source/model/Project/jucer_NewFileWizard.h; sourceTree = SOURCE_ROOT; }; | |||
4179D4C7BF616A4A3C3E11CA = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_Project.cpp; path = ../../Source/model/Project/jucer_Project.cpp; sourceTree = SOURCE_ROOT; }; | |||
@@ -143,8 +143,6 @@ | |||
9C58E022906C193862372BC1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_CodeHelpers.h; path = ../../Source/utility/jucer_CodeHelpers.h; sourceTree = SOURCE_ROOT; }; | |||
AAF3C58696944A256CA61730 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_ColourEditorComponent.h; path = ../../Source/utility/jucer_ColourEditorComponent.h; sourceTree = SOURCE_ROOT; }; | |||
9736236B5C4D6A16FC7E03AC = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_Colours.h; path = ../../Source/utility/jucer_Colours.h; sourceTree = SOURCE_ROOT; }; | |||
C7ADB43F83A83FFC08921A12 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_Coordinate.cpp; path = ../../Source/utility/jucer_Coordinate.cpp; sourceTree = SOURCE_ROOT; }; | |||
EFA0636FB8ABA3377AB6C6F4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_Coordinate.h; path = ../../Source/utility/jucer_Coordinate.h; sourceTree = SOURCE_ROOT; }; | |||
CC9A3046B8B9FCDFE2092F51 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_CoordinatePropertyComponent.h; path = ../../Source/utility/jucer_CoordinatePropertyComponent.h; sourceTree = SOURCE_ROOT; }; | |||
5533704F0D30A9C62058FEC7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_FileHelpers.cpp; path = ../../Source/utility/jucer_FileHelpers.cpp; sourceTree = SOURCE_ROOT; }; | |||
27E71DE11448E4D6721D5508 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_FileHelpers.h; path = ../../Source/utility/jucer_FileHelpers.h; sourceTree = SOURCE_ROOT; }; | |||
@@ -204,7 +202,8 @@ | |||
7C95A5CDB1B24D227D92749E ); name = Component; sourceTree = "<group>"; }; | |||
E70E3BE796E91EA86CFE10FE = { isa = PBXGroup; children = ( | |||
B1471E8698D193FBCF0DD13D, | |||
739F94CA6213B43D867AB0FD ); name = Drawable; sourceTree = "<group>"; }; | |||
739F94CA6213B43D867AB0FD, | |||
BDE8CD9273E1B0D0E500D283 ); name = Drawable; sourceTree = "<group>"; }; | |||
ADA17383E5554BCDF567AACC = { isa = PBXGroup; children = ( | |||
9DCB32BBD7053ACCB598CE79, | |||
201DF0B7B4AA3E03B1AA5144, | |||
@@ -280,8 +279,6 @@ | |||
9C58E022906C193862372BC1, | |||
AAF3C58696944A256CA61730, | |||
9736236B5C4D6A16FC7E03AC, | |||
C7ADB43F83A83FFC08921A12, | |||
EFA0636FB8ABA3377AB6C6F4, | |||
CC9A3046B8B9FCDFE2092F51, | |||
5533704F0D30A9C62058FEC7, | |||
27E71DE11448E4D6721D5508, | |||
@@ -438,7 +435,6 @@ | |||
984444E3B2947675DC7D65DA, | |||
58BF60E87F9A8EDCACC5D1AE, | |||
28B94C4BB7B572E6F5419E5D, | |||
5BF87265418D736250283182, | |||
12C1D006503C664FF07F476F, | |||
DDAB225ABE572196882C3524, | |||
92612DD3884793248F1EC45A, | |||
@@ -154,6 +154,7 @@ | |||
<Filter Name="Drawable"> | |||
<File RelativePath="..\..\Source\model\Drawable\jucer_DrawableDocument.cpp"/> | |||
<File RelativePath="..\..\Source\model\Drawable\jucer_DrawableDocument.h"/> | |||
<File RelativePath="..\..\Source\model\Drawable\jucer_DrawableTypeHandler.h"/> | |||
</Filter> | |||
<Filter Name="Project"> | |||
<File RelativePath="..\..\Source\model\Project\jucer_NewFileWizard.cpp"/> | |||
@@ -229,8 +230,6 @@ | |||
<File RelativePath="..\..\Source\utility\jucer_CodeHelpers.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_ColourEditorComponent.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_Colours.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_Coordinate.cpp"/> | |||
<File RelativePath="..\..\Source\utility\jucer_Coordinate.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_CoordinatePropertyComponent.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_FileHelpers.cpp"/> | |||
<File RelativePath="..\..\Source\utility\jucer_FileHelpers.h"/> | |||
@@ -154,6 +154,7 @@ | |||
<Filter Name="Drawable"> | |||
<File RelativePath="..\..\Source\model\Drawable\jucer_DrawableDocument.cpp"/> | |||
<File RelativePath="..\..\Source\model\Drawable\jucer_DrawableDocument.h"/> | |||
<File RelativePath="..\..\Source\model\Drawable\jucer_DrawableTypeHandler.h"/> | |||
</Filter> | |||
<Filter Name="Project"> | |||
<File RelativePath="..\..\Source\model\Project\jucer_NewFileWizard.cpp"/> | |||
@@ -229,8 +230,6 @@ | |||
<File RelativePath="..\..\Source\utility\jucer_CodeHelpers.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_ColourEditorComponent.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_Colours.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_Coordinate.cpp"/> | |||
<File RelativePath="..\..\Source\utility\jucer_Coordinate.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_CoordinatePropertyComponent.h"/> | |||
<File RelativePath="..\..\Source\utility\jucer_FileHelpers.cpp"/> | |||
<File RelativePath="..\..\Source\utility\jucer_FileHelpers.h"/> | |||
@@ -72,6 +72,8 @@ | |||
file="Source/model/Drawable/jucer_DrawableDocument.cpp"/> | |||
<FILE id="qMcrWuCal" name="jucer_DrawableDocument.h" compile="0" resource="0" | |||
file="Source/model/Drawable/jucer_DrawableDocument.h"/> | |||
<FILE id="tGjXOXiR9" name="jucer_DrawableTypeHandler.h" compile="0" | |||
resource="0" file="Source/model/Drawable/jucer_DrawableTypeHandler.h"/> | |||
</GROUP> | |||
<GROUP id="na25KSPIj" name="Project"> | |||
<FILE id="jqL1mb9xp" name="jucer_NewFileWizard.cpp" compile="1" resource="0" | |||
@@ -205,10 +207,6 @@ | |||
resource="0" file="Source/utility/jucer_ColourEditorComponent.h"/> | |||
<FILE id="bjibbvm3S" name="jucer_Colours.h" compile="0" resource="0" | |||
file="Source/utility/jucer_Colours.h"/> | |||
<FILE id="bDebnoSX" name="jucer_Coordinate.cpp" compile="1" resource="0" | |||
file="Source/utility/jucer_Coordinate.cpp"/> | |||
<FILE id="uqXX3Ga6S" name="jucer_Coordinate.h" compile="0" resource="0" | |||
file="Source/utility/jucer_Coordinate.h"/> | |||
<FILE id="DDCunFHcy" name="jucer_CoordinatePropertyComponent.h" compile="0" | |||
resource="0" file="Source/utility/jucer_CoordinatePropertyComponent.h"/> | |||
<FILE id="WlEYep7NN" name="jucer_FileHelpers.cpp" compile="1" resource="0" | |||
@@ -40,7 +40,7 @@ public: | |||
//============================================================================== | |||
ComponentBoundsEditor (ComponentDocument& document_, const String& name, Type type_, | |||
const ValueTree& compState_, const Value& coordValue_) | |||
: CoordinatePropertyComponent (document_, name, | |||
: CoordinatePropertyComponent (&document_, name, | |||
Value (new CoordExtractor (coordValue_, type_)), | |||
type_ == left || type_ == right), | |||
document (document_), | |||
@@ -184,7 +184,7 @@ Component* ComponentTypeManager::createFromStoredType (ComponentDocument& docume | |||
ComponentTypeHandler* ComponentTypeManager::getHandlerFor (const Identifier& type) | |||
{ | |||
for (int i = handlers.size(); --i >= 0;) | |||
if (handlers.getUnchecked(i)->getXmlTag() == type) | |||
if (handlers.getUnchecked(i)->getValueTreeType() == type) | |||
return handlers.getUnchecked(i); | |||
return 0; | |||
@@ -205,8 +205,8 @@ juce_ImplementSingleton_SingleThreaded (ComponentTypeManager); | |||
//============================================================================== | |||
ComponentTypeHandler::ComponentTypeHandler (const String& displayName_, const String& className_, | |||
const String& xmlTag_, const String& memberNameRoot_) | |||
: displayName (displayName_), className (className_), xmlTag (xmlTag_), | |||
const Identifier& valueTreeType_, const String& memberNameRoot_) | |||
: displayName (displayName_), className (className_), valueTreeType (valueTreeType_), | |||
memberNameRoot (memberNameRoot_) | |||
{ | |||
} | |||
@@ -315,7 +315,7 @@ void ComponentTypeInstance::initialiseNewItemBasics() | |||
void ComponentTypeInstance::updateComponentBasics (Component* comp) | |||
{ | |||
RelativeRectangle pos (state [ComponentDocument::compBoundsProperty].toString()); | |||
comp->setBounds (pos.resolve (document).getSmallestIntegerContainer()); | |||
comp->setBounds (pos.resolve (&document).getSmallestIntegerContainer()); | |||
//comp->setName (state [ComponentDocument::compNameProperty]); | |||
@@ -86,11 +86,12 @@ class ComponentTypeHandler | |||
{ | |||
public: | |||
//============================================================================== | |||
ComponentTypeHandler (const String& displayName_, const String& className_, const String& xmlTag_, const String& memberNameRoot_); | |||
ComponentTypeHandler (const String& displayName_, const String& className_, | |||
const Identifier& valueTreeType_, const String& memberNameRoot_); | |||
virtual ~ComponentTypeHandler(); | |||
const String& getDisplayName() const { return displayName; } | |||
const Identifier& getXmlTag() const { return xmlTag; } | |||
const Identifier& getValueTreeType() const { return valueTreeType; } | |||
const String& getMemberNameRoot() const { return memberNameRoot; } | |||
virtual Component* createComponent() = 0; | |||
@@ -106,7 +107,7 @@ public: | |||
protected: | |||
//============================================================================== | |||
const String displayName, className, memberNameRoot; | |||
const Identifier xmlTag; | |||
const Identifier valueTreeType; | |||
private: | |||
ComponentTypeHandler (const ComponentTypeHandler&); | |||
@@ -359,7 +359,7 @@ const ValueTree ComponentDocument::performNewComponentMenuItem (int menuResultCo | |||
if (handler != 0) | |||
{ | |||
ValueTree state (handler->getXmlTag()); | |||
ValueTree state (handler->getValueTreeType()); | |||
state.setProperty (idProperty, createAlphaNumericUID(), 0); | |||
ComponentTypeInstance comp (*this, state); | |||
@@ -532,7 +532,7 @@ void ComponentDocument::renameAnchor (const String& oldName, const String& newNa | |||
{ | |||
ValueTree v (getComponent(i)); | |||
RelativeRectangle coords (getCoordsFor (v)); | |||
coords.renameAnchorIfUsed (oldName, newName, *this); | |||
coords.renameAnchorIfUsed (oldName, newName, this); | |||
setCoordsFor (v, coords); | |||
} | |||
@@ -551,7 +551,7 @@ void ComponentDocument::addMarkerMenuItem (int i, const RelativeCoordinate& coor | |||
name << '.' << edge; | |||
menu.addItem (i, name, | |||
! (name == fullCoordName || requestedCoord.references (fullCoordName, *this)), | |||
! (name == fullCoordName || requestedCoord.references (fullCoordName, this)), | |||
name == (isAnchor1 ? coord.getAnchorName1() : coord.getAnchorName2())); | |||
} | |||
@@ -780,7 +780,7 @@ bool ComponentDocument::MarkerList::createProperties (Array <PropertyComponent*> | |||
props.add (new TextPropertyComponent (Value (new MarkerListBase::MarkerNameValueSource (this, getNameAsValue (marker))), | |||
"Marker Name", 256, false)); | |||
props.add (new MarkerListBase::PositionPropertyComponent (document, *this, "Position", marker, | |||
props.add (new MarkerListBase::PositionPropertyComponent (&document, *this, "Position", marker, | |||
marker.getPropertyAsValue (getMarkerPosProperty(), document.getUndoManager()))); | |||
return true; | |||
} | |||
@@ -28,7 +28,6 @@ | |||
#include "../../jucer_Headers.h" | |||
#include "../Project/jucer_Project.h" | |||
#include "../../utility/jucer_Coordinate.h" | |||
#include "../../utility/jucer_MarkerListBase.h" | |||
#include "jucer_CodeGenerator.h" | |||
@@ -24,6 +24,54 @@ | |||
*/ | |||
#include "jucer_DrawableDocument.h" | |||
#include "jucer_DrawableTypeHandler.h" | |||
//============================================================================== | |||
class DrawableTypeManager : public DeletedAtShutdown | |||
{ | |||
public: | |||
DrawableTypeManager() | |||
{ | |||
handlers.add (new DrawablePathHandler()); | |||
handlers.add (new DrawableImageHandler()); | |||
} | |||
~DrawableTypeManager() | |||
{ | |||
} | |||
juce_DeclareSingleton_SingleThreaded_Minimal (DrawableTypeManager); | |||
//============================================================================== | |||
int getNumHandlers() const { return handlers.size(); } | |||
DrawableTypeHandler* getHandler (const int index) const { return handlers[index]; } | |||
DrawableTypeHandler* getHandlerFor (const Identifier& type) | |||
{ | |||
for (int i = handlers.size(); --i >= 0;) | |||
if (handlers.getUnchecked(i)->getValueTreeType() == type) | |||
return handlers.getUnchecked(i); | |||
jassertfalse; | |||
return 0; | |||
} | |||
const StringArray getDisplayNames() | |||
{ | |||
StringArray s; | |||
for (int i = 0; i < handlers.size(); ++i) | |||
s.add (handlers.getUnchecked(i)->getDisplayName()); | |||
return s; | |||
} | |||
private: | |||
OwnedArray <DrawableTypeHandler> handlers; | |||
}; | |||
juce_ImplementSingleton_SingleThreaded (DrawableTypeManager); | |||
//============================================================================== | |||
@@ -55,9 +103,9 @@ DrawableDocument::~DrawableDocument() | |||
root.removeListener (this); | |||
} | |||
ValueTree DrawableDocument::getRootDrawableNode() const | |||
DrawableComposite::ValueTreeWrapper DrawableDocument::getRootDrawableNode() const | |||
{ | |||
return root.getChild (0); | |||
return DrawableComposite::ValueTreeWrapper (root.getChild (0)); | |||
} | |||
void DrawableDocument::checkRootObject() | |||
@@ -75,11 +123,6 @@ void DrawableDocument::checkRootObject() | |||
getCanvasHeight() = 500; | |||
} | |||
const String DrawableDocument::getIdFor (const ValueTree& object) | |||
{ | |||
return object [Ids::id_]; | |||
} | |||
//============================================================================== | |||
void DrawableDocument::setName (const String& name) | |||
{ | |||
@@ -194,59 +237,49 @@ void DrawableDocument::changed() | |||
} | |||
//============================================================================== | |||
static const Colour getRandomColour() | |||
{ | |||
return Colours::red.withHue (Random::getSystemRandom().nextFloat()); | |||
} | |||
const int menuItemOffset = 0x63451fa4; | |||
void DrawableDocument::addDrawable (Drawable& d) | |||
void DrawableDocument::addNewItemMenuItems (PopupMenu& menu) const | |||
{ | |||
DrawableComposite dc; | |||
dc.insertDrawable (d.createCopy()); | |||
ValueTree dcNode (dc.createValueTree (0)); | |||
ValueTree subNode (dcNode.getChild(0)); | |||
dcNode.removeChild (subNode, 0); | |||
addMissingIds (subNode); | |||
const StringArray displayNames (DrawableTypeManager::getInstance()->getDisplayNames()); | |||
getRootDrawableNode().addChild (subNode, -1, getUndoManager()); | |||
for (int i = 0; i < displayNames.size(); ++i) | |||
menu.addItem (i + menuItemOffset, "New " + displayNames[i]); | |||
} | |||
void DrawableDocument::addRectangle() | |||
const ValueTree DrawableDocument::performNewItemMenuItem (int menuResultCode) | |||
{ | |||
Path p; | |||
p.addRectangle ((float) Random::getSystemRandom().nextInt (500), | |||
(float) Random::getSystemRandom().nextInt (500), | |||
100.0f, 100.0f); | |||
const StringArray displayNames (DrawableTypeManager::getInstance()->getDisplayNames()); | |||
DrawablePath d; | |||
d.setPath (p); | |||
d.setFill (FillType (getRandomColour())); | |||
if (menuResultCode >= menuItemOffset && menuResultCode < menuItemOffset + displayNames.size()) | |||
{ | |||
DrawableTypeHandler* handler = DrawableTypeManager::getInstance()->getHandler (menuResultCode - menuItemOffset); | |||
jassert (handler != 0); | |||
addDrawable (d); | |||
} | |||
if (handler != 0) | |||
{ | |||
ValueTree state (handler->createNewInstance (*this, | |||
Point<float> (Random::getSystemRandom().nextFloat() * 100.0f + 100.0f, | |||
Random::getSystemRandom().nextFloat() * 100.0f + 100.0f))); | |||
void DrawableDocument::addCircle() | |||
{ | |||
Path p; | |||
p.addEllipse ((float) Random::getSystemRandom().nextInt (500), | |||
(float) Random::getSystemRandom().nextInt (500), | |||
100.0f, 100.0f); | |||
getRootDrawableNode().addDrawable (state, -1, getUndoManager()); | |||
DrawablePath d; | |||
d.setPath (p); | |||
d.setFill (FillType (getRandomColour())); | |||
return state; | |||
} | |||
} | |||
addDrawable (d); | |||
return ValueTree::invalid; | |||
} | |||
void DrawableDocument::addImage (const File& imageFile) | |||
//============================================================================== | |||
Image* DrawableDocument::getImageForIdentifier (const var& imageIdentifier) | |||
{ | |||
jassertfalse | |||
DrawableImage d; | |||
return ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize); | |||
} | |||
addDrawable (d); | |||
const var DrawableDocument::getIdentifierForImage (Image* image) | |||
{ | |||
return var::null; //xxx todo | |||
} | |||
//============================================================================== | |||
@@ -28,13 +28,13 @@ | |||
#include "../../jucer_Headers.h" | |||
#include "../Project/jucer_Project.h" | |||
#include "../../utility/jucer_Coordinate.h" | |||
#include "../../utility/jucer_MarkerListBase.h" | |||
//============================================================================== | |||
class DrawableDocument : public ValueTree::Listener, | |||
public ChangeBroadcaster | |||
public ChangeBroadcaster, | |||
public Drawable::ImageProvider | |||
{ | |||
public: | |||
//============================================================================== | |||
@@ -51,16 +51,13 @@ public: | |||
void changed(); | |||
ValueTree& getRoot() { return root; } | |||
ValueTree getRootDrawableNode() const; | |||
void addRectangle(); | |||
void addCircle(); | |||
void addImage (const File& imageFile); | |||
DrawableComposite::ValueTreeWrapper getRootDrawableNode() const; | |||
Value getCanvasWidth() const { return getRootValueNonUndoable (Ids::width); } | |||
Value getCanvasHeight() const { return getRootValueNonUndoable (Ids::height); } | |||
static const String getIdFor (const ValueTree& object); | |||
void addNewItemMenuItems (PopupMenu& menu) const; | |||
const ValueTree performNewItemMenuItem (int menuResultCode); | |||
//============================================================================== | |||
class MarkerList : public MarkerListBase | |||
@@ -91,6 +88,9 @@ public: | |||
const String getNonexistentMarkerName (const String& name); | |||
void renameAnchor (const String& oldName, const String& newName); | |||
Image* getImageForIdentifier (const var& imageIdentifier); | |||
const var getIdentifierForImage (Image* image); | |||
//============================================================================== | |||
void valueTreePropertyChanged (ValueTree& tree, const Identifier& name); | |||
void valueTreeChildrenChanged (ValueTree& tree); | |||
@@ -0,0 +1,103 @@ | |||
/* | |||
============================================================================== | |||
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 __JUCER_DRAWABLETYPEHANDLER_H_7FB02E2F__ | |||
#define __JUCER_DRAWABLETYPEHANDLER_H_7FB02E2F__ | |||
#include "jucer_DrawableDocument.h" | |||
//============================================================================== | |||
class DrawableTypeHandler | |||
{ | |||
public: | |||
DrawableTypeHandler (const String& displayName_, const Identifier& valueTreeType_) | |||
: displayName (displayName_), valueTreeType (valueTreeType_) | |||
{ | |||
} | |||
virtual ~DrawableTypeHandler() {} | |||
virtual const ValueTree createNewInstance (DrawableDocument& document, const Point<float>& approxPosition) = 0; | |||
const String& getDisplayName() const { return displayName; } | |||
const Identifier& getValueTreeType() const { return valueTreeType; } | |||
private: | |||
const String displayName; | |||
const Identifier valueTreeType; | |||
}; | |||
//============================================================================== | |||
class DrawablePathHandler : public DrawableTypeHandler | |||
{ | |||
public: | |||
DrawablePathHandler() : DrawableTypeHandler ("Polygon", DrawablePath::valueTreeType) {} | |||
~DrawablePathHandler() {} | |||
const ValueTree createNewInstance (DrawableDocument& document, const Point<float>& approxPosition) | |||
{ | |||
Path p; | |||
p.addTriangle (approxPosition.getX(), approxPosition.getY() - 50.0f, | |||
approxPosition.getX() + 50.0f, approxPosition.getY() + 20.0f, | |||
approxPosition.getX() - 50.0f, approxPosition.getY() + 20.0f); | |||
DrawablePath dp; | |||
dp.setPath (p); | |||
dp.setFill (Colours::lightblue.withHue (Random::getSystemRandom().nextFloat())); | |||
return dp.createValueTree (0); | |||
} | |||
}; | |||
//============================================================================== | |||
class DrawableImageHandler : public DrawableTypeHandler | |||
{ | |||
public: | |||
DrawableImageHandler() : DrawableTypeHandler ("Image", DrawableImage::valueTreeType) {} | |||
~DrawableImageHandler() {} | |||
const ValueTree createNewInstance (DrawableDocument& document, const Point<float>& approxPosition) | |||
{ | |||
Image tempImage (Image::ARGB, 100, 100, true); | |||
{ | |||
Graphics g (tempImage); | |||
g.fillAll (Colours::grey.withAlpha (0.3f)); | |||
g.setColour (Colours::red); | |||
g.setFont (40.0f); | |||
g.drawText ("?", 0, 0, 100, 100, Justification::centred, false); | |||
} | |||
DrawableImage di; | |||
di.setTransform (RelativePoint (approxPosition), | |||
RelativePoint (approxPosition + Point<float> (100.0f, 0.0f)), | |||
RelativePoint (approxPosition + Point<float> (0.0f, 100.0f))); | |||
return di.createValueTree (&document); | |||
} | |||
}; | |||
#endif // __JUCER_DRAWABLETYPEHANDLER_H_7FB02E2F__ |
@@ -298,7 +298,7 @@ private: | |||
out << "$(OBJDIR)/" << escapeSpaces (getObjectFileFor (files.getReference(i))) | |||
<< ": " << escapeSpaces (files.getReference(i).toUnixStyle()) << newLine | |||
<< "\t-@mkdir -p $(OBJDIR)" << newLine | |||
<< "\t@echo $(notdir $<)" << newLine | |||
<< "\t@echo \"Compiling " << files.getReference(i).getFileName() << "\"" << newLine | |||
<< (files.getReference(i).hasFileExtension (".c") ? "\t@$(CC) $(CFLAGS) -o \"$@\" -c \"$<\"" | |||
: "\t@$(CXX) $(CXXFLAGS) -o \"$@\" -c \"$<\"") | |||
<< newLine << newLine; | |||
@@ -120,7 +120,7 @@ public: | |||
const Rectangle<int> getObjectPosition (const ValueTree& state) | |||
{ | |||
return getDocument().getCoordsFor (state).resolve (getDocument()).getSmallestIntegerContainer(); | |||
return getDocument().getCoordsFor (state).resolve (&getDocument()).getSmallestIntegerContainer(); | |||
} | |||
RelativeRectangle getObjectCoords (const ValueTree& state) | |||
@@ -176,14 +176,14 @@ public: | |||
const Rectangle<float> getObjectPosition (const ValueTree& state) | |||
{ | |||
ComponentDocument& doc = getDocument(); | |||
return doc.getCoordsFor (state).resolve (doc); | |||
return doc.getCoordsFor (state).resolve (&doc); | |||
} | |||
bool setObjectPosition (ValueTree& state, const Rectangle<float>& newBounds) | |||
{ | |||
ComponentDocument& doc = getDocument(); | |||
RelativeRectangle pr (doc.getCoordsFor (state)); | |||
pr.moveToAbsolute (newBounds, doc); | |||
pr.moveToAbsolute (newBounds, &doc); | |||
return doc.setCoordsFor (state, pr); | |||
} | |||
@@ -191,7 +191,7 @@ public: | |||
float getMarkerPosition (const ValueTree& marker, bool isX) | |||
{ | |||
ComponentDocument& doc = getDocument(); | |||
return (float) doc.getMarkerList (isX).getCoordinate (marker).resolve (doc); | |||
return (float) doc.getMarkerList (isX).getCoordinate (marker).resolve (&doc); | |||
} | |||
}; | |||
@@ -80,7 +80,7 @@ void ComponentViewer::handleAsyncUpdate() | |||
background = Colour::fromString (componentDocument->getBackgroundColour().toString()); | |||
if (layoutManager == 0) | |||
layoutManager = new ComponentAutoLayoutManager (this); | |||
layoutManager = new RelativeRectangleLayoutManager (this); | |||
int i; | |||
for (i = getNumChildComponents(); --i >= 0;) | |||
@@ -62,7 +62,7 @@ private: | |||
ComponentDocument* componentDocument; | |||
ValueTree documentRoot; | |||
ScopedPointer<ComponentAutoLayoutManager> layoutManager; | |||
ScopedPointer<RelativeRectangleLayoutManager> layoutManager; | |||
Colour background; | |||
ComponentViewer (const ComponentViewer&); | |||
@@ -53,7 +53,7 @@ public: | |||
void createCanvas() | |||
{ | |||
initialise (new DrawableEditorCanvas (editor), toolbarFactory, | |||
new DrawableTreeViewItem (editor, editor.getDocument().getRootDrawableNode())); | |||
new DrawableTreeViewItem (editor, editor.getDocument().getRootDrawableNode().getState())); | |||
} | |||
SelectedItemSet<String>& getSelection() | |||
@@ -117,17 +117,10 @@ void DrawableEditor::selectionToBack() | |||
void DrawableEditor::showNewShapeMenu (Component* componentToAttachTo) | |||
{ | |||
/* | |||
PopupMenu m; | |||
getDocument().addNewComponentMenuItems (m); | |||
getDocument().addNewItemMenuItems (m); | |||
const int r = m.showAt (componentToAttachTo); | |||
const ValueTree newComp (getDocument().performNewComponentMenuItem (r)); | |||
if (newComp.isValid()) | |||
getSelection().selectOnly (newComp [ComponentDocument::idProperty]); | |||
*/ | |||
getDocument().performNewItemMenuItem (r); | |||
} | |||
//============================================================================== | |||
@@ -54,8 +54,19 @@ public: | |||
void updateComponents() | |||
{ | |||
drawable = Drawable::createFromValueTree (getEditor().getDocument().getRootDrawableNode(), 0); | |||
getComponentHolder()->repaint(); | |||
DrawableDocument& doc = getEditor().getDocument(); | |||
if (drawable == 0) | |||
{ | |||
drawable = Drawable::createFromValueTree (doc.getRootDrawableNode().getState(), &doc); | |||
getComponentHolder()->repaint(); | |||
} | |||
else | |||
{ | |||
const Rectangle<float> damage (drawable->refreshFromValueTree (doc.getRootDrawableNode().getState(), &doc)); | |||
getComponentHolder()->repaint (damage.getSmallestIntegerContainer()); | |||
} | |||
startTimer (500); | |||
} | |||
@@ -89,9 +100,9 @@ public: | |||
} | |||
else | |||
{ | |||
// getDocument().addNewComponentMenuItems (m); | |||
// const int r = m.show(); | |||
// getDocument().performNewComponentMenuItem (r); | |||
getDocument().addNewItemMenuItems (m); | |||
const int r = m.show(); | |||
getDocument().performNewItemMenuItem (r); | |||
} | |||
} | |||
@@ -38,14 +38,14 @@ public: | |||
DrawableTreeViewItem (DrawableEditor& editor_, const ValueTree& drawableRoot) | |||
: editor (editor_), node (drawableRoot), typeName (drawableRoot.getType().toString()) | |||
{ | |||
node.addListener (this); | |||
node.getState().addListener (this); | |||
editor.getSelection().addChangeListener (this); | |||
} | |||
~DrawableTreeViewItem() | |||
{ | |||
editor.getSelection().removeChangeListener (this); | |||
node.removeListener (this); | |||
node.getState().removeListener (this); | |||
} | |||
//============================================================================== | |||
@@ -55,7 +55,7 @@ public: | |||
void valueTreeChildrenChanged (ValueTree& tree) | |||
{ | |||
if (tree == node) | |||
if (tree == node.getState()) | |||
refreshSubItems(); | |||
} | |||
@@ -67,14 +67,13 @@ public: | |||
// TreeViewItem stuff.. | |||
bool mightContainSubItems() | |||
{ | |||
return node.getType() == DrawableComposite::valueTreeType | |||
&& node.getNumChildren() > 0; | |||
return node.getState().getType() == DrawableComposite::valueTreeType; | |||
} | |||
const String getUniqueName() const | |||
{ | |||
jassert (node [Ids::id_].toString().isNotEmpty()); | |||
return node [Ids::id_]; | |||
jassert (node.getID().isNotEmpty()); | |||
return node.getID(); | |||
} | |||
void itemOpennessChanged (bool isNowOpen) | |||
@@ -85,15 +84,17 @@ public: | |||
void refreshSubItems() | |||
{ | |||
if (node.getType() == DrawableComposite::valueTreeType) | |||
if (node.getState().getType() == DrawableComposite::valueTreeType) | |||
{ | |||
ScopedPointer <XmlElement> oldOpenness (getOpennessState()); | |||
clearSubItems(); | |||
for (int i = 0; i < node.getNumChildren(); ++i) | |||
DrawableComposite::ValueTreeWrapper composite (node.getState()); | |||
for (int i = 0; i < composite.getNumDrawables(); ++i) | |||
{ | |||
ValueTree subNode (node.getChild (i)); | |||
ValueTree subNode (composite.getDrawableState (i)); | |||
DrawableTreeViewItem* const item = new DrawableTreeViewItem (editor, subNode); | |||
addSubItem (item); | |||
} | |||
@@ -114,7 +115,7 @@ public: | |||
const String getRenamingName() const | |||
{ | |||
return node ["name"]; | |||
return node.getID(); | |||
} | |||
void setName (const String& newName) | |||
@@ -138,7 +139,7 @@ public: | |||
void itemSelectionChanged (bool isNowSelected) | |||
{ | |||
const String objectId (DrawableDocument::getIdFor (node)); | |||
const String objectId (node.getID()); | |||
if (isNowSelected) | |||
editor.getSelection().addToSelection (objectId); | |||
@@ -148,7 +149,7 @@ public: | |||
void changeListenerCallback (void*) | |||
{ | |||
setSelected (editor.getSelection().isSelected (DrawableDocument::getIdFor (node)), false); | |||
setSelected (editor.getSelection().isSelected (node.getID()), false); | |||
} | |||
const String getTooltip() | |||
@@ -194,7 +195,7 @@ public: | |||
//============================================================================== | |||
DrawableEditor& editor; | |||
ValueTree node; | |||
Drawable::ValueTreeWrapperBase node; | |||
private: | |||
String typeName; | |||
@@ -243,7 +243,7 @@ public: | |||
void updatePosition() | |||
{ | |||
RelativeCoordinate coord (getMarkerList().getCoordinate (marker)); | |||
const int pos = roundToInt (coord.resolve (getMarkerList())); | |||
const int pos = roundToInt (coord.resolve (&getMarkerList())); | |||
const int width = 8; | |||
if (isX) | |||
@@ -309,7 +309,7 @@ public: | |||
canvas->getUndoManager().beginNewTransaction(); | |||
RelativeCoordinate coord (getMarkerList().getCoordinate (marker)); | |||
dragStartPos = coord.resolve (getMarkerList()); | |||
dragStartPos = coord.resolve (&getMarkerList()); | |||
} | |||
} | |||
@@ -335,7 +335,7 @@ public: | |||
// (can't use getDistanceFromDragStart() because it doesn't take into account auto-scrolling) | |||
coord.moveToAbsolute (jmax (0, roundToInt (dragStartPos + (isX ? e2.x - mouseDownPos.getX() | |||
: e2.y - mouseDownPos.getY()))), | |||
getMarkerList()); | |||
&getMarkerList()); | |||
getMarkerList().setCoordinate (marker, coord); | |||
} | |||
else | |||
@@ -26,10 +26,10 @@ | |||
#ifndef __JUCER_EDITORCANVAS_H_EF886D17__ | |||
#define __JUCER_EDITORCANVAS_H_EF886D17__ | |||
#include "../../utility/jucer_Coordinate.h" | |||
#include "../../utility/jucer_MarkerListBase.h" | |||
class EditorPanelBase; | |||
//============================================================================== | |||
class EditorCanvasBase : public Component, | |||
public ValueTree::Listener, | |||
@@ -1,167 +0,0 @@ | |||
/* | |||
============================================================================== | |||
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 "jucer_Coordinate.h" | |||
//============================================================================== | |||
ComponentAutoLayoutManager::ComponentAutoLayoutManager (Component* parentComponent) | |||
: parent (parentComponent) | |||
{ | |||
parent->addComponentListener (this); | |||
} | |||
ComponentAutoLayoutManager::~ComponentAutoLayoutManager() | |||
{ | |||
parent->removeComponentListener (this); | |||
for (int i = components.size(); --i >= 0;) | |||
components.getUnchecked(i)->component->removeComponentListener (this); | |||
} | |||
void ComponentAutoLayoutManager::setMarker (const String& name, const RelativeCoordinate& coord) | |||
{ | |||
for (int i = markers.size(); --i >= 0;) | |||
{ | |||
MarkerPosition* m = markers.getUnchecked(i); | |||
if (m->markerName == name) | |||
{ | |||
m->position = coord; | |||
applyLayout(); | |||
return; | |||
} | |||
} | |||
markers.add (new MarkerPosition (name, coord)); | |||
applyLayout(); | |||
} | |||
void ComponentAutoLayoutManager::setComponentBounds (Component* comp, const String& name, const RelativeRectangle& coords) | |||
{ | |||
jassert (comp != 0); | |||
// All the components that this layout manages must be inside the parent component.. | |||
jassert (parent->isParentOf (comp)); | |||
for (int i = components.size(); --i >= 0;) | |||
{ | |||
ComponentPosition* c = components.getUnchecked(i); | |||
if (c->component == comp) | |||
{ | |||
c->name = name; | |||
c->coords = coords; | |||
triggerAsyncUpdate(); | |||
return; | |||
} | |||
} | |||
components.add (new ComponentPosition (comp, name, coords)); | |||
comp->addComponentListener (this); | |||
triggerAsyncUpdate(); | |||
} | |||
void ComponentAutoLayoutManager::applyLayout() | |||
{ | |||
for (int i = components.size(); --i >= 0;) | |||
{ | |||
ComponentPosition* c = components.getUnchecked(i); | |||
// All the components that this layout manages must be inside the parent component.. | |||
jassert (parent->isParentOf (c->component)); | |||
c->component->setBounds (c->coords.resolve (*this).getSmallestIntegerContainer()); | |||
} | |||
} | |||
const RelativeCoordinate ComponentAutoLayoutManager::findNamedCoordinate (const String& objectName, const String& edge) const | |||
{ | |||
if (objectName == RelativeCoordinate::Strings::parent) | |||
{ | |||
if (edge == RelativeCoordinate::Strings::right) return RelativeCoordinate ((double) parent->getWidth(), true); | |||
if (edge == RelativeCoordinate::Strings::bottom) return RelativeCoordinate ((double) parent->getHeight(), false); | |||
} | |||
if (objectName.isNotEmpty() && edge.isNotEmpty()) | |||
{ | |||
for (int i = components.size(); --i >= 0;) | |||
{ | |||
ComponentPosition* c = components.getUnchecked(i); | |||
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; | |||
} | |||
} | |||
} | |||
for (int i = markers.size(); --i >= 0;) | |||
{ | |||
MarkerPosition* m = markers.getUnchecked(i); | |||
if (m->markerName == objectName) | |||
return m->position; | |||
} | |||
return RelativeCoordinate(); | |||
} | |||
void ComponentAutoLayoutManager::componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) | |||
{ | |||
triggerAsyncUpdate(); | |||
if (parent == &component) | |||
handleUpdateNowIfNeeded(); | |||
} | |||
void ComponentAutoLayoutManager::componentBeingDeleted (Component& component) | |||
{ | |||
for (int i = components.size(); --i >= 0;) | |||
{ | |||
ComponentPosition* c = components.getUnchecked(i); | |||
if (c->component == &component) | |||
{ | |||
components.remove (i); | |||
break; | |||
} | |||
} | |||
} | |||
void ComponentAutoLayoutManager::handleAsyncUpdate() | |||
{ | |||
applyLayout(); | |||
} | |||
ComponentAutoLayoutManager::MarkerPosition::MarkerPosition (const String& name, const RelativeCoordinate& coord) | |||
: markerName (name), position (coord) | |||
{ | |||
} | |||
ComponentAutoLayoutManager::ComponentPosition::ComponentPosition (Component* component_, const String& name_, const RelativeRectangle& coords_) | |||
: component (component_), name (name_), coords (coords_) | |||
{ | |||
} |
@@ -1,102 +0,0 @@ | |||
/* | |||
============================================================================== | |||
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 __JUCER_COORDINATE_H_EF56ACFA__ | |||
#define __JUCER_COORDINATE_H_EF56ACFA__ | |||
#include "../jucer_Headers.h" | |||
//============================================================================== | |||
/** | |||
*/ | |||
class ComponentAutoLayoutManager : public ComponentListener, | |||
public RelativeCoordinate::NamedCoordinateFinder, | |||
public AsyncUpdater | |||
{ | |||
public: | |||
//============================================================================== | |||
/** | |||
*/ | |||
ComponentAutoLayoutManager (Component* parentComponent); | |||
/** Destructor. */ | |||
~ComponentAutoLayoutManager(); | |||
//============================================================================== | |||
/** | |||
*/ | |||
void setMarker (const String& name, const RelativeCoordinate& coord); | |||
/** | |||
*/ | |||
void setComponentBounds (Component* component, const String& componentName, const RelativeRectangle& bounds); | |||
/** | |||
*/ | |||
void applyLayout(); | |||
//============================================================================== | |||
/** @internal */ | |||
const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const; | |||
/** @internal */ | |||
void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); | |||
/** @internal */ | |||
void componentBeingDeleted (Component& component); | |||
/** @internal */ | |||
void handleAsyncUpdate(); | |||
juce_UseDebuggingNewOperator | |||
private: | |||
//============================================================================== | |||
struct ComponentPosition | |||
{ | |||
ComponentPosition (Component* component, const String& name, const RelativeRectangle& coords); | |||
Component* component; | |||
String name; | |||
RelativeRectangle coords; | |||
}; | |||
struct MarkerPosition | |||
{ | |||
MarkerPosition (const String& name, const RelativeCoordinate& coord); | |||
String markerName; | |||
RelativeCoordinate position; | |||
}; | |||
Component* parent; | |||
OwnedArray <ComponentPosition> components; | |||
OwnedArray <MarkerPosition> markers; | |||
ComponentAutoLayoutManager (const ComponentAutoLayoutManager&); | |||
ComponentAutoLayoutManager& operator= (const ComponentAutoLayoutManager&); | |||
}; | |||
#endif // __JUCER_COORDINATE_H_EF56ACFA__ |
@@ -34,7 +34,7 @@ class CoordinatePropertyComponent : public PropertyComponent, | |||
{ | |||
public: | |||
//============================================================================== | |||
CoordinatePropertyComponent (RelativeCoordinate::NamedCoordinateFinder& nameSource_, const String& name, | |||
CoordinatePropertyComponent (RelativeCoordinate::NamedCoordinateFinder* nameSource_, const String& name, | |||
const Value& coordValue_, bool isHorizontal_) | |||
: PropertyComponent (name, 40), nameSource (nameSource_), | |||
coordValue (coordValue_), | |||
@@ -142,7 +142,7 @@ public: | |||
virtual const String pickMarker (TextButton* button, const String& currentMarker, bool isAnchor1) = 0; | |||
protected: | |||
RelativeCoordinate::NamedCoordinateFinder& nameSource; | |||
RelativeCoordinate::NamedCoordinateFinder* nameSource; | |||
Value coordValue, textValue; | |||
Label* label; | |||
TextButton* proportionButton; | |||
@@ -56,7 +56,7 @@ public: | |||
{ | |||
ValueTree v (getMarker (i)); | |||
RelativeCoordinate coord (getCoordinate (v)); | |||
coord.renameAnchorIfUsed (oldName, newName, *this); | |||
coord.renameAnchorIfUsed (oldName, newName, this); | |||
setCoordinate (v, coord); | |||
} | |||
} | |||
@@ -133,7 +133,7 @@ public: | |||
{ | |||
public: | |||
//============================================================================== | |||
PositionPropertyComponent (NamedCoordinateFinder& nameSource_, MarkerListBase& markerList_, | |||
PositionPropertyComponent (NamedCoordinateFinder* nameSource_, MarkerListBase& markerList_, | |||
const String& name, const ValueTree& markerState_, | |||
const Value& coordValue_) | |||
: CoordinatePropertyComponent (nameSource_, name, coordValue_, markerList_.isHorizontal()), | |||
@@ -266,3 +266,143 @@ void FloatingLabelComponent::paint (Graphics& g) | |||
g.setColour (colour); | |||
glyphs.draw (g, AffineTransform::translation (1.0f, 1.0f)); | |||
} | |||
//============================================================================== | |||
RelativeRectangleLayoutManager::RelativeRectangleLayoutManager (Component* parentComponent) | |||
: parent (parentComponent) | |||
{ | |||
parent->addComponentListener (this); | |||
} | |||
RelativeRectangleLayoutManager::~RelativeRectangleLayoutManager() | |||
{ | |||
parent->removeComponentListener (this); | |||
for (int i = components.size(); --i >= 0;) | |||
components.getUnchecked(i)->component->removeComponentListener (this); | |||
} | |||
void RelativeRectangleLayoutManager::setMarker (const String& name, const RelativeCoordinate& coord) | |||
{ | |||
for (int i = markers.size(); --i >= 0;) | |||
{ | |||
MarkerPosition* m = markers.getUnchecked(i); | |||
if (m->markerName == name) | |||
{ | |||
m->position = coord; | |||
applyLayout(); | |||
return; | |||
} | |||
} | |||
markers.add (new MarkerPosition (name, coord)); | |||
applyLayout(); | |||
} | |||
void RelativeRectangleLayoutManager::setComponentBounds (Component* comp, const String& name, const RelativeRectangle& coords) | |||
{ | |||
jassert (comp != 0); | |||
// All the components that this layout manages must be inside the parent component.. | |||
jassert (parent->isParentOf (comp)); | |||
for (int i = components.size(); --i >= 0;) | |||
{ | |||
ComponentPosition* c = components.getUnchecked(i); | |||
if (c->component == comp) | |||
{ | |||
c->name = name; | |||
c->coords = coords; | |||
triggerAsyncUpdate(); | |||
return; | |||
} | |||
} | |||
components.add (new ComponentPosition (comp, name, coords)); | |||
comp->addComponentListener (this); | |||
triggerAsyncUpdate(); | |||
} | |||
void RelativeRectangleLayoutManager::applyLayout() | |||
{ | |||
for (int i = components.size(); --i >= 0;) | |||
{ | |||
ComponentPosition* c = components.getUnchecked(i); | |||
// All the components that this layout manages must be inside the parent component.. | |||
jassert (parent->isParentOf (c->component)); | |||
c->component->setBounds (c->coords.resolve (this).getSmallestIntegerContainer()); | |||
} | |||
} | |||
const RelativeCoordinate RelativeRectangleLayoutManager::findNamedCoordinate (const String& objectName, const String& edge) const | |||
{ | |||
if (objectName == RelativeCoordinate::Strings::parent) | |||
{ | |||
if (edge == RelativeCoordinate::Strings::right) return RelativeCoordinate ((double) parent->getWidth(), true); | |||
if (edge == RelativeCoordinate::Strings::bottom) return RelativeCoordinate ((double) parent->getHeight(), false); | |||
} | |||
if (objectName.isNotEmpty() && edge.isNotEmpty()) | |||
{ | |||
for (int i = components.size(); --i >= 0;) | |||
{ | |||
ComponentPosition* c = components.getUnchecked(i); | |||
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; | |||
} | |||
} | |||
} | |||
for (int i = markers.size(); --i >= 0;) | |||
{ | |||
MarkerPosition* m = markers.getUnchecked(i); | |||
if (m->markerName == objectName) | |||
return m->position; | |||
} | |||
return RelativeCoordinate(); | |||
} | |||
void RelativeRectangleLayoutManager::componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) | |||
{ | |||
triggerAsyncUpdate(); | |||
if (parent == &component) | |||
handleUpdateNowIfNeeded(); | |||
} | |||
void RelativeRectangleLayoutManager::componentBeingDeleted (Component& component) | |||
{ | |||
for (int i = components.size(); --i >= 0;) | |||
{ | |||
ComponentPosition* c = components.getUnchecked(i); | |||
if (c->component == &component) | |||
{ | |||
components.remove (i); | |||
break; | |||
} | |||
} | |||
} | |||
void RelativeRectangleLayoutManager::handleAsyncUpdate() | |||
{ | |||
applyLayout(); | |||
} | |||
RelativeRectangleLayoutManager::MarkerPosition::MarkerPosition (const String& name, const RelativeCoordinate& coord) | |||
: markerName (name), position (coord) | |||
{ | |||
} | |||
RelativeRectangleLayoutManager::ComponentPosition::ComponentPosition (Component* component_, const String& name_, const RelativeRectangle& coords_) | |||
: component (component_), name (name_), coords (coords_) | |||
{ | |||
} |
@@ -136,3 +136,72 @@ private: | |||
JucerToolbarButton (const JucerToolbarButton&); | |||
JucerToolbarButton& operator= (const JucerToolbarButton&); | |||
}; | |||
//============================================================================== | |||
/** | |||
*/ | |||
class RelativeRectangleLayoutManager : public ComponentListener, | |||
public RelativeCoordinate::NamedCoordinateFinder, | |||
public AsyncUpdater | |||
{ | |||
public: | |||
//============================================================================== | |||
/** | |||
*/ | |||
RelativeRectangleLayoutManager (Component* parentComponent); | |||
/** Destructor. */ | |||
~RelativeRectangleLayoutManager(); | |||
//============================================================================== | |||
/** | |||
*/ | |||
void setMarker (const String& name, const RelativeCoordinate& coord); | |||
/** | |||
*/ | |||
void setComponentBounds (Component* component, const String& componentName, const RelativeRectangle& bounds); | |||
/** | |||
*/ | |||
void applyLayout(); | |||
//============================================================================== | |||
/** @internal */ | |||
const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const; | |||
/** @internal */ | |||
void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); | |||
/** @internal */ | |||
void componentBeingDeleted (Component& component); | |||
/** @internal */ | |||
void handleAsyncUpdate(); | |||
juce_UseDebuggingNewOperator | |||
private: | |||
//============================================================================== | |||
struct ComponentPosition | |||
{ | |||
ComponentPosition (Component* component, const String& name, const RelativeRectangle& coords); | |||
Component* component; | |||
String name; | |||
RelativeRectangle coords; | |||
}; | |||
struct MarkerPosition | |||
{ | |||
MarkerPosition (const String& name, const RelativeCoordinate& coord); | |||
String markerName; | |||
RelativeCoordinate position; | |||
}; | |||
Component* parent; | |||
OwnedArray <ComponentPosition> components; | |||
OwnedArray <MarkerPosition> markers; | |||
RelativeRectangleLayoutManager (const RelativeRectangleLayoutManager&); | |||
RelativeRectangleLayoutManager& operator= (const RelativeRectangleLayoutManager&); | |||
}; |
@@ -63,12 +63,12 @@ clean: | |||
$(OBJDIR)/Main.o: ../../Source/Main.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling Main.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode.o: ../../JuceLibraryCode/JuceLibraryCode.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
-include $(OBJECTS:%.o=%.d) |
@@ -70,47 +70,47 @@ clean: | |||
$(OBJDIR)/FilterGraph.o: ../../Source/FilterGraph.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling FilterGraph.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/GraphEditorPanel.o: ../../Source/GraphEditorPanel.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling GraphEditorPanel.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/HostStartup.o: ../../Source/HostStartup.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling HostStartup.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/InternalFilters.o: ../../Source/InternalFilters.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling InternalFilters.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/MainHostWindow.o: ../../Source/MainHostWindow.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling MainHostWindow.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode1.o: ../../JuceLibraryCode/JuceLibraryCode1.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode1.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode2.o: ../../JuceLibraryCode/JuceLibraryCode2.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode2.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode3.o: ../../JuceLibraryCode/JuceLibraryCode3.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode3.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode4.o: ../../JuceLibraryCode/JuceLibraryCode4.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode4.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
-include $(OBJECTS:%.o=%.d) |
@@ -63,12 +63,12 @@ clean: | |||
$(OBJDIR)/Main.o: ../../Source/Main.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling Main.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode.o: ../../JuceLibraryCode/JuceLibraryCode.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
-include $(OBJECTS:%.o=%.d) |
@@ -67,32 +67,32 @@ clean: | |||
$(OBJDIR)/Main.o: ../../Source/Main.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling Main.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/MainComponent.o: ../../Source/MainComponent.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling MainComponent.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode1.o: ../../JuceLibraryCode/JuceLibraryCode1.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode1.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode2.o: ../../JuceLibraryCode/JuceLibraryCode2.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode2.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode3.o: ../../JuceLibraryCode/JuceLibraryCode3.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode3.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode4.o: ../../JuceLibraryCode/JuceLibraryCode4.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode4.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
-include $(OBJECTS:%.o=%.d) |
@@ -87,132 +87,132 @@ clean: | |||
$(OBJDIR)/ApplicationStartup.o: ../../Source/ApplicationStartup.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling ApplicationStartup.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/MainDemoWindow.o: ../../Source/MainDemoWindow.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling MainDemoWindow.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/AudioDemoLatencyPage.o: ../../Source/demos/AudioDemoLatencyPage.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling AudioDemoLatencyPage.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/AudioDemoPlaybackPage.o: ../../Source/demos/AudioDemoPlaybackPage.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling AudioDemoPlaybackPage.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/AudioDemoRecordPage.o: ../../Source/demos/AudioDemoRecordPage.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling AudioDemoRecordPage.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/AudioDemoSetupPage.o: ../../Source/demos/AudioDemoSetupPage.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling AudioDemoSetupPage.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/AudioDemoSynthPage.o: ../../Source/demos/AudioDemoSynthPage.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling AudioDemoSynthPage.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/AudioDemoTabComponent.o: ../../Source/demos/AudioDemoTabComponent.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling AudioDemoTabComponent.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/CameraDemo.o: ../../Source/demos/CameraDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling CameraDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/CodeEditorDemo.o: ../../Source/demos/CodeEditorDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling CodeEditorDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/DragAndDropDemo.o: ../../Source/demos/DragAndDropDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling DragAndDropDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/FontsAndTextDemo.o: ../../Source/demos/FontsAndTextDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling FontsAndTextDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/InterprocessCommsDemo.o: ../../Source/demos/InterprocessCommsDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling InterprocessCommsDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/OpenGLDemo.o: ../../Source/demos/OpenGLDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling OpenGLDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/QuickTimeDemo.o: ../../Source/demos/QuickTimeDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling QuickTimeDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/RenderingTestComponent.o: ../../Source/demos/RenderingTestComponent.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling RenderingTestComponent.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/TableDemo.o: ../../Source/demos/TableDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling TableDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/ThreadingDemo.o: ../../Source/demos/ThreadingDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling ThreadingDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/TreeViewDemo.o: ../../Source/demos/TreeViewDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling TreeViewDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/WebBrowserDemo.o: ../../Source/demos/WebBrowserDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling WebBrowserDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/WidgetsDemo.o: ../../Source/demos/WidgetsDemo.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling WidgetsDemo.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/BinaryData.o: ../../JuceLibraryCode/BinaryData.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling BinaryData.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode1.o: ../../JuceLibraryCode/JuceLibraryCode1.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode1.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode2.o: ../../JuceLibraryCode/JuceLibraryCode2.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode2.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode3.o: ../../JuceLibraryCode/JuceLibraryCode3.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode3.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
$(OBJDIR)/JuceLibraryCode4.o: ../../JuceLibraryCode/JuceLibraryCode4.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo $(notdir $<) | |||
@echo "Compiling JuceLibraryCode4.cpp" | |||
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<" | |||
-include $(OBJECTS:%.o=%.d) |
@@ -150,7 +150,7 @@ public: | |||
return false; | |||
for (int i = numUsed; --i >= 0;) | |||
if (data.elements [i] != other.data.elements [i]) | |||
if (! (data.elements [i] == other.data.elements [i])) | |||
return false; | |||
return true; | |||
@@ -40,6 +40,11 @@ inline NamedValueSet::NamedValue::NamedValue (const Identifier& name_, const var | |||
{ | |||
} | |||
bool NamedValueSet::NamedValue::operator== (const NamedValueSet::NamedValue& other) const throw() | |||
{ | |||
return name == other.name && value == other.value; | |||
} | |||
//============================================================================== | |||
NamedValueSet::NamedValueSet() throw() | |||
{ | |||
@@ -60,6 +65,16 @@ NamedValueSet::~NamedValueSet() | |||
{ | |||
} | |||
bool NamedValueSet::operator== (const NamedValueSet& other) const | |||
{ | |||
return values == other.values; | |||
} | |||
bool NamedValueSet::operator!= (const NamedValueSet& other) const | |||
{ | |||
return ! operator== (other); | |||
} | |||
int NamedValueSet::size() const throw() | |||
{ | |||
return values.size(); | |||
@@ -51,6 +51,9 @@ public: | |||
/** Destructor. */ | |||
~NamedValueSet(); | |||
bool operator== (const NamedValueSet& other) const; | |||
bool operator!= (const NamedValueSet& other) const; | |||
//============================================================================== | |||
/** Returns the total number of values that the set contains. */ | |||
int size() const throw(); | |||
@@ -108,6 +111,7 @@ private: | |||
{ | |||
NamedValue() throw(); | |||
NamedValue (const Identifier& name, const var& value); | |||
bool operator== (const NamedValue& other) const throw(); | |||
Identifier name; | |||
var value; | |||
@@ -500,6 +500,22 @@ void ValueTree::SharedObject::moveChild (int currentIndex, int newIndex, UndoMan | |||
} | |||
} | |||
bool ValueTree::SharedObject::isEquivalentTo (const SharedObject& other) const | |||
{ | |||
if (type != other.type | |||
|| properties.size() != other.properties.size() | |||
|| children.size() != other.children.size() | |||
|| properties != other.properties) | |||
return false; | |||
for (int i = 0; i < children.size(); ++i) | |||
if (! children.getUnchecked(i)->isEquivalentTo (*other.children.getUnchecked(i))) | |||
return false; | |||
return true; | |||
} | |||
//============================================================================== | |||
ValueTree::ValueTree() throw() | |||
: object (0) | |||
@@ -546,16 +562,22 @@ ValueTree::~ValueTree() | |||
object->valueTreesWithListeners.removeValue (this); | |||
} | |||
bool ValueTree::operator== (const ValueTree& other) const | |||
bool ValueTree::operator== (const ValueTree& other) const throw() | |||
{ | |||
return object == other.object; | |||
} | |||
bool ValueTree::operator!= (const ValueTree& other) const | |||
bool ValueTree::operator!= (const ValueTree& other) const throw() | |||
{ | |||
return object != other.object; | |||
} | |||
bool ValueTree::isEquivalentTo (const ValueTree& other) const | |||
{ | |||
return object == other.object | |||
|| (object != 0 && other.object != 0 && object->isEquivalentTo (*other.object)); | |||
} | |||
ValueTree ValueTree::createCopy() const | |||
{ | |||
return ValueTree (object != 0 ? new SharedObject (*object) : 0); | |||
@@ -710,7 +732,7 @@ int ValueTree::indexOf (const ValueTree& child) const | |||
return object != 0 ? object->indexOf (child) : -1; | |||
} | |||
void ValueTree::addChild (ValueTree child, int index, UndoManager* const undoManager) | |||
void ValueTree::addChild (const ValueTree& child, int index, UndoManager* const undoManager) | |||
{ | |||
if (object != 0) | |||
object->addChild (child.object, index, undoManager); | |||
@@ -102,13 +102,21 @@ public: | |||
Note that this isn't a value comparison - two independently-created trees which | |||
contain identical data are not considered equal. | |||
*/ | |||
bool operator== (const ValueTree& other) const; | |||
bool operator== (const ValueTree& other) const throw(); | |||
/** Returns true if this and the other node refer to different underlying structures. | |||
Note that this isn't a value comparison - two independently-created trees which | |||
contain identical data are not considered equal. | |||
*/ | |||
bool operator!= (const ValueTree& other) const; | |||
bool operator!= (const ValueTree& other) const throw(); | |||
/** Performs a deep comparison between the properties and children of two trees. | |||
If all the properties and children of the two trees are the same (recursively), this | |||
returns true. | |||
The normal operator==() only checks whether two trees refer to the same shared data | |||
structure, so use this method if you need to do a proper value comparison. | |||
*/ | |||
bool isEquivalentTo (const ValueTree& other) const; | |||
//============================================================================== | |||
/** Returns true if this node refers to some valid data. | |||
@@ -233,7 +241,7 @@ public: | |||
If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
so that this change can be undone. | |||
*/ | |||
void addChild (ValueTree child, int index, UndoManager* undoManager); | |||
void addChild (const ValueTree& child, int index, UndoManager* undoManager); | |||
/** Removes the specified child from this node's child-list. | |||
If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
@@ -464,6 +472,7 @@ private: | |||
void removeChild (int childIndex, UndoManager*); | |||
void removeAllChildren (UndoManager*); | |||
void moveChild (int currentIndex, int newIndex, UndoManager*); | |||
bool isEquivalentTo (const SharedObject& other) const; | |||
XmlElement* createXml() const; | |||
juce_UseDebuggingNewOperator | |||
@@ -33,7 +33,7 @@ | |||
*/ | |||
#define JUCE_MAJOR_VERSION 1 | |||
#define JUCE_MINOR_VERSION 52 | |||
#define JUCE_BUILDNUMBER 5 | |||
#define JUCE_BUILDNUMBER 6 | |||
/** Current Juce version number. | |||
@@ -877,8 +877,7 @@ void ListBox::setHeaderComponent (Component* const newHeaderComponent) | |||
void ListBox::repaintRow (const int rowNumber) throw() | |||
{ | |||
const Rectangle<int> r (getRowPosition (rowNumber, true)); | |||
repaint (r.getX(), r.getY(), r.getWidth(), r.getHeight()); | |||
repaint (getRowPosition (rowNumber, true)); | |||
} | |||
Image* ListBox::createSnapshotOfSelectedRows (int& imageX, int& imageY) | |||
@@ -1338,8 +1338,9 @@ void TreeViewItem::repaintItem() const | |||
{ | |||
if (ownerView != 0 && areAllParentsOpen()) | |||
{ | |||
const Rectangle<int> r (getItemPosition (true)); | |||
ownerView->viewport->repaint (0, r.getY(), r.getRight(), r.getHeight()); | |||
Rectangle<int> r (getItemPosition (true)); | |||
r.setLeft (0); | |||
ownerView->viewport->repaint (r); | |||
} | |||
} | |||
@@ -1555,6 +1555,11 @@ void Component::repaint (const int x, const int y, | |||
internalRepaint (x, y, w, h); | |||
} | |||
void Component::repaint (const Rectangle<int>& area) | |||
{ | |||
repaint (area.getX(), area.getY(), area.getWidth(), area.getHeight()); | |||
} | |||
void Component::internalRepaint (int x, int y, int w, int h) | |||
{ | |||
// if component methods are being called from threads other than the message | |||
@@ -1596,7 +1601,7 @@ void Component::internalRepaint (int x, int y, int w, int h) | |||
ComponentPeer* const peer = getPeer(); | |||
if (peer != 0) | |||
peer->repaint (x, y, w, h); | |||
peer->repaint (Rectangle<int> (x, y, w, h)); | |||
} | |||
} | |||
} | |||
@@ -819,6 +819,21 @@ public: | |||
*/ | |||
void repaint (int x, int y, int width, int height); | |||
/** Marks a subsection of this component as needing to be redrawn. | |||
Calling this will not do any repainting immediately, but will mark the given region | |||
of the component as 'dirty'. At some point in the near future the operating system | |||
will send a paint message, which will redraw all the dirty regions of all components. | |||
There's no guarantee about how soon after calling repaint() the redraw will actually | |||
happen, and other queued events may be delivered before a redraw is done. | |||
The region that is passed in will be clipped to keep it within the bounds of this | |||
component. | |||
@see repaint() | |||
*/ | |||
void repaint (const Rectangle<int>& area); | |||
//============================================================================== | |||
/** Makes the component use an internal buffer to optimise its redrawing. | |||
@@ -117,14 +117,14 @@ public: | |||
&& ((unsigned int) position.getY()) < (unsigned int) magnifierComp->getHeight(); | |||
} | |||
void repaint (int x, int y, int w, int h) | |||
void repaint (const Rectangle<int>& area) | |||
{ | |||
const double zoom = magnifierComp->getScaleFactor(); | |||
magnifierComp->repaint ((int) (x * zoom), | |||
(int) (y * zoom), | |||
roundToInt (w * zoom) + 1, | |||
roundToInt (h * zoom) + 1); | |||
magnifierComp->repaint ((int) (area.getX() * zoom), | |||
(int) (area.getY() * zoom), | |||
roundToInt (area.getWidth() * zoom) + 1, | |||
roundToInt (area.getHeight() * zoom) + 1); | |||
} | |||
void performAnyPendingRepaintsNow() | |||
@@ -281,7 +281,7 @@ public: | |||
//============================================================================== | |||
/** Invalidates a region of the window to be repainted asynchronously. */ | |||
virtual void repaint (int x, int y, int w, int h) = 0; | |||
virtual void repaint (const Rectangle<int>& area) = 0; | |||
/** This can be called (from the message thread) to cause the immediate redrawing | |||
of any areas of this window that need repainting. | |||
@@ -95,9 +95,7 @@ DocumentWindow::~DocumentWindow() | |||
//============================================================================== | |||
void DocumentWindow::repaintTitleBar() | |||
{ | |||
const Rectangle<int> titleBarArea (getTitleBarArea()); | |||
repaint (titleBarArea.getX(), titleBarArea.getY(), | |||
titleBarArea.getWidth(), titleBarArea.getHeight()); | |||
repaint (getTitleBarArea()); | |||
} | |||
void DocumentWindow::setName (const String& newName) | |||
@@ -177,12 +177,13 @@ public: | |||
x = endX; | |||
} | |||
levelAccumulator >>= 8; | |||
if (levelAccumulator > 0) | |||
{ | |||
x >>= 8; | |||
jassert (x >= bounds.getX() && x < bounds.getRight()); | |||
levelAccumulator >>= 8; | |||
if (levelAccumulator >> 8) | |||
iterationCallback.handleEdgeTablePixelFull (x); | |||
else | |||
@@ -76,6 +76,16 @@ FillType::~FillType() throw() | |||
{ | |||
} | |||
bool FillType::operator== (const FillType& other) const | |||
{ | |||
return colour == other.colour && gradient == other.gradient && image == other.image; | |||
} | |||
bool FillType::operator!= (const FillType& other) const | |||
{ | |||
return ! operator== (other); | |||
} | |||
void FillType::setColour (const Colour& newColour) throw() | |||
{ | |||
gradient = 0; | |||
@@ -110,4 +120,10 @@ void FillType::setOpacity (const float newOpacity) throw() | |||
colour = colour.withAlpha (newOpacity); | |||
} | |||
bool FillType::isInvisible() const throw() | |||
{ | |||
return colour.isTransparent() || (gradient != 0 && gradient->isInvisible()); | |||
} | |||
END_JUCE_NAMESPACE |
@@ -103,6 +103,12 @@ public: | |||
*/ | |||
float getOpacity() const throw() { return colour.getFloatAlpha(); } | |||
/** Returns true if this fill type is completely transparent. */ | |||
bool isInvisible() const throw(); | |||
bool operator== (const FillType& other) const; | |||
bool operator!= (const FillType& other) const; | |||
/** The solid colour being used. | |||
If the fill type is not a solid colour, the alpha channel of this colour indicates | |||
@@ -1899,41 +1899,38 @@ public: | |||
shapeToFill = clip->applyClipTo (shapeToFill); | |||
if (shapeToFill != 0) | |||
fillShapeWithoutClipping (image, shapeToFill, replaceContents); | |||
} | |||
{ | |||
Image::BitmapData destData (image, 0, 0, image.getWidth(), image.getHeight(), true); | |||
void fillShapeWithoutClipping (Image& image, const SoftwareRendererClasses::ClipRegionBase::Ptr& shapeToFill, const bool replaceContents) | |||
{ | |||
Image::BitmapData destData (image, 0, 0, image.getWidth(), image.getHeight(), true); | |||
if (fillType.isGradient()) | |||
{ | |||
jassert (! replaceContents); // that option is just for solid colours | |||
if (fillType.isGradient()) | |||
{ | |||
jassert (! replaceContents); // that option is just for solid colours | |||
ColourGradient g2 (*(fillType.gradient)); | |||
g2.multiplyOpacity (fillType.getOpacity()); | |||
g2.point1.addXY (-0.5f, -0.5f); | |||
g2.point2.addXY (-0.5f, -0.5f); | |||
AffineTransform transform (fillType.transform.translated ((float) xOffset, (float) yOffset)); | |||
const bool isIdentity = transform.isOnlyTranslation(); | |||
ColourGradient g2 (*(fillType.gradient)); | |||
g2.multiplyOpacity (fillType.getOpacity()); | |||
g2.point1.addXY (-0.5f, -0.5f); | |||
g2.point2.addXY (-0.5f, -0.5f); | |||
AffineTransform transform (fillType.transform.translated ((float) xOffset, (float) yOffset)); | |||
const bool isIdentity = transform.isOnlyTranslation(); | |||
if (isIdentity) | |||
{ | |||
// If our translation doesn't involve any distortion, we can speed it up.. | |||
g2.point1.applyTransform (transform); | |||
g2.point2.applyTransform (transform); | |||
transform = AffineTransform::identity; | |||
} | |||
if (isIdentity) | |||
shapeToFill->fillAllWithGradient (destData, g2, transform, isIdentity); | |||
} | |||
else if (fillType.isTiledImage()) | |||
{ | |||
// If our translation doesn't involve any distortion, we can speed it up.. | |||
g2.point1.applyTransform (transform); | |||
g2.point2.applyTransform (transform); | |||
transform = AffineTransform::identity; | |||
renderImage (image, *(fillType.image), fillType.image->getBounds(), fillType.transform, shapeToFill); | |||
} | |||
else | |||
{ | |||
shapeToFill->fillAllWithColour (destData, fillType.colour.getPixelARGB(), replaceContents); | |||
} | |||
shapeToFill->fillAllWithGradient (destData, g2, transform, isIdentity); | |||
} | |||
else if (fillType.isTiledImage()) | |||
{ | |||
renderImage (image, *(fillType.image), fillType.image->getBounds(), fillType.transform, shapeToFill); | |||
} | |||
else | |||
{ | |||
shapeToFill->fillAllWithColour (destData, fillType.colour.getPixelARGB(), replaceContents); | |||
} | |||
} | |||
@@ -36,7 +36,6 @@ BEGIN_JUCE_NAMESPACE | |||
#include "../../../text/juce_XmlDocument.h" | |||
#include "../../../io/files/juce_FileInputStream.h" | |||
const Identifier Drawable::idProperty ("id"); | |||
//============================================================================== | |||
Drawable::RenderingContext::RenderingContext (Graphics& g_, | |||
@@ -50,6 +49,7 @@ Drawable::RenderingContext::RenderingContext (Graphics& g_, | |||
//============================================================================== | |||
Drawable::Drawable() | |||
: parent (0) | |||
{ | |||
} | |||
@@ -57,8 +57,7 @@ Drawable::~Drawable() | |||
{ | |||
} | |||
void Drawable::draw (Graphics& g, const float opacity, | |||
const AffineTransform& transform) const | |||
void Drawable::draw (Graphics& g, const float opacity, const AffineTransform& transform) const | |||
{ | |||
render (RenderingContext (g, transform, opacity)); | |||
} | |||
@@ -156,4 +155,131 @@ Drawable* Drawable::createFromValueTree (const ValueTree& tree, ImageProvider* i | |||
} | |||
//============================================================================== | |||
const Identifier Drawable::ValueTreeWrapperBase::idProperty ("id"); | |||
const Identifier Drawable::ValueTreeWrapperBase::type ("type"); | |||
const Identifier Drawable::ValueTreeWrapperBase::x1 ("x1"); | |||
const Identifier Drawable::ValueTreeWrapperBase::x2 ("x2"); | |||
const Identifier Drawable::ValueTreeWrapperBase::y1 ("y1"); | |||
const Identifier Drawable::ValueTreeWrapperBase::y2 ("y2"); | |||
const Identifier Drawable::ValueTreeWrapperBase::colour ("colour"); | |||
const Identifier Drawable::ValueTreeWrapperBase::radial ("radial"); | |||
const Identifier Drawable::ValueTreeWrapperBase::colours ("colours"); | |||
Drawable::ValueTreeWrapperBase::ValueTreeWrapperBase (const ValueTree& state_) | |||
: state (state_) | |||
{ | |||
} | |||
Drawable::ValueTreeWrapperBase::~ValueTreeWrapperBase() | |||
{ | |||
} | |||
const String Drawable::ValueTreeWrapperBase::getID() const | |||
{ | |||
return state [idProperty]; | |||
} | |||
void Drawable::ValueTreeWrapperBase::setID (const String& newID, UndoManager* undoManager) | |||
{ | |||
if (newID.isEmpty()) | |||
state.removeProperty (idProperty, undoManager); | |||
else | |||
state.setProperty (idProperty, newID, undoManager); | |||
} | |||
const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v) | |||
{ | |||
const String newType (v[type].toString()); | |||
if (newType == "solid") | |||
{ | |||
const String colourString (v [colour].toString()); | |||
return FillType (Colour (colourString.isEmpty() ? (uint32) 0xff000000 | |||
: (uint32) colourString.getHexValue32())); | |||
} | |||
else if (newType == "gradient") | |||
{ | |||
ColourGradient g; | |||
g.point1.setXY (v[x1], v[y1]); | |||
g.point2.setXY (v[x2], v[y2]); | |||
g.isRadial = v[radial]; | |||
StringArray colourSteps; | |||
colourSteps.addTokens (v[colours].toString(), false); | |||
for (int i = 0; i < colourSteps.size() / 2; ++i) | |||
g.addColour (colourSteps[i * 2].getDoubleValue(), | |||
Colour ((uint32) colourSteps[i * 2 + 1].getHexValue32())); | |||
return FillType (g); | |||
} | |||
else if (newType == "image") | |||
{ | |||
jassertfalse; //xxx todo | |||
} | |||
jassertfalse; | |||
return FillType(); | |||
} | |||
void Drawable::ValueTreeWrapperBase::replaceFillType (const Identifier& tag, const FillType& fillType, UndoManager* undoManager) | |||
{ | |||
ValueTree v (state.getChildWithName (tag)); | |||
if (! v.isValid()) | |||
{ | |||
state.addChild (ValueTree (tag), -1, undoManager); | |||
v = state.getChildWithName (tag); | |||
} | |||
if (fillType.isColour()) | |||
{ | |||
v.setProperty (type, "solid", undoManager); | |||
v.setProperty (colour, String::toHexString ((int) fillType.colour.getARGB()), undoManager); | |||
v.removeProperty (x1, undoManager); | |||
v.removeProperty (x2, undoManager); | |||
v.removeProperty (y1, undoManager); | |||
v.removeProperty (y2, undoManager); | |||
v.removeProperty (radial, undoManager); | |||
v.removeProperty (colours, undoManager); | |||
} | |||
else if (fillType.isGradient()) | |||
{ | |||
v.setProperty (type, "gradient", undoManager); | |||
v.setProperty (x1, fillType.gradient->point1.getX(), undoManager); | |||
v.setProperty (y1, fillType.gradient->point1.getY(), undoManager); | |||
v.setProperty (x2, fillType.gradient->point2.getX(), undoManager); | |||
v.setProperty (y2, fillType.gradient->point2.getY(), undoManager); | |||
v.setProperty (radial, fillType.gradient->isRadial, undoManager); | |||
String s; | |||
for (int i = 0; i < fillType.gradient->getNumColours(); ++i) | |||
s << " " << fillType.gradient->getColourPosition (i) | |||
<< " " << String::toHexString ((int) fillType.gradient->getColour(i).getARGB()); | |||
v.setProperty (colours, s.trimStart(), undoManager); | |||
v.removeProperty (colour, undoManager); | |||
} | |||
else if (fillType.isTiledImage()) | |||
{ | |||
v.setProperty (type, "image", undoManager); | |||
jassertfalse; //xxx todo | |||
v.removeProperty (x1, undoManager); | |||
v.removeProperty (x2, undoManager); | |||
v.removeProperty (y1, undoManager); | |||
v.removeProperty (y2, undoManager); | |||
v.removeProperty (radial, undoManager); | |||
v.removeProperty (colours, undoManager); | |||
v.removeProperty (colour, undoManager); | |||
} | |||
else | |||
{ | |||
jassertfalse; | |||
} | |||
} | |||
END_JUCE_NAMESPACE |
@@ -27,8 +27,10 @@ | |||
#define __JUCE_DRAWABLE_JUCEHEADER__ | |||
#include "../contexts/juce_Graphics.h" | |||
#include "../geometry/juce_RelativeCoordinate.h" | |||
#include "../../../text/juce_XmlElement.h" | |||
#include "../../../containers/juce_ValueTree.h" | |||
class DrawableComposite; | |||
//============================================================================== | |||
@@ -229,11 +231,34 @@ public: | |||
/** Returns the tag ID that is used for a ValueTree that stores this type of drawable. */ | |||
virtual const Identifier getValueTreeType() const = 0; | |||
//============================================================================== | |||
/** Internal class used to manage ValueTrees that represent Drawables. */ | |||
class ValueTreeWrapperBase | |||
{ | |||
public: | |||
ValueTreeWrapperBase (const ValueTree& state); | |||
~ValueTreeWrapperBase(); | |||
ValueTree& getState() throw() { return state; } | |||
const String getID() const; | |||
void setID (const String& newID, UndoManager* undoManager); | |||
protected: | |||
ValueTree state; | |||
static const Identifier idProperty, type, x1, x2, y1, y2, colour, radial, colours; | |||
static const FillType readFillType (const ValueTree& v); | |||
void replaceFillType (const Identifier& tag, const FillType& fillType, UndoManager* undoManager); | |||
}; | |||
//============================================================================== | |||
juce_UseDebuggingNewOperator | |||
protected: | |||
static const Identifier idProperty; | |||
friend class DrawableComposite; | |||
DrawableComposite* parent; | |||
virtual void invalidatePoints() = 0; | |||
private: | |||
String name; | |||
@@ -37,8 +37,21 @@ BEGIN_JUCE_NAMESPACE | |||
//============================================================================== | |||
DrawableComposite::DrawableComposite() | |||
{ | |||
controlPoints[1].setXY (1.0f, 0.0f); | |||
controlPoints[2].setXY (0.0f, 1.0f); | |||
controlPoints[1] = RelativePoint (Point<float> (1.0f, 0.0f)); | |||
controlPoints[2] = RelativePoint (Point<float> (0.0f, 1.0f)); | |||
} | |||
DrawableComposite::DrawableComposite (const DrawableComposite& other) | |||
{ | |||
int i; | |||
for (i = 0; i < 3; ++i) | |||
controlPoints[i] = other.controlPoints[i]; | |||
for (i = 0; i < drawables.size(); ++i) | |||
drawables.add (other.drawables.getUnchecked(i)->createCopy()); | |||
for (i = 0; i < markers.size(); ++i) | |||
markers.add (new Marker (*other.markers.getUnchecked(i))); | |||
} | |||
DrawableComposite::~DrawableComposite() | |||
@@ -51,7 +64,9 @@ void DrawableComposite::insertDrawable (Drawable* drawable, const int index) | |||
if (drawable != 0) | |||
{ | |||
jassert (! drawables.contains (drawable)); // trying to add a drawable that's already in here! | |||
jassert (drawable->parent == 0); // A drawable can only live inside one parent at a time! | |||
drawables.insert (index, drawable); | |||
drawable->parent = this; | |||
} | |||
} | |||
@@ -71,9 +86,9 @@ void DrawableComposite::bringToFront (const int index) | |||
drawables.move (index, -1); | |||
} | |||
void DrawableComposite::setTransform (const Point<float>& targetPositionForOrigin, | |||
const Point<float>& targetPositionForX1Y0, | |||
const Point<float>& targetPositionForX0Y1) | |||
void DrawableComposite::setTransform (const RelativePoint& targetPositionForOrigin, | |||
const RelativePoint& targetPositionForX1Y0, | |||
const RelativePoint& targetPositionForX0Y1) | |||
{ | |||
controlPoints[0] = targetPositionForOrigin; | |||
controlPoints[1] = targetPositionForX1Y0; | |||
@@ -81,11 +96,70 @@ void DrawableComposite::setTransform (const Point<float>& targetPositionForOrigi | |||
} | |||
//============================================================================== | |||
const AffineTransform DrawableComposite::getTransform() const | |||
DrawableComposite::Marker::Marker (const DrawableComposite::Marker& other) | |||
: name (other.name), position (other.position), isOnXAxis (other.isOnXAxis) | |||
{ | |||
} | |||
DrawableComposite::Marker::Marker (const String& name_, const RelativeCoordinate& position_, const bool isOnXAxis_) | |||
: name (name_), position (position_), isOnXAxis (isOnXAxis_) | |||
{ | |||
} | |||
bool DrawableComposite::Marker::operator!= (const DrawableComposite::Marker& other) const throw() | |||
{ | |||
return name != other.name || position != other.position || isOnXAxis != other.isOnXAxis; | |||
} | |||
//============================================================================== | |||
int DrawableComposite::getNumMarkers (bool xAxis) const throw() | |||
{ | |||
return markers.size(); | |||
} | |||
const DrawableComposite::Marker* DrawableComposite::getMarker (int index) const throw() | |||
{ | |||
return markers [index]; | |||
} | |||
void DrawableComposite::setMarker (const String& name, bool xAxis, const RelativeCoordinate& position) | |||
{ | |||
for (int i = 0; i < markers.size(); ++i) | |||
{ | |||
Marker* const m = markers.getUnchecked(i); | |||
if (m->name == name) | |||
{ | |||
jassert (m->isOnXAxis == xAxis); // trying to either have two markers with the same name on different axes? | |||
if (m->position != position) | |||
{ | |||
m->position = position; | |||
invalidatePoints(); | |||
} | |||
return; | |||
} | |||
} | |||
markers.add (new Marker (name, position, xAxis)); | |||
invalidatePoints(); | |||
} | |||
void DrawableComposite::removeMarker (int index) | |||
{ | |||
return AffineTransform::fromTargetPoints (controlPoints[0].getX(), controlPoints[0].getY(), | |||
controlPoints[1].getX(), controlPoints[1].getY(), | |||
controlPoints[2].getX(), controlPoints[2].getY()); | |||
markers.remove (index); | |||
} | |||
//============================================================================== | |||
const AffineTransform DrawableComposite::calculateTransform() const | |||
{ | |||
Point<float> resolved[3]; | |||
for (int i = 0; i < 3; ++i) | |||
resolved[i] = controlPoints[i].resolve (parent); | |||
return AffineTransform::fromTargetPoints (resolved[0].getX(), resolved[0].getY(), | |||
resolved[1].getX(), resolved[1].getY(), | |||
resolved[2].getX(), resolved[2].getY()); | |||
} | |||
void DrawableComposite::render (const Drawable::RenderingContext& context) const | |||
@@ -95,7 +169,7 @@ void DrawableComposite::render (const Drawable::RenderingContext& context) const | |||
if (context.opacity >= 1.0f || drawables.size() == 1) | |||
{ | |||
Drawable::RenderingContext contextCopy (context); | |||
contextCopy.transform = getTransform().followedBy (context.transform); | |||
contextCopy.transform = calculateTransform().followedBy (context.transform); | |||
for (int i = 0; i < drawables.size(); ++i) | |||
drawables.getUnchecked(i)->render (contextCopy); | |||
@@ -121,6 +195,33 @@ void DrawableComposite::render (const Drawable::RenderingContext& context) const | |||
} | |||
} | |||
const RelativeCoordinate DrawableComposite::findNamedCoordinate (const String& objectName, const String& edge) const | |||
{ | |||
if (objectName == RelativeCoordinate::Strings::parent) | |||
{ | |||
if (edge == RelativeCoordinate::Strings::right) | |||
{ | |||
jassertfalse; // a Drawable doesn't have a fixed right-hand edge - use a marker instead if you need a point of reference. | |||
return RelativeCoordinate (100.0, true); | |||
} | |||
if (edge == RelativeCoordinate::Strings::bottom) | |||
{ | |||
jassertfalse; // a Drawable doesn't have a fixed bottom edge - use a marker instead if you need a point of reference. | |||
return RelativeCoordinate (100.0, false); | |||
} | |||
} | |||
for (int i = 0; i < markers.size(); ++i) | |||
{ | |||
Marker* const m = markers.getUnchecked(i); | |||
if (m->name == objectName) | |||
return m->position; | |||
} | |||
return RelativeCoordinate(); | |||
} | |||
const Rectangle<float> DrawableComposite::getUntransformedBounds() const | |||
{ | |||
Rectangle<float> bounds; | |||
@@ -133,12 +234,12 @@ const Rectangle<float> DrawableComposite::getUntransformedBounds() const | |||
const Rectangle<float> DrawableComposite::getBounds() const | |||
{ | |||
return getUntransformedBounds().transformed (getTransform()); | |||
return getUntransformedBounds().transformed (calculateTransform()); | |||
} | |||
bool DrawableComposite::hitTest (float x, float y) const | |||
{ | |||
getTransform().inverted().transformPoint (x, y); | |||
calculateTransform().inverted().transformPoint (x, y); | |||
for (int i = 0; i < drawables.size(); ++i) | |||
if (drawables.getUnchecked(i)->hitTest (x, y)) | |||
@@ -149,125 +250,282 @@ bool DrawableComposite::hitTest (float x, float y) const | |||
Drawable* DrawableComposite::createCopy() const | |||
{ | |||
DrawableComposite* const dc = new DrawableComposite(); | |||
for (int i = 0; i < 3; ++i) | |||
dc->controlPoints[i] = controlPoints[i]; | |||
return new DrawableComposite (*this); | |||
} | |||
void DrawableComposite::invalidatePoints() | |||
{ | |||
for (int i = 0; i < drawables.size(); ++i) | |||
dc->drawables.add (drawables.getUnchecked(i)->createCopy()); | |||
return dc; | |||
drawables.getUnchecked(i)->invalidatePoints(); | |||
} | |||
//============================================================================== | |||
const Identifier DrawableComposite::valueTreeType ("Group"); | |||
namespace DrawableCompositeHelpers | |||
const Identifier DrawableComposite::ValueTreeWrapper::topLeft ("topLeft"); | |||
const Identifier DrawableComposite::ValueTreeWrapper::topRight ("topRight"); | |||
const Identifier DrawableComposite::ValueTreeWrapper::bottomLeft ("bottomLeft"); | |||
const Identifier DrawableComposite::ValueTreeWrapper::childGroupTag ("Drawables"); | |||
const Identifier DrawableComposite::ValueTreeWrapper::markerGroupTag ("Markers"); | |||
const Identifier DrawableComposite::ValueTreeWrapper::markerTag ("Marker"); | |||
const Identifier DrawableComposite::ValueTreeWrapper::nameProperty ("name"); | |||
const Identifier DrawableComposite::ValueTreeWrapper::xAxisProperty ("xAxis"); | |||
const Identifier DrawableComposite::ValueTreeWrapper::posProperty ("position"); | |||
//============================================================================== | |||
DrawableComposite::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_) | |||
: ValueTreeWrapperBase (state_) | |||
{ | |||
jassert (state.hasType (valueTreeType)); | |||
} | |||
ValueTree DrawableComposite::ValueTreeWrapper::getChildList() const | |||
{ | |||
return state.getChildWithName (childGroupTag); | |||
} | |||
ValueTree DrawableComposite::ValueTreeWrapper::getChildListCreating (UndoManager* undoManager) | |||
{ | |||
const ValueTree childList (getChildList()); | |||
if (childList.isValid()) | |||
return childList; | |||
state.addChild (ValueTree (childGroupTag), 0, undoManager); | |||
return getChildList(); | |||
} | |||
ValueTree DrawableComposite::ValueTreeWrapper::getMarkerList() const | |||
{ | |||
static const Identifier topLeft ("topLeft"); | |||
static const Identifier topRight ("topRight"); | |||
static const Identifier bottomLeft ("bottomLeft"); | |||
return state.getChildWithName (markerGroupTag); | |||
} | |||
ValueTree DrawableComposite::ValueTreeWrapper::getMarkerListCreating (UndoManager* undoManager) | |||
{ | |||
const ValueTree markerList (getMarkerList()); | |||
if (markerList.isValid()) | |||
return markerList; | |||
state.addChild (ValueTree (markerGroupTag), -1, undoManager); | |||
return getMarkerList(); | |||
} | |||
int DrawableComposite::ValueTreeWrapper::getNumDrawables() const | |||
{ | |||
return getChildList().getNumChildren(); | |||
} | |||
const ValueTree DrawableComposite::ValueTreeWrapper::getDrawableState (int index) const | |||
{ | |||
return getChildList().getChild (index); | |||
} | |||
void DrawableComposite::ValueTreeWrapper::addDrawable (const ValueTree& newDrawableState, int index, UndoManager* undoManager) | |||
{ | |||
getChildListCreating (undoManager).addChild (newDrawableState, index, undoManager); | |||
} | |||
void DrawableComposite::ValueTreeWrapper::moveDrawableOrder (int currentIndex, int newIndex, UndoManager* undoManager) | |||
{ | |||
getChildListCreating (undoManager).moveChild (currentIndex, newIndex, undoManager); | |||
} | |||
void DrawableComposite::ValueTreeWrapper::removeDrawable (int index, UndoManager* undoManager) | |||
{ | |||
getChildList().removeChild (index, undoManager); | |||
} | |||
const RelativePoint DrawableComposite::ValueTreeWrapper::getTargetPositionForOrigin() const | |||
{ | |||
const String pos (state [topLeft].toString()); | |||
return pos.isNotEmpty() ? RelativePoint (pos) : RelativePoint (); | |||
} | |||
void DrawableComposite::ValueTreeWrapper::setTargetPositionForOrigin (const RelativePoint& newPoint, UndoManager* undoManager) | |||
{ | |||
state.setProperty (topLeft, newPoint.toString(), undoManager); | |||
} | |||
const RelativePoint DrawableComposite::ValueTreeWrapper::getTargetPositionForX1Y0() const | |||
{ | |||
const String pos (state [topRight].toString()); | |||
return pos.isNotEmpty() ? RelativePoint (pos) : RelativePoint (Point<float> (1.0f, 0.0f)); | |||
} | |||
void DrawableComposite::ValueTreeWrapper::setTargetPositionForX1Y0 (const RelativePoint& newPoint, UndoManager* undoManager) | |||
{ | |||
state.setProperty (topRight, newPoint.toString(), undoManager); | |||
} | |||
static void stringToPoint (const String& coords, Point<float>& point) | |||
const RelativePoint DrawableComposite::ValueTreeWrapper::getTargetPositionForX0Y1() const | |||
{ | |||
const String pos (state [bottomLeft].toString()); | |||
return pos.isNotEmpty() ? RelativePoint (pos) : RelativePoint (Point<float> (0.0f, 1.0f)); | |||
} | |||
void DrawableComposite::ValueTreeWrapper::setTargetPositionForX0Y1 (const RelativePoint& newPoint, UndoManager* undoManager) | |||
{ | |||
state.setProperty (bottomLeft, newPoint.toString(), undoManager); | |||
} | |||
int DrawableComposite::ValueTreeWrapper::getNumMarkers() const | |||
{ | |||
return getMarkerList().getNumChildren(); | |||
} | |||
const DrawableComposite::Marker DrawableComposite::ValueTreeWrapper::getMarker (int index) const | |||
{ | |||
const ValueTree marker (getMarkerList().getChild (index)); | |||
const bool isXAxis = marker [xAxisProperty]; | |||
return Marker (marker [nameProperty], | |||
RelativeCoordinate (marker [posProperty].toString(), isXAxis), | |||
isXAxis); | |||
} | |||
void DrawableComposite::ValueTreeWrapper::setMarker (const String& name, bool xAxis, const RelativeCoordinate& position, UndoManager* undoManager) | |||
{ | |||
ValueTree markerList (getMarkerListCreating (undoManager)); | |||
ValueTree marker (markerList.getChildWithProperty (nameProperty, name)); | |||
if (marker.isValid()) | |||
{ | |||
if (coords.isNotEmpty()) | |||
{ | |||
const int comma = coords.indexOfChar (','); | |||
point.setXY (coords.substring (0, comma).getFloatValue(), | |||
coords.substring (comma + 1).getFloatValue()); | |||
} | |||
jassert ((bool) marker [xAxisProperty] == xAxis); // shouldn't change the axis of a marker after it has been created! | |||
marker.setProperty (posProperty, position.toString(), undoManager); | |||
} | |||
static const var pointToString (const Point<float>& point) | |||
else | |||
{ | |||
return String (point.getX()) + ", " + String (point.getY()); | |||
marker = ValueTree (markerTag); | |||
marker.setProperty (nameProperty, name, 0); | |||
marker.setProperty (xAxisProperty, xAxis, 0); | |||
marker.setProperty (posProperty, position.toString(), 0); | |||
markerList.addChild (marker, -1, undoManager); | |||
} | |||
} | |||
const Rectangle<float> DrawableComposite::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) | |||
void DrawableComposite::ValueTreeWrapper::removeMarker (int index, UndoManager* undoManager) | |||
{ | |||
jassert (tree.hasType (valueTreeType)); | |||
return getMarkerList().removeChild (index, undoManager); | |||
} | |||
//============================================================================== | |||
const Rectangle<float> DrawableComposite::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) | |||
{ | |||
Rectangle<float> damageRect; | |||
const ValueTreeWrapper controller (tree); | |||
setName (controller.getID()); | |||
setName (tree [idProperty]); | |||
RelativePoint newControlPoint[3] = { controller.getTargetPositionForOrigin(), | |||
controller.getTargetPositionForX1Y0(), | |||
controller.getTargetPositionForX0Y1() }; | |||
Point<float> newControlPoint[3]; | |||
DrawableCompositeHelpers::stringToPoint (tree [DrawableCompositeHelpers::topLeft].toString(), newControlPoint[0]); | |||
DrawableCompositeHelpers::stringToPoint (tree [DrawableCompositeHelpers::topRight].toString(), newControlPoint[1]); | |||
DrawableCompositeHelpers::stringToPoint (tree [DrawableCompositeHelpers::bottomLeft].toString(), newControlPoint[2]); | |||
bool controlPointsChanged = false; | |||
bool redrawAll = false; | |||
if (controlPoints[0] != newControlPoint[0] | |||
|| controlPoints[1] != newControlPoint[1] | |||
|| controlPoints[2] != newControlPoint[2]) | |||
{ | |||
controlPointsChanged = true; | |||
redrawAll = true; | |||
damageRect = getUntransformedBounds(); | |||
controlPoints[0] = newControlPoint[0]; | |||
controlPoints[1] = newControlPoint[1]; | |||
controlPoints[2] = newControlPoint[2]; | |||
} | |||
// Remove deleted markers... | |||
int i; | |||
for (i = drawables.size(); --i >= tree.getNumChildren();) | |||
for (i = markers.size(); --i >= controller.getNumMarkers();) | |||
{ | |||
if (damageRect.isEmpty()) | |||
damageRect = getUntransformedBounds(); | |||
removeMarker (i); | |||
} | |||
// Update markers and add new ones.. | |||
for (i = 0; i < controller.getNumMarkers(); ++i) | |||
{ | |||
damageRect = damageRect.getUnion (drawables.getUnchecked(i)->getBounds()); | |||
const Marker newMarker (controller.getMarker (i)); | |||
Marker* m = markers[i]; | |||
if (m == 0 || newMarker != *m) | |||
{ | |||
redrawAll = true; | |||
if (damageRect.isEmpty()) | |||
damageRect = getUntransformedBounds(); | |||
if (m == 0) | |||
markers.add (new Marker (newMarker)); | |||
else | |||
*m = newMarker; | |||
} | |||
} | |||
// Remove deleted drawables.. | |||
for (i = drawables.size(); --i >= controller.getNumDrawables();) | |||
{ | |||
Drawable* const d = drawables.getUnchecked(i); | |||
damageRect = damageRect.getUnion (d->getBounds()); | |||
d->parent = 0; | |||
drawables.remove (i); | |||
} | |||
for (int i = 0; i < tree.getNumChildren(); ++i) | |||
// Update drawables and add new ones.. | |||
for (i = 0; i < controller.getNumDrawables(); ++i) | |||
{ | |||
const ValueTree childTree (tree.getChild (i)); | |||
const ValueTree newDrawable (controller.getDrawableState (i)); | |||
Drawable* d = drawables[i]; | |||
if (d != 0) | |||
{ | |||
if (childTree.hasType (d->getValueTreeType())) | |||
if (newDrawable.hasType (d->getValueTreeType())) | |||
{ | |||
damageRect = damageRect.getUnion (d->refreshFromValueTree (childTree, imageProvider)); | |||
damageRect = damageRect.getUnion (d->refreshFromValueTree (newDrawable, imageProvider)); | |||
} | |||
else | |||
{ | |||
damageRect = damageRect.getUnion (d->getBounds()); | |||
d = createFromValueTree (childTree, imageProvider); | |||
d = createFromValueTree (newDrawable, imageProvider); | |||
d->parent = this; | |||
drawables.set (i, d); | |||
damageRect = damageRect.getUnion (d->getBounds()); | |||
} | |||
} | |||
else | |||
{ | |||
d = createFromValueTree (childTree, imageProvider); | |||
d = createFromValueTree (newDrawable, imageProvider); | |||
d->parent = this; | |||
drawables.set (i, d); | |||
damageRect = damageRect.getUnion (d->getBounds()); | |||
} | |||
} | |||
if (controlPointsChanged) | |||
if (redrawAll) | |||
damageRect = damageRect.getUnion (getUntransformedBounds()); | |||
return damageRect.transformed (getTransform()); | |||
return damageRect.transformed (calculateTransform()); | |||
} | |||
const ValueTree DrawableComposite::createValueTree (ImageProvider* imageProvider) const | |||
{ | |||
ValueTree v (valueTreeType); | |||
ValueTree tree (valueTreeType); | |||
ValueTreeWrapper v (tree); | |||
if (getName().isNotEmpty()) | |||
v.setProperty (idProperty, getName(), 0); | |||
v.setID (getName(), 0); | |||
v.setTargetPositionForOrigin (controlPoints[0], 0); | |||
v.setTargetPositionForX1Y0 (controlPoints[1], 0); | |||
v.setTargetPositionForX0Y1 (controlPoints[2], 0); | |||
if (! getTransform().isIdentity()) | |||
int i; | |||
for (i = 0; i < drawables.size(); ++i) | |||
v.addDrawable (drawables.getUnchecked(i)->createValueTree (imageProvider), -1, 0); | |||
for (i = 0; i < markers.size(); ++i) | |||
{ | |||
v.setProperty (DrawableCompositeHelpers::topLeft, DrawableCompositeHelpers::pointToString (controlPoints[0]), 0); | |||
v.setProperty (DrawableCompositeHelpers::topRight, DrawableCompositeHelpers::pointToString (controlPoints[1]), 0); | |||
v.setProperty (DrawableCompositeHelpers::bottomLeft, DrawableCompositeHelpers::pointToString (controlPoints[2]), 0); | |||
const Marker* m = markers.getUnchecked(i); | |||
v.setMarker (m->name, m->isOnXAxis, m->position, 0); | |||
} | |||
for (int i = 0; i < drawables.size(); ++i) | |||
v.addChild (drawables.getUnchecked(i)->createValueTree (imageProvider), -1, 0); | |||
return v; | |||
return tree; | |||
} | |||
@@ -35,14 +35,17 @@ | |||
@see Drawable | |||
*/ | |||
class JUCE_API DrawableComposite : public Drawable | |||
class JUCE_API DrawableComposite : public Drawable, | |||
public RelativeCoordinate::NamedCoordinateFinder | |||
{ | |||
public: | |||
//============================================================================== | |||
/** Creates a composite Drawable. | |||
*/ | |||
/** Creates a composite Drawable. */ | |||
DrawableComposite(); | |||
/** Creates a copy of a DrawableComposite. */ | |||
DrawableComposite (const DrawableComposite& other); | |||
/** Destructor. */ | |||
virtual ~DrawableComposite(); | |||
@@ -122,27 +125,44 @@ public: | |||
@param targetPositionForX0Y1 the position that the local coordinate (0, 1) should be | |||
mapped onto when rendering this object. | |||
*/ | |||
void setTransform (const Point<float>& targetPositionForOrigin, | |||
const Point<float>& targetPositionForX1Y0, | |||
const Point<float>& targetPositionForX0Y1); | |||
void setTransform (const RelativePoint& targetPositionForOrigin, | |||
const RelativePoint& targetPositionForX1Y0, | |||
const RelativePoint& targetPositionForX0Y1); | |||
/** Returns the position to which the local coordinate (0, 0) should be remapped in the target | |||
coordinate space when rendering this object. | |||
@see setTransform | |||
*/ | |||
const Point<float>& getTargetPositionForOrigin() const throw() { return controlPoints[0]; } | |||
const RelativePoint& getTargetPositionForOrigin() const throw() { return controlPoints[0]; } | |||
/** Returns the position to which the local coordinate (1, 0) should be remapped in the target | |||
coordinate space when rendering this object. | |||
@see setTransform | |||
*/ | |||
const Point<float>& getTargetPositionForX1Y0() const throw() { return controlPoints[1]; } | |||
const RelativePoint& getTargetPositionForX1Y0() const throw() { return controlPoints[1]; } | |||
/** Returns the position to which the local coordinate (0, 1) should be remapped in the target | |||
coordinate space when rendering this object. | |||
@see setTransform | |||
*/ | |||
const Point<float>& getTargetPositionForX0Y1() const throw() { return controlPoints[2]; } | |||
const RelativePoint& getTargetPositionForX0Y1() const throw() { return controlPoints[2]; } | |||
//============================================================================== | |||
struct Marker | |||
{ | |||
Marker (const Marker&); | |||
Marker (const String& name, const RelativeCoordinate& position, bool isOnXAxis); | |||
bool operator!= (const Marker&) const throw(); | |||
String name; | |||
RelativeCoordinate position; | |||
bool isOnXAxis; | |||
}; | |||
int getNumMarkers (bool xAxis) const throw(); | |||
const Marker* getMarker (int index) const throw(); | |||
void setMarker (const String& name, bool xAxis, const RelativeCoordinate& position); | |||
void removeMarker (int index); | |||
//============================================================================== | |||
/** @internal */ | |||
@@ -152,12 +172,10 @@ public: | |||
/** @internal */ | |||
bool hitTest (float x, float y) const; | |||
/** @internal */ | |||
int getNumControlPoints() const; | |||
/** @internal */ | |||
const Point<float> getControlPoint (int index) const; | |||
/** @internal */ | |||
Drawable* createCopy() const; | |||
/** @internal */ | |||
void invalidatePoints(); | |||
/** @internal */ | |||
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider); | |||
/** @internal */ | |||
const ValueTree createValueTree (ImageProvider* imageProvider) const; | |||
@@ -165,18 +183,57 @@ public: | |||
static const Identifier valueTreeType; | |||
/** @internal */ | |||
const Identifier getValueTreeType() const { return valueTreeType; } | |||
/** @internal */ | |||
const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const; | |||
//============================================================================== | |||
/** Internally-used class for wrapping a DrawableComposite's state into a ValueTree. */ | |||
class ValueTreeWrapper : public ValueTreeWrapperBase | |||
{ | |||
public: | |||
ValueTreeWrapper (const ValueTree& state); | |||
int getNumDrawables() const; | |||
const ValueTree getDrawableState (int index) const; | |||
void addDrawable (const ValueTree& newDrawableState, int index, UndoManager* undoManager); | |||
void moveDrawableOrder (int currentIndex, int newIndex, UndoManager* undoManager); | |||
void removeDrawable (int index, UndoManager* undoManager); | |||
const RelativePoint getTargetPositionForOrigin() const; | |||
void setTargetPositionForOrigin (const RelativePoint& newPoint, UndoManager* undoManager); | |||
const RelativePoint getTargetPositionForX1Y0() const; | |||
void setTargetPositionForX1Y0 (const RelativePoint& newPoint, UndoManager* undoManager); | |||
const RelativePoint getTargetPositionForX0Y1() const; | |||
void setTargetPositionForX0Y1 (const RelativePoint& newPoint, UndoManager* undoManager); | |||
int getNumMarkers() const; | |||
const Marker getMarker (int index) const; | |||
void setMarker (const String& name, bool xAxis, const RelativeCoordinate& position, UndoManager* undoManager); | |||
void removeMarker (int index, UndoManager* undoManager); | |||
private: | |||
static const Identifier topLeft, topRight, bottomLeft, childGroupTag, markerGroupTag, | |||
markerTag, nameProperty, xAxisProperty, posProperty; | |||
ValueTree getChildList() const; | |||
ValueTree getChildListCreating (UndoManager* undoManager); | |||
ValueTree getMarkerList() const; | |||
ValueTree getMarkerListCreating (UndoManager* undoManager); | |||
}; | |||
//============================================================================== | |||
juce_UseDebuggingNewOperator | |||
private: | |||
OwnedArray <Drawable> drawables; | |||
Point<float> controlPoints[3]; | |||
RelativePoint controlPoints[3]; | |||
OwnedArray <Marker> markers; | |||
const Rectangle<float> getUntransformedBounds() const; | |||
const AffineTransform getTransform() const; | |||
const AffineTransform calculateTransform() const; | |||
DrawableComposite (const DrawableComposite&); | |||
DrawableComposite& operator= (const DrawableComposite&); | |||
}; | |||
@@ -27,8 +27,8 @@ | |||
BEGIN_JUCE_NAMESPACE | |||
#include "juce_DrawableImage.h" | |||
#include "juce_DrawableComposite.h" | |||
#include "../imaging/juce_ImageCache.h" | |||
@@ -39,47 +39,58 @@ DrawableImage::DrawableImage() | |||
opacity (1.0f), | |||
overlayColour (0x00000000) | |||
{ | |||
controlPoints[1].setXY (1.0f, 0.0f); | |||
controlPoints[2].setXY (0.0f, 1.0f); | |||
controlPoints[1] = RelativePoint (Point<float> (1.0f, 0.0f)); | |||
controlPoints[2] = RelativePoint (Point<float> (0.0f, 1.0f)); | |||
} | |||
DrawableImage::~DrawableImage() | |||
DrawableImage::DrawableImage (const DrawableImage& other) | |||
: image (0), | |||
canDeleteImage (false), | |||
opacity (other.opacity), | |||
overlayColour (other.overlayColour) | |||
{ | |||
clearImage(); | |||
for (int i = 0; i < numElementsInArray (controlPoints); ++i) | |||
controlPoints[i] = other.controlPoints[i]; | |||
if (other.image != 0) | |||
{ | |||
if ((! other.canDeleteImage) || ! ImageCache::isImageInCache (other.image)) | |||
{ | |||
setImage (*other.image); | |||
} | |||
else | |||
{ | |||
ImageCache::incReferenceCount (other.image); | |||
setImage (other.image, true); | |||
} | |||
} | |||
} | |||
//============================================================================== | |||
void DrawableImage::clearImage() | |||
DrawableImage::~DrawableImage() | |||
{ | |||
if (canDeleteImage && image != 0) | |||
ImageCache::releaseOrDelete (image); | |||
image = 0; | |||
setImage (0, false); | |||
} | |||
//============================================================================== | |||
void DrawableImage::setImage (const Image& imageToCopy) | |||
{ | |||
clearImage(); | |||
image = new Image (imageToCopy); | |||
canDeleteImage = true; | |||
controlPoints[0].setXY (0.0f, 0.0f); | |||
controlPoints[1].setXY ((float) image->getWidth(), 0.0f); | |||
controlPoints[2].setXY (0.0f, (float) image->getHeight()); | |||
setImage (new Image (imageToCopy), true); | |||
} | |||
void DrawableImage::setImage (Image* imageToUse, | |||
const bool releaseWhenNotNeeded) | |||
{ | |||
clearImage(); | |||
if (canDeleteImage) | |||
ImageCache::releaseOrDelete (image); | |||
image = imageToUse; | |||
canDeleteImage = releaseWhenNotNeeded; | |||
if (image != 0) | |||
{ | |||
controlPoints[0].setXY (0.0f, 0.0f); | |||
controlPoints[1].setXY ((float) image->getWidth(), 0.0f); | |||
controlPoints[2].setXY (0.0f, (float) image->getHeight()); | |||
controlPoints[0] = RelativePoint (Point<float> (0.0f, 0.0f)); | |||
controlPoints[1] = RelativePoint (Point<float> ((float) image->getWidth(), 0.0f)); | |||
controlPoints[2] = RelativePoint (Point<float> (0.0f, (float) image->getHeight())); | |||
} | |||
} | |||
@@ -93,9 +104,9 @@ void DrawableImage::setOverlayColour (const Colour& newOverlayColour) | |||
overlayColour = newOverlayColour; | |||
} | |||
void DrawableImage::setTransform (const Point<float>& imageTopLeftPosition, | |||
const Point<float>& imageTopRightPosition, | |||
const Point<float>& imageBottomLeftPosition) | |||
void DrawableImage::setTransform (const RelativePoint& imageTopLeftPosition, | |||
const RelativePoint& imageTopRightPosition, | |||
const RelativePoint& imageBottomLeftPosition) | |||
{ | |||
controlPoints[0] = imageTopLeftPosition; | |||
controlPoints[1] = imageTopRightPosition; | |||
@@ -103,15 +114,19 @@ void DrawableImage::setTransform (const Point<float>& imageTopLeftPosition, | |||
} | |||
//============================================================================== | |||
const AffineTransform DrawableImage::getTransform() const | |||
const AffineTransform DrawableImage::calculateTransform() const | |||
{ | |||
if (image == 0) | |||
return AffineTransform::identity; | |||
const Point<float> tr (controlPoints[0] + (controlPoints[1] - controlPoints[0]) / (float) image->getWidth()); | |||
const Point<float> bl (controlPoints[0] + (controlPoints[2] - controlPoints[0]) / (float) image->getHeight()); | |||
Point<float> resolved[3]; | |||
for (int i = 0; i < 3; ++i) | |||
resolved[i] = controlPoints[i].resolve (parent); | |||
return AffineTransform::fromTargetPoints (controlPoints[0].getX(), controlPoints[0].getY(), | |||
const Point<float> tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image->getWidth()); | |||
const Point<float> bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image->getHeight()); | |||
return AffineTransform::fromTargetPoints (resolved[0].getX(), resolved[0].getY(), | |||
tr.getX(), tr.getY(), | |||
bl.getX(), bl.getY()); | |||
} | |||
@@ -120,7 +135,7 @@ void DrawableImage::render (const Drawable::RenderingContext& context) const | |||
{ | |||
if (image != 0) | |||
{ | |||
const AffineTransform t (getTransform().followedBy (context.transform)); | |||
const AffineTransform t (calculateTransform().followedBy (context.transform)); | |||
if (opacity > 0.0f && ! overlayColour.isOpaque()) | |||
{ | |||
@@ -141,7 +156,11 @@ const Rectangle<float> DrawableImage::getBounds() const | |||
if (image == 0) | |||
return Rectangle<float>(); | |||
const Point<float> bottomRight (controlPoints[1] + (controlPoints[2] - controlPoints[0])); | |||
Point<float> resolved[3]; | |||
for (int i = 0; i < 3; ++i) | |||
resolved[i] = controlPoints[i].resolve (parent); | |||
const Point<float> bottomRight (resolved[1] + (resolved[2] - resolved[0])); | |||
float minX = bottomRight.getX(); | |||
float maxX = minX; | |||
float minY = bottomRight.getY(); | |||
@@ -149,10 +168,10 @@ const Rectangle<float> DrawableImage::getBounds() const | |||
for (int i = 0; i < 3; ++i) | |||
{ | |||
minX = jmin (minX, controlPoints[i].getX()); | |||
maxX = jmax (maxX, controlPoints[i].getX()); | |||
minY = jmin (minY, controlPoints[i].getY()); | |||
maxY = jmax (maxY, controlPoints[i].getY()); | |||
minX = jmin (minX, resolved[i].getX()); | |||
maxX = jmax (maxX, resolved[i].getX()); | |||
minY = jmin (minY, resolved[i].getY()); | |||
maxY = jmax (maxY, resolved[i].getY()); | |||
} | |||
return Rectangle<float> (minX, minY, maxX - minX, maxY - minY); | |||
@@ -163,7 +182,7 @@ bool DrawableImage::hitTest (float x, float y) const | |||
if (image == 0) | |||
return false; | |||
getTransform().inverted().transformPoint (x, y); | |||
calculateTransform().inverted().transformPoint (x, y); | |||
const int ix = roundToInt (x); | |||
const int iy = roundToInt (y); | |||
@@ -177,81 +196,117 @@ bool DrawableImage::hitTest (float x, float y) const | |||
Drawable* DrawableImage::createCopy() const | |||
{ | |||
DrawableImage* const di = new DrawableImage(); | |||
return new DrawableImage (*this); | |||
} | |||
di->opacity = opacity; | |||
di->overlayColour = overlayColour; | |||
void DrawableImage::invalidatePoints() | |||
{ | |||
} | |||
for (int i = 0; i < 4; ++i) | |||
di->controlPoints[i] = controlPoints[i]; | |||
//============================================================================== | |||
const Identifier DrawableImage::valueTreeType ("Image"); | |||
if (image != 0) | |||
{ | |||
if ((! canDeleteImage) || ! ImageCache::isImageInCache (image)) | |||
{ | |||
di->setImage (*image); | |||
} | |||
else | |||
{ | |||
ImageCache::incReferenceCount (image); | |||
di->setImage (image, true); | |||
} | |||
} | |||
const Identifier DrawableImage::ValueTreeWrapper::opacity ("opacity"); | |||
const Identifier DrawableImage::ValueTreeWrapper::overlay ("overlay"); | |||
const Identifier DrawableImage::ValueTreeWrapper::image ("image"); | |||
const Identifier DrawableImage::ValueTreeWrapper::topLeft ("topLeft"); | |||
const Identifier DrawableImage::ValueTreeWrapper::topRight ("topRight"); | |||
const Identifier DrawableImage::ValueTreeWrapper::bottomLeft ("bottomLeft"); | |||
return di; | |||
//============================================================================== | |||
DrawableImage::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_) | |||
: ValueTreeWrapperBase (state_) | |||
{ | |||
jassert (state.hasType (valueTreeType)); | |||
} | |||
//============================================================================== | |||
const Identifier DrawableImage::valueTreeType ("Image"); | |||
const var DrawableImage::ValueTreeWrapper::getImageIdentifier() const | |||
{ | |||
return state [image]; | |||
} | |||
namespace DrawableImageHelpers | |||
void DrawableImage::ValueTreeWrapper::setImageIdentifier (const var& newIdentifier, UndoManager* undoManager) | |||
{ | |||
static const Identifier opacity ("opacity"); | |||
static const Identifier overlay ("overlay"); | |||
static const Identifier image ("image"); | |||
static const Identifier topLeft ("topLeft"); | |||
static const Identifier topRight ("topRight"); | |||
static const Identifier bottomLeft ("bottomLeft"); | |||
static void stringToPoint (const String& coords, Point<float>& point) | |||
{ | |||
if (coords.isNotEmpty()) | |||
{ | |||
const int comma = coords.indexOfChar (','); | |||
point.setXY (coords.substring (0, comma).getFloatValue(), | |||
coords.substring (comma + 1).getFloatValue()); | |||
} | |||
} | |||
state.setProperty (image, newIdentifier, undoManager); | |||
} | |||
static const var pointToString (const Point<float>& point) | |||
{ | |||
return String (point.getX()) + ", " + String (point.getY()); | |||
} | |||
float DrawableImage::ValueTreeWrapper::getOpacity() const | |||
{ | |||
return (float) state.getProperty (opacity, 1.0); | |||
} | |||
const Rectangle<float> DrawableImage::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) | |||
void DrawableImage::ValueTreeWrapper::setOpacity (float newOpacity, UndoManager* undoManager) | |||
{ | |||
state.setProperty (opacity, newOpacity, undoManager); | |||
} | |||
const Colour DrawableImage::ValueTreeWrapper::getOverlayColour() const | |||
{ | |||
return Colour (state [overlay].toString().getHexValue32()); | |||
} | |||
void DrawableImage::ValueTreeWrapper::setOverlayColour (const Colour& newColour, UndoManager* undoManager) | |||
{ | |||
if (newColour.isTransparent()) | |||
state.removeProperty (overlay, undoManager); | |||
else | |||
state.setProperty (overlay, String::toHexString ((int) newColour.getARGB()), undoManager); | |||
} | |||
const RelativePoint DrawableImage::ValueTreeWrapper::getTargetPositionForTopLeft() const | |||
{ | |||
const String pos (state [topLeft].toString()); | |||
return pos.isNotEmpty() ? RelativePoint (pos) : RelativePoint(); | |||
} | |||
void DrawableImage::ValueTreeWrapper::setTargetPositionForTopLeft (const RelativePoint& newPoint, UndoManager* undoManager) | |||
{ | |||
state.setProperty (topLeft, newPoint.toString(), undoManager); | |||
} | |||
const RelativePoint DrawableImage::ValueTreeWrapper::getTargetPositionForTopRight() const | |||
{ | |||
const String pos (state [topRight].toString()); | |||
return pos.isNotEmpty() ? RelativePoint (pos) : RelativePoint (Point<float> (100.0f, 0.0f)); | |||
} | |||
void DrawableImage::ValueTreeWrapper::setTargetPositionForTopRight (const RelativePoint& newPoint, UndoManager* undoManager) | |||
{ | |||
state.setProperty (topRight, newPoint.toString(), undoManager); | |||
} | |||
const RelativePoint DrawableImage::ValueTreeWrapper::getTargetPositionForBottomLeft() const | |||
{ | |||
const String pos (state [bottomLeft].toString()); | |||
return pos.isNotEmpty() ? RelativePoint (pos) : RelativePoint (Point<float> (0.0f, 100.0f)); | |||
} | |||
void DrawableImage::ValueTreeWrapper::setTargetPositionForBottomLeft (const RelativePoint& newPoint, UndoManager* undoManager) | |||
{ | |||
jassert (tree.hasType (valueTreeType)); | |||
state.setProperty (bottomLeft, newPoint.toString(), undoManager); | |||
} | |||
setName (tree [idProperty]); | |||
//============================================================================== | |||
const Rectangle<float> DrawableImage::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) | |||
{ | |||
const ValueTreeWrapper controller (tree); | |||
setName (controller.getID()); | |||
const float newOpacity = tree.getProperty (DrawableImageHelpers::opacity, 1.0); | |||
const Colour newOverlayColour (tree [DrawableImageHelpers::overlay].toString().getHexValue32()); | |||
const float newOpacity = controller.getOpacity(); | |||
const Colour newOverlayColour (controller.getOverlayColour()); | |||
Image* newImage = 0; | |||
const String imageIdentifier (tree [DrawableImageHelpers::image].toString()); | |||
if (imageIdentifier.isNotEmpty()) | |||
{ | |||
jassert (imageProvider != 0); // if you're using images, you need to provide something that can load and save them! | |||
const var imageIdentifier (controller.getImageIdentifier()); | |||
if (imageProvider != 0) | |||
newImage = imageProvider->getImageForIdentifier (imageIdentifier); | |||
} | |||
jassert (imageProvider != 0 || imageIdentifier.isVoid()); // if you're using images, you need to provide something that can load and save them! | |||
if (imageProvider != 0) | |||
newImage = imageProvider->getImageForIdentifier (imageIdentifier); | |||
Point<float> newControlPoint[3]; | |||
DrawableImageHelpers::stringToPoint (tree [DrawableImageHelpers::topLeft].toString(), newControlPoint[0]); | |||
DrawableImageHelpers::stringToPoint (tree [DrawableImageHelpers::topRight].toString(), newControlPoint[1]); | |||
DrawableImageHelpers::stringToPoint (tree [DrawableImageHelpers::bottomLeft].toString(), newControlPoint[2]); | |||
RelativePoint newControlPoint[3] = { controller.getTargetPositionForTopLeft(), | |||
controller.getTargetPositionForTopRight(), | |||
controller.getTargetPositionForBottomLeft() }; | |||
if (newOpacity != opacity || overlayColour != newOverlayColour || image != newImage | |||
|| controlPoints[0] != newControlPoint[0] | |||
@@ -266,7 +321,10 @@ const Rectangle<float> DrawableImage::refreshFromValueTree (const ValueTree& tre | |||
if (image != newImage) | |||
{ | |||
ImageCache::release (image); | |||
if (canDeleteImage) | |||
ImageCache::releaseOrDelete (image); | |||
canDeleteImage = true; | |||
image = newImage; | |||
} | |||
@@ -279,33 +337,25 @@ const Rectangle<float> DrawableImage::refreshFromValueTree (const ValueTree& tre | |||
const ValueTree DrawableImage::createValueTree (ImageProvider* imageProvider) const | |||
{ | |||
ValueTree v (valueTreeType); | |||
ValueTree tree (valueTreeType); | |||
ValueTreeWrapper v (tree); | |||
if (getName().isNotEmpty()) | |||
v.setProperty (idProperty, getName(), 0); | |||
if (opacity < 1.0f) | |||
v.setProperty (DrawableImageHelpers::opacity, (double) opacity, 0); | |||
if (! overlayColour.isTransparent()) | |||
v.setProperty (DrawableImageHelpers::overlay, String::toHexString ((int) overlayColour.getARGB()), 0); | |||
if (! getTransform().isIdentity()) | |||
{ | |||
v.setProperty (DrawableImageHelpers::topLeft, DrawableImageHelpers::pointToString (controlPoints[0]), 0); | |||
v.setProperty (DrawableImageHelpers::topRight, DrawableImageHelpers::pointToString (controlPoints[1]), 0); | |||
v.setProperty (DrawableImageHelpers::bottomLeft, DrawableImageHelpers::pointToString (controlPoints[2]), 0); | |||
} | |||
v.setID (getName(), 0); | |||
v.setOpacity (opacity, 0); | |||
v.setOverlayColour (overlayColour, 0); | |||
v.setTargetPositionForTopLeft (controlPoints[0], 0); | |||
v.setTargetPositionForTopRight (controlPoints[1], 0); | |||
v.setTargetPositionForBottomLeft (controlPoints[2], 0); | |||
if (image != 0) | |||
{ | |||
jassert (imageProvider != 0); // if you're using images, you need to provide something that can load and save them! | |||
if (imageProvider != 0) | |||
v.setProperty (DrawableImageHelpers::image, imageProvider->getIdentifierForImage (image), 0); | |||
v.setImageIdentifier (imageProvider->getIdentifierForImage (image), 0); | |||
} | |||
return v; | |||
return tree; | |||
} | |||
@@ -40,6 +40,7 @@ class JUCE_API DrawableImage : public Drawable | |||
public: | |||
//============================================================================== | |||
DrawableImage(); | |||
DrawableImage (const DrawableImage& other); | |||
/** Destructor. */ | |||
virtual ~DrawableImage(); | |||
@@ -59,7 +60,7 @@ public: | |||
with ImageCache and pass it in here with releaseWhenNotNeeded = true, then | |||
it'll be released neatly with its reference count being decreased. | |||
@param imageToUse the image to render | |||
@param imageToUse the image to render (may be a null pointer) | |||
@param releaseWhenNotNeeded if false, a simple pointer is kept to the image; if true, | |||
then the image will be deleted when this object no longer | |||
needs it - unless the image was created by the ImageCache, | |||
@@ -70,9 +71,6 @@ public: | |||
/** Returns the current image. */ | |||
Image* getImage() const throw() { return image; } | |||
/** Clears (and possibly deletes) the currently set image. */ | |||
void clearImage(); | |||
/** Sets the opacity to use when drawing the image. */ | |||
void setOpacity (float newOpacity); | |||
@@ -103,27 +101,27 @@ public: | |||
@param imageBottomLeftPosition the position that the image's bottom-left corner should be mapped to | |||
in the target coordinate space. | |||
*/ | |||
void setTransform (const Point<float>& imageTopLeftPosition, | |||
const Point<float>& imageTopRightPosition, | |||
const Point<float>& imageBottomLeftPosition); | |||
void setTransform (const RelativePoint& imageTopLeftPosition, | |||
const RelativePoint& imageTopRightPosition, | |||
const RelativePoint& imageBottomLeftPosition); | |||
/** Returns the position to which the image's top-left corner should be remapped in the target | |||
coordinate space when rendering this object. | |||
@see setTransform | |||
*/ | |||
const Point<float>& getTargetPositionForTopLeft() const throw() { return controlPoints[0]; } | |||
const RelativePoint& getTargetPositionForTopLeft() const throw() { return controlPoints[0]; } | |||
/** Returns the position to which the image's top-right corner should be remapped in the target | |||
coordinate space when rendering this object. | |||
@see setTransform | |||
*/ | |||
const Point<float>& getTargetPositionForTopRight() const throw() { return controlPoints[1]; } | |||
const RelativePoint& getTargetPositionForTopRight() const throw() { return controlPoints[1]; } | |||
/** Returns the position to which the image's bottom-left corner should be remapped in the target | |||
coordinate space when rendering this object. | |||
@see setTransform | |||
*/ | |||
const Point<float>& getTargetPositionForBottomLeft() const throw() { return controlPoints[2]; } | |||
const RelativePoint& getTargetPositionForBottomLeft() const throw() { return controlPoints[2]; } | |||
//============================================================================== | |||
/** @internal */ | |||
@@ -135,6 +133,8 @@ public: | |||
/** @internal */ | |||
Drawable* createCopy() const; | |||
/** @internal */ | |||
void invalidatePoints(); | |||
/** @internal */ | |||
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider); | |||
/** @internal */ | |||
const ValueTree createValueTree (ImageProvider* imageProvider) const; | |||
@@ -143,6 +143,35 @@ public: | |||
/** @internal */ | |||
const Identifier getValueTreeType() const { return valueTreeType; } | |||
//============================================================================== | |||
/** Internally-used class for wrapping a DrawableImage's state into a ValueTree. */ | |||
class ValueTreeWrapper : public ValueTreeWrapperBase | |||
{ | |||
public: | |||
ValueTreeWrapper (const ValueTree& state); | |||
const var getImageIdentifier() const; | |||
void setImageIdentifier (const var& newIdentifier, UndoManager* undoManager); | |||
float getOpacity() const; | |||
void setOpacity (float newOpacity, UndoManager* undoManager); | |||
const Colour getOverlayColour() const; | |||
void setOverlayColour (const Colour& newColour, UndoManager* undoManager); | |||
const RelativePoint getTargetPositionForTopLeft() const; | |||
void setTargetPositionForTopLeft (const RelativePoint& newPoint, UndoManager* undoManager); | |||
const RelativePoint getTargetPositionForTopRight() const; | |||
void setTargetPositionForTopRight (const RelativePoint& newPoint, UndoManager* undoManager); | |||
const RelativePoint getTargetPositionForBottomLeft() const; | |||
void setTargetPositionForBottomLeft (const RelativePoint& newPoint, UndoManager* undoManager); | |||
private: | |||
static const Identifier opacity, overlay, image, topLeft, topRight, bottomLeft; | |||
}; | |||
//============================================================================== | |||
juce_UseDebuggingNewOperator | |||
@@ -151,11 +180,10 @@ private: | |||
bool canDeleteImage; | |||
float opacity; | |||
Colour overlayColour; | |||
Point<float> controlPoints[3]; | |||
RelativePoint controlPoints[3]; | |||
const AffineTransform getTransform() const; | |||
const AffineTransform calculateTransform() const; | |||
DrawableImage (const DrawableImage&); | |||
DrawableImage& operator= (const DrawableImage&); | |||
}; | |||
@@ -28,6 +28,7 @@ | |||
BEGIN_JUCE_NAMESPACE | |||
#include "juce_DrawablePath.h" | |||
#include "juce_DrawableComposite.h" | |||
#include "../../../io/streams/juce_MemoryOutputStream.h" | |||
@@ -35,10 +36,25 @@ BEGIN_JUCE_NAMESPACE | |||
DrawablePath::DrawablePath() | |||
: mainFill (Colours::black), | |||
strokeFill (Colours::transparentBlack), | |||
strokeType (0.0f) | |||
strokeType (0.0f), | |||
pathNeedsUpdating (true), | |||
strokeNeedsUpdating (true) | |||
{ | |||
} | |||
DrawablePath::DrawablePath (const DrawablePath& other) | |||
: mainFill (other.mainFill), | |||
strokeFill (other.strokeFill), | |||
strokeType (other.strokeType), | |||
pathNeedsUpdating (true), | |||
strokeNeedsUpdating (true) | |||
{ | |||
if (other.relativePath != 0) | |||
relativePath = new RelativePointPath (*other.relativePath); | |||
else | |||
path = other.path; | |||
} | |||
DrawablePath::~DrawablePath() | |||
{ | |||
} | |||
@@ -47,7 +63,7 @@ DrawablePath::~DrawablePath() | |||
void DrawablePath::setPath (const Path& newPath) | |||
{ | |||
path = newPath; | |||
updateOutline(); | |||
strokeNeedsUpdating = true; | |||
} | |||
void DrawablePath::setFill (const FillType& newFill) | |||
@@ -63,7 +79,7 @@ void DrawablePath::setStrokeFill (const FillType& newFill) | |||
void DrawablePath::setStrokeType (const PathStrokeType& newStrokeType) | |||
{ | |||
strokeType = newStrokeType; | |||
updateOutline(); | |||
strokeNeedsUpdating = true; | |||
} | |||
void DrawablePath::setStrokeThickness (const float newThickness) | |||
@@ -71,6 +87,55 @@ void DrawablePath::setStrokeThickness (const float newThickness) | |||
setStrokeType (PathStrokeType (newThickness, strokeType.getJointStyle(), strokeType.getEndStyle())); | |||
} | |||
void DrawablePath::updatePath() const | |||
{ | |||
if (pathNeedsUpdating) | |||
{ | |||
pathNeedsUpdating = false; | |||
if (relativePath != 0) | |||
{ | |||
path.clear(); | |||
relativePath->createPath (path, parent); | |||
strokeNeedsUpdating = true; | |||
} | |||
} | |||
} | |||
void DrawablePath::updateStroke() const | |||
{ | |||
if (strokeNeedsUpdating) | |||
{ | |||
strokeNeedsUpdating = false; | |||
updatePath(); | |||
stroke.clear(); | |||
strokeType.createStrokedPath (stroke, path, AffineTransform::identity, 4.0f); | |||
} | |||
} | |||
const Path& DrawablePath::getPath() const | |||
{ | |||
updatePath(); | |||
return path; | |||
} | |||
const Path& DrawablePath::getStrokePath() const | |||
{ | |||
updateStroke(); | |||
return stroke; | |||
} | |||
bool DrawablePath::isStrokeVisible() const throw() | |||
{ | |||
return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.isInvisible(); | |||
} | |||
void DrawablePath::invalidatePoints() | |||
{ | |||
pathNeedsUpdating = true; | |||
strokeNeedsUpdating = true; | |||
} | |||
//============================================================================== | |||
void DrawablePath::render (const Drawable::RenderingContext& context) const | |||
{ | |||
@@ -81,10 +146,10 @@ void DrawablePath::render (const Drawable::RenderingContext& context) const | |||
f.transform = f.transform.followedBy (context.transform); | |||
context.g.setFillType (f); | |||
context.g.fillPath (path, context.transform); | |||
context.g.fillPath (getPath(), context.transform); | |||
} | |||
if (strokeType.getStrokeThickness() > 0.0f) | |||
if (isStrokeVisible()) | |||
{ | |||
FillType f (strokeFill); | |||
if (f.isGradient()) | |||
@@ -92,162 +157,133 @@ void DrawablePath::render (const Drawable::RenderingContext& context) const | |||
f.transform = f.transform.followedBy (context.transform); | |||
context.g.setFillType (f); | |||
context.g.fillPath (stroke, context.transform); | |||
context.g.fillPath (getStrokePath(), context.transform); | |||
} | |||
} | |||
void DrawablePath::updateOutline() | |||
{ | |||
stroke.clear(); | |||
strokeType.createStrokedPath (stroke, path, AffineTransform::identity, 4.0f); | |||
} | |||
const Rectangle<float> DrawablePath::getBounds() const | |||
{ | |||
if (strokeType.getStrokeThickness() > 0.0f) | |||
return stroke.getBounds(); | |||
if (isStrokeVisible()) | |||
return getStrokePath().getBounds(); | |||
else | |||
return path.getBounds(); | |||
return getPath().getBounds(); | |||
} | |||
bool DrawablePath::hitTest (float x, float y) const | |||
{ | |||
return path.contains (x, y) | |||
|| stroke.contains (x, y); | |||
return getPath().contains (x, y) | |||
|| (isStrokeVisible() && getStrokePath().contains (x, y)); | |||
} | |||
Drawable* DrawablePath::createCopy() const | |||
{ | |||
DrawablePath* const dp = new DrawablePath(); | |||
dp->path = path; | |||
dp->stroke = stroke; | |||
dp->mainFill = mainFill; | |||
dp->strokeFill = strokeFill; | |||
dp->strokeType = strokeType; | |||
return dp; | |||
return new DrawablePath (*this); | |||
} | |||
//============================================================================== | |||
const Identifier DrawablePath::valueTreeType ("Path"); | |||
namespace DrawablePathHelpers | |||
{ | |||
static const Identifier type ("type"); | |||
static const Identifier solid ("solid"); | |||
static const Identifier colour ("colour"); | |||
static const Identifier gradient ("gradient"); | |||
static const Identifier x1 ("x1"); | |||
static const Identifier x2 ("x2"); | |||
static const Identifier y1 ("y1"); | |||
static const Identifier y2 ("y2"); | |||
static const Identifier radial ("radial"); | |||
static const Identifier colours ("colours"); | |||
static const Identifier fill ("fill"); | |||
static const Identifier stroke ("stroke"); | |||
static const Identifier jointStyle ("jointStyle"); | |||
static const Identifier capStyle ("capStyle"); | |||
static const Identifier strokeWidth ("strokeWidth"); | |||
static const Identifier path ("path"); | |||
static bool updateFillType (const ValueTree& v, FillType& fillType) | |||
{ | |||
const String type (v[type].toString()); | |||
if (type.equalsIgnoreCase (solid)) | |||
{ | |||
const String colourString (v [colour].toString()); | |||
const Colour newColour (colourString.isEmpty() ? (uint32) 0xff000000 | |||
: (uint32) colourString.getHexValue32()); | |||
if (fillType.isColour() && fillType.colour == newColour) | |||
return false; | |||
const Identifier DrawablePath::ValueTreeWrapper::fill ("fill"); | |||
const Identifier DrawablePath::ValueTreeWrapper::stroke ("stroke"); | |||
const Identifier DrawablePath::ValueTreeWrapper::jointStyle ("jointStyle"); | |||
const Identifier DrawablePath::ValueTreeWrapper::capStyle ("capStyle"); | |||
const Identifier DrawablePath::ValueTreeWrapper::strokeWidth ("strokeWidth"); | |||
const Identifier DrawablePath::ValueTreeWrapper::path ("path"); | |||
fillType.setColour (newColour); | |||
return true; | |||
} | |||
else if (type.equalsIgnoreCase (gradient)) | |||
{ | |||
ColourGradient g; | |||
g.point1.setXY (v[x1], v[y1]); | |||
g.point2.setXY (v[x2], v[y2]); | |||
g.isRadial = v[radial]; | |||
//============================================================================== | |||
DrawablePath::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_) | |||
: ValueTreeWrapperBase (state_) | |||
{ | |||
jassert (state.hasType (valueTreeType)); | |||
} | |||
StringArray colourSteps; | |||
colourSteps.addTokens (v[colours].toString(), false); | |||
const FillType DrawablePath::ValueTreeWrapper::getMainFill() const | |||
{ | |||
return readFillType (state.getChildWithName (fill)); | |||
} | |||
for (int i = 0; i < colourSteps.size() / 2; ++i) | |||
g.addColour (colourSteps[i * 2].getDoubleValue(), | |||
Colour ((uint32) colourSteps[i * 2 + 1].getHexValue32())); | |||
void DrawablePath::ValueTreeWrapper::setMainFill (const FillType& newFill, UndoManager* undoManager) | |||
{ | |||
replaceFillType (fill, newFill, undoManager); | |||
} | |||
if (fillType.isGradient() && *fillType.gradient == g) | |||
return false; | |||
const FillType DrawablePath::ValueTreeWrapper::getStrokeFill() const | |||
{ | |||
return readFillType (state.getChildWithName (stroke)); | |||
} | |||
fillType.setGradient (g); | |||
return true; | |||
} | |||
void DrawablePath::ValueTreeWrapper::setStrokeFill (const FillType& newFill, UndoManager* undoManager) | |||
{ | |||
replaceFillType (stroke, newFill, undoManager); | |||
} | |||
jassertfalse; | |||
return false; | |||
} | |||
const PathStrokeType DrawablePath::ValueTreeWrapper::getStrokeType() const | |||
{ | |||
const String jointStyleString (state [jointStyle].toString()); | |||
const String capStyleString (state [capStyle].toString()); | |||
return PathStrokeType (state [strokeWidth], | |||
jointStyleString == "curved" ? PathStrokeType::curved | |||
: (jointStyleString == "bevel" ? PathStrokeType::beveled | |||
: PathStrokeType::mitered), | |||
capStyleString == "square" ? PathStrokeType::square | |||
: (capStyleString == "round" ? PathStrokeType::rounded | |||
: PathStrokeType::butt)); | |||
} | |||
static ValueTree createFillType (const Identifier& tagName, const FillType& fillType) | |||
{ | |||
ValueTree v (tagName); | |||
void DrawablePath::ValueTreeWrapper::setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager) | |||
{ | |||
state.setProperty (strokeWidth, (double) newStrokeType.getStrokeThickness(), undoManager); | |||
state.setProperty (jointStyle, newStrokeType.getJointStyle() == PathStrokeType::mitered | |||
? "miter" : (newStrokeType.getJointStyle() == PathStrokeType::curved ? "curved" : "bevel"), undoManager); | |||
state.setProperty (capStyle, newStrokeType.getEndStyle() == PathStrokeType::butt | |||
? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager); | |||
} | |||
if (fillType.isColour()) | |||
{ | |||
v.setProperty (type, "solid", 0); | |||
v.setProperty (colour, String::toHexString ((int) fillType.colour.getARGB()), 0); | |||
} | |||
else if (fillType.isGradient()) | |||
{ | |||
v.setProperty (type, "gradient", 0); | |||
v.setProperty (x1, fillType.gradient->point1.getX(), 0); | |||
v.setProperty (y1, fillType.gradient->point1.getY(), 0); | |||
v.setProperty (x2, fillType.gradient->point2.getX(), 0); | |||
v.setProperty (y2, fillType.gradient->point2.getY(), 0); | |||
v.setProperty (radial, fillType.gradient->isRadial, 0); | |||
String s; | |||
for (int i = 0; i < fillType.gradient->getNumColours(); ++i) | |||
s << " " << fillType.gradient->getColourPosition (i) | |||
<< " " << String::toHexString ((int) fillType.gradient->getColour(i).getARGB()); | |||
v.setProperty (colours, s.trimStart(), 0); | |||
} | |||
else | |||
{ | |||
jassertfalse; //xxx | |||
} | |||
void DrawablePath::ValueTreeWrapper::getPath (RelativePointPath& p) const | |||
{ | |||
RelativePointPath newPath (state [path]); | |||
p.swapWith (newPath); | |||
} | |||
return v; | |||
} | |||
void DrawablePath::ValueTreeWrapper::setPath (const String& newPath, UndoManager* undoManager) | |||
{ | |||
state.setProperty (path, newPath, undoManager); | |||
} | |||
const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) | |||
{ | |||
jassert (tree.hasType (valueTreeType)); | |||
Rectangle<float> damageRect; | |||
setName (tree [idProperty]); | |||
ValueTreeWrapper v (tree); | |||
setName (v.getID()); | |||
bool needsRedraw = false; | |||
const FillType newFill (v.getMainFill()); | |||
if (mainFill != newFill) | |||
{ | |||
needsRedraw = true; | |||
mainFill = newFill; | |||
} | |||
const FillType newStrokeFill (v.getStrokeFill()); | |||
bool needsRedraw = DrawablePathHelpers::updateFillType (tree.getChildWithName (DrawablePathHelpers::fill), mainFill); | |||
needsRedraw = DrawablePathHelpers::updateFillType (tree.getChildWithName (DrawablePathHelpers::stroke), strokeFill) || needsRedraw; | |||
if (strokeFill != newStrokeFill) | |||
{ | |||
needsRedraw = true; | |||
strokeFill = newStrokeFill; | |||
} | |||
const String jointStyle (tree [DrawablePathHelpers::jointStyle].toString()); | |||
const String endStyle (tree [DrawablePathHelpers::capStyle].toString()); | |||
const PathStrokeType newStroke (v.getStrokeType()); | |||
PathStrokeType newStroke (tree [DrawablePathHelpers::strokeWidth], | |||
jointStyle == "curved" ? PathStrokeType::curved | |||
: (jointStyle == "bevel" ? PathStrokeType::beveled | |||
: PathStrokeType::mitered), | |||
endStyle == "square" ? PathStrokeType::square | |||
: (endStyle == "round" ? PathStrokeType::rounded | |||
: PathStrokeType::butt)); | |||
ScopedPointer<RelativePointPath> newRelativePath (new RelativePointPath()); | |||
v.getPath (*newRelativePath); | |||
Path newPath; | |||
newPath.restoreFromString (tree [DrawablePathHelpers::path]); | |||
newRelativePath->createPath (newPath, parent); | |||
if (! newRelativePath->containsAnyDynamicPoints()) | |||
newRelativePath = 0; | |||
if (strokeType != newStroke || path != newPath) | |||
{ | |||
@@ -257,6 +293,8 @@ const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree | |||
needsRedraw = true; | |||
} | |||
relativePath = newRelativePath.release(); | |||
if (needsRedraw) | |||
damageRect = damageRect.getUnion (getBounds()); | |||
@@ -265,22 +303,20 @@ const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree | |||
const ValueTree DrawablePath::createValueTree (ImageProvider* imageProvider) const | |||
{ | |||
ValueTree v (valueTreeType); | |||
ValueTree tree (valueTreeType); | |||
ValueTreeWrapper v (tree); | |||
v.addChild (DrawablePathHelpers::createFillType (DrawablePathHelpers::fill, mainFill), -1, 0); | |||
v.addChild (DrawablePathHelpers::createFillType (DrawablePathHelpers::stroke, strokeFill), -1, 0); | |||
v.setID (getName(), 0); | |||
v.setMainFill (mainFill, 0); | |||
v.setStrokeFill (strokeFill, 0); | |||
v.setStrokeType (strokeType, 0); | |||
if (getName().isNotEmpty()) | |||
v.setProperty (idProperty, getName(), 0); | |||
v.setProperty (DrawablePathHelpers::strokeWidth, (double) strokeType.getStrokeThickness(), 0); | |||
v.setProperty (DrawablePathHelpers::jointStyle, strokeType.getJointStyle() == PathStrokeType::mitered | |||
? "miter" : (strokeType.getJointStyle() == PathStrokeType::curved ? "curved" : "bevel"), 0); | |||
v.setProperty (DrawablePathHelpers::capStyle, strokeType.getEndStyle() == PathStrokeType::butt | |||
? "butt" : (strokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), 0); | |||
v.setProperty (DrawablePathHelpers::path, path.toString(), 0); | |||
if (relativePath != 0) | |||
v.setPath (relativePath->toString(), 0); | |||
else | |||
v.setPath (path.toString(), 0); | |||
return v; | |||
return tree; | |||
} | |||
@@ -40,9 +40,9 @@ class JUCE_API DrawablePath : public Drawable | |||
{ | |||
public: | |||
//============================================================================== | |||
/** Creates a DrawablePath. | |||
*/ | |||
/** Creates a DrawablePath. */ | |||
DrawablePath(); | |||
DrawablePath (const DrawablePath& other); | |||
/** Destructor. */ | |||
virtual ~DrawablePath(); | |||
@@ -54,9 +54,6 @@ public: | |||
*/ | |||
void setPath (const Path& newPath); | |||
/** Returns the current path. */ | |||
const Path& getPath() const throw() { return path; } | |||
/** Sets a fill type for the path. | |||
This colour is used to fill the path - if you don't want the path to be | |||
@@ -97,6 +94,13 @@ public: | |||
const PathStrokeType& getStrokeType() const throw() { return strokeType; } | |||
//============================================================================== | |||
/** Returns the current path. */ | |||
const Path& getPath() const; | |||
/** Returns the current path for the outline. */ | |||
const Path& getStrokePath() const; | |||
//============================================================================== | |||
/** @internal */ | |||
void render (const Drawable::RenderingContext& context) const; | |||
@@ -107,6 +111,8 @@ public: | |||
/** @internal */ | |||
Drawable* createCopy() const; | |||
/** @internal */ | |||
void invalidatePoints(); | |||
/** @internal */ | |||
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider); | |||
/** @internal */ | |||
const ValueTree createValueTree (ImageProvider* imageProvider) const; | |||
@@ -115,17 +121,43 @@ public: | |||
/** @internal */ | |||
const Identifier getValueTreeType() const { return valueTreeType; } | |||
//============================================================================== | |||
/** Internally-used class for wrapping a DrawablePath's state into a ValueTree. */ | |||
class ValueTreeWrapper : public ValueTreeWrapperBase | |||
{ | |||
public: | |||
ValueTreeWrapper (const ValueTree& state); | |||
const FillType getMainFill() const; | |||
void setMainFill (const FillType& newFill, UndoManager* undoManager); | |||
const FillType getStrokeFill() const; | |||
void setStrokeFill (const FillType& newFill, UndoManager* undoManager); | |||
const PathStrokeType getStrokeType() const; | |||
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager); | |||
void getPath (RelativePointPath& path) const; | |||
void setPath (const String& newPath, UndoManager* undoManager); | |||
private: | |||
static const Identifier fill, stroke, jointStyle, capStyle, strokeWidth, path; | |||
}; | |||
//============================================================================== | |||
juce_UseDebuggingNewOperator | |||
private: | |||
Path path, stroke; | |||
FillType mainFill, strokeFill; | |||
PathStrokeType strokeType; | |||
ScopedPointer<RelativePointPath> relativePath; | |||
mutable Path path, stroke; | |||
mutable bool pathNeedsUpdating, strokeNeedsUpdating; | |||
void updateOutline(); | |||
void updatePath() const; | |||
void updateStroke() const; | |||
bool isStrokeVisible() const throw(); | |||
DrawablePath (const DrawablePath&); | |||
DrawablePath& operator= (const DrawablePath&); | |||
}; | |||
@@ -36,6 +36,12 @@ DrawableText::DrawableText() | |||
{ | |||
} | |||
DrawableText::DrawableText (const DrawableText& other) | |||
: text (other.text), | |||
colour (other.colour) | |||
{ | |||
} | |||
DrawableText::~DrawableText() | |||
{ | |||
} | |||
@@ -76,21 +82,28 @@ bool DrawableText::hitTest (float x, float y) const | |||
Drawable* DrawableText::createCopy() const | |||
{ | |||
DrawableText* const dt = new DrawableText(); | |||
dt->text = text; | |||
dt->colour = colour; | |||
return new DrawableText (*this); | |||
} | |||
return dt; | |||
void DrawableText::invalidatePoints() | |||
{ | |||
} | |||
//============================================================================== | |||
const Identifier DrawableText::valueTreeType ("Text"); | |||
const Identifier DrawableText::ValueTreeWrapper::text ("text"); | |||
DrawableText::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_) | |||
: ValueTreeWrapperBase (state_) | |||
{ | |||
jassert (state.hasType (valueTreeType)); | |||
} | |||
const Rectangle<float> DrawableText::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) | |||
{ | |||
jassert (tree.hasType (valueTreeType)); | |||
setName (tree [idProperty]); | |||
ValueTreeWrapper v (tree); | |||
setName (v.getID()); | |||
jassertfalse; // xxx not finished! | |||
@@ -99,13 +112,14 @@ const Rectangle<float> DrawableText::refreshFromValueTree (const ValueTree& tree | |||
const ValueTree DrawableText::createValueTree (ImageProvider* imageProvider) const | |||
{ | |||
ValueTree v (valueTreeType); | |||
ValueTree tree (valueTreeType); | |||
ValueTreeWrapper v (tree); | |||
if (getName().isNotEmpty()) | |||
v.setProperty (idProperty, getName(), 0); | |||
v.setID (getName(), 0); | |||
jassertfalse; // xxx not finished! | |||
return v; | |||
return tree; | |||
} | |||
@@ -42,6 +42,7 @@ public: | |||
//============================================================================== | |||
/** Creates a DrawableText object. */ | |||
DrawableText(); | |||
DrawableText (const DrawableText& other); | |||
/** Destructor. */ | |||
virtual ~DrawableText(); | |||
@@ -78,6 +79,8 @@ public: | |||
/** @internal */ | |||
Drawable* createCopy() const; | |||
/** @internal */ | |||
void invalidatePoints(); | |||
/** @internal */ | |||
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider); | |||
/** @internal */ | |||
const ValueTree createValueTree (ImageProvider* imageProvider) const; | |||
@@ -86,6 +89,19 @@ public: | |||
/** @internal */ | |||
const Identifier getValueTreeType() const { return valueTreeType; } | |||
//============================================================================== | |||
/** Internally-used class for wrapping a DrawableText's state into a ValueTree. */ | |||
class ValueTreeWrapper : public ValueTreeWrapperBase | |||
{ | |||
public: | |||
ValueTreeWrapper (const ValueTree& state); | |||
//xxx todo | |||
private: | |||
static const Identifier text; | |||
}; | |||
//============================================================================== | |||
juce_UseDebuggingNewOperator | |||
@@ -93,7 +109,6 @@ private: | |||
GlyphArrangement text; | |||
Colour colour; | |||
DrawableText (const DrawableText&); | |||
DrawableText& operator= (const DrawableText&); | |||
}; | |||
@@ -74,12 +74,7 @@ namespace PathHelpers | |||
while (*t != 0 && ! CharacterFunctions::isWhitespace (*t)) | |||
++t; | |||
const int length = (int) (t - start); | |||
while (CharacterFunctions::isWhitespace (*t)) | |||
++t; | |||
return String (start, length); | |||
return String (start, (int) (t - start)); | |||
} | |||
} | |||
@@ -1479,12 +1474,15 @@ void Path::restoreFromString (const String& stringVersion) | |||
int numValues = 2; | |||
float values [6]; | |||
while (*t != 0) | |||
for (;;) | |||
{ | |||
const String token (PathHelpers::nextToken (t)); | |||
const juce_wchar firstChar = token[0]; | |||
int startNum = 0; | |||
if (firstChar == 0) | |||
break; | |||
if (firstChar == 'm' || firstChar == 'l') | |||
{ | |||
marker = firstChar; | |||
@@ -28,6 +28,8 @@ | |||
BEGIN_JUCE_NAMESPACE | |||
#include "juce_RelativeCoordinate.h" | |||
#include "../../../io/streams/juce_MemoryOutputStream.h" | |||
//============================================================================== | |||
namespace RelativeCoordinateHelpers | |||
@@ -61,9 +63,10 @@ namespace RelativeCoordinateHelpers | |||
return fullName.fromFirstOccurrenceOf (".", false, false); | |||
} | |||
static const RelativeCoordinate findCoordinate (const String& name, const RelativeCoordinate::NamedCoordinateFinder& nameFinder) | |||
static const RelativeCoordinate findCoordinate (const String& name, const RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
{ | |||
return nameFinder.findNamedCoordinate (getObjectName (name), getEdgeName (name)); | |||
return nameFinder != 0 ? nameFinder->findNamedCoordinate (getObjectName (name), getEdgeName (name)) | |||
: RelativeCoordinate(); | |||
} | |||
//============================================================================== | |||
@@ -81,6 +84,13 @@ namespace RelativeCoordinateHelpers | |||
++i; | |||
} | |||
static void skipComma (const String& s, int& i) | |||
{ | |||
skipWhitespace (s, i); | |||
if (s[i] == ',') | |||
++i; | |||
} | |||
static const String readAnchorName (const String& s, int& i) | |||
{ | |||
skipWhitespace (s, i); | |||
@@ -126,10 +136,89 @@ namespace RelativeCoordinateHelpers | |||
return value; | |||
} | |||
static const RelativeCoordinate readNextCoordinate (const String& 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); | |||
if (anchor1.isEmpty()) | |||
anchor1 = getOriginAnchorName (isHorizontal); | |||
skipWhitespace (s, i); | |||
if (s[i] == '-' && s[i + 1] == '>') | |||
{ | |||
i += 2; | |||
anchor2 = readAnchorName (s, i); | |||
} | |||
else | |||
{ | |||
anchor2 = anchor1; | |||
anchor1 = getOriginAnchorName (isHorizontal); | |||
} | |||
} | |||
else | |||
{ | |||
anchor1 = getOriginAnchorName (isHorizontal); | |||
anchor2 = getExtentAnchorName (isHorizontal); | |||
} | |||
return RelativeCoordinate (value, anchor1, anchor2); | |||
} | |||
return RelativeCoordinate (value, isHorizontal); | |||
} | |||
} | |||
static const String limitedAccuracyString (const double n) | |||
{ | |||
return String (n, 3).trimCharactersAtEnd ("0").trimCharactersAtEnd ("."); | |||
} | |||
static bool couldBeMistakenForPathCommand (const String& s) | |||
{ | |||
switch (s[0]) | |||
{ | |||
case 'a': | |||
case 'm': | |||
case 'l': | |||
case 'z': | |||
case 'q': | |||
case 'c': | |||
return s[1] == 0 || CharacterFunctions::isWhitespace (s[1]); | |||
default: | |||
break; | |||
} | |||
return false; | |||
} | |||
} | |||
//============================================================================== | |||
@@ -171,10 +260,27 @@ RelativeCoordinate::RelativeCoordinate (const double relativeProportion, const S | |||
jassert (anchor2.isNotEmpty()); | |||
} | |||
RelativeCoordinate::RelativeCoordinate (const String& s, const bool isHorizontal) | |||
: value (0) | |||
{ | |||
int i = 0; | |||
*this = RelativeCoordinateHelpers::readNextCoordinate (s, i, isHorizontal); | |||
} | |||
RelativeCoordinate::~RelativeCoordinate() | |||
{ | |||
} | |||
bool RelativeCoordinate::operator== (const RelativeCoordinate& other) const throw() | |||
{ | |||
return value == other.value && anchor1 == other.anchor1 && anchor2 == other.anchor2; | |||
} | |||
bool RelativeCoordinate::operator!= (const RelativeCoordinate& other) const throw() | |||
{ | |||
return ! operator== (other); | |||
} | |||
//============================================================================== | |||
const RelativeCoordinate RelativeCoordinate::getAnchorCoordinate1() const | |||
{ | |||
@@ -186,7 +292,7 @@ const RelativeCoordinate RelativeCoordinate::getAnchorCoordinate2() const | |||
return RelativeCoordinate (0.0, anchor2); | |||
} | |||
double RelativeCoordinate::resolveAnchor (const String& anchorName, const NamedCoordinateFinder& nameFinder, int recursionCounter) | |||
double RelativeCoordinate::resolveAnchor (const String& anchorName, const NamedCoordinateFinder* nameFinder, int recursionCounter) | |||
{ | |||
if (RelativeCoordinateHelpers::isOrigin (anchorName)) | |||
return 0.0; | |||
@@ -194,7 +300,7 @@ double RelativeCoordinate::resolveAnchor (const String& anchorName, const NamedC | |||
return RelativeCoordinateHelpers::findCoordinate (anchorName, nameFinder).resolve (nameFinder, recursionCounter + 1); | |||
} | |||
double RelativeCoordinate::resolve (const NamedCoordinateFinder& nameFinder, int recursionCounter) const | |||
double RelativeCoordinate::resolve (const NamedCoordinateFinder* nameFinder, int recursionCounter) const | |||
{ | |||
if (recursionCounter > 150) | |||
{ | |||
@@ -208,7 +314,7 @@ double RelativeCoordinate::resolve (const NamedCoordinateFinder& nameFinder, int | |||
: pos1 + value; | |||
} | |||
double RelativeCoordinate::resolve (const NamedCoordinateFinder& nameFinder) const | |||
double RelativeCoordinate::resolve (const NamedCoordinateFinder* nameFinder) const | |||
{ | |||
try | |||
{ | |||
@@ -220,7 +326,7 @@ double RelativeCoordinate::resolve (const NamedCoordinateFinder& nameFinder) con | |||
return 0.0; | |||
} | |||
bool RelativeCoordinate::isRecursive (const NamedCoordinateFinder& nameFinder) const | |||
bool RelativeCoordinate::isRecursive (const NamedCoordinateFinder* nameFinder) const | |||
{ | |||
try | |||
{ | |||
@@ -234,7 +340,7 @@ bool RelativeCoordinate::isRecursive (const NamedCoordinateFinder& nameFinder) c | |||
return false; | |||
} | |||
void RelativeCoordinate::moveToAbsolute (double newPos, const NamedCoordinateFinder& nameFinder) | |||
void RelativeCoordinate::moveToAbsolute (double newPos, const NamedCoordinateFinder* nameFinder) | |||
{ | |||
try | |||
{ | |||
@@ -256,7 +362,7 @@ void RelativeCoordinate::moveToAbsolute (double newPos, const NamedCoordinateFin | |||
{} | |||
} | |||
void RelativeCoordinate::toggleProportionality (const NamedCoordinateFinder& nameFinder, bool isHorizontal) | |||
void RelativeCoordinate::toggleProportionality (const NamedCoordinateFinder* nameFinder, bool isHorizontal) | |||
{ | |||
const double oldValue = resolve (nameFinder); | |||
@@ -267,8 +373,7 @@ void RelativeCoordinate::toggleProportionality (const NamedCoordinateFinder& nam | |||
moveToAbsolute (oldValue, nameFinder); | |||
} | |||
//============================================================================== | |||
bool RelativeCoordinate::references (const String& coordName, const NamedCoordinateFinder& nameFinder) const | |||
bool RelativeCoordinate::references (const String& coordName, const NamedCoordinateFinder* nameFinder) const | |||
{ | |||
using namespace RelativeCoordinateHelpers; | |||
@@ -281,65 +386,12 @@ bool RelativeCoordinate::references (const String& coordName, const NamedCoordin | |||
|| (isProportional() && findCoordinate (anchor2, nameFinder).references (coordName, nameFinder)); | |||
} | |||
//============================================================================== | |||
RelativeCoordinate::RelativeCoordinate (const String& s, bool isHorizontal) | |||
: value (0) | |||
bool RelativeCoordinate::isDynamic() const | |||
{ | |||
using namespace RelativeCoordinateHelpers; | |||
int i = 0; | |||
anchor1 = readAnchorName (s, i); | |||
if (anchor1.isNotEmpty()) | |||
{ | |||
skipWhitespace (s, i); | |||
if (s[i] == '+') | |||
value = readNumber (s, ++i); | |||
else if (s[i] == '-') | |||
value = -readNumber (s, ++i); | |||
} | |||
else | |||
{ | |||
anchor1 = getOriginAnchorName (isHorizontal); | |||
value = readNumber (s, i); | |||
skipWhitespace (s, i); | |||
if (s[i] == '%') | |||
{ | |||
value /= 100.0; | |||
skipWhitespace (s, ++i); | |||
if (s[i] == '*') | |||
{ | |||
anchor1 = readAnchorName (s, ++i); | |||
if (anchor1.isEmpty()) | |||
anchor1 = getOriginAnchorName (isHorizontal); | |||
skipWhitespace (s, i); | |||
if (s[i] == '-' && s[i + 1] == '>') | |||
{ | |||
i += 2; | |||
anchor2 = readAnchorName (s, i); | |||
} | |||
else | |||
{ | |||
anchor2 = anchor1; | |||
anchor1 = getOriginAnchorName (isHorizontal); | |||
} | |||
} | |||
else | |||
{ | |||
anchor1 = getOriginAnchorName (isHorizontal); | |||
anchor2 = getExtentAnchorName (isHorizontal); | |||
} | |||
} | |||
} | |||
return anchor2.isNotEmpty() || ! RelativeCoordinateHelpers::isOrigin (anchor1); | |||
} | |||
//============================================================================== | |||
const String RelativeCoordinate::toString() const | |||
{ | |||
using namespace RelativeCoordinateHelpers; | |||
@@ -383,7 +435,7 @@ void RelativeCoordinate::setEditableNumber (const double newValue) | |||
} | |||
//============================================================================== | |||
void RelativeCoordinate::changeAnchor1 (const String& newAnchorName, const NamedCoordinateFinder& nameFinder) | |||
void RelativeCoordinate::changeAnchor1 (const String& newAnchorName, const NamedCoordinateFinder* nameFinder) | |||
{ | |||
jassert (newAnchorName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
@@ -392,7 +444,7 @@ void RelativeCoordinate::changeAnchor1 (const String& newAnchorName, const Named | |||
moveToAbsolute (oldValue, nameFinder); | |||
} | |||
void RelativeCoordinate::changeAnchor2 (const String& newAnchorName, const NamedCoordinateFinder& nameFinder) | |||
void RelativeCoordinate::changeAnchor2 (const String& newAnchorName, const NamedCoordinateFinder* nameFinder) | |||
{ | |||
jassert (isProportional()); | |||
jassert (newAnchorName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_.")); | |||
@@ -402,7 +454,7 @@ void RelativeCoordinate::changeAnchor2 (const String& newAnchorName, const Named | |||
moveToAbsolute (oldValue, nameFinder); | |||
} | |||
void RelativeCoordinate::renameAnchorIfUsed (const String& oldName, const String& newName, const NamedCoordinateFinder& nameFinder) | |||
void RelativeCoordinate::renameAnchorIfUsed (const String& oldName, const String& newName, const NamedCoordinateFinder* nameFinder) | |||
{ | |||
using namespace RelativeCoordinateHelpers; | |||
jassert (oldName.isNotEmpty()); | |||
@@ -439,21 +491,36 @@ RelativePoint::RelativePoint (const Point<float>& absolutePoint) | |||
{ | |||
} | |||
RelativePoint::RelativePoint (const String& stringVersion) | |||
RelativePoint::RelativePoint (const RelativeCoordinate& x_, const RelativeCoordinate& y_) | |||
: x (x_), y (y_) | |||
{ | |||
const int separator = stringVersion.indexOfChar (','); | |||
} | |||
x = RelativeCoordinate (stringVersion.substring (0, separator), true); | |||
y = RelativeCoordinate (stringVersion.substring (separator + 1), false); | |||
RelativePoint::RelativePoint (const String& s) | |||
{ | |||
int i = 0; | |||
x = RelativeCoordinateHelpers::readNextCoordinate (s, i, true); | |||
RelativeCoordinateHelpers::skipComma (s, i); | |||
y = RelativeCoordinateHelpers::readNextCoordinate (s, i, false); | |||
} | |||
const Point<float> RelativePoint::resolve (const RelativeCoordinate::NamedCoordinateFinder& nameFinder) const | |||
bool RelativePoint::operator== (const RelativePoint& other) const throw() | |||
{ | |||
return x == other.x && y == other.y; | |||
} | |||
bool RelativePoint::operator!= (const RelativePoint& other) const throw() | |||
{ | |||
return ! operator== (other); | |||
} | |||
const Point<float> RelativePoint::resolve (const RelativeCoordinate::NamedCoordinateFinder* nameFinder) const | |||
{ | |||
return Point<float> ((float) x.resolve (nameFinder), | |||
(float) y.resolve (nameFinder)); | |||
} | |||
void RelativePoint::moveToAbsolute (const Point<float>& newPos, const RelativeCoordinate::NamedCoordinateFinder& nameFinder) | |||
void RelativePoint::moveToAbsolute (const Point<float>& newPos, const RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
{ | |||
x.moveToAbsolute (newPos.getX(), nameFinder); | |||
y.moveToAbsolute (newPos.getY(), nameFinder); | |||
@@ -464,12 +531,17 @@ 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::renameAnchorIfUsed (const String& oldName, const String& newName, const RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
{ | |||
x.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
y.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
} | |||
bool RelativePoint::isDynamic() const | |||
{ | |||
return x.isDynamic() || y.isDynamic(); | |||
} | |||
//============================================================================== | |||
RelativeRectangle::RelativeRectangle() | |||
@@ -484,18 +556,29 @@ RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect, const String | |||
{ | |||
} | |||
RelativeRectangle::RelativeRectangle (const String& stringVersion) | |||
RelativeRectangle::RelativeRectangle (const String& s) | |||
{ | |||
StringArray tokens; | |||
tokens.addTokens (stringVersion, ",", String::empty); | |||
int i = 0; | |||
left = RelativeCoordinateHelpers::readNextCoordinate (s, i, true); | |||
RelativeCoordinateHelpers::skipComma (s, i); | |||
top = RelativeCoordinateHelpers::readNextCoordinate (s, i, false); | |||
RelativeCoordinateHelpers::skipComma (s, i); | |||
right = RelativeCoordinateHelpers::readNextCoordinate (s, i, true); | |||
RelativeCoordinateHelpers::skipComma (s, i); | |||
bottom = RelativeCoordinateHelpers::readNextCoordinate (s, i, false); | |||
} | |||
left = RelativeCoordinate (tokens [0], true); | |||
top = RelativeCoordinate (tokens [1], false); | |||
right = RelativeCoordinate (tokens [2], true); | |||
bottom = RelativeCoordinate (tokens [3], false); | |||
bool RelativeRectangle::operator== (const RelativeRectangle& other) const throw() | |||
{ | |||
return left == other.left && top == other.top && right == other.right && bottom == other.bottom; | |||
} | |||
const Rectangle<float> RelativeRectangle::resolve (const RelativeCoordinate::NamedCoordinateFinder& nameFinder) const | |||
bool RelativeRectangle::operator!= (const RelativeRectangle& other) const throw() | |||
{ | |||
return ! operator== (other); | |||
} | |||
const Rectangle<float> RelativeRectangle::resolve (const RelativeCoordinate::NamedCoordinateFinder* nameFinder) const | |||
{ | |||
const double l = left.resolve (nameFinder); | |||
const double r = right.resolve (nameFinder); | |||
@@ -505,7 +588,7 @@ const Rectangle<float> RelativeRectangle::resolve (const RelativeCoordinate::Nam | |||
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 RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
{ | |||
left.moveToAbsolute (newPos.getX(), nameFinder); | |||
right.moveToAbsolute (newPos.getRight(), nameFinder); | |||
@@ -519,7 +602,7 @@ const String RelativeRectangle::toString() const | |||
} | |||
void RelativeRectangle::renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const RelativeCoordinate::NamedCoordinateFinder& nameFinder) | |||
const RelativeCoordinate::NamedCoordinateFinder* nameFinder) | |||
{ | |||
left.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
right.renameAnchorIfUsed (oldName, newName, nameFinder); | |||
@@ -528,4 +611,264 @@ void RelativeRectangle::renameAnchorIfUsed (const String& oldName, const String& | |||
} | |||
//============================================================================== | |||
RelativePointPath::RelativePointPath() | |||
: usesNonZeroWinding (true), | |||
containsDynamicPoints (false) | |||
{ | |||
} | |||
RelativePointPath::RelativePointPath (const RelativePointPath& other) | |||
: usesNonZeroWinding (true), | |||
containsDynamicPoints (false) | |||
{ | |||
parseString (other.toString()); | |||
} | |||
RelativePointPath::RelativePointPath (const String& s) | |||
: usesNonZeroWinding (true), | |||
containsDynamicPoints (false) | |||
{ | |||
parseString (s); | |||
} | |||
void RelativePointPath::parseString (const String& s) | |||
{ | |||
int i = 0; | |||
juce_wchar marker = 'm'; | |||
int numValues = 2; | |||
RelativePoint points [3]; | |||
for (;;) | |||
{ | |||
RelativeCoordinateHelpers::skipWhitespace (s, i); | |||
const juce_wchar firstChar = s[i]; | |||
if (firstChar == 0) | |||
break; | |||
const juce_wchar secondChar = s[i + 1]; | |||
if (secondChar == 0 || CharacterFunctions::isWhitespace (secondChar)) | |||
{ | |||
if (firstChar == 'm' || firstChar == 'l') | |||
{ | |||
++i; | |||
marker = firstChar; | |||
numValues = 1; | |||
} | |||
else if (firstChar == 'q') | |||
{ | |||
++i; | |||
marker = firstChar; | |||
numValues = 2; | |||
} | |||
else if (firstChar == 'c') | |||
{ | |||
++i; | |||
marker = firstChar; | |||
numValues = 3; | |||
} | |||
else if (firstChar == 'z') | |||
{ | |||
++i; | |||
marker = 'm'; | |||
numValues = 2; | |||
elements.add (new CloseSubPath()); | |||
continue; | |||
} | |||
else if (firstChar == 'a') | |||
{ | |||
++i; | |||
usesNonZeroWinding = false; | |||
continue; | |||
} | |||
} | |||
if (firstChar == '#') | |||
++i; | |||
for (int j = 0; j < numValues; ++j) | |||
{ | |||
const RelativeCoordinate x (RelativeCoordinateHelpers::readNextCoordinate (s, i, true)); | |||
const RelativeCoordinate y (RelativeCoordinateHelpers::readNextCoordinate (s, i, false)); | |||
points[j] = RelativePoint (x, y); | |||
containsDynamicPoints = containsDynamicPoints || points[j].isDynamic(); | |||
} | |||
switch (marker) | |||
{ | |||
case 'm': elements.add (new StartSubPath (points[0])); break; | |||
case 'l': elements.add (new LineTo (points[0])); break; | |||
case 'q': elements.add (new QuadraticTo (points[0], points[1])); break; | |||
case 'c': elements.add (new CubicTo (points[0], points[1], points[2])); break; | |||
default: jassertfalse; break; // illegal string format? | |||
} | |||
} | |||
} | |||
RelativePointPath::~RelativePointPath() | |||
{ | |||
} | |||
void RelativePointPath::swapWith (RelativePointPath& other) throw() | |||
{ | |||
elements.swapWithArray (other.elements); | |||
swapVariables (usesNonZeroWinding, other.usesNonZeroWinding); | |||
} | |||
void RelativePointPath::createPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) | |||
{ | |||
for (int i = 0; i < elements.size(); ++i) | |||
elements.getUnchecked(i)->addToPath (path, coordFinder); | |||
} | |||
bool RelativePointPath::containsAnyDynamicPoints() const | |||
{ | |||
return containsDynamicPoints; | |||
} | |||
const String RelativePointPath::toString() const | |||
{ | |||
ElementType lastType = nullElement; | |||
MemoryOutputStream out; | |||
if (! usesNonZeroWinding) | |||
out << 'a'; | |||
for (int i = 0; i < elements.size(); ++i) | |||
{ | |||
if (out.getDataSize() > 0) | |||
out << ' '; | |||
const ElementBase* const e = elements.getUnchecked(i); | |||
e->write (out, lastType); | |||
lastType = e->type; | |||
} | |||
return out.toUTF8(); | |||
} | |||
//============================================================================== | |||
RelativePointPath::ElementBase::ElementBase (const ElementType type_) : type (type_) | |||
{ | |||
} | |||
//============================================================================== | |||
RelativePointPath::StartSubPath::StartSubPath (const RelativePoint& pos) | |||
: ElementBase (startSubPathElement), startPos (pos) | |||
{ | |||
} | |||
void RelativePointPath::StartSubPath::write (OutputStream& out, ElementType lastTypeWritten) const | |||
{ | |||
const String p (startPos.toString()); | |||
if (lastTypeWritten != startSubPathElement) | |||
out << "m "; | |||
else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p)) | |||
out << '#'; | |||
out << p; | |||
} | |||
void RelativePointPath::StartSubPath::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const | |||
{ | |||
const Point<float> p (startPos.resolve (coordFinder)); | |||
path.startNewSubPath (p.getX(), p.getY()); | |||
} | |||
//============================================================================== | |||
RelativePointPath::CloseSubPath::CloseSubPath() | |||
: ElementBase (closeSubPathElement) | |||
{ | |||
} | |||
void RelativePointPath::CloseSubPath::write (OutputStream& out, ElementType lastTypeWritten) const | |||
{ | |||
if (lastTypeWritten != closeSubPathElement) | |||
out << 'z'; | |||
} | |||
void RelativePointPath::CloseSubPath::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder*) const | |||
{ | |||
path.closeSubPath(); | |||
} | |||
//============================================================================== | |||
RelativePointPath::LineTo::LineTo (const RelativePoint& endPoint_) | |||
: ElementBase (lineToElement), endPoint (endPoint_) | |||
{ | |||
} | |||
void RelativePointPath::LineTo::write (OutputStream& out, ElementType lastTypeWritten) const | |||
{ | |||
const String p (endPoint.toString()); | |||
if (lastTypeWritten != lineToElement) | |||
out << "l "; | |||
else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p)) | |||
out << '#'; | |||
out << p; | |||
} | |||
void RelativePointPath::LineTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const | |||
{ | |||
const Point<float> p (endPoint.resolve (coordFinder)); | |||
path.lineTo (p.getX(), p.getY()); | |||
} | |||
//============================================================================== | |||
RelativePointPath::QuadraticTo::QuadraticTo (const RelativePoint& controlPoint_, const RelativePoint& endPoint_) | |||
: ElementBase (quadraticToElement), controlPoint (controlPoint_), endPoint (endPoint_) | |||
{ | |||
} | |||
void RelativePointPath::QuadraticTo::write (OutputStream& out, ElementType lastTypeWritten) const | |||
{ | |||
const String p1 (controlPoint.toString()); | |||
if (lastTypeWritten != quadraticToElement) | |||
out << "q "; | |||
else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1)) | |||
out << '#'; | |||
out << p1 << ' ' << endPoint.toString(); | |||
} | |||
void RelativePointPath::QuadraticTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const | |||
{ | |||
const Point<float> p1 (controlPoint.resolve (coordFinder)); | |||
const Point<float> p2 (endPoint.resolve (coordFinder)); | |||
path.quadraticTo (p1.getX(), p1.getY(), p2.getX(), p2.getY()); | |||
} | |||
//============================================================================== | |||
RelativePointPath::CubicTo::CubicTo (const RelativePoint& controlPoint1_, const RelativePoint& controlPoint2_, const RelativePoint& endPoint_) | |||
: ElementBase (cubicToElement), controlPoint1 (controlPoint1_), controlPoint2 (controlPoint2_), endPoint (endPoint_) | |||
{ | |||
} | |||
void RelativePointPath::CubicTo::write (OutputStream& out, ElementType lastTypeWritten) const | |||
{ | |||
const String p1 (controlPoint1.toString()); | |||
if (lastTypeWritten != cubicToElement) | |||
out << "c "; | |||
else if (RelativeCoordinateHelpers::couldBeMistakenForPathCommand (p1)) | |||
out << '#'; | |||
out << p1 << ' ' << controlPoint2.toString() << ' ' << endPoint.toString(); | |||
} | |||
void RelativePointPath::CubicTo::addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const | |||
{ | |||
const Point<float> p1 (controlPoint1.resolve (coordFinder)); | |||
const Point<float> p2 (controlPoint2.resolve (coordFinder)); | |||
const Point<float> p3 (endPoint.resolve (coordFinder)); | |||
path.cubicTo (p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY()); | |||
} | |||
END_JUCE_NAMESPACE |
@@ -26,7 +26,9 @@ | |||
#ifndef __JUCE_RELATIVECOORDINATE_JUCEHEADER__ | |||
#define __JUCE_RELATIVECOORDINATE_JUCEHEADER__ | |||
#include "juce_Path.h" | |||
#include "juce_Rectangle.h" | |||
#include "../../../containers/juce_OwnedArray.h" | |||
//============================================================================== | |||
@@ -101,8 +103,8 @@ public: | |||
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", "parent.top", "parent.right" and "parent.bottom" are always available, representing the | |||
extents of the target coordinate space. | |||
"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 | |||
@param isHorizontal this must be true if this is an X coordinate, or false if it's on the Y axis. | |||
@@ -114,6 +116,9 @@ public: | |||
/** Destructor. */ | |||
~RelativeCoordinate(); | |||
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. | |||
@@ -145,15 +150,18 @@ public: | |||
You'll need to provide a suitable NamedCoordinateFinder for looking up any coordinates that may | |||
be needed to calculate the result. | |||
*/ | |||
double resolve (const NamedCoordinateFinder& nameFinder) const; | |||
double resolve (const NamedCoordinateFinder* nameFinder) 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 NamedCoordinateFinder* nameFinder) 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 NamedCoordinateFinder* nameFinder) const; | |||
/** Returns true if this coordinate depends on any other coordinates for its position. */ | |||
bool isDynamic() const; | |||
//============================================================================== | |||
/** Changes the value of this coord to make it resolve to the specified position. | |||
@@ -162,7 +170,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); | |||
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 | |||
@@ -173,7 +181,7 @@ public: | |||
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, bool isHorizontal); | |||
void toggleProportionality (const NamedCoordinateFinder* nameFinder, bool isHorizontal); | |||
/** 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 | |||
@@ -212,12 +220,12 @@ public: | |||
/** 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); | |||
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 changeAnchor2 (const String& newAnchor, const NamedCoordinateFinder* nameFinder); | |||
/** Tells the coordinate that an object is changing its name or being deleted. | |||
@@ -227,7 +235,7 @@ public: | |||
instead. | |||
*/ | |||
void renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const NamedCoordinateFinder& nameFinder); | |||
const NamedCoordinateFinder* nameFinder); | |||
//============================================================================== | |||
/** Returns a string which represents this coordinate. | |||
@@ -261,8 +269,8 @@ private: | |||
String anchor1, anchor2; | |||
double value; | |||
double resolve (const NamedCoordinateFinder& nameFinder, int recursionCounter) const; | |||
static double resolveAnchor (const String& anchorName, const NamedCoordinateFinder& nameFinder, int recursionCounter); | |||
double resolve (const NamedCoordinateFinder* nameFinder, int recursionCounter) const; | |||
static double resolveAnchor (const String& anchorName, const NamedCoordinateFinder* nameFinder, int recursionCounter); | |||
}; | |||
@@ -281,19 +289,25 @@ public: | |||
/** Creates an absolute point, relative to the origin. */ | |||
RelativePoint (const Point<float>& absolutePoint); | |||
/** Creates an absolute point from two coordinates. */ | |||
RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y); | |||
/** Creates a point from a stringified representation. | |||
The string must contain a pair of coordinates, separated by a comma. The syntax for the coordinate | |||
The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate | |||
strings is explained in the RelativeCoordinate class. | |||
@see toString | |||
*/ | |||
RelativePoint (const String& stringVersion); | |||
bool operator== (const RelativePoint& other) const throw(); | |||
bool operator!= (const RelativePoint& other) const throw(); | |||
/** Calculates the absolute position of this point. | |||
You'll need to provide a suitable NamedCoordinateFinder 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 RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
/** Changes the values of this point's coordinates to make it resolve to the specified position. | |||
@@ -301,7 +315,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 RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
/** Returns a string which represents this point. | |||
This returns a comma-separated pair of coordinates. For details of the string syntax used by the | |||
@@ -314,7 +328,10 @@ public: | |||
This calls RelativeCoordinate::renameAnchorIfUsed() on its X and Y coordinates. | |||
*/ | |||
void renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const RelativeCoordinate::NamedCoordinateFinder& nameFinder); | |||
const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
/** Returns true if this point depends on any other coordinates for its position. */ | |||
bool isDynamic() const; | |||
// The actual X and Y coords... | |||
RelativeCoordinate x, y; | |||
@@ -347,13 +364,16 @@ public: | |||
*/ | |||
explicit RelativeRectangle (const String& stringVersion); | |||
bool operator== (const RelativeRectangle& other) const throw(); | |||
bool operator!= (const RelativeRectangle& other) const throw(); | |||
//============================================================================== | |||
/** Calculates the absolute position of this rectangle. | |||
You'll need to provide a suitable NamedCoordinateFinder 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 RelativeCoordinate::NamedCoordinateFinder* nameFinder) const; | |||
/** Changes the values of this rectangle's coordinates to make it resolve to the specified position. | |||
@@ -361,7 +381,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 RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
/** 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 | |||
@@ -374,11 +394,139 @@ public: | |||
This calls RelativeCoordinate::renameAnchorIfUsed() on the rectangle's coordinates. | |||
*/ | |||
void renameAnchorIfUsed (const String& oldName, const String& newName, | |||
const RelativeCoordinate::NamedCoordinateFinder& nameFinder); | |||
const RelativeCoordinate::NamedCoordinateFinder* nameFinder); | |||
// The actual rectangle coords... | |||
RelativeCoordinate left, right, top, bottom; | |||
}; | |||
//============================================================================== | |||
/** | |||
A path object that consists of RelativePoint coordinates rather than the normal fixed ones. | |||
One of these paths can be converted into a Path object for drawing and manipulation, but | |||
unlike a Path, its points can be dynamic instead of just fixed. | |||
@see RelativePoint, RelativeCoordinate | |||
*/ | |||
class JUCE_API RelativePointPath | |||
{ | |||
public: | |||
//============================================================================== | |||
RelativePointPath(); | |||
RelativePointPath (const RelativePointPath& other); | |||
RelativePointPath (const String& stringVersion); | |||
~RelativePointPath(); | |||
//============================================================================== | |||
/** Resolves this points in this path and adds them to a normal Path object. */ | |||
void createPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder); | |||
/** Returns true if the path contains any non-fixed points. */ | |||
bool containsAnyDynamicPoints() const; | |||
/** Returns a string version of the path. | |||
This has the same format as Path::toString(), but since it can contain RelativeCoordinate | |||
positions, it can't be parsed by the Path class if any of the points are dynamic. | |||
*/ | |||
const String toString() const; | |||
/** Quickly swaps the contents of this path with another. */ | |||
void swapWith (RelativePointPath& other) throw(); | |||
//============================================================================== | |||
/** The types of element that may be contained in this path. | |||
@see RelativePointPath::ElementBase | |||
*/ | |||
enum ElementType | |||
{ | |||
nullElement, | |||
startSubPathElement, | |||
closeSubPathElement, | |||
lineToElement, | |||
quadraticToElement, | |||
cubicToElement | |||
}; | |||
//============================================================================== | |||
/** Base class for the elements that make up a RelativePointPath. | |||
*/ | |||
class JUCE_API ElementBase | |||
{ | |||
public: | |||
ElementBase (ElementType type); | |||
virtual ~ElementBase() {} | |||
virtual void write (OutputStream& out, ElementType lastTypeWritten) const = 0; | |||
virtual void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const = 0; | |||
const ElementType type; | |||
}; | |||
class JUCE_API StartSubPath : public ElementBase | |||
{ | |||
public: | |||
StartSubPath (const RelativePoint& pos); | |||
~StartSubPath() {} | |||
void write (OutputStream& out, ElementType lastTypeWritten) const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
RelativePoint startPos; | |||
}; | |||
class JUCE_API CloseSubPath : public ElementBase | |||
{ | |||
public: | |||
CloseSubPath(); | |||
~CloseSubPath() {} | |||
void write (OutputStream& out, ElementType lastTypeWritten) const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
}; | |||
class JUCE_API LineTo : public ElementBase | |||
{ | |||
public: | |||
LineTo (const RelativePoint& endPoint); | |||
~LineTo() {} | |||
void write (OutputStream& out, ElementType lastTypeWritten) const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
RelativePoint endPoint; | |||
}; | |||
class JUCE_API QuadraticTo : public ElementBase | |||
{ | |||
public: | |||
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint); | |||
~QuadraticTo() {} | |||
void write (OutputStream& out, ElementType lastTypeWritten) const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
RelativePoint controlPoint, endPoint; | |||
}; | |||
class JUCE_API CubicTo : public ElementBase | |||
{ | |||
public: | |||
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint); | |||
~CubicTo() {} | |||
void write (OutputStream& out, ElementType lastTypeWritten) const; | |||
void addToPath (Path& path, RelativeCoordinate::NamedCoordinateFinder* coordFinder) const; | |||
RelativePoint controlPoint1, controlPoint2, endPoint; | |||
}; | |||
//============================================================================== | |||
OwnedArray <ElementBase> elements; | |||
bool usesNonZeroWinding; | |||
private: | |||
bool containsDynamicPoints; | |||
void parseString (const String& s); | |||
RelativePointPath& operator= (const RelativePointPath&); | |||
}; | |||
#endif // __JUCE_RELATIVECOORDINATE_JUCEHEADER__ |
@@ -131,6 +131,9 @@ void ImageCache::releaseOrDelete (Image* const imageToRelease) | |||
bool ImageCache::isImageInCache (Image* const imageToLookFor) | |||
{ | |||
if (imageToLookFor == 0) | |||
return false; | |||
if (instance != 0) | |||
{ | |||
const ScopedLock sl (instance->lock); | |||
@@ -35,7 +35,7 @@ DirectoryIterator::DirectoryIterator (const File& directory, | |||
bool isRecursive_, | |||
const String& wildCard_, | |||
const int whatToLookFor_) | |||
: fileFinder (directory, isRecursive ? "*" : wildCard_), | |||
: fileFinder (directory, isRecursive_ ? "*" : wildCard_), | |||
wildCard (wildCard_), | |||
path (File::addTrailingSeparator (directory.getFullPathName())), | |||
index (-1), | |||
@@ -1091,15 +1091,9 @@ public: | |||
{ | |||
} | |||
void repaint (int x, int y, int w, int h) | |||
void repaint (const Rectangle<int>& area) | |||
{ | |||
if (Rectangle<int>::intersectRectangles (x, y, w, h, | |||
0, 0, | |||
getComponent()->getWidth(), | |||
getComponent()->getHeight())) | |||
{ | |||
repainter->repaint (x, y, w, h); | |||
} | |||
repainter->repaint (area.getIntersection (getComponent()->getLocalBounds())); | |||
} | |||
void performAnyPendingRepaintsNow() | |||
@@ -1526,8 +1520,8 @@ public: | |||
&child); | |||
} | |||
repaint (exposeEvent->x, exposeEvent->y, | |||
exposeEvent->width, exposeEvent->height); | |||
repaint (Rectangle<int> (exposeEvent->x, exposeEvent->y, | |||
exposeEvent->width, exposeEvent->height)); | |||
while (XEventsQueued (display, QueuedAfterFlush) > 0) | |||
{ | |||
@@ -1537,8 +1531,8 @@ public: | |||
XNextEvent (display, (XEvent*) &nextEvent); | |||
XExposeEvent* nextExposeEvent = (XExposeEvent*) &nextEvent.xexpose; | |||
repaint (nextExposeEvent->x, nextExposeEvent->y, | |||
nextExposeEvent->width, nextExposeEvent->height); | |||
repaint (Rectangle<int> (nextExposeEvent->x, nextExposeEvent->y, | |||
nextExposeEvent->width, nextExposeEvent->height)); | |||
} | |||
break; | |||
@@ -1838,12 +1832,12 @@ private: | |||
} | |||
} | |||
void repaint (int x, int y, int w, int h) | |||
void repaint (const Rectangle<int>& area) | |||
{ | |||
if (! isTimerRunning()) | |||
startTimer (repaintTimerPeriod); | |||
regionsNeedingRepaint.add (x, y, w, h); | |||
regionsNeedingRepaint.add (area); | |||
} | |||
void performAnyPendingRepaintsNow() | |||
@@ -138,7 +138,7 @@ public: | |||
void handleTouches (UIEvent* e, bool isDown, bool isUp, bool isCancel); | |||
//============================================================================== | |||
void repaint (int x, int y, int w, int h); | |||
void repaint (const Rectangle<int>& area); | |||
void performAnyPendingRepaintsNow(); | |||
//============================================================================== | |||
@@ -849,19 +849,20 @@ public: | |||
void messageCallback() | |||
{ | |||
if (ComponentPeer::isValidPeer (peer)) | |||
peer->repaint (rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); | |||
peer->repaint (rect); | |||
} | |||
}; | |||
void UIViewComponentPeer::repaint (int x, int y, int w, int h) | |||
void UIViewComponentPeer::repaint (const Rectangle<int>& area) | |||
{ | |||
if (insideDrawRect || ! MessageManager::getInstance()->isThisTheMessageThread()) | |||
{ | |||
(new AsyncRepaintMessage (this, Rectangle<int> (x, y, w, h)))->post(); | |||
(new AsyncRepaintMessage (this, area))->post(); | |||
} | |||
else | |||
{ | |||
[view setNeedsDisplayInRect: CGRectMake ((float) x, (float) y, (float) w, (float) h)]; | |||
[view setNeedsDisplayInRect: CGRectMake ((float) area.getX(), (float) area.getY(), | |||
(float) area.getWidth(), (float) area.getHeight())]; | |||
} | |||
} | |||
@@ -253,7 +253,7 @@ public: | |||
void textInputRequired (const Point<int>& position); | |||
//============================================================================== | |||
void repaint (int x, int y, int w, int h); | |||
void repaint (const Rectangle<int>& area); | |||
void performAnyPendingRepaintsNow(); | |||
//============================================================================== | |||
@@ -1631,20 +1631,20 @@ public: | |||
void messageCallback() | |||
{ | |||
if (ComponentPeer::isValidPeer (peer)) | |||
peer->repaint (rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); | |||
peer->repaint (rect); | |||
} | |||
}; | |||
void NSViewComponentPeer::repaint (int x, int y, int w, int h) | |||
void NSViewComponentPeer::repaint (const Rectangle<int>& area) | |||
{ | |||
if (insideDrawRect) | |||
{ | |||
(new AsyncRepaintMessage (this, Rectangle<int> (x, y, w, h)))->post(); | |||
(new AsyncRepaintMessage (this, area))->post(); | |||
} | |||
else | |||
{ | |||
[view setNeedsDisplayInRect: NSMakeRect ((float) x, (float) ([view frame].size.height - (y + h)), | |||
(float) w, (float) h)]; | |||
[view setNeedsDisplayInRect: NSMakeRect ((float) area.getX(), [view frame].size.height - (float) area.getBottom(), | |||
(float) area.getWidth(), (float) area.getHeight())]; | |||
} | |||
} | |||
@@ -597,7 +597,10 @@ public: | |||
Thread::sleep (20); | |||
isStarted = false; | |||
isOpen_ = false; | |||
close(); | |||
const String errorCopy (error); | |||
close(); // (this resets the error string) | |||
error = errorCopy; | |||
} | |||
needToReset = false; | |||
@@ -288,8 +288,7 @@ public: | |||
void repaint() | |||
{ | |||
const Rectangle<int> bounds (nativeWindow->getBounds()); | |||
nativeWindow->repaint (0, 0, bounds.getWidth(), bounds.getHeight()); | |||
nativeWindow->repaint (nativeWindow->getBounds().withPosition (Point<int>())); | |||
} | |||
void swapBuffers() | |||
@@ -685,7 +685,7 @@ public: | |||
int getInputLatencyInSamples() { return latencyIn; } | |||
const BigInteger getActiveOutputChannels() const { return outputDevice != 0 ? outputDevice->channels : BigInteger(); } | |||
const BigInteger getActiveInputChannels() const { return inputDevice != 0 ? inputDevice->channels : BigInteger(); } | |||
const String getLastError() { return lastError; } | |||
const String getLastError() { return lastError; } | |||
const String open (const BigInteger& inputChannels, const BigInteger& outputChannels, | |||
@@ -705,9 +705,9 @@ public: | |||
SetCaretPos (0, 0); | |||
} | |||
void repaint (int x, int y, int w, int h) | |||
void repaint (const Rectangle<int>& area) | |||
{ | |||
const RECT r = { x, y, x + w, y + h }; | |||
const RECT r = { area.getX(), area.getY(), area.getRight(), area.getBottom() }; | |||
InvalidateRect (hwnd, &r, FALSE); | |||
} | |||
@@ -1055,9 +1055,7 @@ static int indexOfMatch (const juce_wchar* const wildcard, | |||
else | |||
{ | |||
if (wc == '*' && (wildcard [i + 1] == 0 | |||
|| indexOfMatch (wildcard + i + 1, | |||
test + start + i, | |||
ignoreCase) >= 0)) | |||
|| indexOfMatch (wildcard + i + 1, test + start + i, ignoreCase) >= 0)) | |||
{ | |||
return start; | |||
} | |||
@@ -1093,9 +1091,7 @@ bool String::matchesWildcard (const String& wildcard, const bool ignoreCase) con | |||
else | |||
{ | |||
return wc == '*' && (wildcard [i + 1] == 0 | |||
|| indexOfMatch (wildcard.text + i + 1, | |||
text + i, | |||
ignoreCase) >= 0); | |||
|| indexOfMatch (wildcard.text + i + 1, text + i, ignoreCase) >= 0); | |||
} | |||
} | |||
} | |||