Browse Source

Projucer: Implement PIPGenerator

tags/2021-05-28
ed 7 years ago
parent
commit
47af78fe0b
31 changed files with 1249 additions and 450 deletions
  1. +6
    -0
      extras/Projucer/Builds/LinuxMakefile/Makefile
  2. +4
    -0
      extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj
  3. +1
    -0
      extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj
  4. +3
    -0
      extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters
  5. +1
    -0
      extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj
  6. +3
    -0
      extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters
  7. +1
    -0
      extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj
  8. +3
    -0
      extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters
  9. +2
    -0
      extras/Projucer/Projucer.jucer
  10. +56
    -48
      extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h
  11. +316
    -10
      extras/Projucer/Source/Application/jucer_Application.cpp
  12. +21
    -0
      extras/Projucer/Source/Application/jucer_Application.h
  13. +7
    -4
      extras/Projucer/Source/Application/jucer_CommandIDs.h
  14. +31
    -3
      extras/Projucer/Source/Application/jucer_CommandLine.cpp
  15. +1
    -1
      extras/Projucer/Source/Application/jucer_Main.cpp
  16. +199
    -11
      extras/Projucer/Source/Application/jucer_MainWindow.cpp
  17. +8
    -2
      extras/Projucer/Source/Application/jucer_MainWindow.h
  18. +5
    -0
      extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp
  19. +1
    -0
      extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.h
  20. +2
    -2
      extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h
  21. +372
    -0
      extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp
  22. +50
    -260
      extras/Projucer/Source/Project/UI/jucer_HeaderComponent.h
  23. +12
    -10
      extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp
  24. +1
    -1
      extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h
  25. +53
    -1
      extras/Projucer/Source/Project/jucer_Project.cpp
  26. +20
    -1
      extras/Projucer/Source/Project/jucer_Project.h
  27. +26
    -0
      extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h
  28. +0
    -34
      extras/Projucer/Source/Utility/UI/jucer_Icons.cpp
  29. +4
    -10
      extras/Projucer/Source/Utility/UI/jucer_Icons.h
  30. +2
    -0
      extras/Projucer/Source/Utility/UI/jucer_UserSettingsPopup.h
  31. +38
    -52
      extras/Projucer/Source/Wizards/jucer_TemplateThumbnailsComponent.h

+ 6
- 0
extras/Projucer/Builds/LinuxMakefile/Makefile View File

