mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-21 01:24:21 +00:00
Projucer: Various fixes and improvements to PIPGenerator
This commit is contained in:
parent
711e75bdc8
commit
ef2d1fa9fd
12 changed files with 194 additions and 28 deletions
|
|
@ -28,7 +28,8 @@
|
|||
|
||||
|
||||
//==============================================================================
|
||||
class GlobalPathsWindowComponent : public Component
|
||||
class GlobalPathsWindowComponent : public Component,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
GlobalPathsWindowComponent()
|
||||
|
|
@ -66,6 +67,12 @@ public:
|
|||
g.fillAll (findColour (backgroundColourId));
|
||||
}
|
||||
|
||||
void paintOverChildren (Graphics& g) override
|
||||
{
|
||||
g.setColour (findColour (defaultHighlightColourId).withAlpha (flashAlpha));
|
||||
g.fillRect (boundsToHighlight);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto b = getLocalBounds().reduced (10);
|
||||
|
|
@ -77,6 +84,8 @@ public:
|
|||
info.setBounds (osSelector.getBounds().withWidth (osSelector.getHeight()).translated ((osSelector.getWidth() + 5), 0).reduced (2));
|
||||
|
||||
int labelIndex = 0;
|
||||
bool isFirst = true;
|
||||
|
||||
for (auto* pathComp : pathPropertyComponents)
|
||||
{
|
||||
if (pathComp == nullptr)
|
||||
|
|
@ -87,9 +96,28 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
if (isFirst)
|
||||
b.removeFromTop (20);
|
||||
|
||||
pathComp->setBounds (b.removeFromTop (pathComp->getPreferredHeight()));
|
||||
b.removeFromTop (5);
|
||||
}
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
|
||||
void highlightJUCEPath()
|
||||
{
|
||||
if (! isTimerRunning() && isSelectedOSThisOS())
|
||||
{
|
||||
if (auto* jucePathComp = pathPropertyComponents.getFirst())
|
||||
boundsToHighlight = jucePathComp->getBounds();
|
||||
|
||||
flashAlpha = 0.0f;
|
||||
hasFlashed = false;
|
||||
|
||||
startTimer (25);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,6 +128,30 @@ private:
|
|||
ComboBox osSelector;
|
||||
InfoButton info;
|
||||
|
||||
Rectangle<int> boundsToHighlight;
|
||||
float flashAlpha = 0.0f;
|
||||
bool hasFlashed = false;
|
||||
|
||||
//==============================================================================
|
||||
void timerCallback() override
|
||||
{
|
||||
flashAlpha += (hasFlashed ? -0.05f : 0.05f);
|
||||
|
||||
if (flashAlpha > 0.75f)
|
||||
{
|
||||
hasFlashed = true;
|
||||
}
|
||||
else if (flashAlpha < 0.0f)
|
||||
{
|
||||
flashAlpha = 0.0f;
|
||||
boundsToHighlight = {};
|
||||
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isSelectedOSThisOS() { return TargetOS::getThisOS() == getSelectedOS(); }
|
||||
|
||||
|
|
@ -126,6 +178,9 @@ private:
|
|||
|
||||
if (isSelectedOSThisOS())
|
||||
{
|
||||
addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::jucePath),
|
||||
"Path to JUCE", true)));
|
||||
|
||||
pathPropertyComponents.add (nullptr);
|
||||
|
||||
addAndMakeVisible (pathPropertyComponents.add (new FilePathPropertyComponent (settings.getStoredPath (Ids::defaultJuceModulePath),
|
||||
|
|
|
|||
|
|
@ -177,6 +177,9 @@ void ProjucerApplication::handleAsyncUpdate()
|
|||
setAnalyticsEnabled (licenseController->getState().applicationUsageDataState == LicenseState::ApplicationUsageData::enabled);
|
||||
Analytics::getInstance()->logEvent ("Startup", {}, ProjucerAnalyticsEvent::appEvent);
|
||||
}
|
||||
|
||||
if (! isRunningCommandLine && settings->shouldAskUserToSetJUCEPath())
|
||||
showSetJUCEPathAlert();
|
||||
}
|
||||
|
||||
void ProjucerApplication::initialiseWindows (const String& commandLine)
|
||||
|
|
@ -345,7 +348,8 @@ enum
|
|||
activeDocumentsBaseID = 400,
|
||||
colourSchemeBaseID = 1000,
|
||||
codeEditorColourSchemeBaseID = 1500,
|
||||
examplesBaseID = 2000,
|
||||
showPathsID = 1999,
|
||||
examplesBaseID = 2000
|
||||
};
|
||||
|
||||
MenuBarModel* ProjucerApplication::getMenuModel()
|
||||
|
|
@ -592,7 +596,7 @@ void ProjucerApplication::createExamplesPopupMenu (PopupMenu& menu) noexcept
|
|||
|
||||
if (numExamples == 0)
|
||||
{
|
||||
menu.addCommandItem (commandManager, CommandIDs::showGlobalPathsWindow, "Set path to JUCE...");
|
||||
menu.addItem (showPathsID, "Set path to JUCE...");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -615,7 +619,7 @@ Array<File> ProjucerApplication::getSortedExampleDirectories() const noexcept
|
|||
{
|
||||
auto exampleDirectory = iter.getFile();
|
||||
|
||||
if (exampleDirectory.getFileName() != "DemoRunner" && exampleDirectory.getFileName() != "Resources")
|
||||
if (exampleDirectory.getFileName() != "DemoRunner" && exampleDirectory.getFileName() != "Assets")
|
||||
exampleDirectories.add (exampleDirectory);
|
||||
}
|
||||
|
||||
|
|
@ -860,6 +864,10 @@ void ProjucerApplication::handleMainMenuCommand (int menuItemID)
|
|||
{
|
||||
showEditorColourSchemeWindow();
|
||||
}
|
||||
else if (menuItemID == showPathsID)
|
||||
{
|
||||
showPathsWindow (true);
|
||||
}
|
||||
else if (menuItemID >= examplesBaseID && menuItemID < (examplesBaseID + numExamples))
|
||||
{
|
||||
findAndLaunchExample (menuItemID - examplesBaseID);
|
||||
|
|
@ -1028,7 +1036,7 @@ bool ProjucerApplication::perform (const InvocationInfo& info)
|
|||
case CommandIDs::clearRecentFiles: clearRecentFiles(); break;
|
||||
case CommandIDs::showUTF8Tool: showUTF8ToolWindow(); break;
|
||||
case CommandIDs::showSVGPathTool: showSVGPathDataToolWindow(); break;
|
||||
case CommandIDs::showGlobalPathsWindow: showPathsWindow(); break;
|
||||
case CommandIDs::showGlobalPathsWindow: showPathsWindow (false); break;
|
||||
case CommandIDs::showAboutWindow: showAboutWindow(); break;
|
||||
case CommandIDs::showAppUsageWindow: showApplicationUsageDataAgreementPopup(); break;
|
||||
case CommandIDs::showForum: launchForumBrowser(); break;
|
||||
|
|
@ -1166,7 +1174,7 @@ void ProjucerApplication::dismissApplicationUsageDataAgreementPopup()
|
|||
applicationUsageDataWindow.reset();
|
||||
}
|
||||
|
||||
void ProjucerApplication::showPathsWindow()
|
||||
void ProjucerApplication::showPathsWindow (bool highlightJUCEPath)
|
||||
{
|
||||
if (pathsWindow != nullptr)
|
||||
pathsWindow->toFront (true);
|
||||
|
|
@ -1174,7 +1182,11 @@ void ProjucerApplication::showPathsWindow()
|
|||
new FloatingToolWindow ("Global Paths",
|
||||
"pathsWindowPos",
|
||||
new GlobalPathsWindowComponent(), pathsWindow, false,
|
||||
600, 550, 600, 550, 600, 550);
|
||||
600, 650, 600, 650, 600, 650);
|
||||
|
||||
if (highlightJUCEPath)
|
||||
if (auto* pathsComp = dynamic_cast<GlobalPathsWindowComponent*> (pathsWindow->getChildComponent (0)))
|
||||
pathsComp->highlightJUCEPath();
|
||||
}
|
||||
|
||||
void ProjucerApplication::showEditorColourSchemeWindow()
|
||||
|
|
@ -1345,6 +1357,27 @@ void ProjucerApplication::setupAnalytics()
|
|||
Analytics::getInstance()->setUserProperties (userData);
|
||||
}
|
||||
|
||||
void ProjucerApplication::showSetJUCEPathAlert()
|
||||
{
|
||||
auto& lf = Desktop::getInstance().getDefaultLookAndFeel();
|
||||
pathAlert = lf.createAlertWindow ("Set JUCE Path", "Your global JUCE path is invalid. This path is used to access the JUCE examples and demo project - "
|
||||
"would you like to set it now?",
|
||||
"Set path", "Cancel", "Don't ask again",
|
||||
AlertWindow::WarningIcon, 3,
|
||||
mainWindowList.getFrontmostWindow (false));
|
||||
|
||||
pathAlert->enterModalState (true, ModalCallbackFunction::create ([this] (int retVal)
|
||||
{
|
||||
pathAlert.reset (nullptr);
|
||||
|
||||
if (retVal == 1)
|
||||
showPathsWindow (true);
|
||||
else if (retVal == 0)
|
||||
settings->setDontAskAboutJUCEPathAgain();
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
void ProjucerApplication::selectEditorColourSchemeWithName (const String& schemeName)
|
||||
{
|
||||
auto& appearanceSettings = getAppSettings().appearance;
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ public:
|
|||
void showApplicationUsageDataAgreementPopup();
|
||||
void dismissApplicationUsageDataAgreementPopup();
|
||||
|
||||
void showPathsWindow();
|
||||
void showPathsWindow (bool highlightJUCEPath = false);
|
||||
void showEditorColourSchemeWindow();
|
||||
|
||||
void launchForumBrowser();
|
||||
|
|
@ -194,6 +194,9 @@ private:
|
|||
void resetAnalytics() noexcept;
|
||||
void setupAnalytics();
|
||||
|
||||
void showSetJUCEPathAlert();
|
||||
ScopedPointer<AlertWindow> pathAlert;
|
||||
|
||||
//==============================================================================
|
||||
void setColourScheme (int index, bool saveSetting);
|
||||
|
||||
|
|
|
|||
|
|
@ -717,10 +717,6 @@ namespace
|
|||
#endif
|
||||
|
||||
auto settingsFile = userAppData.getChildFile ("Projucer").getChildFile ("Projucer.settings");
|
||||
|
||||
if (! settingsFile.existsAsFile())
|
||||
throw CommandLineError ("Expected settings file at " + settingsFile.getFullPathName() + " not found!");
|
||||
|
||||
ScopedPointer<XmlElement> xml (XmlDocument::parse (settingsFile));
|
||||
auto settingsTree = ValueTree::fromXml (*xml);
|
||||
|
||||
|
|
@ -743,15 +739,14 @@ namespace
|
|||
if (! childToSet.isValid())
|
||||
throw CommandLineError ("Failed to set the requested setting!");
|
||||
|
||||
childToSet.setProperty (args[2], args[3], nullptr);
|
||||
childToSet.setProperty (args[2], File::getCurrentWorkingDirectory().getChildFile (args[3]).getFullPathName(), nullptr);
|
||||
|
||||
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.");
|
||||
checkArgumentCount (args, 3);
|
||||
|
||||
auto pipFile = File::getCurrentWorkingDirectory().getChildFile (args[1].unquoted());
|
||||
if (! pipFile.existsAsFile())
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ ProjucerAnalyticsDestination::ProjucerAnalyticsDestination()
|
|||
}
|
||||
|
||||
auto dataDir = File::getSpecialLocation (File::userApplicationDataDirectory)
|
||||
#if JUCE_MAC
|
||||
.getChildFile ("Application Support")
|
||||
#endif
|
||||
.getChildFile ("Projucer")
|
||||
.getChildFile ("Analytics");
|
||||
|
||||
|
|
|
|||
|
|
@ -491,13 +491,39 @@ void Project::moveTemporaryDirectory (const File& newParentDirectory)
|
|||
auto newDirectory = newParentDirectory.getChildFile (tempDirectory.getFileName());
|
||||
auto oldJucerFileName = getFile().getFileName();
|
||||
|
||||
saveProjectRootToFile();
|
||||
|
||||
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));
|
||||
{
|
||||
Component::SafePointer<MainWindow> safeWindow (window);
|
||||
|
||||
MessageManager::callAsync ([safeWindow, newDirectory, oldJucerFileName]
|
||||
{
|
||||
if (safeWindow != nullptr)
|
||||
safeWindow.getComponent()->moveProject (newDirectory.getChildFile (oldJucerFileName));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool Project::saveProjectRootToFile()
|
||||
{
|
||||
ScopedPointer<XmlElement> xml (projectRoot.createXml());
|
||||
|
||||
if (xml == nullptr)
|
||||
{
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
MemoryOutputStream mo;
|
||||
xml->writeToStream (mo, {});
|
||||
|
||||
return FileHelpers::overwriteFileWithNewDataIfDifferent (getFile(), mo);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -367,6 +367,7 @@ private:
|
|||
|
||||
void askUserWhereToSaveProject();
|
||||
void moveTemporaryDirectory (const File&);
|
||||
bool saveProjectRootToFile();
|
||||
|
||||
//==============================================================================
|
||||
bool hasSentGUIBuilderAnalyticsEvent = false;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ StoredSettings::StoredSettings()
|
|||
{
|
||||
updateOldProjectSettingsFiles();
|
||||
reload();
|
||||
checkJUCEPaths();
|
||||
|
||||
projectDefaults.addListener (this);
|
||||
fallbackPaths.addListener (this);
|
||||
}
|
||||
|
|
@ -195,6 +197,34 @@ void StoredSettings::updateOldProjectSettingsFiles()
|
|||
}
|
||||
}
|
||||
|
||||
void StoredSettings::checkJUCEPaths()
|
||||
{
|
||||
auto moduleFolder = projectDefaults.getProperty (Ids::defaultJuceModulePath).toString();
|
||||
auto juceFolder = projectDefaults.getProperty (Ids::jucePath).toString();
|
||||
|
||||
auto validModuleFolder = isGlobalPathValid ({}, Ids::defaultJuceModulePath, moduleFolder);
|
||||
auto validJuceFolder = isGlobalPathValid ({}, Ids::jucePath, juceFolder);
|
||||
|
||||
if (validModuleFolder && ! validJuceFolder)
|
||||
projectDefaults.getPropertyAsValue (Ids::jucePath, nullptr) = File (moduleFolder).getParentDirectory().getFullPathName();
|
||||
else if (! validModuleFolder && validJuceFolder)
|
||||
projectDefaults.getPropertyAsValue (Ids::defaultJuceModulePath, nullptr) = File (juceFolder).getChildFile ("modules").getFullPathName();
|
||||
}
|
||||
|
||||
bool StoredSettings::shouldAskUserToSetJUCEPath() noexcept
|
||||
{
|
||||
if (! isGlobalPathValid ({}, Ids::jucePath, projectDefaults.getProperty (Ids::jucePath).toString())
|
||||
&& getGlobalProperties().getValue ("dontAskAboutJUCEPath", {}).isEmpty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void StoredSettings::setDontAskAboutJUCEPathAgain() noexcept
|
||||
{
|
||||
getGlobalProperties().setValue ("dontAskAboutJUCEPath", 1);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void StoredSettings::loadSwatchColours()
|
||||
{
|
||||
|
|
@ -271,7 +301,12 @@ Value StoredSettings::getFallbackPathForOS (const Identifier& key, DependencyPat
|
|||
|
||||
if (v.toString().isEmpty())
|
||||
{
|
||||
if (key == Ids::defaultJuceModulePath)
|
||||
if (key == Ids::jucePath)
|
||||
{
|
||||
v = (os == TargetOS::windows ? "C:\\JUCE"
|
||||
: "~/JUCE");
|
||||
}
|
||||
else if (key == Ids::defaultJuceModulePath)
|
||||
{
|
||||
v = (os == TargetOS::windows ? "C:\\JUCE\\modules"
|
||||
: "~/JUCE/modules");
|
||||
|
|
@ -334,13 +369,13 @@ Value StoredSettings::getFallbackPathForOS (const Identifier& key, DependencyPat
|
|||
return v;
|
||||
}
|
||||
|
||||
static bool doesSDKPathContainFile (const File& relativeTo, const String& path, const String& fileToCheckFor)
|
||||
static bool doesSDKPathContainFile (const File& relativeTo, const String& path, const String& fileToCheckFor) noexcept
|
||||
{
|
||||
auto actualPath = path.replace ("${user.home}", File::getSpecialLocation (File::userHomeDirectory).getFullPathName());
|
||||
return relativeTo.getChildFile (actualPath + "/" + fileToCheckFor).exists();
|
||||
}
|
||||
|
||||
bool StoredSettings::isGlobalPathValid (const File& relativeTo, const Identifier& key, const String& path)
|
||||
bool StoredSettings::isGlobalPathValid (const File& relativeTo, const Identifier& key, const String& path) const noexcept
|
||||
{
|
||||
String fileToCheckFor;
|
||||
|
||||
|
|
@ -390,6 +425,10 @@ bool StoredSettings::isGlobalPathValid (const File& relativeTo, const Identifier
|
|||
fileToCheckFor = "../clion.sh";
|
||||
#endif
|
||||
}
|
||||
else if (key == Ids::jucePath)
|
||||
{
|
||||
fileToCheckFor = "ChangeList.txt";
|
||||
}
|
||||
else
|
||||
{
|
||||
// didn't recognise the key provided!
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ public:
|
|||
Value getStoredPath (const Identifier& key);
|
||||
Value getFallbackPathForOS (const Identifier& key, DependencyPathOS);
|
||||
|
||||
bool isGlobalPathValid (const File& relativeTo, const Identifier& key, const String& path);
|
||||
bool isGlobalPathValid (const File& relativeTo, const Identifier& key, const String& path) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
bool shouldAskUserToSetJUCEPath() noexcept;
|
||||
void setDontAskAboutJUCEPathAgain() noexcept;
|
||||
|
||||
private:
|
||||
OwnedArray<PropertiesFile> propertyFiles;
|
||||
|
|
@ -96,6 +100,7 @@ private:
|
|||
void saveSwatchColours();
|
||||
|
||||
void updateOldProjectSettingsFiles();
|
||||
void checkJUCEPaths();
|
||||
|
||||
//==============================================================================
|
||||
void valueTreePropertyChanged (ValueTree& vt, const Identifier&) override { changed (vt == projectDefaults); }
|
||||
|
|
|
|||
|
|
@ -405,7 +405,12 @@ bool isPIPFile (const File& file) noexcept
|
|||
|
||||
File getJUCEExamplesDirectoryPathFromGlobal() noexcept
|
||||
{
|
||||
return File (getAppSettings().getStoredPath (Ids::defaultJuceModulePath).toString()).getSiblingFile ("examples");
|
||||
auto globalPath = getAppSettings().getStoredPath (Ids::jucePath).toString();
|
||||
|
||||
if (globalPath.isNotEmpty())
|
||||
return File (getAppSettings().getStoredPath (Ids::jucePath).toString()).getChildFile ("examples");
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool isValidJUCEExamplesDirectory (const File& directory) noexcept
|
||||
|
|
@ -413,5 +418,5 @@ bool isValidJUCEExamplesDirectory (const File& directory) noexcept
|
|||
if (! directory.exists() || ! directory.isDirectory() || ! directory.containsSubDirectories())
|
||||
return false;
|
||||
|
||||
return directory.getChildFile ("Resources").getChildFile ("juce_icon.png").existsAsFile();
|
||||
return directory.getChildFile ("Assets").getChildFile ("juce_icon.png").existsAsFile();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ namespace Ids
|
|||
DECLARE_ID (osxFallback);
|
||||
DECLARE_ID (windowsFallback);
|
||||
DECLARE_ID (linuxFallback);
|
||||
DECLARE_ID (jucePath);
|
||||
DECLARE_ID (defaultJuceModulePath);
|
||||
DECLARE_ID (defaultUserModulePath);
|
||||
DECLARE_ID (vst3Folder);
|
||||
|
|
|
|||
|
|
@ -256,15 +256,15 @@ void PIPGenerator::createFiles (ValueTree& jucerTree)
|
|||
|
||||
if (relativeFiles.size() > 0)
|
||||
{
|
||||
ValueTree resources (Ids::GROUP);
|
||||
resources.setProperty (Ids::ID, createAlphaNumericUID(), nullptr);
|
||||
resources.setProperty (Ids::name, "Resources", nullptr);
|
||||
ValueTree assets (Ids::GROUP);
|
||||
assets.setProperty (Ids::ID, createAlphaNumericUID(), nullptr);
|
||||
assets.setProperty (Ids::name, "Assets", nullptr);
|
||||
|
||||
for (auto& f : relativeFiles)
|
||||
if (copyRelativeFileToLocalSourceDirectory (f))
|
||||
addFileToTree (resources, f.getFileName(), f.getFileExtension() == ".cpp", "Source/" + f.getFileName());
|
||||
addFileToTree (assets, f.getFileName(), f.getFileExtension() == ".cpp", "Source/" + f.getFileName());
|
||||
|
||||
mainGroup.addChild (resources, -1, nullptr);
|
||||
mainGroup.addChild (assets, -1, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +400,7 @@ Result PIPGenerator::setProjectSettings (ValueTree& jucerTree)
|
|||
if (isValidJUCEExamplesDirectory (examplesDirectory))
|
||||
{
|
||||
defines += ((defines.isEmpty() ? "" : " ") + String ("PIP_JUCE_EXAMPLES_DIRECTORY=")
|
||||
+ examplesDirectory.getFullPathName());
|
||||
+ Base64::toBase64 (examplesDirectory.getFullPathName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue