| @@ -101,6 +101,7 @@ OBJECTS_APP := \ | |||||
| $(JUCE_OBJDIR)/jucer_CompileEngineClient_aee8c99c.o \ | $(JUCE_OBJDIR)/jucer_CompileEngineClient_aee8c99c.o \ | ||||
| $(JUCE_OBJDIR)/jucer_CompileEngineServer_5d8914.o \ | $(JUCE_OBJDIR)/jucer_CompileEngineServer_5d8914.o \ | ||||
| $(JUCE_OBJDIR)/jucer_DownloadCompileEngineThread_19bb4bb3.o \ | $(JUCE_OBJDIR)/jucer_DownloadCompileEngineThread_19bb4bb3.o \ | ||||
| $(JUCE_OBJDIR)/jucer_HeaderComponent_1ebf72ba.o \ | |||||
| $(JUCE_OBJDIR)/jucer_Module_3f7666a5.o \ | $(JUCE_OBJDIR)/jucer_Module_3f7666a5.o \ | ||||
| $(JUCE_OBJDIR)/jucer_Project_c131864a.o \ | $(JUCE_OBJDIR)/jucer_Project_c131864a.o \ | ||||
| $(JUCE_OBJDIR)/jucer_ProjectExporter_cf377b25.o \ | $(JUCE_OBJDIR)/jucer_ProjectExporter_cf377b25.o \ | ||||
| @@ -304,6 +305,11 @@ $(JUCE_OBJDIR)/jucer_DownloadCompileEngineThread_19bb4bb3.o: ../../Source/LiveBu | |||||
| @echo "Compiling jucer_DownloadCompileEngineThread.cpp" | @echo "Compiling jucer_DownloadCompileEngineThread.cpp" | ||||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | ||||
| $(JUCE_OBJDIR)/jucer_HeaderComponent_1ebf72ba.o: ../../Source/Project/UI/jucer_HeaderComponent.cpp | |||||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | |||||
| @echo "Compiling jucer_HeaderComponent.cpp" | |||||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | |||||
| $(JUCE_OBJDIR)/jucer_Module_3f7666a5.o: ../../Source/Project/jucer_Module.cpp | $(JUCE_OBJDIR)/jucer_Module_3f7666a5.o: ../../Source/Project/jucer_Module.cpp | ||||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | -$(V_AT)mkdir -p $(JUCE_OBJDIR) | ||||
| @echo "Compiling jucer_Module.cpp" | @echo "Compiling jucer_Module.cpp" | ||||
| @@ -57,6 +57,7 @@ | |||||
| D25EBE02B55DB244BE0D5635 = {isa = PBXBuildFile; fileRef = DE3E6B2614229FAD56D50770; }; | D25EBE02B55DB244BE0D5635 = {isa = PBXBuildFile; fileRef = DE3E6B2614229FAD56D50770; }; | ||||
| 85E7FCB0516EFF853FA7B380 = {isa = PBXBuildFile; fileRef = D2FE76E4CF003856278343CC; }; | 85E7FCB0516EFF853FA7B380 = {isa = PBXBuildFile; fileRef = D2FE76E4CF003856278343CC; }; | ||||
| CC6C4D351BA9B473E5F95791 = {isa = PBXBuildFile; fileRef = ADA538034910F52FDD2DC88D; }; | CC6C4D351BA9B473E5F95791 = {isa = PBXBuildFile; fileRef = ADA538034910F52FDD2DC88D; }; | ||||
| 05A08E366EBF8D650974E695 = {isa = PBXBuildFile; fileRef = 516D6D7C564DD5DF5C15CB06; }; | |||||
| 3FCA61C401007B243E2E9035 = {isa = PBXBuildFile; fileRef = F797071D88542C813CF7222A; }; | 3FCA61C401007B243E2E9035 = {isa = PBXBuildFile; fileRef = F797071D88542C813CF7222A; }; | ||||
| 30B921C38DCEE787B294B746 = {isa = PBXBuildFile; fileRef = BAC43B20E14A340CCF14119C; }; | 30B921C38DCEE787B294B746 = {isa = PBXBuildFile; fileRef = BAC43B20E14A340CCF14119C; }; | ||||
| 244567D3AE2E417A8CB2B95E = {isa = PBXBuildFile; fileRef = C3BB9F92B02B06D04A73794C; }; | 244567D3AE2E417A8CB2B95E = {isa = PBXBuildFile; fileRef = C3BB9F92B02B06D04A73794C; }; | ||||
| @@ -180,6 +181,7 @@ | |||||
| 50498FF6EA3901CBD58223B3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ObjectTypes.h"; path = "../../Source/ComponentEditor/jucer_ObjectTypes.h"; sourceTree = "SOURCE_ROOT"; }; | 50498FF6EA3901CBD58223B3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_ObjectTypes.h"; path = "../../Source/ComponentEditor/jucer_ObjectTypes.h"; sourceTree = "SOURCE_ROOT"; }; | ||||
| 512D80BE12634967A085A1DC = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_PaintElement.cpp"; path = "../../Source/ComponentEditor/PaintElements/jucer_PaintElement.cpp"; sourceTree = "SOURCE_ROOT"; }; | 512D80BE12634967A085A1DC = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_PaintElement.cpp"; path = "../../Source/ComponentEditor/PaintElements/jucer_PaintElement.cpp"; sourceTree = "SOURCE_ROOT"; }; | ||||
| 514F2FAFDBF535AC03FA2E6C = {isa = PBXFileReference; lastKnownFileType = file.svg; name = "background_logo.svg"; path = "../../Source/BinaryData/Icons/background_logo.svg"; sourceTree = "SOURCE_ROOT"; }; | 514F2FAFDBF535AC03FA2E6C = {isa = PBXFileReference; lastKnownFileType = file.svg; name = "background_logo.svg"; path = "../../Source/BinaryData/Icons/background_logo.svg"; sourceTree = "SOURCE_ROOT"; }; | ||||
| 516D6D7C564DD5DF5C15CB06 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_HeaderComponent.cpp"; path = "../../Source/Project/UI/jucer_HeaderComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; | |||||
| 51BC758EF5D33197CF543E67 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_DocumentEditorComponent.h"; path = "../../Source/CodeEditor/jucer_DocumentEditorComponent.h"; sourceTree = "SOURCE_ROOT"; }; | 51BC758EF5D33197CF543E67 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_DocumentEditorComponent.h"; path = "../../Source/CodeEditor/jucer_DocumentEditorComponent.h"; sourceTree = "SOURCE_ROOT"; }; | ||||
| 51CBE59779A36D1B80B26974 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_LicenseController.cpp"; path = "../../Source/Licenses/jucer_LicenseController.cpp"; sourceTree = "SOURCE_ROOT"; }; | 51CBE59779A36D1B80B26974 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "jucer_LicenseController.cpp"; path = "../../Source/Licenses/jucer_LicenseController.cpp"; sourceTree = "SOURCE_ROOT"; }; | ||||
| 5432B7B9B2CF2EAEC8B66D5C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_UtilityFunctions.h"; path = "../../Source/ComponentEditor/jucer_UtilityFunctions.h"; sourceTree = "SOURCE_ROOT"; }; | 5432B7B9B2CF2EAEC8B66D5C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "jucer_UtilityFunctions.h"; path = "../../Source/ComponentEditor/jucer_UtilityFunctions.h"; sourceTree = "SOURCE_ROOT"; }; | ||||
| @@ -633,6 +635,7 @@ | |||||
| 236D186F5A6536C59D6E751C, | 236D186F5A6536C59D6E751C, | ||||
| 32ECBC08D903418CA0825870, | 32ECBC08D903418CA0825870, | ||||
| A509BC22854D50E4C786EB32, | A509BC22854D50E4C786EB32, | ||||
| 516D6D7C564DD5DF5C15CB06, | |||||
| 16751E04B0F3737BDF52CEB4, | 16751E04B0F3737BDF52CEB4, | ||||
| B3528C08B84CBC950252EA69, | B3528C08B84CBC950252EA69, | ||||
| 1B0F18E1D96F727C062B05FA, | 1B0F18E1D96F727C062B05FA, | ||||
| @@ -964,6 +967,7 @@ | |||||
| D25EBE02B55DB244BE0D5635, | D25EBE02B55DB244BE0D5635, | ||||
| 85E7FCB0516EFF853FA7B380, | 85E7FCB0516EFF853FA7B380, | ||||
| CC6C4D351BA9B473E5F95791, | CC6C4D351BA9B473E5F95791, | ||||
| 05A08E366EBF8D650974E695, | |||||
| 3FCA61C401007B243E2E9035, | 3FCA61C401007B243E2E9035, | ||||
| 30B921C38DCEE787B294B746, | 30B921C38DCEE787B294B746, | ||||
| 244567D3AE2E417A8CB2B95E, | 244567D3AE2E417A8CB2B95E, | ||||
| @@ -226,6 +226,7 @@ | |||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/> | ||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/> | ||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"/> | |||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | ||||
| <ExcludedFromBuild>true</ExcludedFromBuild> | <ExcludedFromBuild>true</ExcludedFromBuild> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -442,6 +442,9 @@ | |||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"> | ||||
| <Filter>Projucer\LiveBuildEngine</Filter> | <Filter>Projucer\LiveBuildEngine</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"> | |||||
| <Filter>Projucer\Project\UI</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | ||||
| <Filter>Projucer\Project\UI</Filter> | <Filter>Projucer\Project\UI</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -226,6 +226,7 @@ | |||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/> | ||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/> | ||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"/> | |||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | ||||
| <ExcludedFromBuild>true</ExcludedFromBuild> | <ExcludedFromBuild>true</ExcludedFromBuild> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -442,6 +442,9 @@ | |||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"> | ||||
| <Filter>Projucer\LiveBuildEngine</Filter> | <Filter>Projucer\LiveBuildEngine</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"> | |||||
| <Filter>Projucer\Project\UI</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | ||||
| <Filter>Projucer\Project\UI</Filter> | <Filter>Projucer\Project\UI</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -226,6 +226,7 @@ | |||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/> | ||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/> | ||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/> | ||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"/> | |||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | ||||
| <ExcludedFromBuild>true</ExcludedFromBuild> | <ExcludedFromBuild>true</ExcludedFromBuild> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -442,6 +442,9 @@ | |||||
| <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"> | <ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"> | ||||
| <Filter>Projucer\LiveBuildEngine</Filter> | <Filter>Projucer\LiveBuildEngine</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"> | |||||
| <Filter>Projucer\Project\UI</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | <ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp"> | ||||
| <Filter>Projucer\Project\UI</Filter> | <Filter>Projucer\Project\UI</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -542,6 +542,8 @@ | |||||
| resource="0" file="Source/Project/UI/jucer_ContentViewComponents.h"/> | resource="0" file="Source/Project/UI/jucer_ContentViewComponents.h"/> | ||||
| <FILE id="wFypDd" name="jucer_FileGroupInformationComponent.h" compile="0" | <FILE id="wFypDd" name="jucer_FileGroupInformationComponent.h" compile="0" | ||||
| resource="0" file="Source/Project/UI/jucer_FileGroupInformationComponent.h"/> | resource="0" file="Source/Project/UI/jucer_FileGroupInformationComponent.h"/> | ||||
| <FILE id="P6wdlv" name="jucer_HeaderComponent.cpp" compile="1" resource="0" | |||||
| file="Source/Project/UI/jucer_HeaderComponent.cpp"/> | |||||
| <FILE id="QVjJdU" name="jucer_HeaderComponent.h" compile="0" resource="0" | <FILE id="QVjJdU" name="jucer_HeaderComponent.h" compile="0" resource="0" | ||||
| file="Source/Project/UI/jucer_HeaderComponent.h"/> | file="Source/Project/UI/jucer_HeaderComponent.h"/> | ||||
| <FILE id="dN0Xzo" name="jucer_ModulesInformationComponent.h" compile="0" | <FILE id="dN0Xzo" name="jucer_ModulesInformationComponent.h" compile="0" | ||||
| @@ -28,25 +28,12 @@ | |||||
| //============================================================================== | //============================================================================== | ||||
| class GlobalSearchPathsWindowComponent : public Component | |||||
| class GlobalPathsWindowComponent : public Component | |||||
| { | { | ||||
| public: | public: | ||||
| GlobalSearchPathsWindowComponent() | |||||
| : modulesLabel ("modulesLabel", "Modules"), | |||||
| sdksLabel ("sdksLabel", "SDKs"), | |||||
| cLionLabel ("cLionLabel", "CLion") | |||||
| GlobalPathsWindowComponent() | |||||
| { | { | ||||
| addAndMakeVisible (modulesLabel); | |||||
| addAndMakeVisible (sdksLabel); | |||||
| addAndMakeVisible (cLionLabel); | |||||
| modulesLabel.setFont (Font (18.0f, Font::FontStyleFlags::bold)); | |||||
| sdksLabel .setFont (Font (18.0f, Font::FontStyleFlags::bold)); | |||||
| cLionLabel .setFont (Font (18.0f, Font::FontStyleFlags::bold)); | |||||
| modulesLabel.setJustificationType (Justification::centredLeft); | |||||
| sdksLabel .setJustificationType (Justification::centredLeft); | |||||
| cLionLabel .setJustificationType (Justification::centredLeft); | |||||
| addLabelsAndSetProperties(); | |||||
| addAndMakeVisible (info); | addAndMakeVisible (info); | ||||
| info.setInfoToDisplay ("Use this dropdown to set the global paths for different OSes. " | info.setInfoToDisplay ("Use this dropdown to set the global paths for different OSes. " | ||||
| @@ -59,7 +46,11 @@ public: | |||||
| osSelector.addItem ("Windows", 2); | osSelector.addItem ("Windows", 2); | ||||
| osSelector.addItem ("Linux", 3); | osSelector.addItem ("Linux", 3); | ||||
| osSelector.onChange = [this] { updateFilePathPropertyComponents(); }; | |||||
| osSelector.onChange = [this] | |||||
| { | |||||
| addLabelsAndSetProperties(); | |||||
| updateFilePathPropertyComponents(); | |||||
| }; | |||||
| auto os = TargetOS::getThisOS(); | auto os = TargetOS::getThisOS(); | ||||
| @@ -85,40 +76,33 @@ public: | |||||
| info.setBounds (osSelector.getBounds().withWidth (osSelector.getHeight()).translated ((osSelector.getWidth() + 5), 0).reduced (2)); | info.setBounds (osSelector.getBounds().withWidth (osSelector.getHeight()).translated ((osSelector.getWidth() + 5), 0).reduced (2)); | ||||
| modulesLabel.setBounds (b.removeFromTop (20)); | |||||
| b.removeFromTop (20); | |||||
| auto thisOS = TargetOS::getThisOS(); | |||||
| auto selectedOS = getSelectedOS(); | |||||
| const int numComps = pathPropertyComponents.size(); | |||||
| for (int i = 0; i < numComps; ++i) | |||||
| int labelIndex = 0; | |||||
| for (auto* pathComp : pathPropertyComponents) | |||||
| { | { | ||||
| pathPropertyComponents[i]->setBounds (b.removeFromTop (pathPropertyComponents[i]->getPreferredHeight())); | |||||
| b.removeFromTop (5); | |||||
| if (i == 1) | |||||
| if (pathComp == nullptr) | |||||
| { | { | ||||
| b.removeFromTop (15); | b.removeFromTop (15); | ||||
| sdksLabel.setBounds (b.removeFromTop (20)); | |||||
| pathPropertyLabels.getUnchecked (labelIndex++)->setBounds (b.removeFromTop (20)); | |||||
| b.removeFromTop (20); | b.removeFromTop (20); | ||||
| } | } | ||||
| if (selectedOS == thisOS && i == numComps - 2) | |||||
| else | |||||
| { | { | ||||
| b.removeFromTop (15); | |||||
| cLionLabel.setBounds (b.removeFromTop (20)); | |||||
| b.removeFromTop (20); | |||||
| pathComp->setBounds (b.removeFromTop (pathComp->getPreferredHeight())); | |||||
| b.removeFromTop (5); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| private: | private: | ||||
| Label modulesLabel, sdksLabel, cLionLabel; | |||||
| OwnedArray<Label> pathPropertyLabels; | |||||
| OwnedArray<PropertyComponent> pathPropertyComponents; | OwnedArray<PropertyComponent> pathPropertyComponents; | ||||
| ComboBox osSelector; | ComboBox osSelector; | ||||
| InfoButton info; | InfoButton info; | ||||
| //============================================================================== | |||||
| bool isSelectedOSThisOS() { return TargetOS::getThisOS() == getSelectedOS(); } | |||||
| TargetOS::OS getSelectedOS() const | TargetOS::OS getSelectedOS() const | ||||
| { | { | ||||
| auto selectedOS = TargetOS::unknown; | auto selectedOS = TargetOS::unknown; | ||||
| @@ -138,27 +122,28 @@ private: | |||||
| { | { | ||||
| pathPropertyComponents.clear(); | pathPropertyComponents.clear(); | ||||
| const auto thisOS = TargetOS::getThisOS(); | |||||
| const auto selectedOS = getSelectedOS(); | |||||
| auto& settings = getAppSettings(); | auto& settings = getAppSettings(); | ||||
| if (selectedOS == thisOS) | |||||
| if (isSelectedOSThisOS()) | |||||
| { | { | ||||
| pathPropertyComponents.add (nullptr); | |||||
| addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::defaultJuceModulePath), | addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::defaultJuceModulePath), | ||||
| "JUCE Modules", true))); | "JUCE Modules", true))); | ||||
| addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::defaultUserModulePath), | addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::defaultUserModulePath), | ||||
| "User Modules", true, {}, {}, true))); | "User Modules", true, {}, {}, true))); | ||||
| pathPropertyComponents.add (nullptr); | |||||
| addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::vst3Path), | addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::vst3Path), | ||||
| "VST3 SDK", true))); | "VST3 SDK", true))); | ||||
| if (selectedOS == TargetOS::linux) | |||||
| if (getSelectedOS() == TargetOS::linux) | |||||
| { | { | ||||
| addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (Value(), "RTAS SDK", true))); | |||||
| addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent ({}, "RTAS SDK", true))); | |||||
| pathPropertyComponents.getLast()->setEnabled (false); | pathPropertyComponents.getLast()->setEnabled (false); | ||||
| addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (Value(), "AAX SDK", true))); | |||||
| addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent ({}, "AAX SDK", true))); | |||||
| pathPropertyComponents.getLast()->setEnabled (false); | pathPropertyComponents.getLast()->setEnabled (false); | ||||
| } | } | ||||
| else | else | ||||
| @@ -174,6 +159,8 @@ private: | |||||
| addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::androidNDKPath), | addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::androidNDKPath), | ||||
| "Android NDK", true))); | "Android NDK", true))); | ||||
| pathPropertyComponents.add (nullptr); | |||||
| #if JUCE_MAC | #if JUCE_MAC | ||||
| String exeLabel ("app"); | String exeLabel ("app"); | ||||
| #elif JUCE_WINDOWS | #elif JUCE_WINDOWS | ||||
| @@ -186,13 +173,18 @@ private: | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| auto selectedOS = getSelectedOS(); | |||||
| auto maxChars = 1024; | auto maxChars = 1024; | ||||
| pathPropertyComponents.add (nullptr); | |||||
| addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::defaultJuceModulePath, selectedOS), | addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::defaultJuceModulePath, selectedOS), | ||||
| "JUCE Modules", maxChars, false))); | "JUCE Modules", maxChars, false))); | ||||
| addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::defaultUserModulePath, selectedOS), | addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::defaultUserModulePath, selectedOS), | ||||
| "User Modules", maxChars, false))); | "User Modules", maxChars, false))); | ||||
| pathPropertyComponents.add (nullptr); | |||||
| addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::vst3Path, selectedOS), | addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::vst3Path, selectedOS), | ||||
| "VST3 SDK", maxChars, false))); | "VST3 SDK", maxChars, false))); | ||||
| @@ -207,19 +199,35 @@ private: | |||||
| else | else | ||||
| { | { | ||||
| addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::rtasPath, selectedOS), | addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::rtasPath, selectedOS), | ||||
| "RTAS SDK", maxChars, false))); | |||||
| "RTAS SDK", maxChars, false))); | |||||
| addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::aaxPath, selectedOS), | addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::aaxPath, selectedOS), | ||||
| "AAX SDK", maxChars, false))); | |||||
| "AAX SDK", maxChars, false))); | |||||
| } | } | ||||
| addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::androidSDKPath, selectedOS), | addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::androidSDKPath, selectedOS), | ||||
| "Android SDK", maxChars, false))); | |||||
| "Android SDK", maxChars, false))); | |||||
| addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::androidNDKPath, selectedOS), | addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::androidNDKPath, selectedOS), | ||||
| "Android NDK", maxChars, false))); | |||||
| "Android NDK", maxChars, false))); | |||||
| } | } | ||||
| resized(); | resized(); | ||||
| } | } | ||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlobalSearchPathsWindowComponent) | |||||
| void addLabelsAndSetProperties() | |||||
| { | |||||
| pathPropertyLabels.clear(); | |||||
| pathPropertyLabels.add (new Label ("modulesLabel", "Modules")); | |||||
| pathPropertyLabels.add (new Label ("sdksLabel", "SDKs")); | |||||
| pathPropertyLabels.add (new Label ("otherLabel", "Other")); | |||||
| for (auto* l : pathPropertyLabels) | |||||
| { | |||||
| addAndMakeVisible (l); | |||||
| l->setFont (Font (18.0f, Font::FontStyleFlags::bold)); | |||||
| l->setJustificationType (Justification::centredLeft); | |||||
| } | |||||
| } | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlobalPathsWindowComponent) | |||||
| }; | }; | ||||
| @@ -224,6 +224,10 @@ void ProjucerApplication::shutdown() | |||||
| LookAndFeel::setDefaultLookAndFeel (nullptr); | LookAndFeel::setDefaultLookAndFeel (nullptr); | ||||
| // clean up after ourselves and delete any temp project files that may have | |||||
| // been created from PIPs | |||||
| deleteTemporaryFiles(); | |||||
| if (! isRunningCommandLine) | if (! isRunningCommandLine) | ||||
| Logger::writeToLog ("Shutdown"); | Logger::writeToLog ("Shutdown"); | ||||
| @@ -332,7 +336,8 @@ enum | |||||
| openWindowsBaseID = 300, | openWindowsBaseID = 300, | ||||
| activeDocumentsBaseID = 400, | activeDocumentsBaseID = 400, | ||||
| colourSchemeBaseID = 1000, | colourSchemeBaseID = 1000, | ||||
| codeEditorColourSchemeBaseID = 2000, | |||||
| codeEditorColourSchemeBaseID = 1500, | |||||
| examplesBaseID = 2000, | |||||
| }; | }; | ||||
| MenuBarModel* ProjucerApplication::getMenuModel() | MenuBarModel* ProjucerApplication::getMenuModel() | ||||
| @@ -362,6 +367,7 @@ void ProjucerApplication::createMenu (PopupMenu& menu, const String& menuName) | |||||
| void ProjucerApplication::createFileMenu (PopupMenu& menu) | void ProjucerApplication::createFileMenu (PopupMenu& menu) | ||||
| { | { | ||||
| menu.addCommandItem (commandManager, CommandIDs::newProject); | menu.addCommandItem (commandManager, CommandIDs::newProject); | ||||
| menu.addCommandItem (commandManager, CommandIDs::newProjectFromClipboard); | |||||
| menu.addSeparator(); | menu.addSeparator(); | ||||
| menu.addCommandItem (commandManager, CommandIDs::open); | menu.addCommandItem (commandManager, CommandIDs::open); | ||||
| @@ -379,6 +385,13 @@ void ProjucerApplication::createFileMenu (PopupMenu& menu) | |||||
| menu.addSubMenu ("Open Recent", recentFiles); | menu.addSubMenu ("Open Recent", recentFiles); | ||||
| } | } | ||||
| { | |||||
| PopupMenu examples; | |||||
| createExamplesPopupMenu (examples); | |||||
| menu.addSubMenu ("Open Example", examples); | |||||
| } | |||||
| menu.addSeparator(); | menu.addSeparator(); | ||||
| menu.addCommandItem (commandManager, CommandIDs::closeDocument); | menu.addCommandItem (commandManager, CommandIDs::closeDocument); | ||||
| menu.addCommandItem (commandManager, CommandIDs::saveDocument); | menu.addCommandItem (commandManager, CommandIDs::saveDocument); | ||||
| @@ -554,6 +567,244 @@ void ProjucerApplication::createExtraAppleMenuItems (PopupMenu& menu) | |||||
| menu.addCommandItem (commandManager, CommandIDs::showGlobalPathsWindow); | menu.addCommandItem (commandManager, CommandIDs::showGlobalPathsWindow); | ||||
| } | } | ||||
| void ProjucerApplication::createExamplesPopupMenu (PopupMenu& menu) noexcept | |||||
| { | |||||
| numExamples = 0; | |||||
| for (auto& dir : getSortedExampleDirectories()) | |||||
| { | |||||
| PopupMenu m; | |||||
| for (auto& f : getSortedExampleFilesInDirectory (dir)) | |||||
| { | |||||
| m.addItem (examplesBaseID + numExamples, f.getFileNameWithoutExtension()); | |||||
| ++numExamples; | |||||
| } | |||||
| menu.addSubMenu (dir.getFileName(), m); | |||||
| } | |||||
| if (numExamples == 0) | |||||
| { | |||||
| menu.addCommandItem (commandManager, CommandIDs::showGlobalPathsWindow, "Set path to JUCE..."); | |||||
| } | |||||
| else | |||||
| { | |||||
| menu.addSeparator(); | |||||
| menu.addCommandItem (commandManager, CommandIDs::launchDemoRunner); | |||||
| } | |||||
| } | |||||
| Array<File> ProjucerApplication::getSortedExampleDirectories() const noexcept | |||||
| { | |||||
| Array<File> exampleDirectories; | |||||
| auto examplesPath = getJUCEExamplesDirectoryPathFromGlobal(); | |||||
| if (! isValidJUCEExamplesDirectory (examplesPath)) | |||||
| return {}; | |||||
| DirectoryIterator iter (examplesPath, false, "*", File::findDirectories); | |||||
| while (iter.next()) | |||||
| { | |||||
| auto exampleDirectory = iter.getFile(); | |||||
| if (exampleDirectory.getFileName() != "DemoRunner" && exampleDirectory.getFileName() != "Resources") | |||||
| exampleDirectories.add (exampleDirectory); | |||||
| } | |||||
| exampleDirectories.sort(); | |||||
| return exampleDirectories; | |||||
| } | |||||
| Array<File> ProjucerApplication::getSortedExampleFilesInDirectory (const File& directory) const noexcept | |||||
| { | |||||
| Array<File> exampleFiles; | |||||
| DirectoryIterator iter (directory, false, "*.h", File::findFiles); | |||||
| while (iter.next()) | |||||
| exampleFiles.add (iter.getFile()); | |||||
| exampleFiles.sort(); | |||||
| return exampleFiles; | |||||
| } | |||||
| bool ProjucerApplication::findWindowAndOpenPIP (const File& pip) | |||||
| { | |||||
| auto* window = mainWindowList.getFrontmostWindow(); | |||||
| bool shouldCloseWindow = false; | |||||
| if (window == nullptr) | |||||
| { | |||||
| window = mainWindowList.getOrCreateEmptyWindow(); | |||||
| shouldCloseWindow = true; | |||||
| } | |||||
| if (window->tryToOpenPIP (pip)) | |||||
| return true; | |||||
| if (shouldCloseWindow) | |||||
| mainWindowList.closeWindow (window); | |||||
| return false; | |||||
| } | |||||
| void ProjucerApplication::findAndLaunchExample (int selectedIndex) | |||||
| { | |||||
| File example; | |||||
| for (auto& dir : getSortedExampleDirectories()) | |||||
| { | |||||
| auto exampleFiles = getSortedExampleFilesInDirectory (dir); | |||||
| if (selectedIndex < exampleFiles.size()) | |||||
| { | |||||
| example = exampleFiles.getUnchecked (selectedIndex); | |||||
| break; | |||||
| } | |||||
| selectedIndex -= exampleFiles.size(); | |||||
| } | |||||
| // example doesn't exist? | |||||
| jassert (example != File()); | |||||
| findWindowAndOpenPIP (example); | |||||
| } | |||||
| File ProjucerApplication::findDemoRunnerExecutable() const noexcept | |||||
| { | |||||
| auto buildsPath = getJUCEExamplesDirectoryPathFromGlobal().getChildFile ("DemoRunner").getChildFile ("Builds"); | |||||
| if (! buildsPath.exists()) | |||||
| return {}; | |||||
| String extension; | |||||
| #if JUCE_MAC | |||||
| auto osxBuildFolder = buildsPath.getChildFile ("MacOSX").getChildFile ("build"); | |||||
| auto demoRunnerExecutable = osxBuildFolder.getChildFile ("Release").getChildFile ("DemoRunner.app"); | |||||
| if (demoRunnerExecutable.exists()) | |||||
| return demoRunnerExecutable; | |||||
| demoRunnerExecutable = osxBuildFolder.getChildFile ("Debug").getChildFile ("DemoRunner.app"); | |||||
| if (demoRunnerExecutable.exists()) | |||||
| return demoRunnerExecutable; | |||||
| extension = ".app"; | |||||
| #elif JUCE_WINDOWS | |||||
| auto windowsBuildFolder = buildsPath.getChildFile ("VisualStudio2017").getChildFile ("x64"); | |||||
| auto demoRunnerExecutable = windowsBuildFolder.getChildFile ("Release").getChildFile ("App").getChildFile ("DemoRunner.exe"); | |||||
| if (demoRunnerExecutable.existsAsFile()) | |||||
| return demoRunnerExecutable; | |||||
| demoRunnerExecutable = windowsBuildFolder.getChildFile ("Debug").getChildFile ("App").getChildFile ("DemoRunner.exe"); | |||||
| if (demoRunnerExecutable.existsAsFile()) | |||||
| return demoRunnerExecutable; | |||||
| extension = ".exe"; | |||||
| #elif JUCE_LINUX | |||||
| auto linuxBuildFolder = buildsPath.getChildFile ("LinuxMakefile").getChildFile ("build"); | |||||
| auto demoRunnerExecutable = linuxBuildFolder.getChildFile ("DemoRunner"); | |||||
| if (demoRunnerExecutable.existsAsFile()) | |||||
| return demoRunnerExecutable; | |||||
| extension = {}; | |||||
| #endif | |||||
| auto precompiledFile = getJUCEExamplesDirectoryPathFromGlobal().getChildFile ("DemoRunner" + extension); | |||||
| #if JUCE_MAC | |||||
| if (precompiledFile.exists()) | |||||
| #else | |||||
| if (precompiledFile.existsAsFile()) | |||||
| #endif | |||||
| return precompiledFile; | |||||
| return {}; | |||||
| } | |||||
| File ProjucerApplication::findDemoRunnerProject() const noexcept | |||||
| { | |||||
| auto buildsPath = getJUCEExamplesDirectoryPathFromGlobal().getChildFile ("DemoRunner").getChildFile ("Builds"); | |||||
| if (! buildsPath.exists()) | |||||
| return {}; | |||||
| #if JUCE_MAC | |||||
| auto file = buildsPath.getChildFile ("MacOSX").getChildFile ("DemoRunner.xcodeproj"); | |||||
| if (file.exists()) | |||||
| return file; | |||||
| #elif JUCE_WINDOW | |||||
| auto file = buildsPath.getChildFile ("VisualStudio2017").getChildFile ("DemoRunner.sln"); | |||||
| if (file.existsAsFile()) | |||||
| return file; | |||||
| #elif JUCE_LINUX | |||||
| auto file = buildsPath.getChildFile ("LinuxMakeFile").getChildFile ("Makefile"); | |||||
| if (file.existsAsFile()) | |||||
| return file; | |||||
| #endif | |||||
| return {}; | |||||
| } | |||||
| void ProjucerApplication::launchDemoRunner() | |||||
| { | |||||
| if (findDemoRunnerExecutable() != File()) | |||||
| { | |||||
| bool succeeded = true; | |||||
| if (! findDemoRunnerExecutable().startAsProcess()) | |||||
| { | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Error", "There was an error opening the Demo Runner file."); | |||||
| succeeded = false; | |||||
| } | |||||
| } | |||||
| else if (findDemoRunnerProject() != File()) | |||||
| { | |||||
| auto& lf = Desktop::getInstance().getDefaultLookAndFeel(); | |||||
| demoRunnerAlert = lf.createAlertWindow ("Open Project", | |||||
| "Couldn't find a compiled version of the Demo Runner." | |||||
| #if JUCE_LINUX | |||||
| " Do you want to build it now?", "Build project", "Cancel", | |||||
| #else | |||||
| " Do you want to open the project?", "Open project", "Cancel", | |||||
| #endif | |||||
| {}, | |||||
| AlertWindow::QuestionIcon, 2, | |||||
| mainWindowList.getFrontmostWindow (false)); | |||||
| demoRunnerAlert->enterModalState (true, ModalCallbackFunction::create ([this] (int retVal) | |||||
| { | |||||
| demoRunnerAlert.reset (nullptr); | |||||
| if (retVal == 1) | |||||
| { | |||||
| auto projectFile = findDemoRunnerProject(); | |||||
| #if JUCE_LINUX | |||||
| String command ("make -C " + projectFile.getParentDirectory().getFullPathName() + " CONFIG=Release -j3"); | |||||
| if (! makeProcess.start (command)) | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Error", "Error building Demo Runner."); | |||||
| #else | |||||
| projectFile.startAsProcess(); | |||||
| #endif | |||||
| } | |||||
| }), false); | |||||
| } | |||||
| else | |||||
| { | |||||
| jassertfalse; | |||||
| } | |||||
| } | |||||
| void ProjucerApplication::handleMainMenuCommand (int menuItemID) | void ProjucerApplication::handleMainMenuCommand (int menuItemID) | ||||
| { | { | ||||
| if (menuItemID >= recentProjectsBaseID && menuItemID < (recentProjectsBaseID + 100)) | if (menuItemID >= recentProjectsBaseID && menuItemID < (recentProjectsBaseID + 100)) | ||||
| @@ -586,6 +837,10 @@ void ProjucerApplication::handleMainMenuCommand (int menuItemID) | |||||
| { | { | ||||
| showEditorColourSchemeWindow(); | showEditorColourSchemeWindow(); | ||||
| } | } | ||||
| else if (menuItemID >= examplesBaseID && menuItemID < (examplesBaseID + numExamples)) | |||||
| { | |||||
| findAndLaunchExample (menuItemID - examplesBaseID); | |||||
| } | |||||
| else | else | ||||
| { | { | ||||
| handleGUIEditorMenuCommand (menuItemID); | handleGUIEditorMenuCommand (menuItemID); | ||||
| @@ -598,7 +853,9 @@ void ProjucerApplication::getAllCommands (Array <CommandID>& commands) | |||||
| JUCEApplication::getAllCommands (commands); | JUCEApplication::getAllCommands (commands); | ||||
| const CommandID ids[] = { CommandIDs::newProject, | const CommandID ids[] = { CommandIDs::newProject, | ||||
| CommandIDs::newProjectFromClipboard, | |||||
| CommandIDs::open, | CommandIDs::open, | ||||
| CommandIDs::launchDemoRunner, | |||||
| CommandIDs::closeAllWindows, | CommandIDs::closeAllWindows, | ||||
| CommandIDs::closeAllDocuments, | CommandIDs::closeAllDocuments, | ||||
| CommandIDs::clearRecentFiles, | CommandIDs::clearRecentFiles, | ||||
| @@ -622,18 +879,38 @@ void ProjucerApplication::getCommandInfo (CommandID commandID, ApplicationComman | |||||
| switch (commandID) | switch (commandID) | ||||
| { | { | ||||
| case CommandIDs::newProject: | case CommandIDs::newProject: | ||||
| result.setInfo ("New Project...", "Creates a new Jucer project", CommandCategories::general, 0); | |||||
| result.setInfo ("New Project...", "Creates a new JUCE project", CommandCategories::general, 0); | |||||
| result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier, 0)); | result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier, 0)); | ||||
| break; | break; | ||||
| case CommandIDs::newProjectFromClipboard: | |||||
| result.setInfo ("New Project From Clipboard...", "Creates a new JUCE project from the clipboard contents", CommandCategories::general, 0); | |||||
| result.defaultKeypresses.add (KeyPress ('n', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0)); | |||||
| break; | |||||
| case CommandIDs::launchDemoRunner: | |||||
| #if JUCE_LINUX | |||||
| if (makeProcess.isRunning()) | |||||
| { | |||||
| result.setInfo ("Building Demo Runner...", "The Demo Runner project is currently building", CommandCategories::general, 0); | |||||
| result.setActive (false); | |||||
| } | |||||
| else | |||||
| #endif | |||||
| { | |||||
| result.setInfo ("Launch Demo Runner", "Launches the JUCE demo runner application, or the project if it can't be found", CommandCategories::general, 0); | |||||
| result.setActive (findDemoRunnerExecutable() != File() || findDemoRunnerProject() != File()); | |||||
| } | |||||
| break; | |||||
| case CommandIDs::open: | case CommandIDs::open: | ||||
| result.setInfo ("Open...", "Opens a Jucer project", CommandCategories::general, 0); | |||||
| result.setInfo ("Open...", "Opens a JUCE project", CommandCategories::general, 0); | |||||
| result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0)); | result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0)); | ||||
| break; | break; | ||||
| case CommandIDs::showGlobalPathsWindow: | case CommandIDs::showGlobalPathsWindow: | ||||
| result.setInfo ("Global Search Paths...", | |||||
| "Shows the window to change the global search paths.", | |||||
| result.setInfo ("Global Paths...", | |||||
| "Shows the window to change the stored global paths.", | |||||
| CommandCategories::general, 0); | CommandCategories::general, 0); | ||||
| break; | break; | ||||
| @@ -719,7 +996,9 @@ bool ProjucerApplication::perform (const InvocationInfo& info) | |||||
| switch (info.commandID) | switch (info.commandID) | ||||
| { | { | ||||
| case CommandIDs::newProject: createNewProject(); break; | case CommandIDs::newProject: createNewProject(); break; | ||||
| case CommandIDs::newProjectFromClipboard: createNewProjectFromClipboard(); break; | |||||
| case CommandIDs::open: askUserToOpenFile(); break; | case CommandIDs::open: askUserToOpenFile(); break; | ||||
| case CommandIDs::launchDemoRunner: launchDemoRunner(); break; | |||||
| case CommandIDs::saveAll: openDocumentManager.saveAll(); break; | case CommandIDs::saveAll: openDocumentManager.saveAll(); break; | ||||
| case CommandIDs::closeAllWindows: closeAllMainWindowsAndQuitIfNeeded(); break; | case CommandIDs::closeAllWindows: closeAllMainWindowsAndQuitIfNeeded(); break; | ||||
| case CommandIDs::closeAllDocuments: closeAllDocuments (true); break; | case CommandIDs::closeAllDocuments: closeAllDocuments (true); break; | ||||
| @@ -743,11 +1022,30 @@ bool ProjucerApplication::perform (const InvocationInfo& info) | |||||
| //============================================================================== | //============================================================================== | ||||
| void ProjucerApplication::createNewProject() | void ProjucerApplication::createNewProject() | ||||
| { | { | ||||
| MainWindow* mw = mainWindowList.getOrCreateEmptyWindow(); | |||||
| mw->showNewProjectWizard(); | |||||
| auto* mw = mainWindowList.getOrCreateEmptyWindow(); | |||||
| mw->showStartPage(); | |||||
| mainWindowList.avoidSuperimposedWindows (mw); | mainWindowList.avoidSuperimposedWindows (mw); | ||||
| } | } | ||||
| void ProjucerApplication::createNewProjectFromClipboard() | |||||
| { | |||||
| auto tempFile = File::getSpecialLocation (File::SpecialLocationType::tempDirectory).getChildFile ("PIPs").getChildFile ("Clipboard") | |||||
| .getChildFile ("PIPFile_" + String (std::abs (Random::getSystemRandom().nextInt())) + ".h"); | |||||
| if (tempFile.existsAsFile()) | |||||
| tempFile.deleteFile(); | |||||
| tempFile.create(); | |||||
| tempFile.appendText (SystemClipboard::getTextFromClipboard()); | |||||
| if (! findWindowAndOpenPIP (tempFile)) | |||||
| { | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Error", "Couldn't create project from clipboard contents."); | |||||
| tempFile.deleteFile(); | |||||
| } | |||||
| } | |||||
| void ProjucerApplication::updateNewlyOpenedProject (Project& p) | void ProjucerApplication::updateNewlyOpenedProject (Project& p) | ||||
| { | { | ||||
| LiveBuildProjectSettings::updateNewlyOpenedProject (p); | LiveBuildProjectSettings::updateNewlyOpenedProject (p); | ||||
| @@ -850,10 +1148,10 @@ void ProjucerApplication::showPathsWindow() | |||||
| if (pathsWindow != nullptr) | if (pathsWindow != nullptr) | ||||
| pathsWindow->toFront (true); | pathsWindow->toFront (true); | ||||
| else | else | ||||
| new FloatingToolWindow ("Global Search Paths", | |||||
| new FloatingToolWindow ("Global Paths", | |||||
| "pathsWindowPos", | "pathsWindowPos", | ||||
| new GlobalSearchPathsWindowComponent(), pathsWindow, false, | |||||
| 600, 500, 600, 500, 600, 500); | |||||
| new GlobalPathsWindowComponent(), pathsWindow, false, | |||||
| 600, 550, 600, 550, 600, 550); | |||||
| } | } | ||||
| void ProjucerApplication::showEditorColourSchemeWindow() | void ProjucerApplication::showEditorColourSchemeWindow() | ||||
| @@ -980,6 +1278,14 @@ void ProjucerApplication::initCommandManager() | |||||
| registerGUIEditorCommands(); | registerGUIEditorCommands(); | ||||
| } | } | ||||
| void ProjucerApplication::deleteTemporaryFiles() const noexcept | |||||
| { | |||||
| auto tempDirectory = File::getSpecialLocation (File::SpecialLocationType::tempDirectory).getChildFile ("PIPs"); | |||||
| if (tempDirectory.exists()) | |||||
| tempDirectory.deleteRecursively(); | |||||
| } | |||||
| void ProjucerApplication::selectEditorColourSchemeWithName (const String& schemeName) | void ProjucerApplication::selectEditorColourSchemeWithName (const String& schemeName) | ||||
| { | { | ||||
| auto& appearanceSettings = getAppSettings().appearance; | auto& appearanceSettings = getAppSettings().appearance; | ||||
| @@ -88,6 +88,7 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| void createNewProject(); | void createNewProject(); | ||||
| void createNewProjectFromClipboard(); | |||||
| void updateNewlyOpenedProject (Project&); | void updateNewlyOpenedProject (Project&); | ||||
| void askUserToOpenFile(); | void askUserToOpenFile(); | ||||
| bool openFile (const File&); | bool openFile (const File&); | ||||
| @@ -166,6 +167,26 @@ private: | |||||
| void handleAsyncUpdate() override; | void handleAsyncUpdate() override; | ||||
| void initCommandManager(); | void initCommandManager(); | ||||
| void deleteTemporaryFiles() const noexcept; | |||||
| void createExamplesPopupMenu (PopupMenu&) noexcept; | |||||
| Array<File> getSortedExampleDirectories() const noexcept; | |||||
| Array<File> getSortedExampleFilesInDirectory (const File&) const noexcept; | |||||
| bool findWindowAndOpenPIP (const File&); | |||||
| void findAndLaunchExample (int); | |||||
| File findDemoRunnerExecutable() const noexcept; | |||||
| File findDemoRunnerProject() const noexcept; | |||||
| void launchDemoRunner(); | |||||
| int numExamples = 0; | |||||
| ScopedPointer<AlertWindow> demoRunnerAlert; | |||||
| #if JUCE_LINUX | |||||
| ChildProcess makeProcess; | |||||
| #endif | |||||
| //============================================================================== | //============================================================================== | ||||
| void setColourScheme (int index, bool saveSetting); | void setColourScheme (int index, bool saveSetting); | ||||
| @@ -34,10 +34,13 @@ namespace CommandIDs | |||||
| enum | enum | ||||
| { | { | ||||
| newProject = 0x300000, | newProject = 0x300000, | ||||
| open = 0x300001, | |||||
| closeDocument = 0x300002, | |||||
| saveDocument = 0x300003, | |||||
| saveDocumentAs = 0x300004, | |||||
| newProjectFromClipboard = 0x300001, | |||||
| open = 0x300002, | |||||
| closeDocument = 0x300003, | |||||
| saveDocument = 0x300004, | |||||
| saveDocumentAs = 0x300005, | |||||
| launchDemoRunner = 0x300006, | |||||
| closeProject = 0x300010, | closeProject = 0x300010, | ||||
| saveProject = 0x300011, | saveProject = 0x300011, | ||||
| @@ -27,6 +27,7 @@ | |||||
| #include "jucer_Headers.h" | #include "jucer_Headers.h" | ||||
| #include "../Project/jucer_Module.h" | #include "../Project/jucer_Module.h" | ||||
| #include "../Utility/Helpers/jucer_TranslationHelpers.h" | #include "../Utility/Helpers/jucer_TranslationHelpers.h" | ||||
| #include "../Utility/PIPs/jucer_PIPGenerator.h" | |||||
| #include "jucer_CommandLine.h" | #include "jucer_CommandLine.h" | ||||
| @@ -34,8 +35,6 @@ | |||||
| //============================================================================== | //============================================================================== | ||||
| namespace | namespace | ||||
| { | { | ||||
| static const char* getLineEnding() { return "\r\n"; } | |||||
| struct CommandLineError | struct CommandLineError | ||||
| { | { | ||||
| CommandLineError (const String& s) : message (s) {} | CommandLineError (const String& s) : message (s) {} | ||||
| @@ -749,6 +748,31 @@ namespace | |||||
| settingsFile.replaceWithText (settingsTree.toXmlString()); | settingsFile.replaceWithText (settingsTree.toXmlString()); | ||||
| } | } | ||||
| static void createProjectFromPIP (const StringArray& args) | |||||
| { | |||||
| if (args.size() < 3) | |||||
| throw CommandLineError ("Not enough arguments. Usage: --create-project-from-pip path/to/PIP path/to/output."); | |||||
| auto pipFile = File::getCurrentWorkingDirectory().getChildFile (args[1].unquoted()); | |||||
| if (! pipFile.existsAsFile()) | |||||
| throw CommandLineError ("PIP file doesn't exist."); | |||||
| auto outputDir = File::getCurrentWorkingDirectory().getChildFile (args[2].unquoted()); | |||||
| if (! outputDir.exists()) | |||||
| { | |||||
| auto res = outputDir.createDirectory(); | |||||
| std::cout << "Creating directory " << outputDir.getFullPathName() << std::endl; | |||||
| } | |||||
| PIPGenerator generator (pipFile, outputDir); | |||||
| if (! generator.createJucerFile()) | |||||
| throw CommandLineError ("Failed to create .jucer file in " + outputDir.getFullPathName()+ "."); | |||||
| if (! generator.createMainCpp()) | |||||
| throw CommandLineError ("Failed to create Main.cpp."); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| static void showHelp() | static void showHelp() | ||||
| { | { | ||||
| @@ -812,8 +836,11 @@ namespace | |||||
| << " Creates a completed translations mapping file, that can be used to initialise a LocalisedStrings object. This allows you to localise the strings in your project" << std::endl | << " Creates a completed translations mapping file, that can be used to initialise a LocalisedStrings object. This allows you to localise the strings in your project" << std::endl | ||||
| << std::endl | << std::endl | ||||
| << " " << appName << " --set-global-search-path os identifier_to_set new_path" << std::endl | << " " << appName << " --set-global-search-path os identifier_to_set new_path" << std::endl | ||||
| << " Sets the global search path for a specified os and identifier. The os should be either osx, windows or linux and the identifiers can be any of the following: " | |||||
| << " Sets the global path for a specified os and identifier. The os should be either osx, windows or linux and the identifiers can be any of the following: " | |||||
| << "defaultJuceModulePath, defaultUserModulePath, vst3path, aaxPath (not valid on linux), rtasPath (not valid on linux), androidSDKPath or androidNDKPath." << std::endl | << "defaultJuceModulePath, defaultUserModulePath, vst3path, aaxPath (not valid on linux), rtasPath (not valid on linux), androidSDKPath or androidNDKPath." << std::endl | ||||
| << std::endl | |||||
| << " " << appName << " --create-project-from-pip path/to/PIP path/to/output" << std::endl | |||||
| << " Generates a JUCE project from a PIP file." << std::endl | |||||
| << std::endl; | << std::endl; | ||||
| } | } | ||||
| } | } | ||||
| @@ -849,6 +876,7 @@ int performCommandLine (const String& commandLine) | |||||
| if (matchArgument (command, "trans")) { scanFoldersForTranslationFiles (args); return 0; } | if (matchArgument (command, "trans")) { scanFoldersForTranslationFiles (args); return 0; } | ||||
| if (matchArgument (command, "trans-finish")) { createFinishedTranslationFile (args); return 0; } | if (matchArgument (command, "trans-finish")) { createFinishedTranslationFile (args); return 0; } | ||||
| if (matchArgument (command, "set-global-search-path")) { setGlobalPath (args); return 0; } | if (matchArgument (command, "set-global-search-path")) { setGlobalPath (args); return 0; } | ||||
| if (matchArgument (command, "create-project-from-pip")) { createProjectFromPIP (args); return 0; } | |||||
| } | } | ||||
| catch (const CommandLineError& error) | catch (const CommandLineError& error) | ||||
| { | { | ||||
| @@ -36,7 +36,7 @@ | |||||
| #include "Windows/jucer_AboutWindowComponent.h" | #include "Windows/jucer_AboutWindowComponent.h" | ||||
| #include "Windows/jucer_ApplicationUsageDataWindowComponent.h" | #include "Windows/jucer_ApplicationUsageDataWindowComponent.h" | ||||
| #include "Windows/jucer_EditorColourSchemeWindowComponent.h" | #include "Windows/jucer_EditorColourSchemeWindowComponent.h" | ||||
| #include "Windows/jucer_GlobalSearchPathsWindowComponent.h" | |||||
| #include "Windows/jucer_GlobalPathsWindowComponent.h" | |||||
| #include "Windows/jucer_FloatingToolWindow.h" | #include "Windows/jucer_FloatingToolWindow.h" | ||||
| #include "../LiveBuildEngine/jucer_MessageIDs.h" | #include "../LiveBuildEngine/jucer_MessageIDs.h" | ||||
| @@ -29,7 +29,7 @@ | |||||
| #include "jucer_MainWindow.h" | #include "jucer_MainWindow.h" | ||||
| #include "../Wizards/jucer_NewProjectWizardClasses.h" | #include "../Wizards/jucer_NewProjectWizardClasses.h" | ||||
| #include "../Utility/UI/jucer_JucerTreeViewBase.h" | #include "../Utility/UI/jucer_JucerTreeViewBase.h" | ||||
| #include "../ProjectSaving/jucer_ProjectSaver.h" | |||||
| //============================================================================== | //============================================================================== | ||||
| MainWindow::MainWindow() | MainWindow::MainWindow() | ||||
| @@ -140,7 +140,7 @@ void MainWindow::closeButtonPressed() | |||||
| ProjucerApplication::getApp().mainWindowList.closeWindow (this); | ProjucerApplication::getApp().mainWindowList.closeWindow (this); | ||||
| } | } | ||||
| bool MainWindow::closeProject (Project* project) | |||||
| bool MainWindow::closeProject (Project* project, bool askUserToSave) | |||||
| { | { | ||||
| jassert (project == currentProject && project != nullptr); | jassert (project == currentProject && project != nullptr); | ||||
| @@ -156,12 +156,10 @@ bool MainWindow::closeProject (Project* project) | |||||
| pcc->hideEditor(); | pcc->hideEditor(); | ||||
| } | } | ||||
| if (! ProjucerApplication::getApp().openDocumentManager.closeAllDocumentsUsingProject (*project, true)) | |||||
| if (! ProjucerApplication::getApp().openDocumentManager.closeAllDocumentsUsingProject (*project, askUserToSave)) | |||||
| return false; | return false; | ||||
| auto r = project->saveIfNeededAndUserAgrees(); | |||||
| if (r == FileBasedDocument::savedOk) | |||||
| if (! askUserToSave || (project->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk)) | |||||
| { | { | ||||
| setProject (nullptr); | setProject (nullptr); | ||||
| return true; | return true; | ||||
| @@ -175,6 +173,21 @@ bool MainWindow::closeCurrentProject() | |||||
| return currentProject == nullptr || closeProject (currentProject.get()); | return currentProject == nullptr || closeProject (currentProject.get()); | ||||
| } | } | ||||
| void MainWindow::moveProject (File newProjectFileToOpen) | |||||
| { | |||||
| auto openInIDE = currentProject->shouldOpenInIDEAfterSaving(); | |||||
| closeProject (currentProject, false); | |||||
| openFile (newProjectFileToOpen); | |||||
| if (currentProject != nullptr) | |||||
| { | |||||
| ProjucerApplication::getApp().getCommandManager().invokeDirectly (openInIDE ? CommandIDs::saveAndOpenInIDE | |||||
| : CommandIDs::saveProject, | |||||
| false); | |||||
| } | |||||
| } | |||||
| void MainWindow::setProject (Project* newProject) | void MainWindow::setProject (Project* newProject) | ||||
| { | { | ||||
| createProjectContentCompIfNeeded(); | createProjectContentCompIfNeeded(); | ||||
| @@ -186,6 +199,12 @@ void MainWindow::setProject (Project* newProject) | |||||
| else | else | ||||
| projectNameValue.referTo (Value()); | projectNameValue.referTo (Value()); | ||||
| if (newProject != nullptr) | |||||
| { | |||||
| if (auto* peer = getPeer()) | |||||
| peer->setRepresentedFile (newProject->getFile()); | |||||
| } | |||||
| ProjucerApplication::getCommandManager().commandStatusChanged(); | ProjucerApplication::getCommandManager().commandStatusChanged(); | ||||
| } | } | ||||
| @@ -241,6 +260,142 @@ bool MainWindow::openFile (const File& file) | |||||
| return false; | return false; | ||||
| } | } | ||||
| bool MainWindow::tryToOpenPIP (const File& pipFile) | |||||
| { | |||||
| PIPGenerator generator (pipFile); | |||||
| if (! generator.hasValidPIP()) | |||||
| return false; | |||||
| auto generatorResult = generator.createJucerFile(); | |||||
| if (generatorResult != Result::ok()) | |||||
| { | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| "PIP Error.", | |||||
| generatorResult.getErrorMessage()); | |||||
| return false; | |||||
| } | |||||
| if (! generator.createMainCpp()) | |||||
| { | |||||
| AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, | |||||
| "PIP Error.", | |||||
| "Failed to create Main.cpp."); | |||||
| return false; | |||||
| } | |||||
| if (! ProjucerApplication::getApp().mainWindowList.openFile (generator.getJucerFile())) | |||||
| return false; | |||||
| openPIP (generator, pipFile.getFileName()); | |||||
| return true; | |||||
| } | |||||
| static bool isDivider (const String& line) | |||||
| { | |||||
| auto afterIndent = line.trim(); | |||||
| if (afterIndent.startsWith ("//") && afterIndent.length() > 20) | |||||
| { | |||||
| afterIndent = afterIndent.substring (2); | |||||
| if (afterIndent.containsOnly ("=") | |||||
| || afterIndent.containsOnly ("/") | |||||
| || afterIndent.containsOnly ("-")) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool isEndOfCommentBlock (const String& line) | |||||
| { | |||||
| if (line.contains ("*/")) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| static int getIndexOfCommentBlockStart (const StringArray& lines, int blockEndIndex) | |||||
| { | |||||
| for (int i = blockEndIndex; i >= 0; --i) | |||||
| { | |||||
| if (lines[i].contains ("/*")) | |||||
| return i; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static int findBestLineToScrollTo (StringArray lines, StringRef className) | |||||
| { | |||||
| for (auto line : lines) | |||||
| { | |||||
| if (line.contains ("struct " + className) || line.contains ("class " + className)) | |||||
| { | |||||
| auto index = lines.indexOf (line); | |||||
| if (isDivider (lines[index - 1])) | |||||
| return index - 1; | |||||
| if (isEndOfCommentBlock (lines[index - 1])) | |||||
| { | |||||
| auto blockStartIndex = getIndexOfCommentBlockStart (lines, index - 1); | |||||
| if (blockStartIndex > 0 && isDivider (lines [blockStartIndex - 1])) | |||||
| return blockStartIndex - 1; | |||||
| return blockStartIndex; | |||||
| } | |||||
| return lines.indexOf (line); | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| void MainWindow::openPIP (PIPGenerator& generator, StringRef fileName) | |||||
| { | |||||
| if (auto* window = ProjucerApplication::getApp().mainWindowList.getMainWindowForFile (generator.getJucerFile())) | |||||
| { | |||||
| if (auto* project = window->getProject()) | |||||
| { | |||||
| project->setTemporaryDirectory (generator.getOutputDirectory()); | |||||
| ProjectSaver liveBuildSaver (*project, project->getFile()); | |||||
| liveBuildSaver.saveContentNeededForLiveBuild(); | |||||
| if (auto* pcc = window->getProjectContentComponent()) | |||||
| { | |||||
| pcc->invokeDirectly (CommandIDs::toggleBuildEnabled, true); | |||||
| pcc->invokeDirectly (CommandIDs::buildNow, true); | |||||
| pcc->invokeDirectly (CommandIDs::toggleContinuousBuild, true); | |||||
| auto fileToDisplay = project->getSourceFilesFolder().getChildFile (fileName); | |||||
| if (fileToDisplay != File()) | |||||
| { | |||||
| pcc->showEditorForFile (fileToDisplay, true); | |||||
| if (auto* sourceCodeEditor = dynamic_cast <SourceCodeEditor*> (pcc->getEditorComponent())) | |||||
| { | |||||
| sourceCodeEditor->editor->scrollToLine (findBestLineToScrollTo (StringArray::fromLines (fileToDisplay.loadFileAsString()), | |||||
| generator.getMainClassName())); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| bool MainWindow::isInterestedInFileDrag (const StringArray& filenames) | bool MainWindow::isInterestedInFileDrag (const StringArray& filenames) | ||||
| { | { | ||||
| for (auto& filename : filenames) | for (auto& filename : filenames) | ||||
| @@ -256,7 +411,10 @@ void MainWindow::filesDropped (const StringArray& filenames, int /*mouseX*/, int | |||||
| { | { | ||||
| const File f (filename); | const File f (filename); | ||||
| if (canOpenFile (f) && openFile (f)) | |||||
| if (tryToOpenPIP (f)) | |||||
| continue; | |||||
| if (! isPIPFile (f) && (canOpenFile (f) && openFile (f))) | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| @@ -326,9 +484,15 @@ void MainWindow::activeWindowStatusChanged() | |||||
| { | { | ||||
| if (auto* project = getProject()) | if (auto* project = getProject()) | ||||
| { | { | ||||
| auto oldTemporaryDirectory = project->getTemporaryDirectory(); | |||||
| auto projectFile = project->getFile(); | auto projectFile = project->getFile(); | ||||
| setProject (nullptr); | setProject (nullptr); | ||||
| openFile (projectFile); | openFile (projectFile); | ||||
| if (oldTemporaryDirectory != File()) | |||||
| if (auto* newProject = getProject()) | |||||
| newProject->setTemporaryDirectory (oldTemporaryDirectory); | |||||
| } | } | ||||
| } | } | ||||
| else | else | ||||
| @@ -340,13 +504,16 @@ void MainWindow::activeWindowStatusChanged() | |||||
| } | } | ||||
| } | } | ||||
| void MainWindow::showNewProjectWizard() | |||||
| void MainWindow::showStartPage() | |||||
| { | { | ||||
| jassert (currentProject == nullptr); | jassert (currentProject == nullptr); | ||||
| setContentOwned (createNewProjectWizardComponent(), true); | setContentOwned (createNewProjectWizardComponent(), true); | ||||
| centreWithSize (900, 630); | centreWithSize (900, 630); | ||||
| setVisible (true); | setVisible (true); | ||||
| addToDesktop(); | addToDesktop(); | ||||
| getContentComponent()->grabKeyboardFocus(); | getContentComponent()->grabKeyboardFocus(); | ||||
| } | } | ||||
| @@ -453,7 +620,7 @@ bool MainWindowList::askAllWindowsToClose() | |||||
| void MainWindowList::createWindowIfNoneAreOpen() | void MainWindowList::createWindowIfNoneAreOpen() | ||||
| { | { | ||||
| if (windows.size() == 0) | if (windows.size() == 0) | ||||
| createNewMainWindow()->showNewProjectWizard(); | |||||
| createNewMainWindow()->showStartPage(); | |||||
| } | } | ||||
| void MainWindowList::closeWindow (MainWindow* w) | void MainWindowList::closeWindow (MainWindow* w) | ||||
| @@ -542,7 +709,10 @@ bool MainWindowList::openFile (const File& file, bool openInBackground) | |||||
| return ok; | return ok; | ||||
| } | } | ||||
| if (file.exists()) | |||||
| if (getFrontmostWindow()->tryToOpenPIP (file)) | |||||
| return true; | |||||
| if (! isPIPFile (file) && file.exists()) | |||||
| return getFrontmostWindow()->openFile (file); | return getFrontmostWindow()->openFile (file); | ||||
| return false; | return false; | ||||
| @@ -599,6 +769,23 @@ MainWindow* MainWindowList::getOrCreateEmptyWindow() | |||||
| return createNewMainWindow(); | return createNewMainWindow(); | ||||
| } | } | ||||
| MainWindow* MainWindowList::getMainWindowForFile (const File& file) | |||||
| { | |||||
| if (windows.size() > 0) | |||||
| { | |||||
| for (auto* window : windows) | |||||
| { | |||||
| if (auto* project = window->getProject()) | |||||
| { | |||||
| if (project->getFile() == file) | |||||
| return window; | |||||
| } | |||||
| } | |||||
| } | |||||
| return nullptr; | |||||
| } | |||||
| void MainWindowList::avoidSuperimposedWindows (MainWindow* const mw) | void MainWindowList::avoidSuperimposedWindows (MainWindow* const mw) | ||||
| { | { | ||||
| for (int i = windows.size(); --i >= 0;) | for (int i = windows.size(); --i >= 0;) | ||||
| @@ -633,7 +820,8 @@ void MainWindowList::saveCurrentlyOpenProjectList() | |||||
| { | { | ||||
| if (auto* mw = dynamic_cast<MainWindow*> (desktop.getComponent(i))) | if (auto* mw = dynamic_cast<MainWindow*> (desktop.getComponent(i))) | ||||
| if (auto* p = mw->getProject()) | if (auto* p = mw->getProject()) | ||||
| projects.add (p->getFile()); | |||||
| if (! p->isTemporaryProject()) | |||||
| projects.add (p->getFile()); | |||||
| } | } | ||||
| getAppSettings().setLastProjects (projects); | getAppSettings().setLastProjects (projects); | ||||
| @@ -27,6 +27,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "../Project/UI/jucer_ProjectContentComponent.h" | #include "../Project/UI/jucer_ProjectContentComponent.h" | ||||
| #include "../Utility/PIPs/jucer_PIPGenerator.h" | |||||
| //============================================================================== | //============================================================================== | ||||
| /** | /** | ||||
| @@ -51,13 +52,15 @@ public: | |||||
| bool openFile (const File& file); | bool openFile (const File& file); | ||||
| void setProject (Project* newProject); | void setProject (Project* newProject); | ||||
| Project* getProject() const { return currentProject.get(); } | Project* getProject() const { return currentProject.get(); } | ||||
| bool tryToOpenPIP (const File& f); | |||||
| void makeVisible(); | void makeVisible(); | ||||
| void restoreWindowPosition(); | void restoreWindowPosition(); | ||||
| bool closeProject (Project* project); | |||||
| bool closeProject (Project* project, bool askToSave = true); | |||||
| bool closeCurrentProject(); | bool closeCurrentProject(); | ||||
| void moveProject (File newProjectFile); | |||||
| void showNewProjectWizard(); | |||||
| void showStartPage(); | |||||
| bool isInterestedInFileDrag (const StringArray& files) override; | bool isInterestedInFileDrag (const StringArray& files) override; | ||||
| void filesDropped (const StringArray& filenames, int mouseX, int mouseY) override; | void filesDropped (const StringArray& filenames, int mouseX, int mouseY) override; | ||||
| @@ -82,6 +85,8 @@ private: | |||||
| void createProjectContentCompIfNeeded(); | void createProjectContentCompIfNeeded(); | ||||
| void setTitleBarIcon(); | void setTitleBarIcon(); | ||||
| void openPIP (PIPGenerator&, StringRef fileName); | |||||
| void valueChanged (Value&) override; | void valueChanged (Value&) override; | ||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow) | ||||
| @@ -106,6 +111,7 @@ public: | |||||
| MainWindow* createNewMainWindow(); | MainWindow* createNewMainWindow(); | ||||
| MainWindow* getFrontmostWindow (bool createIfNotFound = true); | MainWindow* getFrontmostWindow (bool createIfNotFound = true); | ||||
| MainWindow* getOrCreateEmptyWindow(); | MainWindow* getOrCreateEmptyWindow(); | ||||
| MainWindow* getMainWindowForFile (const File&); | |||||
| Project* getFrontmostProject(); | Project* getFrontmostProject(); | ||||
| @@ -684,6 +684,11 @@ void CompileEngineChildProcess::handleAppQuit() | |||||
| runningAppProcess.reset(); | runningAppProcess.reset(); | ||||
| } | } | ||||
| bool CompileEngineChildProcess::isAppRunning() const noexcept | |||||
| { | |||||
| return runningAppProcess != nullptr && runningAppProcess->isRunningApp; | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| struct CompileEngineChildProcess::Editor : private CodeDocument::Listener, | struct CompileEngineChildProcess::Editor : private CodeDocument::Listener, | ||||
| private Timer | private Timer | ||||
| @@ -52,6 +52,7 @@ public: | |||||
| void launchApp(); | void launchApp(); | ||||
| bool canKillApp() const; | bool canKillApp() const; | ||||
| void killApp(); | void killApp(); | ||||
| bool isAppRunning() const noexcept; | |||||
| const ClassDatabase::ClassList& getComponentList() const { return lastComponentList; } | const ClassDatabase::ClassList& getComponentList() const { return lastComponentList; } | ||||
| @@ -192,8 +192,8 @@ private: | |||||
| globalPathValue.referTo (modules.getShouldUseGlobalPathValue (moduleID)); | globalPathValue.referTo (modules.getShouldUseGlobalPathValue (moduleID)); | ||||
| auto menuItemString = (TargetOS::getThisOS() == TargetOS::osx ? "\"Projucer->Global Search Paths...\"" | |||||
| : "\"File->Global Search Paths...\""); | |||||
| auto menuItemString = (TargetOS::getThisOS() == TargetOS::osx ? "\"Projucer->Global Paths...\"" | |||||
| : "\"File->Global Paths...\""); | |||||
| props.add (new BooleanPropertyComponent (globalPathValue, | props.add (new BooleanPropertyComponent (globalPathValue, | ||||
| "Use global path", "Use global path for this module"), | "Use global path", "Use global path for this module"), | ||||
| @@ -0,0 +1,372 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2017 - ROLI Ltd. | |||||
| JUCE is an open source library subject to commercial or open-source | |||||
| licensing. | |||||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||||
| 27th April 2017). | |||||
| End User License Agreement: www.juce.com/juce-5-licence | |||||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||||
| Or: You may also use this code under the terms of the GPL v3 (see | |||||
| www.gnu.org/licenses). | |||||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||||
| DISCLAIMED. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "jucer_HeaderComponent.h" | |||||
| #include "../../ProjectSaving/jucer_ProjectExporter.h" | |||||
| #include "../../Project/UI/jucer_ProjectContentComponent.h" | |||||
| #include "../../LiveBuildEngine/jucer_MessageIDs.h" | |||||
| #include "../../LiveBuildEngine/jucer_SourceCodeRange.h" | |||||
| #include "../../LiveBuildEngine/jucer_ClassDatabase.h" | |||||
| #include "../../LiveBuildEngine/jucer_DiagnosticMessage.h" | |||||
| #include "../../LiveBuildEngine/jucer_CompileEngineClient.h" | |||||
| //====================================================================== | |||||
| HeaderComponent::HeaderComponent() | |||||
| { | |||||
| addAndMakeVisible (configLabel); | |||||
| addAndMakeVisible (exporterBox); | |||||
| exporterBox.onChange = [this] { updateExporterButton(); }; | |||||
| addAndMakeVisible (juceIcon = new ImageComponent ("icon")); | |||||
| juceIcon->setImage (ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize), | |||||
| RectanglePlacement::centred); | |||||
| projectNameLabel.setText ({}, dontSendNotification); | |||||
| addAndMakeVisible (projectNameLabel); | |||||
| initialiseButtons(); | |||||
| } | |||||
| HeaderComponent::~HeaderComponent() | |||||
| { | |||||
| if (userSettingsWindow != nullptr) | |||||
| userSettingsWindow->dismiss(); | |||||
| if (childProcess != nullptr) | |||||
| { | |||||
| childProcess->activityList.removeChangeListener(this); | |||||
| childProcess->errorList.removeChangeListener (this); | |||||
| } | |||||
| } | |||||
| //====================================================================== | |||||
| void HeaderComponent::resized() | |||||
| { | |||||
| auto bounds = getLocalBounds(); | |||||
| configLabel.setFont ({ bounds.getHeight() / 3.0f }); | |||||
| //====================================================================== | |||||
| { | |||||
| auto headerBounds = bounds.removeFromLeft (tabsWidth); | |||||
| const int buttonSize = 25; | |||||
| auto buttonBounds = headerBounds.removeFromRight (buttonSize); | |||||
| projectSettingsButton->setBounds (buttonBounds.removeFromBottom (buttonSize).reduced (2)); | |||||
| juceIcon->setBounds (headerBounds.removeFromLeft (headerBounds.getHeight()).reduced (2)); | |||||
| headerBounds.removeFromRight (5); | |||||
| projectNameLabel.setBounds (headerBounds); | |||||
| } | |||||
| //====================================================================== | |||||
| auto exporterWidth = jmin (400, bounds.getWidth() / 2); | |||||
| Rectangle<int> exporterBounds (0, 0, exporterWidth, bounds.getHeight()); | |||||
| exporterBounds.setCentre (bounds.getCentre()); | |||||
| runAppButton->setBounds (exporterBounds.removeFromRight (exporterBounds.getHeight()).reduced (2)); | |||||
| saveAndOpenInIDEButton->setBounds (exporterBounds.removeFromRight (exporterBounds.getHeight()).reduced (2)); | |||||
| exporterBounds.removeFromRight (5); | |||||
| exporterBox.setBounds (exporterBounds.removeFromBottom (roundToInt (exporterBounds.getHeight() / 1.8f))); | |||||
| configLabel.setBounds (exporterBounds); | |||||
| bounds.removeFromRight (5); | |||||
| userSettingsButton->setBounds (bounds.removeFromRight (bounds.getHeight()).reduced (2)); | |||||
| } | |||||
| void HeaderComponent::paint (Graphics& g) | |||||
| { | |||||
| g.fillAll (findColour (backgroundColourId)); | |||||
| if (isBuilding) | |||||
| getLookAndFeel().drawSpinningWaitAnimation (g, findColour (treeIconColourId), | |||||
| runAppButton->getX(), runAppButton->getY(), | |||||
| runAppButton->getWidth(), runAppButton->getHeight()); | |||||
| } | |||||
| //====================================================================== | |||||
| void HeaderComponent::setCurrentProject (Project* p) noexcept | |||||
| { | |||||
| project = p; | |||||
| exportersTree = project->getExporters(); | |||||
| exportersTree.addListener (this); | |||||
| updateExporters(); | |||||
| project->addChangeListener (this); | |||||
| updateName(); | |||||
| isBuilding = false; | |||||
| stopTimer(); | |||||
| repaint(); | |||||
| childProcess = ProjucerApplication::getApp().childProcessCache->getExisting (*project); | |||||
| if (childProcess != nullptr) | |||||
| { | |||||
| childProcess->activityList.addChangeListener (this); | |||||
| childProcess->errorList.addChangeListener (this); | |||||
| } | |||||
| if (childProcess != nullptr) | |||||
| { | |||||
| runAppButton->setTooltip ({}); | |||||
| runAppButton->setEnabled (true); | |||||
| } | |||||
| else | |||||
| { | |||||
| runAppButton->setTooltip ("Enable live-build engine to launch application"); | |||||
| runAppButton->setEnabled (false); | |||||
| } | |||||
| } | |||||
| //====================================================================== | |||||
| void HeaderComponent::updateExporters() noexcept | |||||
| { | |||||
| auto selectedName = getSelectedExporterName(); | |||||
| exporterBox.clear(); | |||||
| auto preferredExporterIndex = -1; | |||||
| int i = 0; | |||||
| for (Project::ExporterIterator exporter (*project); exporter.next(); ++i) | |||||
| { | |||||
| exporterBox.addItem (exporter->getName(), i + 1); | |||||
| if (selectedName == exporter->getName()) | |||||
| exporterBox.setSelectedId (i + 1); | |||||
| if (exporter->canLaunchProject() && preferredExporterIndex == -1) | |||||
| preferredExporterIndex = i; | |||||
| } | |||||
| if (exporterBox.getSelectedItemIndex() == -1) | |||||
| exporterBox.setSelectedItemIndex (preferredExporterIndex != -1 ? preferredExporterIndex | |||||
| : 0); | |||||
| updateExporterButton(); | |||||
| } | |||||
| String HeaderComponent::getSelectedExporterName() const noexcept | |||||
| { | |||||
| return exporterBox.getItemText (exporterBox.getSelectedItemIndex()); | |||||
| } | |||||
| bool HeaderComponent::canCurrentExporterLaunchProject() const noexcept | |||||
| { | |||||
| for (Project::ExporterIterator exporter (*project); exporter.next();) | |||||
| if (exporter->getName() == getSelectedExporterName() && exporter->canLaunchProject()) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| //====================================================================== | |||||
| int HeaderComponent::getUserButtonWidth() const noexcept | |||||
| { | |||||
| return userSettingsButton->getWidth(); | |||||
| } | |||||
| void HeaderComponent::sidebarTabsWidthChanged (int newWidth) noexcept | |||||
| { | |||||
| tabsWidth = newWidth; | |||||
| resized(); | |||||
| } | |||||
| //====================================================================== | |||||
| void HeaderComponent::showUserSettings() noexcept | |||||
| { | |||||
| #if JUCER_ENABLE_GPL_MODE | |||||
| auto settingsPopupHeight = 40; | |||||
| auto settingsPopupWidth = 200; | |||||
| #else | |||||
| auto settingsPopupHeight = 150; | |||||
| auto settingsPopupWidth = 250; | |||||
| #endif | |||||
| auto* content = new UserSettingsPopup (false); | |||||
| content->setSize (settingsPopupWidth, settingsPopupHeight); | |||||
| userSettingsWindow = &CallOutBox::launchAsynchronously (content, userSettingsButton->getScreenBounds(), nullptr); | |||||
| } | |||||
| //========================================================================== | |||||
| void HeaderComponent::lookAndFeelChanged() | |||||
| { | |||||
| if (userSettingsWindow != nullptr) | |||||
| userSettingsWindow->sendLookAndFeelChange(); | |||||
| } | |||||
| void HeaderComponent::changeListenerCallback (ChangeBroadcaster* source) | |||||
| { | |||||
| if (source == project) | |||||
| { | |||||
| updateName(); | |||||
| updateExporters(); | |||||
| } | |||||
| else if (childProcess != nullptr) | |||||
| { | |||||
| if (childProcess->activityList.getNumActivities() > 0) | |||||
| buildPing(); | |||||
| else | |||||
| buildFinished (childProcess->errorList.getNumErrors() == 0); | |||||
| } | |||||
| } | |||||
| void HeaderComponent::timerCallback() | |||||
| { | |||||
| repaint(); | |||||
| } | |||||
| //====================================================================== | |||||
| void HeaderComponent::initialiseButtons() noexcept | |||||
| { | |||||
| auto& icons = getIcons(); | |||||
| addAndMakeVisible (projectSettingsButton = new IconButton ("Project Settings", &icons.settings)); | |||||
| projectSettingsButton->onClick = [this] | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| pcc->showProjectSettings(); | |||||
| }; | |||||
| addAndMakeVisible (saveAndOpenInIDEButton = new IconButton ("Save and Open in IDE", nullptr)); | |||||
| saveAndOpenInIDEButton->isIDEButton = true; | |||||
| saveAndOpenInIDEButton->onClick = [this] | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| pcc->openInSelectedIDE (true); | |||||
| }; | |||||
| addAndMakeVisible (userSettingsButton = new IconButton ("User Settings", &icons.user)); | |||||
| userSettingsButton->isUserButton = true; | |||||
| userSettingsButton->onClick = [this] | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| showUserSettings(); | |||||
| }; | |||||
| addAndMakeVisible (runAppButton = new IconButton ("Run Application", &icons.play)); | |||||
| runAppButton->onClick = [this] | |||||
| { | |||||
| if (childProcess != nullptr) | |||||
| childProcess->launchApp(); | |||||
| }; | |||||
| updateExporterButton(); | |||||
| updateUserAvatar(); | |||||
| } | |||||
| void HeaderComponent::updateName() noexcept | |||||
| { | |||||
| projectNameLabel.setText (project->getDocumentTitle(), dontSendNotification); | |||||
| } | |||||
| void HeaderComponent::updateExporterButton() noexcept | |||||
| { | |||||
| auto currentExporterName = getSelectedExporterName(); | |||||
| for (auto info : ProjectExporter::getExporterTypes()) | |||||
| { | |||||
| if (currentExporterName.contains (info.name)) | |||||
| { | |||||
| saveAndOpenInIDEButton->iconImage = info.getIcon(); | |||||
| saveAndOpenInIDEButton->repaint(); | |||||
| saveAndOpenInIDEButton->setEnabled (canCurrentExporterLaunchProject()); | |||||
| } | |||||
| } | |||||
| } | |||||
| void HeaderComponent::updateUserAvatar() noexcept | |||||
| { | |||||
| if (auto* controller = ProjucerApplication::getApp().licenseController.get()) | |||||
| { | |||||
| auto state = controller->getState(); | |||||
| userSettingsButton->iconImage = state.avatar; | |||||
| userSettingsButton->repaint(); | |||||
| } | |||||
| } | |||||
| //====================================================================== | |||||
| void HeaderComponent::buildPing() | |||||
| { | |||||
| if (! isTimerRunning()) | |||||
| { | |||||
| isBuilding = true; | |||||
| runAppButton->setEnabled (false); | |||||
| runAppButton->setTooltip ("Building..."); | |||||
| startTimer (50); | |||||
| } | |||||
| } | |||||
| void HeaderComponent::buildFinished (bool success) | |||||
| { | |||||
| stopTimer(); | |||||
| isBuilding = false; | |||||
| repaint(); | |||||
| setRunAppButtonState (success); | |||||
| } | |||||
| void HeaderComponent::setRunAppButtonState (bool buildWasSuccessful) | |||||
| { | |||||
| bool shouldEnableButton = false; | |||||
| if (buildWasSuccessful) | |||||
| { | |||||
| if (childProcess != nullptr) | |||||
| { | |||||
| if (childProcess->isAppRunning() || (! childProcess->isAppRunning() && childProcess->canLaunchApp())) | |||||
| { | |||||
| runAppButton->setTooltip ("Launch application"); | |||||
| shouldEnableButton = true; | |||||
| } | |||||
| else | |||||
| { | |||||
| runAppButton->setTooltip ("Application can't be launched"); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| runAppButton->setTooltip ("Enable live-build engine to launch application"); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| runAppButton->setTooltip ("Error building application"); | |||||
| } | |||||
| runAppButton->setEnabled (shouldEnableButton); | |||||
| } | |||||
| @@ -26,205 +26,48 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "../../Application/jucer_Headers.h" | |||||
| #include "../../Utility/UI/jucer_IconButton.h" | #include "../../Utility/UI/jucer_IconButton.h" | ||||
| #include "../../Utility/UI/jucer_UserSettingsPopup.h" | #include "../../Utility/UI/jucer_UserSettingsPopup.h" | ||||
| class Project; | |||||
| //============================================================================== | //============================================================================== | ||||
| class HeaderComponent : public Component, | class HeaderComponent : public Component, | ||||
| private ValueTree::Listener, | private ValueTree::Listener, | ||||
| private ChangeListener | |||||
| private ChangeListener, | |||||
| private Timer | |||||
| { | { | ||||
| public: | public: | ||||
| HeaderComponent() | |||||
| : configLabel ("Config Label", "Selected exporter") | |||||
| { | |||||
| addAndMakeVisible (configLabel); | |||||
| addAndMakeVisible (exporterBox); | |||||
| exporterBox.onChange = [this] { updateExporterButton(); }; | |||||
| addAndMakeVisible (juceIcon = new ImageComponent ("icon")); | |||||
| juceIcon->setImage (ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize), | |||||
| RectanglePlacement::centred); | |||||
| projectNameLabel.setText (String(), dontSendNotification); | |||||
| addAndMakeVisible (projectNameLabel); | |||||
| initialiseButtons(); | |||||
| } | |||||
| ~HeaderComponent() | |||||
| { | |||||
| if (userSettingsWindow != nullptr) | |||||
| userSettingsWindow->dismiss(); | |||||
| } | |||||
| void resized() override | |||||
| { | |||||
| auto bounds = getLocalBounds(); | |||||
| configLabel.setFont ({ bounds.getHeight() / 3.0f }); | |||||
| //====================================================================== | |||||
| auto projectHeaderBounds = bounds.removeFromLeft (tabsWidth); | |||||
| juceIcon->setBounds (projectHeaderBounds.removeFromLeft (projectHeaderBounds.getHeight()).reduced (5, 5)); | |||||
| projectSettingsButton->setBounds (projectHeaderBounds.removeFromRight (projectHeaderBounds.getHeight()).reduced (2, 2)); | |||||
| projectNameLabel.setBounds (projectHeaderBounds); | |||||
| //====================================================================== | |||||
| bounds.removeFromLeft (33); | |||||
| continuousRebuildButton->setBounds (bounds.removeFromLeft (bounds.getHeight()).reduced (2, 2)); | |||||
| bounds.removeFromLeft (5); | |||||
| buildNowButton->setBounds (bounds.removeFromLeft (bounds.getHeight()).reduced (2, 2)); | |||||
| bounds.removeFromRight (5); | |||||
| userSettingsButton->setBounds (bounds.removeFromRight (bounds.getHeight()).reduced (2, 2)); | |||||
| auto exporterWidth = jmax (250, bounds.getWidth() / 2); | |||||
| auto spacing = bounds.getWidth() - exporterWidth; | |||||
| auto leftSpacing = jmax (20, spacing / 3); | |||||
| auto rightSpacing = jmax (40, 2 * (spacing / 3)); | |||||
| bounds.removeFromLeft (leftSpacing); | |||||
| bounds.removeFromRight (rightSpacing); | |||||
| saveAndOpenInIDEButton->setBounds (bounds.removeFromRight (bounds.getHeight()).reduced (2, 2)); | |||||
| bounds.removeFromRight (5); | |||||
| exporterSettingsButton->setBounds (bounds.removeFromRight (bounds.getHeight()).reduced (2, 2)); | |||||
| bounds.removeFromRight (10); | |||||
| exporterBox.setBounds (bounds.removeFromBottom (roundToInt (bounds.getHeight() / 1.8f))); | |||||
| configLabel.setBounds (bounds); | |||||
| } | |||||
| void paint (Graphics& g) override | |||||
| { | |||||
| g.fillAll (findColour (backgroundColourId)); | |||||
| } | |||||
| void setCurrentProject (Project* p) | |||||
| { | |||||
| project = p; | |||||
| exportersTree = project->getExporters(); | |||||
| exportersTree.addListener (this); | |||||
| updateExporters(); | |||||
| project->addChangeListener (this); | |||||
| updateName(); | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| updateBuildButtons (pcc->isBuildEnabled(), pcc->isContinuousRebuildEnabled()); | |||||
| } | |||||
| void updateExporters() | |||||
| { | |||||
| auto selectedName = getSelectedExporterName(); | |||||
| exporterBox.clear(); | |||||
| auto preferredExporterIndex = -1; | |||||
| int i = 0; | |||||
| for (Project::ExporterIterator exporter (*project); exporter.next(); ++i) | |||||
| { | |||||
| exporterBox.addItem (exporter->getName(), i + 1); | |||||
| if (selectedName == exporter->getName()) | |||||
| exporterBox.setSelectedId (i + 1); | |||||
| if (exporter->canLaunchProject() && preferredExporterIndex == -1) | |||||
| preferredExporterIndex = i; | |||||
| } | |||||
| if (exporterBox.getSelectedItemIndex() == -1) | |||||
| exporterBox.setSelectedItemIndex (preferredExporterIndex != -1 ? preferredExporterIndex | |||||
| : 0); | |||||
| updateExporterButton(); | |||||
| } | |||||
| String getSelectedExporterName() | |||||
| { | |||||
| return exporterBox.getItemText (exporterBox.getSelectedItemIndex()); | |||||
| } | |||||
| bool canCurrentExporterLaunchProject() | |||||
| { | |||||
| for (Project::ExporterIterator exporter (*project); exporter.next();) | |||||
| if (exporter->getName() == getSelectedExporterName() && exporter->canLaunchProject()) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| int getUserButtonWidth() { return userSettingsButton->getWidth(); } | |||||
| void sidebarTabsWidthChanged (int newWidth) | |||||
| { | |||||
| tabsWidth = newWidth; | |||||
| resized(); | |||||
| } | |||||
| void showUserSettings() | |||||
| { | |||||
| #if JUCER_ENABLE_GPL_MODE | |||||
| auto settingsPopupHeight = 40; | |||||
| auto settingsPopupWidth = 200; | |||||
| #else | |||||
| auto settingsPopupHeight = 150; | |||||
| auto settingsPopupWidth = 250; | |||||
| #endif | |||||
| HeaderComponent(); | |||||
| ~HeaderComponent(); | |||||
| auto* content = new UserSettingsPopup (false); | |||||
| content->setSize (settingsPopupWidth, settingsPopupHeight); | |||||
| //========================================================================== | |||||
| void resized() override; | |||||
| void paint (Graphics&) override; | |||||
| userSettingsWindow = &CallOutBox::launchAsynchronously (content, userSettingsButton->getScreenBounds(), nullptr); | |||||
| } | |||||
| //========================================================================== | |||||
| void setCurrentProject (Project*) noexcept; | |||||
| void updateBuildButtons (bool isBuildEnabled, bool isContinuousRebuildEnabled) | |||||
| { | |||||
| buildNowButton->setEnabled (isBuildEnabled && ! isContinuousRebuildEnabled); | |||||
| continuousRebuildButton->setEnabled (isBuildEnabled); | |||||
| //========================================================================== | |||||
| void updateExporters() noexcept; | |||||
| String getSelectedExporterName() const noexcept; | |||||
| bool canCurrentExporterLaunchProject() const noexcept; | |||||
| continuousRebuildButton->icon = Icon (isContinuousRebuildEnabled ? &getIcons().continuousBuildStop : &getIcons().continuousBuildStart, | |||||
| Colours::transparentBlack); | |||||
| repaint(); | |||||
| } | |||||
| //========================================================================== | |||||
| int getUserButtonWidth() const noexcept; | |||||
| void sidebarTabsWidthChanged (int newWidth) noexcept; | |||||
| void lookAndFeelChanged() override | |||||
| { | |||||
| if (userSettingsWindow != nullptr) | |||||
| userSettingsWindow->sendLookAndFeelChange(); | |||||
| } | |||||
| //========================================================================== | |||||
| void showUserSettings() noexcept; | |||||
| private: | private: | ||||
| Project* project = nullptr; | |||||
| ValueTree exportersTree; | |||||
| Label configLabel, projectNameLabel; | |||||
| ComboBox exporterBox; | |||||
| ScopedPointer<ImageComponent> juceIcon; | |||||
| ScopedPointer<IconButton> projectSettingsButton, continuousRebuildButton, buildNowButton, | |||||
| exporterSettingsButton, saveAndOpenInIDEButton, userSettingsButton; | |||||
| SafePointer<CallOutBox> userSettingsWindow; | |||||
| int tabsWidth = 200; | |||||
| //========================================================================== | //========================================================================== | ||||
| void changeListenerCallback (ChangeBroadcaster* source) override | |||||
| { | |||||
| if (source == project) | |||||
| { | |||||
| updateName(); | |||||
| updateExporters(); | |||||
| } | |||||
| } | |||||
| void lookAndFeelChanged() override; | |||||
| void changeListenerCallback (ChangeBroadcaster* source) override; | |||||
| void timerCallback() override; | |||||
| //========================================================================== | |||||
| void valueTreePropertyChanged (ValueTree&, const Identifier&) override {} | void valueTreePropertyChanged (ValueTree&, const Identifier&) override {} | ||||
| void valueTreeParentChanged (ValueTree&) override {} | void valueTreeParentChanged (ValueTree&) override {} | ||||
| @@ -232,94 +75,41 @@ private: | |||||
| void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { updateIfNeeded (parentTree); } | void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { updateIfNeeded (parentTree); } | ||||
| void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { updateIfNeeded (parentTree); } | void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { updateIfNeeded (parentTree); } | ||||
| void initialiseButtons() | |||||
| void updateIfNeeded (ValueTree tree) noexcept | |||||
| { | { | ||||
| auto& icons = getIcons(); | |||||
| addAndMakeVisible (projectSettingsButton = new IconButton ("Project Settings", &icons.settings)); | |||||
| projectSettingsButton->onClick = [this] | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| pcc->showProjectSettings(); | |||||
| }; | |||||
| addAndMakeVisible (continuousRebuildButton = new IconButton ("Continuous Rebuild", &icons.continuousBuildStart)); | |||||
| continuousRebuildButton->onClick = [this] | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| pcc->setContinuousRebuildEnabled (! pcc->isContinuousRebuildEnabled()); | |||||
| }; | |||||
| addAndMakeVisible (buildNowButton = new IconButton ("Build Now", &icons.buildNow)); | |||||
| buildNowButton->onClick = [this] | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| pcc->rebuildNow(); | |||||
| }; | |||||
| addAndMakeVisible (exporterSettingsButton = new IconButton ("Exporter Settings", &icons.edit)); | |||||
| exporterSettingsButton->onClick = [this] | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| pcc->showExporterSettings (getSelectedExporterName()); | |||||
| }; | |||||
| if (tree == exportersTree) | |||||
| updateExporters(); | |||||
| } | |||||
| addAndMakeVisible (saveAndOpenInIDEButton = new IconButton ("Save and Open in IDE", nullptr)); | |||||
| saveAndOpenInIDEButton->isIDEButton = true; | |||||
| saveAndOpenInIDEButton->onClick = [this] | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| pcc->openInSelectedIDE (true); | |||||
| }; | |||||
| //========================================================================== | |||||
| void initialiseButtons() noexcept; | |||||
| addAndMakeVisible (userSettingsButton = new IconButton ("User Settings", &icons.user)); | |||||
| userSettingsButton->isUserButton = true; | |||||
| userSettingsButton->onClick = [this] | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| showUserSettings(); | |||||
| }; | |||||
| void updateName() noexcept; | |||||
| void updateExporterButton() noexcept; | |||||
| void updateUserAvatar() noexcept; | |||||
| updateExporterButton(); | |||||
| updateUserAvatar(); | |||||
| } | |||||
| //========================================================================== | |||||
| void buildPing(); | |||||
| void buildFinished (bool); | |||||
| void setRunAppButtonState (bool); | |||||
| void updateIfNeeded (ValueTree tree) | |||||
| { | |||||
| if (tree == exportersTree) | |||||
| updateExporters(); | |||||
| } | |||||
| //========================================================================== | |||||
| int tabsWidth = 200; | |||||
| bool isBuilding = false; | |||||
| void updateName() | |||||
| { | |||||
| projectNameLabel.setText (project->getDocumentTitle(), dontSendNotification); | |||||
| } | |||||
| Project* project = nullptr; | |||||
| ValueTree exportersTree; | |||||
| void updateExporterButton() | |||||
| { | |||||
| auto currentExporterName = getSelectedExporterName(); | |||||
| ComboBox exporterBox; | |||||
| Label configLabel { "Config Label", "Selected exporter" }, | |||||
| projectNameLabel; | |||||
| for (auto info : ProjectExporter::getExporterTypes()) | |||||
| { | |||||
| if (currentExporterName.contains (info.name)) | |||||
| { | |||||
| saveAndOpenInIDEButton->iconImage = info.getIcon(); | |||||
| saveAndOpenInIDEButton->repaint(); | |||||
| saveAndOpenInIDEButton->setEnabled (canCurrentExporterLaunchProject()); | |||||
| } | |||||
| } | |||||
| } | |||||
| ScopedPointer<ImageComponent> juceIcon; | |||||
| ScopedPointer<IconButton> projectSettingsButton, saveAndOpenInIDEButton, userSettingsButton, runAppButton; | |||||
| void updateUserAvatar() | |||||
| { | |||||
| if (auto* controller = ProjucerApplication::getApp().licenseController.get()) | |||||
| { | |||||
| auto state = controller->getState(); | |||||
| SafePointer<CallOutBox> userSettingsWindow; | |||||
| userSettingsButton->iconImage = state.avatar; | |||||
| userSettingsButton->repaint(); | |||||
| } | |||||
| } | |||||
| ReferenceCountedObjectPtr<CompileEngineChildProcess> childProcess; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HeaderComponent) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HeaderComponent) | ||||
| }; | }; | ||||
| @@ -478,7 +478,9 @@ void ProjectContentComponent::saveDocument() | |||||
| showSaveWarning (currentDocument); | showSaveWarning (currentDocument); | ||||
| } | } | ||||
| else | else | ||||
| { | |||||
| saveProject(); | saveProject(); | ||||
| } | |||||
| } | } | ||||
| void ProjectContentComponent::saveAs() | void ProjectContentComponent::saveAs() | ||||
| @@ -521,11 +523,13 @@ bool ProjectContentComponent::goToCounterpart() | |||||
| return false; | return false; | ||||
| } | } | ||||
| bool ProjectContentComponent::saveProject (bool shouldWait) | |||||
| bool ProjectContentComponent::saveProject (bool shouldWait, bool openInIDE) | |||||
| { | { | ||||
| if (project != nullptr) | if (project != nullptr) | ||||
| { | { | ||||
| const ScopedValueSetter<bool> valueSetter (project->shouldWaitAfterSaving, shouldWait, false); | const ScopedValueSetter<bool> valueSetter (project->shouldWaitAfterSaving, shouldWait, false); | ||||
| project->setOpenInIDEAfterSaving (openInIDE); | |||||
| return (project->save (true, true) == FileBasedDocument::savedOk); | return (project->save (true, true) == FileBasedDocument::savedOk); | ||||
| } | } | ||||
| @@ -637,11 +641,16 @@ void ProjectContentComponent::openInSelectedIDE (bool saveFirst) | |||||
| { | { | ||||
| if (exporter->canLaunchProject() && exporter->getName() == selectedIDE) | if (exporter->canLaunchProject() && exporter->getName() == selectedIDE) | ||||
| { | { | ||||
| if (saveFirst && ! saveProject (exporter->isXcode())) | |||||
| auto tempProject = project->isTemporaryProject(); // store this before saving as it will always be false after | |||||
| if (saveFirst && ! saveProject (exporter->isXcode(), true)) | |||||
| return; | |||||
| if (tempProject) | |||||
| return; | return; | ||||
| exporter->launchProject(); | exporter->launchProject(); | ||||
| break; | |||||
| return; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1155,9 +1164,6 @@ void ProjectContentComponent::setBuildEnabled (bool isEnabled, bool displayError | |||||
| LiveBuildProjectSettings::setBuildDisabled (*project, ! isEnabled); | LiveBuildProjectSettings::setBuildDisabled (*project, ! isEnabled); | ||||
| killChildProcess(); | killChildProcess(); | ||||
| refreshTabsIfBuildStatusChanged(); | refreshTabsIfBuildStatusChanged(); | ||||
| if (auto* h = dynamic_cast<HeaderComponent*> (header.get())) | |||||
| h->updateBuildButtons (isEnabled, isContinuousRebuildEnabled()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1300,11 +1306,7 @@ void ProjectContentComponent::setContinuousRebuildEnabled (bool b) | |||||
| { | { | ||||
| childProcess->setContinuousRebuild (b); | childProcess->setContinuousRebuild (b); | ||||
| if (auto* h = dynamic_cast<HeaderComponent*> (header.get())) | |||||
| h->updateBuildButtons (isBuildEnabled(), b); | |||||
| getAppSettings().getGlobalProperties().setValue ("continuousRebuild", b); | getAppSettings().getGlobalProperties().setValue ("continuousRebuild", b); | ||||
| ProjucerApplication::getCommandManager().commandStatusChanged(); | ProjucerApplication::getCommandManager().commandStatusChanged(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -75,7 +75,7 @@ public: | |||||
| bool canGoToCounterpart() const; | bool canGoToCounterpart() const; | ||||
| bool goToCounterpart(); | bool goToCounterpart(); | ||||
| bool saveProject (bool shouldWait = false); | |||||
| bool saveProject (bool shouldWait = false, bool openInIDE = false); | |||||
| void closeProject(); | void closeProject(); | ||||
| void openInSelectedIDE (bool saveFirst); | void openInSelectedIDE (bool saveFirst); | ||||
| void showNewExporterMenu(); | void showNewExporterMenu(); | ||||
| @@ -394,6 +394,13 @@ static void registerRecentFile (const File& file) | |||||
| getAppSettings().flush(); | getAppSettings().flush(); | ||||
| } | } | ||||
| static void forgetRecentFile (const File& file) | |||||
| { | |||||
| RecentlyOpenedFilesList::forgetRecentFileNatively (file); | |||||
| getAppSettings().recentFiles.removeFile (file); | |||||
| getAppSettings().flush(); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| Result Project::loadDocument (const File& file) | Result Project::loadDocument (const File& file) | ||||
| { | { | ||||
| @@ -408,6 +415,7 @@ Result Project::loadDocument (const File& file) | |||||
| return Result::fail ("The document contains errors and couldn't be parsed!"); | return Result::fail ("The document contains errors and couldn't be parsed!"); | ||||
| registerRecentFile (file); | registerRecentFile (file); | ||||
| enabledModulesList.reset(); | enabledModulesList.reset(); | ||||
| projectRoot = newTree; | projectRoot = newTree; | ||||
| @@ -437,9 +445,15 @@ Result Project::saveProject (const File& file, bool isCommandLineApp) | |||||
| if (isSaving) | if (isSaving) | ||||
| return Result::ok(); | return Result::ok(); | ||||
| if (isTemporaryProject()) | |||||
| { | |||||
| askUserWhereToSaveProject(); | |||||
| return Result::ok(); | |||||
| } | |||||
| updateProjectSettings(); | updateProjectSettings(); | ||||
| if (! isCommandLineApp) | |||||
| if (! isCommandLineApp && ! isTemporaryProject()) | |||||
| registerRecentFile (file); | registerRecentFile (file); | ||||
| const ScopedValueSetter<bool> vs (isSaving, true, false); | const ScopedValueSetter<bool> vs (isSaving, true, false); | ||||
| @@ -454,17 +468,55 @@ Result Project::saveResourcesOnly (const File& file) | |||||
| return saver.saveResourcesOnly(); | return saver.saveResourcesOnly(); | ||||
| } | } | ||||
| //============================================================================== | |||||
| void Project::setTemporaryDirectory (const File& dir) noexcept | |||||
| { | |||||
| tempDirectory = dir; | |||||
| // remove this file from the recent documents list as it is a temporary project | |||||
| forgetRecentFile (getFile()); | |||||
| } | |||||
| void Project::askUserWhereToSaveProject() | |||||
| { | |||||
| FileChooser fc ("Save Project"); | |||||
| fc.browseForDirectory(); | |||||
| if (fc.getResult().exists()) | |||||
| moveTemporaryDirectory (fc.getResult()); | |||||
| } | |||||
| void Project::moveTemporaryDirectory (const File& newParentDirectory) | |||||
| { | |||||
| auto newDirectory = newParentDirectory.getChildFile (tempDirectory.getFileName()); | |||||
| auto oldJucerFileName = getFile().getFileName(); | |||||
| tempDirectory.copyDirectoryTo (newDirectory); | |||||
| tempDirectory.deleteRecursively(); | |||||
| tempDirectory = File(); | |||||
| // reload project from new location | |||||
| if (auto* window = ProjucerApplication::getApp().mainWindowList.getMainWindowForFile (getFile())) | |||||
| window->moveProject (newDirectory.getChildFile (oldJucerFileName)); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| void Project::valueTreePropertyChanged (ValueTree& tree, const Identifier& property) | void Project::valueTreePropertyChanged (ValueTree& tree, const Identifier& property) | ||||
| { | { | ||||
| if (tree.getRoot() == tree) | if (tree.getRoot() == tree) | ||||
| { | { | ||||
| if (property == Ids::projectType) | if (property == Ids::projectType) | ||||
| { | |||||
| sendChangeMessage(); | sendChangeMessage(); | ||||
| } | |||||
| else if (property == Ids::name) | else if (property == Ids::name) | ||||
| { | |||||
| setTitle (projectRoot [Ids::name]); | setTitle (projectRoot [Ids::name]); | ||||
| } | |||||
| else if (property == Ids::defines) | else if (property == Ids::defines) | ||||
| { | |||||
| parsedPreprocessorDefs = parsePreprocessorDefs (preprocessorDefsValue.get()); | parsedPreprocessorDefs = parsePreprocessorDefs (preprocessorDefsValue.get()); | ||||
| } | |||||
| changed(); | changed(); | ||||
| } | } | ||||
| @@ -31,6 +31,7 @@ | |||||
| class ProjectExporter; | class ProjectExporter; | ||||
| class LibraryModule; | class LibraryModule; | ||||
| class EnabledModuleList; | class EnabledModuleList; | ||||
| class ProjectContentComponent; | |||||
| //============================================================================== | //============================================================================== | ||||
| class Project : public FileBasedDocument, | class Project : public FileBasedDocument, | ||||
| @@ -331,10 +332,18 @@ public: | |||||
| String getUniqueTargetFolderSuffixForExporter (const String& exporterName, const String& baseTargetFolder); | String getUniqueTargetFolderSuffixForExporter (const String& exporterName, const String& baseTargetFolder); | ||||
| //============================================================================== | //============================================================================== | ||||
| bool isCurrentlySaving() const noexcept { return isSaving; } | |||||
| bool isCurrentlySaving() const noexcept { return isSaving; } | |||||
| bool shouldWaitAfterSaving = false; | bool shouldWaitAfterSaving = false; | ||||
| String specifiedExporterToSave = {}; | String specifiedExporterToSave = {}; | ||||
| //============================================================================== | |||||
| bool isTemporaryProject() const noexcept { return tempDirectory != File(); } | |||||
| File getTemporaryDirectory() const noexcept { return tempDirectory; } | |||||
| void setTemporaryDirectory (const File&) noexcept; | |||||
| void setOpenInIDEAfterSaving (bool open) noexcept { openInIDEAfterSaving = open; } | |||||
| bool shouldOpenInIDEAfterSaving() const noexcept { return openInIDEAfterSaving; } | |||||
| private: | private: | ||||
| ValueTree projectRoot { Ids::JUCERPROJECT }; | ValueTree projectRoot { Ids::JUCERPROJECT }; | ||||
| @@ -349,6 +358,16 @@ private: | |||||
| pluginAUMainTypeValue, pluginRTASCategoryValue, pluginRTASBypassDisabledValue, pluginRTASMultiMonoDisabledValue, | pluginAUMainTypeValue, pluginRTASCategoryValue, pluginRTASBypassDisabledValue, pluginRTASMultiMonoDisabledValue, | ||||
| pluginAAXIdentifierValue, pluginAAXCategoryValue, pluginAAXBypassDisabledValue, pluginAAXMultiMonoDisabledValue; | pluginAAXIdentifierValue, pluginAAXCategoryValue, pluginAAXBypassDisabledValue, pluginAAXMultiMonoDisabledValue; | ||||
| //============================================================================== | |||||
| File tempDirectory = {}; | |||||
| bool openInIDEAfterSaving = false; | |||||
| void askUserWhereToSaveProject(); | |||||
| void moveTemporaryDirectory (const File&); | |||||
| //============================================================================== | |||||
| bool hasSentGUIBuilderAnalyticsEvent = false; | |||||
| //============================================================================== | //============================================================================== | ||||
| friend class Item; | friend class Item; | ||||
| ScopedPointer<EnabledModuleList> enabledModulesList; | ScopedPointer<EnabledModuleList> enabledModulesList; | ||||
| @@ -138,6 +138,32 @@ public: | |||||
| return Result::ok(); | return Result::ok(); | ||||
| } | } | ||||
| Result saveContentNeededForLiveBuild() | |||||
| { | |||||
| OwnedArray<LibraryModule> modules; | |||||
| project.getModules().createRequiredModules (modules); | |||||
| checkModuleValidity (modules); | |||||
| if (errors.size() == 0) | |||||
| { | |||||
| writeAppConfigFile (modules, loadUserContentFromAppConfig()); | |||||
| writeBinaryDataFiles(); | |||||
| writeAppHeader (modules); | |||||
| writeModuleCppWrappers (modules); | |||||
| if (project.getProjectType().isAudioPlugin()) | |||||
| { | |||||
| writePluginCharacteristicsFile(); | |||||
| writeAppConfigFile (modules, loadUserContentFromAppConfig()); | |||||
| } | |||||
| return Result::ok(); | |||||
| } | |||||
| return Result::fail (errors[0]); | |||||
| } | |||||
| Project::Item saveGeneratedFile (const String& filePath, const MemoryOutputStream& newData) | Project::Item saveGeneratedFile (const String& filePath, const MemoryOutputStream& newData) | ||||
| { | { | ||||
| if (! generatedCodeFolder.createDirectory()) | if (! generatedCodeFolder.createDirectory()) | ||||
| @@ -97,12 +97,6 @@ const uint8 graph[] = { 110,109,166,158,186,66,184,11,143,67,108,113,151,95,67,9 | |||||
| 36,62,67,57,208,166,67,183,75,46,67,100,188,174,67,183,75,46,67,68,107,184,67,108,183,75,46,67,119,233,224,67,98,183,75,46,67,87,152,234,67,13,36,62,67,130,132,242,67,205,129,81,67,130,132,242,67,108,25,63,145,67,130,132,242,67,98,249,237,154,67,130, | 36,62,67,57,208,166,67,183,75,46,67,100,188,174,67,183,75,46,67,68,107,184,67,108,183,75,46,67,119,233,224,67,98,183,75,46,67,87,152,234,67,13,36,62,67,130,132,242,67,205,129,81,67,130,132,242,67,108,25,63,145,67,130,132,242,67,98,249,237,154,67,130, | ||||
| 132,242,67,36,218,162,67,87,152,234,67,36,218,162,67,119,233,224,67,108,36,218,162,67,68,107,184,67,98,36,218,162,67,100,188,174,67,249,237,154,67,57,208,166,67,25,63,145,67,57,208,166,67,99,101,0,0 }; | 132,242,67,36,218,162,67,87,152,234,67,36,218,162,67,119,233,224,67,108,36,218,162,67,68,107,184,67,98,36,218,162,67,100,188,174,67,249,237,154,67,57,208,166,67,25,63,145,67,57,208,166,67,99,101,0,0 }; | ||||
| //const uint8 exporter[] = { 110,109,253,221,132,67,144,191,123,65,98,211,214,32,67,144,191,123,65,105,218,146,66,8,213,167,66,10,213,39,66,90,82,50,67,108,224,205,195,66,90,82,50,67,98,141,191,251,66,210,69,227,66,55,143,62,67,24,93,136,66,253,221,132,67,24,93,136,66,98,3,145,183, | |||||
| //67,24,93,136,66,183,198,223,67,130,89,22,67,183,198,223,67,0,0,122,67,98,183,198,223,67,5,179,175,67,59,177,182,67,185,232,215,67,253,221,132,67,185,232,215,67,98,55,143,62,67,185,232,215,67,142,191,251,66,138,46,193,67,224,205,195,66,211,214,160,67, | |||||
| //108,9,213,39,66,211,214,160,67,98,77,91,143,66,189,10,208,67,211,214,32,67,2,34,242,67,253,221,132,67,2,34,242,67,98,109,141,197,67,2,34,242,67,0,0,250,67,112,175,189,67,0,0,250,67,254,255,121,67,98,0,0,250,67,60,66,241,66,109,141,197,67,144,191,123, | |||||
| //65,253,221,132,67,144,191,123,65,99,109,196,78,64,67,211,214,160,67,108,69,23,159,67,254,255,121,67,108,195,78,64,67,88,82,50,67,108,195,78,64,67,13,136,90,67,108,0,0,0,0,13,136,90,67,108,0,0,0,0,191,155,141,67,108,196,78,64,67,191,155,141,67,108,196, | |||||
| //78,64,67,211,214,160,67,99,101,0,0 }; | |||||
| const uint8 jigsaw[] = { 110,109,244,9,155,65,198,29,87,67,98,244,9,155,65,198,29,87,67,43,107,174,66,227,15,248,66,97,208,255,66,78,89,17,67,98,202,154,40,67,140,186,36,67,99,79,240,66,200,156,71,67,44,234,30,67,230,13,89,67,98,168,172,69,67,2,127,106,67,96,208,127,67,166,45, | const uint8 jigsaw[] = { 110,109,244,9,155,65,198,29,87,67,98,244,9,155,65,198,29,87,67,43,107,174,66,227,15,248,66,97,208,255,66,78,89,17,67,98,202,154,40,67,140,186,36,67,99,79,240,66,200,156,71,67,44,234,30,67,230,13,89,67,98,168,172,69,67,2,127,106,67,96,208,127,67,166,45, | ||||
| 85,67,164,47,116,67,76,218,32,67,98,198,158,102,67,229,13,217,66,72,93,79,67,78,89,17,67,42,236,61,67,35,111,236,66,98,12,123,44,67,169,43,182,66,239,136,139,67,232,142,232,65,239,136,139,67,232,142,232,65,98,239,136,139,67,232,142,232,65,10,123,172, | 85,67,164,47,116,67,76,218,32,67,98,198,158,102,67,229,13,217,66,72,93,79,67,78,89,17,67,42,236,61,67,35,111,236,66,98,12,123,44,67,169,43,182,66,239,136,139,67,232,142,232,65,239,136,139,67,232,142,232,65,98,239,136,139,67,232,142,232,65,10,123,172, | ||||
| 67,44,234,30,67,154,51,181,67,225,15,248,66,98,89,212,192,67,173,170,166,66,151,53,212,67,110,202,34,66,228,142,232,67,103,77,209,66,98,228,142,232,67,103,77,209,66,0,0,250,67,172,41,23,67,4,127,234,67,234,138,42,67,98,6,254,218,67,40,236,61,67,55,101, | 67,44,234,30,67,154,51,181,67,225,15,248,66,98,89,212,192,67,173,170,166,66,151,53,212,67,110,202,34,66,228,142,232,67,103,77,209,66,98,228,142,232,67,103,77,209,66,0,0,250,67,172,41,23,67,4,127,234,67,234,138,42,67,98,6,254,218,67,40,236,61,67,55,101, | ||||
| @@ -146,8 +140,6 @@ const uint8 bug[] = { 110,109,169,227,237,67,143,189,46,67,108,94,183,187,67,17, | |||||
| 67,237,54,242,67,22,232,192,67,98,73,207,244,67,210,148,188,67,97,20,243,67,26,100,183,67,29,193,238,67,190,203,180,67,108,70,114,189,67,60,29,153,67,98,162,10,192,67,112,35,140,67,22,232,192,67,70,83,126,67,162,10,192,67,76,75,107,67,108,96,20,243,67, | 67,237,54,242,67,22,232,192,67,98,73,207,244,67,210,148,188,67,97,20,243,67,26,100,183,67,29,193,238,67,190,203,180,67,108,70,114,189,67,60,29,153,67,98,162,10,192,67,112,35,140,67,22,232,192,67,70,83,126,67,162,10,192,67,76,75,107,67,108,96,20,243,67, | ||||
| 202,156,79,67,98,164,103,247,67,226,225,77,67,0,0,250,67,114,128,67,67,140,34,249,67,234,217,58,67,98,166,103,247,67,96,51,50,67,237,54,242,67,168,2,45,67,169,227,237,67,143,189,46,67,99,101,0,0 }; | 202,156,79,67,98,164,103,247,67,226,225,77,67,0,0,250,67,114,128,67,67,140,34,249,67,234,217,58,67,98,166,103,247,67,96,51,50,67,237,54,242,67,168,2,45,67,169,227,237,67,143,189,46,67,99,101,0,0 }; | ||||
| //const uint8 play[] = { 110,109,84,227,213,64,188,116,205,65,108,43,135,194,65,0,0,120,65,108,84,227,213,64,14,45,170,64,108,84,227,213,64,188,116,205,65,99,101,0,0 }; | |||||
| const uint8 code[] = { 110,109,190,159,130,64,240,167,130,64,108,190,159,130,64,191,159,226,64,108,4,86,215,65,191,159,226,64,108,4,86,215,65,240,167,130,64,108,190,159,130,64,240,167,130,64,99,109,190,159,130,64,176,114,162,65,108,4,86,215,65,176,114,162,65,108,4,86,215,65, | const uint8 code[] = { 110,109,190,159,130,64,240,167,130,64,108,190,159,130,64,191,159,226,64,108,4,86,215,65,191,159,226,64,108,4,86,215,65,240,167,130,64,108,190,159,130,64,240,167,130,64,99,109,190,159,130,64,176,114,162,65,108,4,86,215,65,176,114,162,65,108,4,86,215,65, | ||||
| 188,116,138,65,108,190,159,130,64,188,116,138,65,108,190,159,130,64,176,114,162,65,99,109,190,159,130,64,160,26,91,65,108,4,86,215,65,160,26,91,65,108,4,86,215,65,184,30,43,65,108,190,159,130,64,184,30,43,65,108,190,159,130,64,160,26,91,65,99,109,190, | 188,116,138,65,108,190,159,130,64,188,116,138,65,108,190,159,130,64,176,114,162,65,99,109,190,159,130,64,160,26,91,65,108,4,86,215,65,160,26,91,65,108,4,86,215,65,184,30,43,65,108,190,159,130,64,184,30,43,65,108,190,159,130,64,160,26,91,65,99,109,190, | ||||
| 159,130,64,4,86,215,65,108,4,86,215,65,4,86,215,65,108,4,86,215,65,16,88,191,65,108,190,159,130,64,16,88,191,65,108,190,159,130,64,4,86,215,65,99,101,0,0 }; | 159,130,64,4,86,215,65,108,4,86,215,65,4,86,215,65,108,4,86,215,65,16,88,191,65,108,190,159,130,64,16,88,191,65,108,190,159,130,64,4,86,215,65,99,101,0,0 }; | ||||
| @@ -1038,26 +1030,6 @@ const uint8 settings[] = { 110,109,202,111,210,64,243,226,61,64,108,0,0,224,64,0 | |||||
| const uint8 singleModule[] = { 110,109,165,48,137,63,179,12,91,64,108,0,0,224,64,0,0,0,0,108,235,217,78,65,179,12,91,64,108,0,0,224,64,176,12,219,64,108,165,48,137,63,179,12,91,64,99,109,51,10,147,61,80,243,164,64,108,0,0,192,64,211,60,9,65,108,0,0,192,64,45,195,118,65,108,51,10,147, | const uint8 singleModule[] = { 110,109,165,48,137,63,179,12,91,64,108,0,0,224,64,0,0,0,0,108,235,217,78,65,179,12,91,64,108,0,0,224,64,176,12,219,64,108,165,48,137,63,179,12,91,64,99,109,51,10,147,61,80,243,164,64,108,0,0,192,64,211,60,9,65,108,0,0,192,64,45,195,118,65,108,51,10,147, | ||||
| 61,0,0,64,65,108,51,10,147,61,80,243,164,64,99,109,235,217,94,65,80,243,164,64,108,235,217,94,65,0,0,64,65,108,0,0,0,65,45,195,118,65,108,0,0,0,65,211,60,9,65,108,235,217,94,65,80,243,164,64,99,101,0,0 }; | 61,0,0,64,65,108,51,10,147,61,80,243,164,64,99,109,235,217,94,65,80,243,164,64,108,235,217,94,65,0,0,64,65,108,0,0,0,65,45,195,118,65,108,0,0,0,65,211,60,9,65,108,235,217,94,65,80,243,164,64,99,101,0,0 }; | ||||
| const uint8 buildNow[] = { 110,109,0,128,57,65,0,0,11,63,98,171,165,35,65,179,98,241,62,24,105,13,65,129,238,116,63,0,112,249,64,0,0,0,64,98,91,21,203,64,75,181,92,64,242,83,191,64,108,13,178,64,0,192,213,64,0,112,235,64,108,0,128,72,63,0,24,84,65,98,36,57,13,59,45,151,96,65,68, | |||||
| 51,13,59,211,216,116,65,0,128,72,63,0,172,128,65,98,102,57,200,63,150,235,134,65,78,35,53,64,150,235,134,65,0,32,103,64,0,172,128,65,108,0,24,24,65,0,0,35,65,98,59,204,52,65,87,61,46,65,246,166,86,65,10,81,40,65,0,216,109,65,0,32,17,65,98,196,117,128, | |||||
| 65,238,24,252,64,30,44,132,65,217,124,199,64,0,16,130,65,0,16,150,64,108,0,240,85,65,0,112,242,64,108,0,112,34,65,0,224,214,64,108,0,160,20,65,0,160,95,64,108,0,208,66,65,0,128,27,63,98,50,185,63,65,138,15,19,63,49,159,60,65,134,157,13,63,0,128,57,65, | |||||
| 0,0,11,63,99,101,0,0 }; | |||||
| const uint8 continuousBuildStart[] = { 110,109,0,16,55,65,0,128,53,63,98,76,48,50,65,24,205,49,63,88,83,45,65,191,4,50,63,0,128,40,65,0,0,54,63,98,192,47,221,64,7,199,101,63,113,249,100,64,108,248,76,64,0,192,16,64,0,48,218,64,108,0,224,76,64,0,48,229,64,98,19,172,152,64,120,86,54,64,157, | |||||
| 101,24,65,103,159,33,63,0,104,93,65,0,224,12,64,98,64,148,133,65,2,124,79,64,7,4,149,65,255,247,181,64,0,56,153,65,0,136,7,65,108,0,168,144,65,0,112,8,65,108,0,56,159,65,0,200,59,65,108,0,8,171,65,0,176,5,65,108,0,84,161,65,0,176,6,65,98,39,235,156,65, | |||||
| 182,193,167,64,118,99,139,65,136,68,28,64,0,232,98,65,0,128,161,63,98,134,113,84,65,142,198,110,63,28,175,69,65,184,152,64,63,0,16,55,65,0,128,53,63,99,109,0,152,8,65,0,96,195,64,98,29,15,4,65,249,102,195,64,0,0,0,65,166,157,202,64,0,0,0,65,0,16,215, | |||||
| 64,108,0,0,0,65,0,120,84,65,98,0,0,0,65,44,177,90,65,29,15,4,65,0,80,94,65,0,152,8,65,0,80,94,65,98,31,114,10,65,0,80,94,65,62,243,12,65,54,180,93,65,0,40,15,65,0,112,92,65,98,167,130,45,65,197,243,74,65,90,229,75,65,191,112,57,65,0,64,106,65,0,248,39, | |||||
| 65,98,72,217,113,65,117,149,35,65,80,241,113,65,139,106,28,65,0,88,106,65,0,8,24,65,98,113,239,75,65,65,143,6,65,153,136,45,65,118,24,234,64,0,32,15,65,0,32,199,64,98,61,235,12,65,147,151,196,64,31,114,10,65,0,96,195,64,0,152,8,65,0,96,195,64,99,109, | |||||
| 0,64,6,64,0,56,4,65,108,0,0,31,63,0,80,58,65,108,0,128,228,63,0,88,57,65,98,209,237,21,64,250,1,108,65,133,239,144,64,4,85,140,65,0,112,248,64,0,192,149,65,98,136,90,73,65,147,201,163,65,109,114,143,65,68,217,143,65,0,124,157,65,0,144,82,65,108,0,244, | |||||
| 149,65,0,24,77,65,98,251,100,137,65,49,13,137,65,98,186,70,65,5,203,154,65,0,184,1,65,0,60,142,65,98,142,44,168,64,25,238,133,65,64,34,85,64,173,230,100,65,0,32,51,64,0,128,56,65,108,0,192,122,64,0,144,55,65,108,0,64,6,64,0,56,4,65,99,101,0,0 }; | |||||
| const uint8 continuousBuildStop[] = { 110,109,0,16,55,65,0,128,53,63,98,76,48,50,65,24,205,49,63,88,83,45,65,191,4,50,63,0,128,40,65,0,0,54,63,98,192,47,221,64,7,199,101,63,113,249,100,64,108,248,76,64,0,192,16,64,0,48,218,64,108,0,224,76,64,0,48,229,64,98,19,172,152,64,120,86,54,64,157, | |||||
| 101,24,65,103,159,33,63,0,104,93,65,0,224,12,64,98,64,148,133,65,2,124,79,64,7,4,149,65,255,247,181,64,0,56,153,65,0,136,7,65,108,0,168,144,65,0,112,8,65,108,0,56,159,65,0,200,59,65,108,0,8,171,65,0,176,5,65,108,0,84,161,65,0,176,6,65,98,39,235,156,65, | |||||
| 182,193,167,64,118,99,139,65,136,68,28,64,0,232,98,65,0,128,161,63,98,134,113,84,65,142,198,110,63,28,175,69,65,184,152,64,63,0,16,55,65,0,128,53,63,99,109,0,0,0,65,0,0,224,64,108,0,0,0,65,0,0,80,65,108,0,0,96,65,0,0,80,65,108,0,0,96,65,0,0,224,64,108, | |||||
| 0,0,0,65,0,0,224,64,99,109,0,64,6,64,0,56,4,65,108,0,0,31,63,0,80,58,65,108,0,128,228,63,0,88,57,65,98,209,237,21,64,250,1,108,65,133,239,144,64,4,85,140,65,0,112,248,64,0,192,149,65,98,136,90,73,65,147,201,163,65,109,114,143,65,68,217,143,65,0,124,157, | |||||
| 65,0,144,82,65,108,0,244,149,65,0,24,77,65,98,251,100,137,65,49,13,137,65,98,186,70,65,5,203,154,65,0,184,1,65,0,60,142,65,98,142,44,168,64,25,238,133,65,64,34,85,64,173,230,100,65,0,32,51,64,0,128,56,65,108,0,192,122,64,0,144,55,65,108,0,64,6,64,0,56, | |||||
| 4,65,99,101,0,0 }; | |||||
| const uint8 edit[] = { 110,109,0,16,92,65,0,0,74,62,108,0,104,69,65,0,64,206,63,108,0,168,132,65,0,80,187,64,108,0,248,143,65,0,16,142,64,108,0,16,92,65,0,0,74,62,99,109,0,200,46,65,0,160,65,64,108,0,32,28,64,0,40,56,65,108,0,208,213,64,0,16,124,65,108,0,176,114,65,0,144,232, | const uint8 edit[] = { 110,109,0,16,92,65,0,0,74,62,108,0,104,69,65,0,64,206,63,108,0,168,132,65,0,80,187,64,108,0,248,143,65,0,16,142,64,108,0,16,92,65,0,0,74,62,99,109,0,200,46,65,0,160,65,64,108,0,32,28,64,0,40,56,65,108,0,208,213,64,0,16,124,65,108,0,176,114,65,0,144,232, | ||||
| 64,108,0,200,46,65,0,160,65,64,99,109,0,192,135,63,0,56,78,65,108,0,0,160,60,0,96,145,65,108,0,176,169,64,0,12,137,65,108,0,192,135,63,0,56,78,65,99,101,0,0 }; | 64,108,0,200,46,65,0,160,65,64,99,109,0,192,135,63,0,56,78,65,108,0,0,160,60,0,96,145,65,108,0,176,169,64,0,12,137,65,108,0,192,135,63,0,56,78,65,99,101,0,0 }; | ||||
| @@ -1588,17 +1560,14 @@ Icons::Icons() | |||||
| JUCE_LOAD_PATH_DATA (imageDoc) | JUCE_LOAD_PATH_DATA (imageDoc) | ||||
| JUCE_LOAD_PATH_DATA (config) | JUCE_LOAD_PATH_DATA (config) | ||||
| JUCE_LOAD_PATH_DATA (graph) | JUCE_LOAD_PATH_DATA (graph) | ||||
| // JUCE_LOAD_PATH_DATA (exporter) | |||||
| JUCE_LOAD_PATH_DATA (jigsaw) | JUCE_LOAD_PATH_DATA (jigsaw) | ||||
| JUCE_LOAD_PATH_DATA (info) | JUCE_LOAD_PATH_DATA (info) | ||||
| JUCE_LOAD_PATH_DATA (warning) | JUCE_LOAD_PATH_DATA (warning) | ||||
| JUCE_LOAD_PATH_DATA (bug) | JUCE_LOAD_PATH_DATA (bug) | ||||
| // JUCE_LOAD_PATH_DATA (play) | |||||
| JUCE_LOAD_PATH_DATA (code) | JUCE_LOAD_PATH_DATA (code) | ||||
| JUCE_LOAD_PATH_DATA (box) | JUCE_LOAD_PATH_DATA (box) | ||||
| JUCE_LOAD_PATH_DATA (juceLogo) | JUCE_LOAD_PATH_DATA (juceLogo) | ||||
| JUCE_LOAD_PATH_DATA (mainJuceLogo) | JUCE_LOAD_PATH_DATA (mainJuceLogo) | ||||
| JUCE_LOAD_PATH_DATA (user) | JUCE_LOAD_PATH_DATA (user) | ||||
| JUCE_LOAD_PATH_DATA (closedFolder) | JUCE_LOAD_PATH_DATA (closedFolder) | ||||
| JUCE_LOAD_PATH_DATA (exporter) | JUCE_LOAD_PATH_DATA (exporter) | ||||
| @@ -1610,9 +1579,6 @@ Icons::Icons() | |||||
| JUCE_LOAD_PATH_DATA (play) | JUCE_LOAD_PATH_DATA (play) | ||||
| JUCE_LOAD_PATH_DATA (settings) | JUCE_LOAD_PATH_DATA (settings) | ||||
| JUCE_LOAD_PATH_DATA (singleModule) | JUCE_LOAD_PATH_DATA (singleModule) | ||||
| JUCE_LOAD_PATH_DATA (buildNow) | |||||
| JUCE_LOAD_PATH_DATA (continuousBuildStart) | |||||
| JUCE_LOAD_PATH_DATA (continuousBuildStop) | |||||
| JUCE_LOAD_PATH_DATA (edit) | JUCE_LOAD_PATH_DATA (edit) | ||||
| JUCE_LOAD_PATH_DATA (plus); | JUCE_LOAD_PATH_DATA (plus); | ||||
| JUCE_LOAD_PATH_DATA (android); | JUCE_LOAD_PATH_DATA (android); | ||||
| @@ -72,16 +72,10 @@ class Icons | |||||
| public: | public: | ||||
| Icons(); | Icons(); | ||||
| Path folder, document, imageDoc, | |||||
| config, /*exporter,*/ juceLogo, | |||||
| graph, jigsaw, info, warning, | |||||
| bug, /*play,*/ code, box, | |||||
| mainJuceLogo; | |||||
| Path user, closedFolder, exporter, fileExplorer, file, | |||||
| buildTab, modules, openFolder, play, settings, singleModule, | |||||
| buildNow, continuousBuildStart, continuousBuildStop, edit, plus, | |||||
| android, codeBlocks, linux, xcode, visualStudio, clion; | |||||
| Path folder, document, imageDoc, config, juceLogo, graph, jigsaw, info, warning, bug, | |||||
| code, box, mainJuceLogo, user, closedFolder, exporter, fileExplorer, file, buildTab, | |||||
| modules, openFolder, play, settings, singleModule, edit, plus, android, codeBlocks, | |||||
| linux, xcode, visualStudio, clion; | |||||
| private: | private: | ||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Icons) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Icons) | ||||
| @@ -26,6 +26,8 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "../../Licenses/jucer_LicenseController.h" | |||||
| #include "../../Application/jucer_Application.h" | |||||
| //============================================================================== | //============================================================================== | ||||
| class UserSettingsPopup : public Component | class UserSettingsPopup : public Component | ||||
| @@ -158,13 +158,15 @@ public: | |||||
| // Handle Open Project button functionality | // Handle Open Project button functionality | ||||
| ApplicationCommandManager& commandManager = ProjucerApplication::getCommandManager(); | ApplicationCommandManager& commandManager = ProjucerApplication::getCommandManager(); | ||||
| addAndMakeVisible (blankProjectButton = new TemplateOptionButton ("Create Blank Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg)); | |||||
| addAndMakeVisible (exampleProjectButton = new TemplateOptionButton ("Open Example Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg)); | |||||
| addAndMakeVisible (openProjectButton = new TemplateOptionButton ("Open Existing Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg)); | |||||
| addAndMakeVisible (blankProjectButton); | |||||
| addAndMakeVisible (openProjectButton); | |||||
| addAndMakeVisible (browseDemosButton); | |||||
| addAndMakeVisible (viewTutorialsButton); | |||||
| blankProjectButton->onClick = [this] { createBlankProject(); }; | |||||
| exampleProjectButton->onClick = [this] { openExampleProject(); }; | |||||
| openProjectButton->setCommandToTrigger (&commandManager, CommandIDs::open, true); | |||||
| blankProjectButton.onClick = [this] { createBlankProject(); }; | |||||
| openProjectButton.setCommandToTrigger (&commandManager, CommandIDs::open, true); | |||||
| browseDemosButton.setCommandToTrigger (&commandManager, CommandIDs::launchDemoRunner, true); | |||||
| viewTutorialsButton.setCommandToTrigger (&commandManager, CommandIDs::showTutorials, true); | |||||
| newProjectWizard = projectWizard; | newProjectWizard = projectWizard; | ||||
| } | } | ||||
| @@ -185,35 +187,41 @@ public: | |||||
| for (int i = 0; i < optionButtons.size(); ++i) | for (int i = 0; i < optionButtons.size(); ++i) | ||||
| if (optionButtons.getUnchecked(i)->isOver()) | if (optionButtons.getUnchecked(i)->isOver()) | ||||
| g.drawFittedText (optionButtons.getUnchecked(i)->getDescription(), descriptionBox, Justification::centred, 5, 1.0f); | |||||
| g.drawFittedText (optionButtons.getUnchecked(i)->getDescription(), descriptionBox, Justification::centredBottom, 5, 1.0f); | |||||
| } | } | ||||
| void resized() override | void resized() override | ||||
| { | { | ||||
| auto allOpts = getLocalBounds().reduced (40, 60); | |||||
| allOpts.removeFromBottom (allOpts.getHeight() / 4); | |||||
| auto bounds = getLocalBounds().reduced (40, 0); | |||||
| bounds.removeFromTop (60); | |||||
| const auto numHorizIcons = 4; | |||||
| const auto optStep = allOpts.getWidth() / numHorizIcons; | |||||
| for (int i = 0; i < optionButtons.size(); ++i) | |||||
| { | { | ||||
| const auto yShift = i < numHorizIcons ? 0 : 1; | |||||
| auto optionBounds = bounds.removeFromTop (roundToInt (bounds.getHeight() * 0.65f)); | |||||
| auto topSlice = optionBounds.removeFromTop (optionBounds.getHeight() / 2).reduced (0, 10); | |||||
| auto bottomSlice = optionBounds.reduced (0, 10); | |||||
| const int numHorizontal = 4; | |||||
| for (int i = 0; i < optionButtons.size(); ++i) | |||||
| { | |||||
| auto& sliceToUse = (i < numHorizontal ? topSlice : bottomSlice); | |||||
| optionButtons.getUnchecked(i)->setBounds (Rectangle<int> (allOpts.getX() + (i % numHorizIcons) * optStep, | |||||
| allOpts.getY() + yShift * allOpts.getHeight() / 2, | |||||
| optStep, allOpts.getHeight() / 2) | |||||
| .reduced (10, 10)); | |||||
| optionButtons.getUnchecked (i)->setBounds (sliceToUse.removeFromLeft (sliceToUse.getWidth() / (4 - (i % 4))).reduced (10, 0)); | |||||
| } | |||||
| } | } | ||||
| auto openButtonBounds = getLocalBounds(); | |||||
| openButtonBounds.removeFromBottom (proportionOfHeight (0.12f)); | |||||
| openButtonBounds = openButtonBounds.removeFromBottom (120); | |||||
| openButtonBounds.reduce (50, 40); | |||||
| bounds.removeFromTop (20); | |||||
| auto topButtonBounds = bounds.removeFromTop (50); | |||||
| openProjectButton.setBounds (topButtonBounds.reduced (80, 0)); | |||||
| bounds.removeFromTop (10); | |||||
| auto bottomButtonBounds = bounds.removeFromTop (35); | |||||
| blankProjectButton->setBounds (openButtonBounds.removeFromLeft (optStep - 20)); | |||||
| exampleProjectButton->setBounds (openButtonBounds.removeFromRight (optStep - 20)); | |||||
| openProjectButton->setBounds (openButtonBounds.reduced (18, 0)); | |||||
| blankProjectButton.setBounds (bottomButtonBounds.removeFromLeft (bottomButtonBounds.getWidth() / 3).reduced (10, 0)); | |||||
| browseDemosButton.setBounds (bottomButtonBounds.removeFromLeft (bottomButtonBounds.getWidth() / 2).reduced (10, 0)); | |||||
| viewTutorialsButton.setBounds (bottomButtonBounds.removeFromLeft (bottomButtonBounds.getWidth()).reduced (10, 0)); | |||||
| } | } | ||||
| void showWizard (const String& name) | void showWizard (const String& name) | ||||
| @@ -231,36 +239,14 @@ public: | |||||
| showWizard (BlankAppWizard().getName()); | showWizard (BlankAppWizard().getName()); | ||||
| } | } | ||||
| void openExampleProject() | |||||
| { | |||||
| FileChooser fc ("Open File", findExamplesFolder()); | |||||
| if (fc.browseForFileToOpen()) | |||||
| ProjucerApplication::getApp().openFile (fc.getResult()); | |||||
| } | |||||
| static File findExamplesFolder() | |||||
| { | |||||
| File appFolder (File::getSpecialLocation (File::currentApplicationFile)); | |||||
| while (appFolder.exists() | |||||
| && appFolder.getParentDirectory() != appFolder) | |||||
| { | |||||
| File examples (appFolder.getSiblingFile ("examples")); | |||||
| if (examples.exists()) | |||||
| return examples; | |||||
| appFolder = appFolder.getParentDirectory(); | |||||
| } | |||||
| return {}; | |||||
| } | |||||
| private: | private: | ||||
| OwnedArray<TemplateOptionButton> optionButtons; | OwnedArray<TemplateOptionButton> optionButtons; | ||||
| NewProjectWizardClasses::WizardComp* newProjectWizard; | NewProjectWizardClasses::WizardComp* newProjectWizard; | ||||
| ScopedPointer<TemplateOptionButton> blankProjectButton, openProjectButton, exampleProjectButton; | |||||
| TemplateOptionButton blankProjectButton { "Create Blank Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg }, | |||||
| openProjectButton { "Open Existing Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg }, | |||||
| browseDemosButton { "Browse JUCE Demos", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg }, | |||||
| viewTutorialsButton { "View JUCE Tutorials", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg }; | |||||
| void showWizardButton (Button* b) | void showWizardButton (Button* b) | ||||
| { | { | ||||