@@ -101,6 +101,7 @@ OBJECTS_APP := \
$(JUCE_OBJDIR)/jucer_CompileEngineClient_aee8c99c.o \
$(JUCE_OBJDIR)/jucer_CompileEngineServer_5d8914.o \
$(JUCE_OBJDIR)/jucer_DownloadCompileEngineThread_19bb4bb3.o \
$(JUCE_OBJDIR)/jucer_HeaderComponent_1ebf72ba.o \
$(JUCE_OBJDIR)/jucer_Module_3f7666a5.o \
$(JUCE_OBJDIR)/jucer_Project_c131864a.o \
$(JUCE_OBJDIR)/jucer_ProjectExporter_cf377b25.o \
@@ -304,6 +305,11 @@ $(JUCE_OBJDIR)/jucer_DownloadCompileEngineThread_19bb4bb3.o: ../../Source/LiveBu
@echo "Compiling jucer_DownloadCompileEngineThread.cpp"
$(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
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
@echo "Compiling jucer_Module.cpp"


+ 4
- 0
extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj View File

@@ -57,6 +57,7 @@
D25EBE02B55DB244BE0D5635 = {isa = PBXBuildFile; fileRef = DE3E6B2614229FAD56D50770; };
85E7FCB0516EFF853FA7B380 = {isa = PBXBuildFile; fileRef = D2FE76E4CF003856278343CC; };
CC6C4D351BA9B473E5F95791 = {isa = PBXBuildFile; fileRef = ADA538034910F52FDD2DC88D; };
05A08E366EBF8D650974E695 = {isa = PBXBuildFile; fileRef = 516D6D7C564DD5DF5C15CB06; };
3FCA61C401007B243E2E9035 = {isa = PBXBuildFile; fileRef = F797071D88542C813CF7222A; };
30B921C38DCEE787B294B746 = {isa = PBXBuildFile; fileRef = BAC43B20E14A340CCF14119C; };
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"; };
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"; };
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"; };
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"; };
@@ -633,6 +635,7 @@
236D186F5A6536C59D6E751C,
32ECBC08D903418CA0825870,
A509BC22854D50E4C786EB32,
516D6D7C564DD5DF5C15CB06,
16751E04B0F3737BDF52CEB4,
B3528C08B84CBC950252EA69,
1B0F18E1D96F727C062B05FA,
@@ -964,6 +967,7 @@
D25EBE02B55DB244BE0D5635,
85E7FCB0516EFF853FA7B380,
CC6C4D351BA9B473E5F95791,
05A08E366EBF8D650974E695,
3FCA61C401007B243E2E9035,
30B921C38DCEE787B294B746,
244567D3AE2E417A8CB2B95E,


+ 1
- 0
extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj View File

@@ -226,6 +226,7 @@
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/>
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/>
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/>
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"/>
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>


+ 3
- 0
extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters View File

@@ -442,6 +442,9 @@
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp">
<Filter>Projucer\LiveBuildEngine</Filter>
</ClCompile>
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp">
<Filter>Projucer\Project\UI</Filter>
</ClCompile>
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
<Filter>Projucer\Project\UI</Filter>
</ClCompile>


+ 1
- 0
extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj View File

@@ -226,6 +226,7 @@
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/>
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/>
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/>
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"/>
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>


+ 3
- 0
extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters View File

@@ -442,6 +442,9 @@
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp">
<Filter>Projucer\LiveBuildEngine</Filter>
</ClCompile>
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp">
<Filter>Projucer\Project\UI</Filter>
</ClCompile>
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
<Filter>Projucer\Project\UI</Filter>
</ClCompile>


+ 1
- 0
extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj View File

@@ -226,6 +226,7 @@
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineClient.cpp"/>
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_CompileEngineServer.cpp"/>
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp"/>
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp"/>
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>


+ 3
- 0
extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters View File

@@ -442,6 +442,9 @@
<ClCompile Include="..\..\Source\LiveBuildEngine\jucer_DownloadCompileEngineThread.cpp">
<Filter>Projucer\LiveBuildEngine</Filter>
</ClCompile>
<ClCompile Include="..\..\Source\Project\UI\jucer_HeaderComponent.cpp">
<Filter>Projucer\Project\UI</Filter>
</ClCompile>
<ClCompile Include="..\..\Source\Project\UI\jucer_ProjectContentComponent.cpp">
<Filter>Projucer\Project\UI</Filter>
</ClCompile>


+ 2
- 0
extras/Projucer/Projucer.jucer View File

@@ -542,6 +542,8 @@
resource="0" file="Source/Project/UI/jucer_ContentViewComponents.h"/>
<FILE id="wFypDd" name="jucer_FileGroupInformationComponent.h" compile="0"
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="Source/Project/UI/jucer_HeaderComponent.h"/>
<FILE id="dN0Xzo" name="jucer_ModulesInformationComponent.h" compile="0"


extras/Projucer/Source/Application/Windows/jucer_GlobalSearchPathsWindowComponent.h → extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h View File

@@ -28,25 +28,12 @@
//==============================================================================
class GlobalSearchPathsWindowComponent : public Component
class GlobalPathsWindowComponent : public Component
{
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);
info.setInfoToDisplay ("Use this dropdown to set the global paths for different OSes. "
@@ -59,7 +46,11 @@ public:
osSelector.addItem ("Windows", 2);
osSelector.addItem ("Linux", 3);
osSelector.onChange = [this] { updateFilePathPropertyComponents(); };
osSelector.onChange = [this]
{
addLabelsAndSetProperties();
updateFilePathPropertyComponents();
};
auto os = TargetOS::getThisOS();
@@ -85,40 +76,33 @@ public:
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);
sdksLabel.setBounds (b.removeFromTop (20));
pathPropertyLabels.getUnchecked (labelIndex++)->setBounds (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:
Label modulesLabel, sdksLabel, cLionLabel;
OwnedArray<Label> pathPropertyLabels;
OwnedArray<PropertyComponent> pathPropertyComponents;
ComboBox osSelector;
InfoButton info;
//==============================================================================
bool isSelectedOSThisOS() { return TargetOS::getThisOS() == getSelectedOS(); }
TargetOS::OS getSelectedOS() const
{
auto selectedOS = TargetOS::unknown;
@@ -138,27 +122,28 @@ private:
{
pathPropertyComponents.clear();
const auto thisOS = TargetOS::getThisOS();
const auto selectedOS = getSelectedOS();
auto& settings = getAppSettings();
if (selectedOS == thisOS)
if (isSelectedOSThisOS())
{
pathPropertyComponents.add (nullptr);
addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::defaultJuceModulePath),
"JUCE Modules", true)));
addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::defaultUserModulePath),
"User Modules", true, {}, {}, true)));
pathPropertyComponents.add (nullptr);
addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::vst3Path),
"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);
addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (Value(), "AAX SDK", true)));
addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent ({}, "AAX SDK", true)));
pathPropertyComponents.getLast()->setEnabled (false);
}
else
@@ -174,6 +159,8 @@ private:
addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::androidNDKPath),
"Android NDK", true)));
pathPropertyComponents.add (nullptr);
#if JUCE_MAC
String exeLabel ("app");
#elif JUCE_WINDOWS
@@ -186,13 +173,18 @@ private:
}
else
{
auto selectedOS = getSelectedOS();
auto maxChars = 1024;
pathPropertyComponents.add (nullptr);
addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::defaultJuceModulePath, selectedOS),
"JUCE Modules", maxChars, false)));
addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::defaultUserModulePath, selectedOS),
"User Modules", maxChars, false)));
pathPropertyComponents.add (nullptr);
addAndMakeVisible (pathPropertyComponents.add (new TextPropertyComponent (settings.getFallbackPathForOS (Ids::vst3Path, selectedOS),
"VST3 SDK", maxChars, false)));
@@ -207,19 +199,35 @@ private:
else
{
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),
"AAX SDK", maxChars, false)));
"AAX SDK", maxChars, false)));
}
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),
"Android NDK", maxChars, false)));
"Android NDK", maxChars, false)));
}
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)
};

+ 316
- 10
extras/Projucer/Source/Application/jucer_Application.cpp View File

@@ -224,6 +224,10 @@ void ProjucerApplication::shutdown()
LookAndFeel::setDefaultLookAndFeel (nullptr);
// clean up after ourselves and delete any temp project files that may have
// been created from PIPs
deleteTemporaryFiles();
if (! isRunningCommandLine)
Logger::writeToLog ("Shutdown");
@@ -332,7 +336,8 @@ enum
openWindowsBaseID = 300,
activeDocumentsBaseID = 400,
colourSchemeBaseID = 1000,
codeEditorColourSchemeBaseID = 2000,
codeEditorColourSchemeBaseID = 1500,
examplesBaseID = 2000,
};
MenuBarModel* ProjucerApplication::getMenuModel()
@@ -362,6 +367,7 @@ void ProjucerApplication::createMenu (PopupMenu& menu, const String& menuName)
void ProjucerApplication::createFileMenu (PopupMenu& menu)
{
menu.addCommandItem (commandManager, CommandIDs::newProject);
menu.addCommandItem (commandManager, CommandIDs::newProjectFromClipboard);
menu.addSeparator();
menu.addCommandItem (commandManager, CommandIDs::open);
@@ -379,6 +385,13 @@ void ProjucerApplication::createFileMenu (PopupMenu& menu)
menu.addSubMenu ("Open Recent", recentFiles);
}
{
PopupMenu examples;
createExamplesPopupMenu (examples);
menu.addSubMenu ("Open Example", examples);
}
menu.addSeparator();
menu.addCommandItem (commandManager, CommandIDs::closeDocument);
menu.addCommandItem (commandManager, CommandIDs::saveDocument);
@@ -554,6 +567,244 @@ void ProjucerApplication::createExtraAppleMenuItems (PopupMenu& menu)
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)
{
if (menuItemID >= recentProjectsBaseID && menuItemID < (recentProjectsBaseID + 100))
@@ -586,6 +837,10 @@ void ProjucerApplication::handleMainMenuCommand (int menuItemID)
{
showEditorColourSchemeWindow();
}
else if (menuItemID >= examplesBaseID && menuItemID < (examplesBaseID + numExamples))
{
findAndLaunchExample (menuItemID - examplesBaseID);
}
else
{
handleGUIEditorMenuCommand (menuItemID);
@@ -598,7 +853,9 @@ void ProjucerApplication::getAllCommands (Array <CommandID>& commands)
JUCEApplication::getAllCommands (commands);
const CommandID ids[] = { CommandIDs::newProject,
CommandIDs::newProjectFromClipboard,
CommandIDs::open,
CommandIDs::launchDemoRunner,
CommandIDs::closeAllWindows,
CommandIDs::closeAllDocuments,
CommandIDs::clearRecentFiles,
@@ -622,18 +879,38 @@ void ProjucerApplication::getCommandInfo (CommandID commandID, ApplicationComman
switch (commandID)
{
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));
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:
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));
break;
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);
break;
@@ -719,7 +996,9 @@ bool ProjucerApplication::perform (const InvocationInfo& info)
switch (info.commandID)
{
case CommandIDs::newProject: createNewProject(); break;
case CommandIDs::newProjectFromClipboard: createNewProjectFromClipboard(); break;
case CommandIDs::open: askUserToOpenFile(); break;
case CommandIDs::launchDemoRunner: launchDemoRunner(); break;
case CommandIDs::saveAll: openDocumentManager.saveAll(); break;
case CommandIDs::closeAllWindows: closeAllMainWindowsAndQuitIfNeeded(); break;
case CommandIDs::closeAllDocuments: closeAllDocuments (true); break;
@@ -743,11 +1022,30 @@ bool ProjucerApplication::perform (const InvocationInfo& info)
//==============================================================================
void ProjucerApplication::createNewProject()
{
MainWindow* mw = mainWindowList.getOrCreateEmptyWindow();
mw->showNewProjectWizard();
auto* mw = mainWindowList.getOrCreateEmptyWindow();
mw->showStartPage();
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)
{
LiveBuildProjectSettings::updateNewlyOpenedProject (p);
@@ -850,10 +1148,10 @@ void ProjucerApplication::showPathsWindow()
if (pathsWindow != nullptr)
pathsWindow->toFront (true);
else
new FloatingToolWindow ("Global Search Paths",
new FloatingToolWindow ("Global Paths",
"pathsWindowPos",
new GlobalSearchPathsWindowComponent(), pathsWindow, false,
600, 500, 600, 500, 600, 500);
new GlobalPathsWindowComponent(), pathsWindow, false,
600, 550, 600, 550, 600, 550);
}
void ProjucerApplication::showEditorColourSchemeWindow()
@@ -980,6 +1278,14 @@ void ProjucerApplication::initCommandManager()
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)
{
auto& appearanceSettings = getAppSettings().appearance;


+ 21
- 0
extras/Projucer/Source/Application/jucer_Application.h View File

@@ -88,6 +88,7 @@ public:
//==============================================================================
void createNewProject();
void createNewProjectFromClipboard();
void updateNewlyOpenedProject (Project&);
void askUserToOpenFile();
bool openFile (const File&);
@@ -166,6 +167,26 @@ private:
void handleAsyncUpdate() override;
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);


+ 7
- 4
extras/Projucer/Source/Application/jucer_CommandIDs.h View File

@@ -34,10 +34,13 @@ namespace CommandIDs
enum
{
newProject = 0x300000,
open = 0x300001,
closeDocument = 0x300002,
saveDocument = 0x300003,
saveDocumentAs = 0x300004,
newProjectFromClipboard = 0x300001,
open = 0x300002,
closeDocument = 0x300003,
saveDocument = 0x300004,
saveDocumentAs = 0x300005,
launchDemoRunner = 0x300006,
closeProject = 0x300010,
saveProject = 0x300011,


+ 31
- 3
extras/Projucer/Source/Application/jucer_CommandLine.cpp View File

@@ -27,6 +27,7 @@
#include "jucer_Headers.h"
#include "../Project/jucer_Module.h"
#include "../Utility/Helpers/jucer_TranslationHelpers.h"
#include "../Utility/PIPs/jucer_PIPGenerator.h"
#include "jucer_CommandLine.h"
@@ -34,8 +35,6 @@
//==============================================================================
namespace
{
static const char* getLineEnding() { return "\r\n"; }
struct CommandLineError
{
CommandLineError (const String& s) : message (s) {}
@@ -749,6 +748,31 @@ namespace
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()
{
@@ -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
<< 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
<< 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;
}
}
@@ -849,6 +876,7 @@ int performCommandLine (const String& commandLine)
if (matchArgument (command, "trans")) { scanFoldersForTranslationFiles (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, "create-project-from-pip")) { createProjectFromPIP (args); return 0; }
}
catch (const CommandLineError& error)
{


+ 1
- 1
extras/Projucer/Source/Application/jucer_Main.cpp View File

@@ -36,7 +36,7 @@
#include "Windows/jucer_AboutWindowComponent.h"
#include "Windows/jucer_ApplicationUsageDataWindowComponent.h"
#include "Windows/jucer_EditorColourSchemeWindowComponent.h"
#include "Windows/jucer_GlobalSearchPathsWindowComponent.h"
#include "Windows/jucer_GlobalPathsWindowComponent.h"
#include "Windows/jucer_FloatingToolWindow.h"
#include "../LiveBuildEngine/jucer_MessageIDs.h"


+ 199
- 11
extras/Projucer/Source/Application/jucer_MainWindow.cpp View File

@@ -29,7 +29,7 @@
#include "jucer_MainWindow.h"
#include "../Wizards/jucer_NewProjectWizardClasses.h"
#include "../Utility/UI/jucer_JucerTreeViewBase.h"
#include "../ProjectSaving/jucer_ProjectSaver.h"
//==============================================================================
MainWindow::MainWindow()
@@ -140,7 +140,7 @@ void MainWindow::closeButtonPressed()
ProjucerApplication::getApp().mainWindowList.closeWindow (this);
}
bool MainWindow::closeProject (Project* project)
bool MainWindow::closeProject (Project* project, bool askUserToSave)
{
jassert (project == currentProject && project != nullptr);
@@ -156,12 +156,10 @@ bool MainWindow::closeProject (Project* project)
pcc->hideEditor();
}
if (! ProjucerApplication::getApp().openDocumentManager.closeAllDocumentsUsingProject (*project, true))
if (! ProjucerApplication::getApp().openDocumentManager.closeAllDocumentsUsingProject (*project, askUserToSave))
return false;
auto r = project->saveIfNeededAndUserAgrees();
if (r == FileBasedDocument::savedOk)
if (! askUserToSave || (project->saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk))
{
setProject (nullptr);
return true;
@@ -175,6 +173,21 @@ bool MainWindow::closeCurrentProject()
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)
{
createProjectContentCompIfNeeded();
@@ -186,6 +199,12 @@ void MainWindow::setProject (Project* newProject)
else
projectNameValue.referTo (Value());
if (newProject != nullptr)
{
if (auto* peer = getPeer())
peer->setRepresentedFile (newProject->getFile());
}
ProjucerApplication::getCommandManager().commandStatusChanged();
}
@@ -241,6 +260,142 @@ bool MainWindow::openFile (const File& file)
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)
{
for (auto& filename : filenames)
@@ -256,7 +411,10 @@ void MainWindow::filesDropped (const StringArray& filenames, int /*mouseX*/, int
{
const File f (filename);
if (canOpenFile (f) && openFile (f))
if (tryToOpenPIP (f))
continue;
if (! isPIPFile (f) && (canOpenFile (f) && openFile (f)))
break;
}
}
@@ -326,9 +484,15 @@ void MainWindow::activeWindowStatusChanged()
{
if (auto* project = getProject())
{
auto oldTemporaryDirectory = project->getTemporaryDirectory();
auto projectFile = project->getFile();
setProject (nullptr);
openFile (projectFile);
if (oldTemporaryDirectory != File())
if (auto* newProject = getProject())
newProject->setTemporaryDirectory (oldTemporaryDirectory);
}
}
else
@@ -340,13 +504,16 @@ void MainWindow::activeWindowStatusChanged()
}
}
void MainWindow::showNewProjectWizard()
void MainWindow::showStartPage()
{
jassert (currentProject == nullptr);
setContentOwned (createNewProjectWizardComponent(), true);
centreWithSize (900, 630);
setVisible (true);
addToDesktop();
getContentComponent()->grabKeyboardFocus();
}
@@ -453,7 +620,7 @@ bool MainWindowList::askAllWindowsToClose()
void MainWindowList::createWindowIfNoneAreOpen()
{
if (windows.size() == 0)
createNewMainWindow()->showNewProjectWizard();
createNewMainWindow()->showStartPage();
}
void MainWindowList::closeWindow (MainWindow* w)
@@ -542,7 +709,10 @@ bool MainWindowList::openFile (const File& file, bool openInBackground)
return ok;
}
if (file.exists())
if (getFrontmostWindow()->tryToOpenPIP (file))
return true;
if (! isPIPFile (file) && file.exists())
return getFrontmostWindow()->openFile (file);
return false;
@@ -599,6 +769,23 @@ MainWindow* MainWindowList::getOrCreateEmptyWindow()
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)
{
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* p = mw->getProject())
projects.add (p->getFile());
if (! p->isTemporaryProject())
projects.add (p->getFile());
}
getAppSettings().setLastProjects (projects);


+ 8
- 2
extras/Projucer/Source/Application/jucer_MainWindow.h View File

@@ -27,6 +27,7 @@
#pragma once
#include "../Project/UI/jucer_ProjectContentComponent.h"
#include "../Utility/PIPs/jucer_PIPGenerator.h"
//==============================================================================
/**
@@ -51,13 +52,15 @@ public:
bool openFile (const File& file);
void setProject (Project* newProject);
Project* getProject() const { return currentProject.get(); }
bool tryToOpenPIP (const File& f);
void makeVisible();
void restoreWindowPosition();
bool closeProject (Project* project);
bool closeProject (Project* project, bool askToSave = true);
bool closeCurrentProject();
void moveProject (File newProjectFile);
void showNewProjectWizard();
void showStartPage();
bool isInterestedInFileDrag (const StringArray& files) override;
void filesDropped (const StringArray& filenames, int mouseX, int mouseY) override;
@@ -82,6 +85,8 @@ private:
void createProjectContentCompIfNeeded();
void setTitleBarIcon();
void openPIP (PIPGenerator&, StringRef fileName);
void valueChanged (Value&) override;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
@@ -106,6 +111,7 @@ public:
MainWindow* createNewMainWindow();
MainWindow* getFrontmostWindow (bool createIfNotFound = true);
MainWindow* getOrCreateEmptyWindow();
MainWindow* getMainWindowForFile (const File&);
Project* getFrontmostProject();


+ 5
- 0
extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.cpp View File

@@ -684,6 +684,11 @@ void CompileEngineChildProcess::handleAppQuit()
runningAppProcess.reset();
}
bool CompileEngineChildProcess::isAppRunning() const noexcept
{
return runningAppProcess != nullptr && runningAppProcess->isRunningApp;
}
//==============================================================================
struct CompileEngineChildProcess::Editor : private CodeDocument::Listener,
private Timer


+ 1
- 0
extras/Projucer/Source/LiveBuildEngine/jucer_CompileEngineClient.h View File

@@ -52,6 +52,7 @@ public:
void launchApp();
bool canKillApp() const;
void killApp();
bool isAppRunning() const noexcept;
const ClassDatabase::ClassList& getComponentList() const { return lastComponentList; }


+ 2
- 2
extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h View File

@@ -192,8 +192,8 @@ private:
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,
"Use global path", "Use global path for this module"),


+ 372
- 0
extras/Projucer/Source/Project/UI/jucer_HeaderComponent.cpp View File

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

+ 50
- 260
extras/Projucer/Source/Project/UI/jucer_HeaderComponent.h View File

@@ -26,205 +26,48 @@
#pragma once
#include "../../Application/jucer_Headers.h"
#include "../../Utility/UI/jucer_IconButton.h"
#include "../../Utility/UI/jucer_UserSettingsPopup.h"
class Project;
//==============================================================================
class HeaderComponent : public Component,
private ValueTree::Listener,
private ChangeListener
private ChangeListener,
private Timer
{
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:
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 valueTreeParentChanged (ValueTree&) override {}
@@ -232,94 +75,41 @@ private:
void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, 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)
};

+ 12
- 10
extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp View File

@@ -478,7 +478,9 @@ void ProjectContentComponent::saveDocument()
showSaveWarning (currentDocument);
}
else
{
saveProject();
}
}
void ProjectContentComponent::saveAs()
@@ -521,11 +523,13 @@ bool ProjectContentComponent::goToCounterpart()
return false;
}
bool ProjectContentComponent::saveProject (bool shouldWait)
bool ProjectContentComponent::saveProject (bool shouldWait, bool openInIDE)
{
if (project != nullptr)
{
const ScopedValueSetter<bool> valueSetter (project->shouldWaitAfterSaving, shouldWait, false);
project->setOpenInIDEAfterSaving (openInIDE);
return (project->save (true, true) == FileBasedDocument::savedOk);
}
@@ -637,11 +641,16 @@ void ProjectContentComponent::openInSelectedIDE (bool saveFirst)
{
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;
exporter->launchProject();
break;
return;
}
}
}
@@ -1155,9 +1164,6 @@ void ProjectContentComponent::setBuildEnabled (bool isEnabled, bool displayError
LiveBuildProjectSettings::setBuildDisabled (*project, ! isEnabled);
killChildProcess();
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);
if (auto* h = dynamic_cast<HeaderComponent*> (header.get()))
h->updateBuildButtons (isBuildEnabled(), b);
getAppSettings().getGlobalProperties().setValue ("continuousRebuild", b);
ProjucerApplication::getCommandManager().commandStatusChanged();
}
}


+ 1
- 1
extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h View File

@@ -75,7 +75,7 @@ public:
bool canGoToCounterpart() const;
bool goToCounterpart();
bool saveProject (bool shouldWait = false);
bool saveProject (bool shouldWait = false, bool openInIDE = false);
void closeProject();
void openInSelectedIDE (bool saveFirst);
void showNewExporterMenu();


+ 53
- 1
extras/Projucer/Source/Project/jucer_Project.cpp View File

@@ -394,6 +394,13 @@ static void registerRecentFile (const File& file)
getAppSettings().flush();
}
static void forgetRecentFile (const File& file)
{
RecentlyOpenedFilesList::forgetRecentFileNatively (file);
getAppSettings().recentFiles.removeFile (file);
getAppSettings().flush();
}
//==============================================================================
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!");
registerRecentFile (file);
enabledModulesList.reset();
projectRoot = newTree;
@@ -437,9 +445,15 @@ Result Project::saveProject (const File& file, bool isCommandLineApp)
if (isSaving)
return Result::ok();
if (isTemporaryProject())
{
askUserWhereToSaveProject();
return Result::ok();
}
updateProjectSettings();
if (! isCommandLineApp)
if (! isCommandLineApp && ! isTemporaryProject())
registerRecentFile (file);
const ScopedValueSetter<bool> vs (isSaving, true, false);
@@ -454,17 +468,55 @@ Result Project::saveResourcesOnly (const File& file)
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)
{
if (tree.getRoot() == tree)
{
if (property == Ids::projectType)
{
sendChangeMessage();
}
else if (property == Ids::name)
{
setTitle (projectRoot [Ids::name]);
}
else if (property == Ids::defines)
{
parsedPreprocessorDefs = parsePreprocessorDefs (preprocessorDefsValue.get());
}
changed();
}


+ 20
- 1
extras/Projucer/Source/Project/jucer_Project.h View File

@@ -31,6 +31,7 @@
class ProjectExporter;
class LibraryModule;
class EnabledModuleList;
class ProjectContentComponent;
//==============================================================================
class Project : public FileBasedDocument,
@@ -331,10 +332,18 @@ public:
String getUniqueTargetFolderSuffixForExporter (const String& exporterName, const String& baseTargetFolder);
//==============================================================================
bool isCurrentlySaving() const noexcept { return isSaving; }
bool isCurrentlySaving() const noexcept { return isSaving; }
bool shouldWaitAfterSaving = false;
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:
ValueTree projectRoot { Ids::JUCERPROJECT };
@@ -349,6 +358,16 @@ private:
pluginAUMainTypeValue, pluginRTASCategoryValue, pluginRTASBypassDisabledValue, pluginRTASMultiMonoDisabledValue,
pluginAAXIdentifierValue, pluginAAXCategoryValue, pluginAAXBypassDisabledValue, pluginAAXMultiMonoDisabledValue;
//==============================================================================
File tempDirectory = {};
bool openInIDEAfterSaving = false;
void askUserWhereToSaveProject();
void moveTemporaryDirectory (const File&);
//==============================================================================
bool hasSentGUIBuilderAnalyticsEvent = false;
//==============================================================================
friend class Item;
ScopedPointer<EnabledModuleList> enabledModulesList;


+ 26
- 0
extras/Projucer/Source/ProjectSaving/jucer_ProjectSaver.h View File

@@ -138,6 +138,32 @@ public:
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)
{
if (! generatedCodeFolder.createDirectory())


+ 0
- 34
extras/Projucer/Source/Utility/UI/jucer_Icons.cpp View File

@@ -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,
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,
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,
@@ -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,
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,
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 };
@@ -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,
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,
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 (config)
JUCE_LOAD_PATH_DATA (graph)
// JUCE_LOAD_PATH_DATA (exporter)
JUCE_LOAD_PATH_DATA (jigsaw)
JUCE_LOAD_PATH_DATA (info)
JUCE_LOAD_PATH_DATA (warning)
JUCE_LOAD_PATH_DATA (bug)
// JUCE_LOAD_PATH_DATA (play)
JUCE_LOAD_PATH_DATA (code)
JUCE_LOAD_PATH_DATA (box)
JUCE_LOAD_PATH_DATA (juceLogo)
JUCE_LOAD_PATH_DATA (mainJuceLogo)
JUCE_LOAD_PATH_DATA (user)
JUCE_LOAD_PATH_DATA (closedFolder)
JUCE_LOAD_PATH_DATA (exporter)
@@ -1610,9 +1579,6 @@ Icons::Icons()
JUCE_LOAD_PATH_DATA (play)
JUCE_LOAD_PATH_DATA (settings)
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 (plus);
JUCE_LOAD_PATH_DATA (android);


+ 4
- 10
extras/Projucer/Source/Utility/UI/jucer_Icons.h View File

@@ -72,16 +72,10 @@ class Icons
public:
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:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Icons)


+ 2
- 0
extras/Projucer/Source/Utility/UI/jucer_UserSettingsPopup.h View File

@@ -26,6 +26,8 @@
#pragma once
#include "../../Licenses/jucer_LicenseController.h"
#include "../../Application/jucer_Application.h"
//==============================================================================
class UserSettingsPopup : public Component


+ 38
- 52
extras/Projucer/Source/Wizards/jucer_TemplateThumbnailsComponent.h View File

@@ -158,13 +158,15 @@ public:
// Handle Open Project button functionality
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;
}
@@ -185,35 +187,41 @@ public:
for (int i = 0; i < optionButtons.size(); ++i)
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
{
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)
@@ -231,36 +239,14 @@ public:
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:
OwnedArray<TemplateOptionButton> optionButtons;
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)
{


Loading…
Cancel
Save