git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
326
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_ContentComponents.h
vendored
Normal file
326
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_ContentComponents.h
vendored
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../ProjectSaving/jucer_ProjectExporter.h"
|
||||
#include "../../Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h"
|
||||
#include "../../Utility/Helpers/jucer_ValueWithDefaultWrapper.h"
|
||||
|
||||
#include "jucer_NewProjectWizard.h"
|
||||
|
||||
//==============================================================================
|
||||
class ItemHeader : public Component
|
||||
{
|
||||
public:
|
||||
ItemHeader (StringRef name, StringRef description, const char* iconSvgData)
|
||||
: nameLabel ({}, name),
|
||||
descriptionLabel ({}, description),
|
||||
icon (makeIcon (iconSvgData))
|
||||
{
|
||||
addAndMakeVisible (nameLabel);
|
||||
nameLabel.setFont (18.0f);
|
||||
nameLabel.setMinimumHorizontalScale (1.0f);
|
||||
|
||||
addAndMakeVisible (descriptionLabel);
|
||||
descriptionLabel.setMinimumHorizontalScale (1.0f);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
auto topSlice = bounds.removeFromTop (50);
|
||||
iconBounds = topSlice.removeFromRight (75);
|
||||
nameLabel.setBounds (topSlice);
|
||||
|
||||
bounds.removeFromTop (10);
|
||||
descriptionLabel.setBounds (bounds.removeFromTop (50));
|
||||
bounds.removeFromTop (20);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
|
||||
if (icon != nullptr)
|
||||
icon->drawWithin (g, iconBounds.toFloat(), RectanglePlacement::centred, 1.0f);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::unique_ptr<Drawable> makeIcon (const char* iconSvgData)
|
||||
{
|
||||
if (auto svg = XmlDocument::parse (iconSvgData))
|
||||
return Drawable::createFromSVG (*svg);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Label nameLabel, descriptionLabel;
|
||||
|
||||
Rectangle<int> iconBounds;
|
||||
std::unique_ptr<Drawable> icon;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ItemHeader)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TemplateComponent : public Component
|
||||
{
|
||||
public:
|
||||
TemplateComponent (const NewProjectTemplates::ProjectTemplate& temp,
|
||||
std::function<void (std::unique_ptr<Project>)>&& createdCallback)
|
||||
: projectTemplate (temp),
|
||||
projectCreatedCallback (std::move (createdCallback)),
|
||||
header (projectTemplate.displayName, projectTemplate.description, projectTemplate.icon)
|
||||
{
|
||||
createProjectButton.onClick = [this]
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Save Project", NewProjectWizard::getLastWizardFolder());
|
||||
auto browserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories;
|
||||
|
||||
chooser->launchAsync (browserFlags, [this] (const FileChooser& fc)
|
||||
{
|
||||
auto dir = fc.getResult();
|
||||
|
||||
if (dir == File{})
|
||||
return;
|
||||
|
||||
SafePointer<TemplateComponent> safeThis { this };
|
||||
NewProjectWizard::createNewProject (projectTemplate,
|
||||
dir.getChildFile (projectNameValue.get().toString()),
|
||||
projectNameValue.get(),
|
||||
modulesValue.get(),
|
||||
exportersValue.get(),
|
||||
fileOptionsValue.get(),
|
||||
modulePathValue.getCurrentValue(),
|
||||
modulePathValue.getWrappedValueWithDefault().isUsingDefault(),
|
||||
[safeThis, dir] (std::unique_ptr<Project> project)
|
||||
{
|
||||
if (safeThis == nullptr)
|
||||
return;
|
||||
|
||||
safeThis->projectCreatedCallback (std::move (project));
|
||||
getAppSettings().lastWizardFolder = dir;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
addAndMakeVisible (createProjectButton);
|
||||
addAndMakeVisible (header);
|
||||
|
||||
modulePathValue.init ({ settingsTree, Ids::defaultJuceModulePath, nullptr },
|
||||
getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()),
|
||||
TargetOS::getThisOS());
|
||||
|
||||
panel.addProperties (buildPropertyList(), 2);
|
||||
addAndMakeVisible (panel);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (10);
|
||||
|
||||
header.setBounds (bounds.removeFromTop (150));
|
||||
createProjectButton.setBounds (bounds.removeFromBottom (30).removeFromRight (150));
|
||||
bounds.removeFromBottom (5);
|
||||
|
||||
panel.setBounds (bounds);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
private:
|
||||
NewProjectTemplates::ProjectTemplate projectTemplate;
|
||||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
std::function<void (std::unique_ptr<Project>)> projectCreatedCallback;
|
||||
|
||||
ItemHeader header;
|
||||
TextButton createProjectButton { "Create Project..." };
|
||||
|
||||
ValueTree settingsTree { "NewProjectSettings" };
|
||||
|
||||
ValueWithDefault projectNameValue { settingsTree, Ids::name, nullptr, "NewProject" },
|
||||
modulesValue { settingsTree, Ids::dependencies_, nullptr, projectTemplate.requiredModules, "," },
|
||||
exportersValue { settingsTree, Ids::exporters, nullptr, StringArray (ProjectExporter::getCurrentPlatformExporterTypeInfo().identifier.toString()), "," },
|
||||
fileOptionsValue { settingsTree, Ids::file, nullptr, NewProjectTemplates::getVarForFileOption (projectTemplate.defaultFileOption) };
|
||||
|
||||
ValueWithDefaultWrapper modulePathValue;
|
||||
|
||||
PropertyPanel panel;
|
||||
|
||||
//==============================================================================
|
||||
PropertyComponent* createProjectNamePropertyComponent()
|
||||
{
|
||||
return new TextPropertyComponent (projectNameValue, "Project Name", 1024, false);
|
||||
}
|
||||
|
||||
PropertyComponent* createModulesPropertyComponent()
|
||||
{
|
||||
Array<var> moduleVars;
|
||||
var requiredModules;
|
||||
|
||||
for (auto& m : getJUCEModules())
|
||||
{
|
||||
moduleVars.add (m);
|
||||
|
||||
if (projectTemplate.requiredModules.contains (m))
|
||||
requiredModules.append (m);
|
||||
}
|
||||
|
||||
modulesValue = requiredModules;
|
||||
|
||||
return new MultiChoicePropertyComponent (modulesValue, "Modules",
|
||||
getJUCEModules(), moduleVars);
|
||||
}
|
||||
|
||||
PropertyComponent* createModulePathPropertyComponent()
|
||||
{
|
||||
return new FilePathPropertyComponent (modulePathValue.getWrappedValueWithDefault(), "Path to Modules", true);
|
||||
}
|
||||
|
||||
PropertyComponent* createExportersPropertyValue()
|
||||
{
|
||||
Array<var> exporterVars;
|
||||
StringArray exporterNames;
|
||||
|
||||
for (auto& exporterTypeInfo : ProjectExporter::getExporterTypeInfos())
|
||||
{
|
||||
exporterVars.add (exporterTypeInfo.identifier.toString());
|
||||
exporterNames.add (exporterTypeInfo.displayName);
|
||||
}
|
||||
|
||||
return new MultiChoicePropertyComponent (exportersValue, "Exporters", exporterNames, exporterVars);
|
||||
}
|
||||
|
||||
PropertyComponent* createFileCreationOptionsPropertyComponent()
|
||||
{
|
||||
Array<var> optionVars;
|
||||
StringArray optionStrings;
|
||||
|
||||
for (auto& opt : projectTemplate.fileOptionsAndFiles)
|
||||
{
|
||||
optionVars.add (NewProjectTemplates::getVarForFileOption (opt.first));
|
||||
optionStrings.add (NewProjectTemplates::getStringForFileOption (opt.first));
|
||||
}
|
||||
|
||||
return new ChoicePropertyComponent (fileOptionsValue, "File Creation Options", optionStrings, optionVars);
|
||||
}
|
||||
|
||||
Array<PropertyComponent*> buildPropertyList()
|
||||
{
|
||||
PropertyListBuilder builder;
|
||||
|
||||
builder.add (createProjectNamePropertyComponent());
|
||||
builder.add (createModulesPropertyComponent());
|
||||
builder.add (createModulePathPropertyComponent());
|
||||
builder.add (createExportersPropertyValue());
|
||||
|
||||
if (! projectTemplate.fileOptionsAndFiles.empty())
|
||||
builder.add (createFileCreationOptionsPropertyComponent());
|
||||
|
||||
return builder.components;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemplateComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ExampleComponent : public Component
|
||||
{
|
||||
public:
|
||||
ExampleComponent (const File& f, std::function<void (const File&)> selectedCallback)
|
||||
: exampleFile (f),
|
||||
metadata (parseJUCEHeaderMetadata (exampleFile)),
|
||||
exampleSelectedCallback (std::move (selectedCallback)),
|
||||
header (metadata[Ids::name].toString(), metadata[Ids::description].toString(), BinaryData::background_logo_svg),
|
||||
codeViewer (doc, &cppTokeniser)
|
||||
{
|
||||
setTitle (exampleFile.getFileName());
|
||||
setFocusContainerType (FocusContainerType::focusContainer);
|
||||
|
||||
addAndMakeVisible (header);
|
||||
|
||||
openExampleButton.onClick = [this] { exampleSelectedCallback (exampleFile); };
|
||||
addAndMakeVisible (openExampleButton);
|
||||
|
||||
setupCodeViewer();
|
||||
addAndMakeVisible (codeViewer);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (10);
|
||||
|
||||
header.setBounds (bounds.removeFromTop (125));
|
||||
openExampleButton.setBounds (bounds.removeFromBottom (30).removeFromRight (150));
|
||||
codeViewer.setBounds (bounds);
|
||||
}
|
||||
|
||||
private:
|
||||
void setupCodeViewer()
|
||||
{
|
||||
auto fileString = exampleFile.loadFileAsString();
|
||||
|
||||
doc.replaceAllContent (fileString);
|
||||
|
||||
codeViewer.setScrollbarThickness (6);
|
||||
codeViewer.setReadOnly (true);
|
||||
codeViewer.setTitle ("Code");
|
||||
getAppSettings().appearance.applyToCodeEditor (codeViewer);
|
||||
|
||||
codeViewer.scrollToLine (findBestLineToScrollToForClass (StringArray::fromLines (fileString),
|
||||
metadata[Ids::name].toString(),
|
||||
metadata[Ids::type] == "AudioProcessor"));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File exampleFile;
|
||||
var metadata;
|
||||
|
||||
std::function<void (const File&)> exampleSelectedCallback;
|
||||
|
||||
ItemHeader header;
|
||||
|
||||
CPlusPlusCodeTokeniser cppTokeniser;
|
||||
CodeDocument doc;
|
||||
CodeEditorComponent codeViewer;
|
||||
|
||||
TextButton openExampleButton { "Open Example..." };
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExampleComponent)
|
||||
};
|
251
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_NewProjectTemplates.h
vendored
Normal file
251
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_NewProjectTemplates.h
vendored
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Utility/Helpers/jucer_MiscUtilities.h"
|
||||
|
||||
//==============================================================================
|
||||
namespace NewProjectTemplates
|
||||
{
|
||||
enum class ProjectCategory
|
||||
{
|
||||
application,
|
||||
plugin,
|
||||
library
|
||||
};
|
||||
|
||||
inline String getProjectCategoryString (ProjectCategory category)
|
||||
{
|
||||
if (category == ProjectCategory::application) return "Application";
|
||||
if (category == ProjectCategory::plugin) return "Plug-In";
|
||||
if (category == ProjectCategory::library) return "Library";
|
||||
|
||||
jassertfalse;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
enum class FileCreationOptions
|
||||
{
|
||||
noFiles,
|
||||
main,
|
||||
header,
|
||||
headerAndCpp,
|
||||
processorAndEditor
|
||||
};
|
||||
|
||||
using FilenameAndContent = std::pair<String, String>;
|
||||
using OptionAndFilenameAndContent = std::pair<FileCreationOptions, std::vector<FilenameAndContent>>;
|
||||
using OptionsAndFiles = std::vector<OptionAndFilenameAndContent>;
|
||||
|
||||
struct ProjectTemplate
|
||||
{
|
||||
ProjectCategory category;
|
||||
String displayName, description, projectTypeString;
|
||||
|
||||
const char* icon;
|
||||
StringArray requiredModules;
|
||||
OptionsAndFiles fileOptionsAndFiles;
|
||||
FileCreationOptions defaultFileOption;
|
||||
|
||||
std::vector<FilenameAndContent> getFilesForOption (FileCreationOptions option) const
|
||||
{
|
||||
auto iter = std::find_if (fileOptionsAndFiles.begin(), fileOptionsAndFiles.end(),
|
||||
[option] (const OptionAndFilenameAndContent& opt) { return opt.first == option; });
|
||||
|
||||
if (iter != fileOptionsAndFiles.end())
|
||||
return iter->second;
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
inline bool isApplication (const ProjectTemplate& t) noexcept { return t.category == ProjectCategory::application; }
|
||||
inline bool isPlugin (const ProjectTemplate& t) noexcept { return t.category == ProjectCategory::plugin; }
|
||||
inline bool isLibrary (const ProjectTemplate& t) noexcept { return t.category == ProjectCategory::library; }
|
||||
|
||||
//==============================================================================
|
||||
inline var getVarForFileOption (FileCreationOptions opt)
|
||||
{
|
||||
if (opt == FileCreationOptions::noFiles) return "none";
|
||||
if (opt == FileCreationOptions::main) return "main";
|
||||
if (opt == FileCreationOptions::header) return "header";
|
||||
if (opt == FileCreationOptions::headerAndCpp) return "headercpp";
|
||||
if (opt == FileCreationOptions::processorAndEditor) return "processoreditor";
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
inline FileCreationOptions getFileOptionForVar (var opt)
|
||||
{
|
||||
if (opt == "none") return FileCreationOptions::noFiles;
|
||||
if (opt == "main") return FileCreationOptions::main;
|
||||
if (opt == "header") return FileCreationOptions::header;
|
||||
if (opt == "headercpp") return FileCreationOptions::headerAndCpp;
|
||||
if (opt == "processoreditor") return FileCreationOptions::processorAndEditor;
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
inline String getStringForFileOption (FileCreationOptions opt)
|
||||
{
|
||||
if (opt == FileCreationOptions::noFiles) return "No Files";
|
||||
if (opt == FileCreationOptions::main) return "Main.cpp";
|
||||
if (opt == FileCreationOptions::header) return "Main.cpp + .h";
|
||||
if (opt == FileCreationOptions::headerAndCpp) return "Main.cpp + .h/.cpp ";
|
||||
if (opt == FileCreationOptions::processorAndEditor) return "Processor and Editor";
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
template <typename... Strings>
|
||||
inline StringArray addAndReturn (StringArray arr, Strings... strings)
|
||||
{
|
||||
arr.addArray ({ strings... });
|
||||
return arr;
|
||||
}
|
||||
|
||||
inline std::vector<ProjectTemplate> getAllTemplates()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ ProjectCategory::application,
|
||||
"Blank", "Creates a blank JUCE GUI application.",
|
||||
build_tools::ProjectType_GUIApp::getTypeName(),
|
||||
BinaryData::wizard_GUI_svg,
|
||||
getModulesRequiredForComponent(),
|
||||
{},
|
||||
FileCreationOptions::noFiles
|
||||
},
|
||||
|
||||
{ ProjectCategory::application,
|
||||
"GUI", "Creates a blank JUCE GUI application with a single window component.",
|
||||
build_tools::ProjectType_GUIApp::getTypeName(),
|
||||
BinaryData::wizard_GUI_svg,
|
||||
getModulesRequiredForComponent(),
|
||||
{
|
||||
{ FileCreationOptions::noFiles, {} },
|
||||
{ FileCreationOptions::main, { { "Main.cpp", "jucer_MainTemplate_NoWindow_cpp" } } },
|
||||
{ FileCreationOptions::header, { { "Main.cpp", "jucer_MainTemplate_Window_cpp" },
|
||||
{ "MainComponent.h", "jucer_ContentCompSimpleTemplate_h" } } },
|
||||
{ FileCreationOptions::headerAndCpp, { { "Main.cpp", "jucer_MainTemplate_Window_cpp" },
|
||||
{ "MainComponent.h", "jucer_ContentCompTemplate_h" },
|
||||
{ "MainComponent.cpp", "jucer_ContentCompTemplate_cpp" } } }
|
||||
},
|
||||
FileCreationOptions::headerAndCpp },
|
||||
|
||||
{ ProjectCategory::application,
|
||||
"Audio", "Creates a blank JUCE GUI application with a single window component and audio and MIDI in/out functions.",
|
||||
build_tools::ProjectType_GUIApp::getTypeName(),
|
||||
BinaryData::wizard_AudioApp_svg,
|
||||
addAndReturn (getModulesRequiredForComponent(), "juce_audio_basics", "juce_audio_devices", "juce_audio_formats",
|
||||
"juce_audio_processors", "juce_audio_utils", "juce_gui_extra"),
|
||||
{
|
||||
{ FileCreationOptions::header, { { "Main.cpp", "jucer_MainTemplate_Window_cpp" },
|
||||
{ "MainComponent.h", "jucer_AudioComponentSimpleTemplate_h" } } },
|
||||
{ FileCreationOptions::headerAndCpp, { { "Main.cpp", "jucer_MainTemplate_Window_cpp" },
|
||||
{ "MainComponent.h", "jucer_AudioComponentTemplate_h" },
|
||||
{ "MainComponent.cpp", "jucer_AudioComponentTemplate_cpp" } } }
|
||||
},
|
||||
FileCreationOptions::headerAndCpp },
|
||||
|
||||
{ ProjectCategory::application,
|
||||
"Console", "Creates a command-line application without GUI support.",
|
||||
build_tools::ProjectType_ConsoleApp::getTypeName(),
|
||||
BinaryData::wizard_ConsoleApp_svg,
|
||||
getModulesRequiredForConsole(),
|
||||
{
|
||||
{ FileCreationOptions::noFiles, {} },
|
||||
{ FileCreationOptions::main, { { "Main.cpp", "jucer_MainConsoleAppTemplate_cpp" } } }
|
||||
},
|
||||
FileCreationOptions::main },
|
||||
|
||||
{ ProjectCategory::application,
|
||||
"Animated", "Creates a JUCE GUI application which draws an animated graphical display.",
|
||||
build_tools::ProjectType_GUIApp::getTypeName(),
|
||||
BinaryData::wizard_AnimatedApp_svg,
|
||||
addAndReturn (getModulesRequiredForComponent(), "juce_gui_extra"),
|
||||
{
|
||||
{ FileCreationOptions::header, { { "Main.cpp", "jucer_MainTemplate_Window_cpp" },
|
||||
{ "MainComponent.h", "jucer_AudioComponentSimpleTemplate_h" } } },
|
||||
{ FileCreationOptions::headerAndCpp, { { "Main.cpp", "jucer_MainTemplate_Window_cpp" },
|
||||
{ "MainComponent.h", "jucer_AnimatedComponentTemplate_h" },
|
||||
{ "MainComponent.cpp", "jucer_AnimatedComponentTemplate_cpp" } } }
|
||||
},
|
||||
FileCreationOptions::headerAndCpp },
|
||||
|
||||
{ ProjectCategory::application,
|
||||
"OpenGL", "Creates a blank JUCE application with a single window component. "
|
||||
"This component supports openGL drawing features including 3D model import and GLSL shaders.",
|
||||
build_tools::ProjectType_GUIApp::getTypeName(),
|
||||
BinaryData::wizard_OpenGL_svg,
|
||||
addAndReturn (getModulesRequiredForComponent(), "juce_gui_extra", "juce_opengl"),
|
||||
{
|
||||
{ FileCreationOptions::header, { { "Main.cpp", "jucer_MainTemplate_Window_cpp" },
|
||||
{ "MainComponent.h", "jucer_AudioComponentSimpleTemplate_h" } } },
|
||||
{ FileCreationOptions::headerAndCpp, { { "Main.cpp", "jucer_MainTemplate_Window_cpp" },
|
||||
{ "MainComponent.h", "jucer_OpenGLComponentTemplate_h" },
|
||||
{ "MainComponent.cpp", "jucer_OpenGLComponentTemplate_cpp" } } }
|
||||
},
|
||||
FileCreationOptions::headerAndCpp },
|
||||
|
||||
{ ProjectCategory::plugin,
|
||||
"Basic", "Creates an audio plug-in with a single window GUI and audio/MIDI IO functions.",
|
||||
build_tools::ProjectType_AudioPlugin::getTypeName(),
|
||||
BinaryData::wizard_AudioPlugin_svg,
|
||||
getModulesRequiredForAudioProcessor(),
|
||||
{
|
||||
{ FileCreationOptions::processorAndEditor, { { "PluginProcessor.cpp", "jucer_AudioPluginFilterTemplate_cpp" },
|
||||
{ "PluginProcessor.h", "jucer_AudioPluginFilterTemplate_h" },
|
||||
{ "PluginEditor.cpp", "jucer_AudioPluginEditorTemplate_cpp" },
|
||||
{ "PluginEditor.h", "jucer_AudioPluginEditorTemplate_h" } } }
|
||||
},
|
||||
FileCreationOptions::processorAndEditor
|
||||
},
|
||||
|
||||
{ ProjectCategory::library,
|
||||
"Static Library", "Creates a static library.",
|
||||
build_tools::ProjectType_StaticLibrary::getTypeName(),
|
||||
BinaryData::wizard_StaticLibrary_svg,
|
||||
getModulesRequiredForConsole(),
|
||||
{},
|
||||
FileCreationOptions::noFiles
|
||||
},
|
||||
|
||||
{ ProjectCategory::library,
|
||||
"Dynamic Library", "Creates a dynamic library.",
|
||||
build_tools::ProjectType_DLL::getTypeName(),
|
||||
BinaryData::wizard_DLL_svg,
|
||||
getModulesRequiredForConsole(),
|
||||
{},
|
||||
FileCreationOptions::noFiles
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
310
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.cpp
vendored
Normal file
310
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.cpp
vendored
Normal file
@ -0,0 +1,310 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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_Headers.h"
|
||||
#include "../jucer_Application.h"
|
||||
#include "../../ProjectSaving/jucer_ProjectExporter.h"
|
||||
|
||||
#include "jucer_NewProjectWizard.h"
|
||||
|
||||
//==============================================================================
|
||||
static String getFileTemplate (const String& templateName)
|
||||
{
|
||||
int dataSize = 0;
|
||||
|
||||
if (auto* data = BinaryData::getNamedResource (templateName.toUTF8(), dataSize))
|
||||
return String::fromUTF8 (data, dataSize);
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
static String getJuceHeaderInclude()
|
||||
{
|
||||
return CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename());
|
||||
}
|
||||
|
||||
static String getContentComponentName()
|
||||
{
|
||||
return "MainComponent";
|
||||
}
|
||||
|
||||
using Opts = NewProjectTemplates::FileCreationOptions;
|
||||
|
||||
static bool shouldCreateHeaderFile (Opts opts) noexcept { return opts == Opts::header || opts == Opts::headerAndCpp; }
|
||||
static bool shouldCreateCppFile (Opts opts) noexcept { return opts == Opts::headerAndCpp; }
|
||||
|
||||
static void doBasicProjectSetup (Project& project, const NewProjectTemplates::ProjectTemplate& projectTemplate, const String& name)
|
||||
{
|
||||
project.setTitle (name);
|
||||
project.setProjectType (projectTemplate.projectTypeString);
|
||||
project.getMainGroup().addNewSubGroup ("Source", 0);
|
||||
|
||||
project.getConfigFlag ("JUCE_STRICT_REFCOUNTEDPOINTER") = true;
|
||||
project.getProjectValue (Ids::useAppConfig) = false;
|
||||
project.getProjectValue (Ids::addUsingNamespaceToJuceHeader) = false;
|
||||
|
||||
if (! ProjucerApplication::getApp().getLicenseController().getCurrentState().canUnlockFullFeatures())
|
||||
project.getProjectValue (Ids::displaySplashScreen) = true;
|
||||
|
||||
if (NewProjectTemplates::isPlugin (projectTemplate))
|
||||
project.getConfigFlag ("JUCE_VST3_CAN_REPLACE_VST2") = 0;
|
||||
}
|
||||
|
||||
static std::map<String, String> getSharedFileTokenReplacements()
|
||||
{
|
||||
return { { "%%app_headers%%", getJuceHeaderInclude() } };
|
||||
}
|
||||
|
||||
static std::map<String, String> getApplicationFileTokenReplacements (const String& name,
|
||||
NewProjectTemplates::FileCreationOptions fileOptions,
|
||||
const File& sourceFolder)
|
||||
{
|
||||
auto tokenReplacements = getSharedFileTokenReplacements();
|
||||
|
||||
tokenReplacements.insert ({ "%%app_class_name%%",
|
||||
build_tools::makeValidIdentifier (name + "Application", false, true, false) });
|
||||
tokenReplacements.insert ({ "%%content_component_class%%",
|
||||
getContentComponentName() });
|
||||
tokenReplacements.insert ({ "%%include_juce%%",
|
||||
getJuceHeaderInclude() });
|
||||
|
||||
if (shouldCreateHeaderFile (fileOptions))
|
||||
tokenReplacements["%%app_headers%%"] << newLine
|
||||
<< CodeHelpers::createIncludeStatement (sourceFolder.getChildFile ("MainComponent.h"),
|
||||
sourceFolder.getChildFile ("Main.cpp"));
|
||||
|
||||
if (shouldCreateCppFile (fileOptions))
|
||||
tokenReplacements.insert ({ "%%include_corresponding_header%%",
|
||||
CodeHelpers::createIncludeStatement (sourceFolder.getChildFile ("MainComponent.h"),
|
||||
sourceFolder.getChildFile ("MainComponent.cpp")) });
|
||||
|
||||
return tokenReplacements;
|
||||
}
|
||||
|
||||
static std::map<String, String> getPluginFileTokenReplacements (const String& name,
|
||||
const File& sourceFolder)
|
||||
{
|
||||
auto tokenReplacements = getSharedFileTokenReplacements();
|
||||
|
||||
auto processorCppFile = sourceFolder.getChildFile ("PluginProcessor.cpp");
|
||||
auto processorHFile = processorCppFile.withFileExtension (".h");
|
||||
auto editorCppFile = sourceFolder.getChildFile ("PluginEditor.cpp");
|
||||
auto editorHFile = editorCppFile.withFileExtension (".h");
|
||||
|
||||
auto processorHInclude = CodeHelpers::createIncludeStatement (processorHFile, processorCppFile);
|
||||
auto editorHInclude = CodeHelpers::createIncludeStatement (editorHFile, processorCppFile);
|
||||
|
||||
auto processorClassName = build_tools::makeValidIdentifier (name, false, true, false) + "AudioProcessor";
|
||||
processorClassName = processorClassName.substring (0, 1).toUpperCase() + processorClassName.substring (1);
|
||||
auto editorClassName = processorClassName + "Editor";
|
||||
|
||||
tokenReplacements.insert ({"%%filter_headers%%", processorHInclude + newLine + editorHInclude });
|
||||
tokenReplacements.insert ({"%%filter_class_name%%", processorClassName });
|
||||
tokenReplacements.insert ({"%%editor_class_name%%", editorClassName });
|
||||
tokenReplacements.insert ({"%%editor_cpp_headers%%", processorHInclude + newLine + editorHInclude });
|
||||
tokenReplacements.insert ({"%%editor_headers%%", getJuceHeaderInclude() + newLine + processorHInclude });
|
||||
|
||||
return tokenReplacements;
|
||||
}
|
||||
|
||||
static bool addFiles (Project& project, const NewProjectTemplates::ProjectTemplate& projectTemplate,
|
||||
const String& name, var fileOptionsVar, StringArray& failedFiles)
|
||||
{
|
||||
auto sourceFolder = project.getFile().getSiblingFile ("Source");
|
||||
|
||||
if (! sourceFolder.createDirectory())
|
||||
{
|
||||
failedFiles.add (sourceFolder.getFullPathName());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto fileOptions = NewProjectTemplates::getFileOptionForVar (fileOptionsVar);
|
||||
|
||||
if (fileOptions == Opts::noFiles)
|
||||
return true;
|
||||
|
||||
auto tokenReplacements = [&]() -> std::map<String, String>
|
||||
{
|
||||
if (NewProjectTemplates::isApplication (projectTemplate))
|
||||
return getApplicationFileTokenReplacements (name, fileOptions, sourceFolder);
|
||||
|
||||
if (NewProjectTemplates::isPlugin (projectTemplate))
|
||||
return getPluginFileTokenReplacements (name, sourceFolder);
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}();
|
||||
|
||||
auto sourceGroup = project.getMainGroup().getOrCreateSubGroup ("Source");
|
||||
|
||||
for (auto& files : projectTemplate.getFilesForOption (fileOptions))
|
||||
{
|
||||
auto file = sourceFolder.getChildFile (files.first);
|
||||
auto fileContent = getFileTemplate (files.second);
|
||||
|
||||
for (auto& tokenReplacement : tokenReplacements)
|
||||
fileContent = fileContent.replace (tokenReplacement.first, tokenReplacement.second, false);
|
||||
|
||||
if (! build_tools::overwriteFileWithNewDataIfDifferent (file, fileContent))
|
||||
{
|
||||
failedFiles.add (file.getFullPathName());
|
||||
return false;
|
||||
}
|
||||
|
||||
sourceGroup.addFileAtIndex (file, -1, (file.hasFileExtension (sourceFileExtensions)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void addModules (Project& project, Array<var> modules, const String& modulePath, bool useGlobalPath)
|
||||
{
|
||||
AvailableModulesList list;
|
||||
list.scanPaths ({ modulePath });
|
||||
|
||||
auto& projectModules = project.getEnabledModules();
|
||||
|
||||
for (auto& mod : list.getAllModules())
|
||||
if (modules.contains (mod.first))
|
||||
projectModules.addModule (mod.second, false, useGlobalPath);
|
||||
|
||||
for (auto& mod : projectModules.getModulesWithMissingDependencies())
|
||||
projectModules.tryToFixMissingDependencies (mod);
|
||||
}
|
||||
|
||||
static void addExporters (Project& project, Array<var> exporters)
|
||||
{
|
||||
for (auto exporter : exporters)
|
||||
project.addNewExporter (exporter.toString());
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
for (ProjectExporter::ConfigIterator config (*exporter); config.next();)
|
||||
config->getValue (Ids::targetName) = project.getProjectFilenameRootString();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
File NewProjectWizard::getLastWizardFolder()
|
||||
{
|
||||
if (getAppSettings().lastWizardFolder.isDirectory())
|
||||
return getAppSettings().lastWizardFolder;
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
static File lastFolderFallback (File::getSpecialLocation (File::userDocumentsDirectory));
|
||||
#else
|
||||
static File lastFolderFallback (File::getSpecialLocation (File::userHomeDirectory));
|
||||
#endif
|
||||
|
||||
return lastFolderFallback;
|
||||
}
|
||||
|
||||
static void displayFailedFilesMessage (const StringArray& failedFiles)
|
||||
{
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
|
||||
TRANS("Errors in Creating Project!"),
|
||||
TRANS("The following files couldn't be written:")
|
||||
+ "\n\n"
|
||||
+ failedFiles.joinIntoString ("\n", 0, 10));
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
static void prepareDirectory (const File& targetFolder, Callback&& callback)
|
||||
{
|
||||
StringArray failedFiles;
|
||||
|
||||
if (! targetFolder.exists())
|
||||
{
|
||||
if (! targetFolder.createDirectory())
|
||||
{
|
||||
displayFailedFilesMessage ({ targetFolder.getFullPathName() });
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder))
|
||||
{
|
||||
AlertWindow::showOkCancelBox (MessageBoxIconType::InfoIcon,
|
||||
TRANS("New JUCE Project"),
|
||||
TRANS("You chose the folder:\n\nXFLDRX\n\n").replace ("XFLDRX", targetFolder.getFullPathName())
|
||||
+ TRANS("This folder isn't empty - are you sure you want to create the project there?")
|
||||
+ "\n\n"
|
||||
+ TRANS("Any existing files with the same names may be overwritten by the new files."),
|
||||
{},
|
||||
{},
|
||||
nullptr,
|
||||
ModalCallbackFunction::create ([callback] (int result)
|
||||
{
|
||||
if (result != 0)
|
||||
callback();
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
|
||||
void NewProjectWizard::createNewProject (const NewProjectTemplates::ProjectTemplate& projectTemplate,
|
||||
const File& targetFolder, const String& name, var modules, var exporters, var fileOptions,
|
||||
const String& modulePath, bool useGlobalModulePath,
|
||||
std::function<void (std::unique_ptr<Project>)> callback)
|
||||
{
|
||||
prepareDirectory (targetFolder, [=]
|
||||
{
|
||||
auto project = std::make_unique<Project> (targetFolder.getChildFile (File::createLegalFileName (name))
|
||||
.withFileExtension (Project::projectFileExtension));
|
||||
|
||||
doBasicProjectSetup (*project, projectTemplate, name);
|
||||
|
||||
StringArray failedFiles;
|
||||
|
||||
if (addFiles (*project, projectTemplate, name, fileOptions, failedFiles))
|
||||
{
|
||||
addExporters (*project, *exporters.getArray());
|
||||
addModules (*project, *modules.getArray(), modulePath, useGlobalModulePath);
|
||||
|
||||
auto sharedProject = std::make_shared<std::unique_ptr<Project>> (std::move (project));
|
||||
(*sharedProject)->saveAsync (false, true, [sharedProject, failedFiles, callback] (FileBasedDocument::SaveResult r)
|
||||
{
|
||||
auto uniqueProject = std::move (*sharedProject.get());
|
||||
|
||||
if (r == FileBasedDocument::savedOk)
|
||||
{
|
||||
uniqueProject->setChangedFlag (false);
|
||||
uniqueProject->loadFrom (uniqueProject->getFile(), true);
|
||||
callback (std::move (uniqueProject));
|
||||
return;
|
||||
}
|
||||
|
||||
auto failedFilesCopy = failedFiles;
|
||||
failedFilesCopy.add (uniqueProject->getFile().getFullPathName());
|
||||
displayFailedFilesMessage (failedFilesCopy);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
displayFailedFilesMessage (failedFiles);
|
||||
});
|
||||
}
|
39
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.h
vendored
Normal file
39
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.h
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_NewProjectTemplates.h"
|
||||
|
||||
//==============================================================================
|
||||
namespace NewProjectWizard
|
||||
{
|
||||
File getLastWizardFolder();
|
||||
|
||||
void createNewProject (const NewProjectTemplates::ProjectTemplate& projectTemplate,
|
||||
const File& targetFolder, const String& name, var modules, var exporters, var fileOptions,
|
||||
const String& modulePath, bool useGlobalModulePath,
|
||||
std::function<void (std::unique_ptr<Project>)> callback);
|
||||
}
|
288
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_StartPageComponent.cpp
vendored
Normal file
288
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_StartPageComponent.cpp
vendored
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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_Headers.h"
|
||||
#include "../jucer_Application.h"
|
||||
|
||||
#include "jucer_StartPageComponent.h"
|
||||
#include "jucer_StartPageTreeHolder.h"
|
||||
#include "jucer_NewProjectTemplates.h"
|
||||
#include "jucer_ContentComponents.h"
|
||||
|
||||
//==============================================================================
|
||||
struct ContentComponent : public Component
|
||||
{
|
||||
ContentComponent()
|
||||
{
|
||||
setTitle ("Content");
|
||||
setFocusContainerType (FocusContainerType::focusContainer);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
if (content != nullptr)
|
||||
content->setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
void setContent (std::unique_ptr<Component>&& newContent)
|
||||
{
|
||||
if (content.get() != newContent.get())
|
||||
{
|
||||
content = std::move (newContent);
|
||||
addAndMakeVisible (content.get());
|
||||
resized();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Component> content;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_LEAK_DETECTOR (ContentComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static File findExampleFile (int dirIndex, int index)
|
||||
{
|
||||
auto dir = ProjucerApplication::getSortedExampleDirectories()[dirIndex];
|
||||
return ProjucerApplication::getSortedExampleFilesInDirectory (dir)[index];
|
||||
}
|
||||
|
||||
static std::unique_ptr<Component> createExampleProjectsTab (ContentComponent& content, std::function<void (const File&)> cb)
|
||||
{
|
||||
StringArray exampleCategories;
|
||||
std::vector<StringArray> examples;
|
||||
|
||||
for (auto& dir : ProjucerApplication::getSortedExampleDirectories())
|
||||
{
|
||||
exampleCategories.add (dir.getFileName());
|
||||
|
||||
StringArray ex;
|
||||
for (auto& f : ProjucerApplication::getSortedExampleFilesInDirectory (dir))
|
||||
ex.add (f.getFileNameWithoutExtension());
|
||||
|
||||
examples.push_back (ex);
|
||||
}
|
||||
|
||||
if (exampleCategories.isEmpty())
|
||||
return nullptr;
|
||||
|
||||
auto selectedCallback = [&, cb] (int category, int index) mutable
|
||||
{
|
||||
content.setContent (std::make_unique<ExampleComponent> (findExampleFile (category, index), cb));
|
||||
};
|
||||
|
||||
return std::make_unique<StartPageTreeHolder> ("Examples",
|
||||
exampleCategories,
|
||||
examples,
|
||||
std::move (selectedCallback),
|
||||
StartPageTreeHolder::Open::no);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static StringArray getAllTemplateCategoryStrings()
|
||||
{
|
||||
StringArray categories;
|
||||
|
||||
for (auto& t : NewProjectTemplates::getAllTemplates())
|
||||
categories.addIfNotAlreadyThere (NewProjectTemplates::getProjectCategoryString (t.category));
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
static std::vector<NewProjectTemplates::ProjectTemplate> getTemplatesInCategory (const String& category)
|
||||
{
|
||||
std::vector<NewProjectTemplates::ProjectTemplate> templates;
|
||||
|
||||
for (auto& t : NewProjectTemplates::getAllTemplates())
|
||||
if (NewProjectTemplates::getProjectCategoryString (t.category) == category)
|
||||
templates.push_back (t);
|
||||
|
||||
return templates;
|
||||
}
|
||||
|
||||
static StringArray getAllTemplateNamesForCategory (const String& category)
|
||||
{
|
||||
StringArray types;
|
||||
|
||||
for (auto& t : getTemplatesInCategory (category))
|
||||
types.add (t.displayName);
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Component> createProjectTemplatesTab (ContentComponent& content,
|
||||
std::function<void (std::unique_ptr<Project>&&)>&& cb)
|
||||
{
|
||||
auto categories = getAllTemplateCategoryStrings();
|
||||
|
||||
std::vector<StringArray> templateNames;
|
||||
|
||||
for (auto& c : categories)
|
||||
templateNames.push_back (getAllTemplateNamesForCategory (c));
|
||||
|
||||
auto selectedCallback = [&, cb] (int category, int index)
|
||||
{
|
||||
auto categoryString = getAllTemplateCategoryStrings()[category];
|
||||
auto templates = getTemplatesInCategory (categoryString);
|
||||
|
||||
content.setContent (std::make_unique<TemplateComponent> (templates[(size_t) index], std::move (cb)));
|
||||
};
|
||||
|
||||
auto holder = std::make_unique<StartPageTreeHolder> ("Templates",
|
||||
categories,
|
||||
templateNames,
|
||||
std::move (selectedCallback),
|
||||
StartPageTreeHolder::Open::yes);
|
||||
holder->setSelectedItem (categories[0], 1);
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move")
|
||||
return std::move (holder);
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct ProjectTemplatesAndExamples : public TabbedComponent
|
||||
{
|
||||
ProjectTemplatesAndExamples (ContentComponent& c,
|
||||
std::function<void (std::unique_ptr<Project>&&)>&& newProjectCb,
|
||||
std::function<void (const File&)>&& exampleCb)
|
||||
: TabbedComponent (TabbedButtonBar::Orientation::TabsAtTop),
|
||||
content (c),
|
||||
exampleSelectedCallback (std::move (exampleCb))
|
||||
{
|
||||
setTitle ("Templates and Examples");
|
||||
setFocusContainerType (FocusContainerType::focusContainer);
|
||||
|
||||
addTab ("New Project",
|
||||
Colours::transparentBlack,
|
||||
createProjectTemplatesTab (content, std::move (newProjectCb)).release(),
|
||||
true);
|
||||
|
||||
refreshExamplesTab();
|
||||
}
|
||||
|
||||
void refreshExamplesTab()
|
||||
{
|
||||
auto wasOpen = (getCurrentTabIndex() == 1);
|
||||
|
||||
removeTab (1);
|
||||
|
||||
auto exampleTabs = createExampleProjectsTab (content, exampleSelectedCallback);
|
||||
|
||||
addTab ("Open Example",
|
||||
Colours::transparentBlack,
|
||||
exampleTabs == nullptr ? new SetJUCEPathComponent (*this) : exampleTabs.release(),
|
||||
true);
|
||||
|
||||
if (wasOpen)
|
||||
setCurrentTabIndex (1);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct SetJUCEPathComponent : public Component,
|
||||
private ChangeListener
|
||||
{
|
||||
explicit SetJUCEPathComponent (ProjectTemplatesAndExamples& o)
|
||||
: owner (o)
|
||||
{
|
||||
getGlobalProperties().addChangeListener (this);
|
||||
|
||||
setPathButton.setButtonText ("Set path to JUCE...");
|
||||
setPathButton.onClick = [] { ProjucerApplication::getApp().showPathsWindow (true); };
|
||||
|
||||
addAndMakeVisible (setPathButton);
|
||||
}
|
||||
|
||||
~SetJUCEPathComponent() override
|
||||
{
|
||||
getGlobalProperties().removeChangeListener (this);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (5);
|
||||
bounds.removeFromTop (25);
|
||||
|
||||
setPathButton.setBounds (bounds.removeFromTop (25));
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
if (isValidJUCEExamplesDirectory (ProjucerApplication::getJUCEExamplesDirectoryPathFromGlobal()))
|
||||
owner.refreshExamplesTab();
|
||||
}
|
||||
|
||||
ProjectTemplatesAndExamples& owner;
|
||||
TextButton setPathButton;
|
||||
};
|
||||
|
||||
ContentComponent& content;
|
||||
std::function<void (const File&)> exampleSelectedCallback;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
StartPageComponent::StartPageComponent (std::function<void (std::unique_ptr<Project>&&)>&& newProjectCb,
|
||||
std::function<void (const File&)>&& exampleCb)
|
||||
: content (std::make_unique<ContentComponent>()),
|
||||
tabs (std::make_unique<ProjectTemplatesAndExamples> (*content, std::move (newProjectCb), std::move (exampleCb)))
|
||||
{
|
||||
tabs->setOutline (0);
|
||||
addAndMakeVisible (*tabs);
|
||||
|
||||
addAndMakeVisible (openExistingButton);
|
||||
openExistingButton.setCommandToTrigger (&ProjucerApplication::getCommandManager(), CommandIDs::open, true);
|
||||
|
||||
addAndMakeVisible (*content);
|
||||
|
||||
setSize (900, 600);
|
||||
}
|
||||
|
||||
void StartPageComponent::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (findColour (backgroundColourId));
|
||||
}
|
||||
|
||||
void StartPageComponent::resized()
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (10);
|
||||
|
||||
auto tabBounds = bounds.removeFromLeft (bounds.getWidth() / 3);
|
||||
|
||||
openExistingButton.setBounds (tabBounds.removeFromBottom (30).reduced (10, 0));
|
||||
tabBounds.removeFromBottom (5);
|
||||
|
||||
tabs->setBounds (tabBounds);
|
||||
bounds.removeFromLeft (10);
|
||||
|
||||
content->setBounds (bounds);
|
||||
}
|
50
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_StartPageComponent.h
vendored
Normal file
50
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_StartPageComponent.h
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ContentComponent;
|
||||
struct ProjectTemplatesAndExamples;
|
||||
|
||||
//==============================================================================
|
||||
class StartPageComponent : public Component
|
||||
{
|
||||
public:
|
||||
StartPageComponent (std::function<void (std::unique_ptr<Project>&&)>&& newProjectCb,
|
||||
std::function<void (const File&)>&& exampleCb);
|
||||
|
||||
void paint (Graphics& g) override;
|
||||
void resized() override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
std::unique_ptr<ContentComponent> content;
|
||||
std::unique_ptr<ProjectTemplatesAndExamples> tabs;
|
||||
|
||||
TextButton openExistingButton { "Open Existing Project..." };
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StartPageComponent)
|
||||
};
|
182
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_StartPageTreeHolder.h
vendored
Normal file
182
deps/juce/extras/Projucer/Source/Application/StartPage/jucer_StartPageTreeHolder.h
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//==============================================================================
|
||||
class StartPageTreeHolder : public Component
|
||||
{
|
||||
public:
|
||||
enum class Open { no, yes };
|
||||
|
||||
StartPageTreeHolder (const String& title,
|
||||
const StringArray& headerNames,
|
||||
const std::vector<StringArray>& itemNames,
|
||||
std::function<void (int, int)>&& selectedCallback,
|
||||
Open shouldBeOpen)
|
||||
: headers (headerNames),
|
||||
items (itemNames),
|
||||
itemSelectedCallback (std::move (selectedCallback))
|
||||
{
|
||||
jassert (headers.size() == (int) items.size());
|
||||
|
||||
tree.setTitle (title);
|
||||
tree.setRootItem (new TreeRootItem (*this));
|
||||
tree.setRootItemVisible (false);
|
||||
tree.setIndentSize (15);
|
||||
tree.setDefaultOpenness (shouldBeOpen == Open::yes);
|
||||
|
||||
addAndMakeVisible (tree);
|
||||
}
|
||||
|
||||
~StartPageTreeHolder() override
|
||||
{
|
||||
tree.deleteRootItem();
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
tree.setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
void setSelectedItem (const String& category, int index)
|
||||
{
|
||||
auto* root = tree.getRootItem();
|
||||
|
||||
for (int i = root->getNumSubItems(); --i >=0;)
|
||||
{
|
||||
if (auto* item = root->getSubItem (i))
|
||||
{
|
||||
if (item->getUniqueName() == category)
|
||||
item->getSubItem (index)->setSelected (true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class TreeSubItem : public TreeViewItem
|
||||
{
|
||||
public:
|
||||
TreeSubItem (StartPageTreeHolder& o, const String& n, const StringArray& subItemsIn)
|
||||
: owner (o), name (n), isHeader (subItemsIn.size() > 0)
|
||||
{
|
||||
for (auto& s : subItemsIn)
|
||||
addSubItem (new TreeSubItem (owner, s, {}));
|
||||
}
|
||||
|
||||
bool mightContainSubItems() override { return isHeader; }
|
||||
bool canBeSelected() const override { return ! isHeader; }
|
||||
|
||||
int getItemWidth() const override { return -1; }
|
||||
int getItemHeight() const override { return 25; }
|
||||
|
||||
String getUniqueName() const override { return name; }
|
||||
String getAccessibilityName() override { return getUniqueName(); }
|
||||
|
||||
void paintOpenCloseButton (Graphics& g, const Rectangle<float>& area, Colour, bool isMouseOver) override
|
||||
{
|
||||
g.setColour (getOwnerView()->findColour (isSelected() ? defaultHighlightedTextColourId
|
||||
: treeIconColourId));
|
||||
|
||||
TreeViewItem::paintOpenCloseButton (g, area, getOwnerView()->findColour (defaultIconColourId), isMouseOver);
|
||||
}
|
||||
|
||||
void paintItem (Graphics& g, int w, int h) override
|
||||
{
|
||||
Rectangle<int> bounds (w, h);
|
||||
|
||||
auto shouldBeHighlighted = isSelected();
|
||||
|
||||
if (shouldBeHighlighted)
|
||||
{
|
||||
g.setColour (getOwnerView()->findColour (defaultHighlightColourId));
|
||||
g.fillRect (bounds);
|
||||
}
|
||||
|
||||
g.setColour (shouldBeHighlighted ? getOwnerView()->findColour (defaultHighlightedTextColourId)
|
||||
: getOwnerView()->findColour (defaultTextColourId));
|
||||
|
||||
g.drawFittedText (name, bounds.reduced (5).withTrimmedLeft (10), Justification::centredLeft, 1);
|
||||
}
|
||||
|
||||
void itemClicked (const MouseEvent& e) override
|
||||
{
|
||||
if (isSelected())
|
||||
itemSelectionChanged (true);
|
||||
|
||||
if (e.mods.isPopupMenu() && mightContainSubItems())
|
||||
setOpen (! isOpen());
|
||||
}
|
||||
|
||||
void itemSelectionChanged (bool isNowSelected) override
|
||||
{
|
||||
jassert (! isHeader);
|
||||
|
||||
if (isNowSelected)
|
||||
owner.itemSelectedCallback (getParentItem()->getIndexInParent(), getIndexInParent());
|
||||
}
|
||||
|
||||
private:
|
||||
StartPageTreeHolder& owner;
|
||||
String name;
|
||||
bool isHeader = false;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeSubItem)
|
||||
};
|
||||
|
||||
struct TreeRootItem : public TreeViewItem
|
||||
{
|
||||
explicit TreeRootItem (StartPageTreeHolder& o)
|
||||
: owner (o)
|
||||
{
|
||||
for (int i = 0; i < owner.headers.size(); ++i)
|
||||
addSubItem (new TreeSubItem (owner, owner.headers[i], owner.items[(size_t) i]));
|
||||
}
|
||||
|
||||
bool mightContainSubItems() override { return ! owner.headers.isEmpty();}
|
||||
|
||||
StartPageTreeHolder& owner;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeRootItem)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
TreeView tree;
|
||||
StringArray headers;
|
||||
std::vector<StringArray> items;
|
||||
|
||||
std::function<void (int, int)> itemSelectedCallback;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StartPageTreeHolder)
|
||||
};
|
224
deps/juce/extras/Projucer/Source/Application/UserAccount/jucer_LicenseController.h
vendored
Normal file
224
deps/juce/extras/Projucer/Source/Application/UserAccount/jucer_LicenseController.h
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_LicenseState.h"
|
||||
#include "jucer_LicenseQueryThread.h"
|
||||
|
||||
//==============================================================================
|
||||
class LicenseController : private Timer
|
||||
{
|
||||
public:
|
||||
LicenseController()
|
||||
{
|
||||
checkLicense();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static LicenseState getGPLState()
|
||||
{
|
||||
return { LicenseState::Type::gpl, projucerMajorVersion, {}, {} };
|
||||
}
|
||||
|
||||
LicenseState getCurrentState() const noexcept
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
void setState (const LicenseState& newState)
|
||||
{
|
||||
if (state != newState)
|
||||
{
|
||||
state = newState;
|
||||
licenseStateToSettings (state, getGlobalProperties());
|
||||
|
||||
stateListeners.call ([] (LicenseStateListener& l) { l.licenseStateChanged(); });
|
||||
}
|
||||
}
|
||||
|
||||
void resetState()
|
||||
{
|
||||
setState ({});
|
||||
}
|
||||
|
||||
void signIn (const String& email, const String& password,
|
||||
std::function<void (const String&)> completionCallback)
|
||||
{
|
||||
licenseQueryThread.doSignIn (email, password,
|
||||
[this, completionCallback] (LicenseQueryThread::ErrorMessageAndType error,
|
||||
LicenseState newState)
|
||||
{
|
||||
completionCallback (error.first);
|
||||
setState (newState);
|
||||
});
|
||||
}
|
||||
|
||||
void cancelSignIn()
|
||||
{
|
||||
licenseQueryThread.cancelRunningJobs();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct LicenseStateListener
|
||||
{
|
||||
virtual ~LicenseStateListener() = default;
|
||||
virtual void licenseStateChanged() = 0;
|
||||
};
|
||||
|
||||
void addListener (LicenseStateListener* listenerToAdd)
|
||||
{
|
||||
stateListeners.add (listenerToAdd);
|
||||
}
|
||||
|
||||
void removeListener (LicenseStateListener* listenerToRemove)
|
||||
{
|
||||
stateListeners.remove (listenerToRemove);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
static const char* getLicenseStateValue (LicenseState::Type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LicenseState::Type::gpl: return "GPL";
|
||||
case LicenseState::Type::personal: return "personal";
|
||||
case LicenseState::Type::educational: return "edu";
|
||||
case LicenseState::Type::indie: return "indie";
|
||||
case LicenseState::Type::pro: return "pro";
|
||||
case LicenseState::Type::none:
|
||||
default: break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static LicenseState::Type getLicenseTypeFromValue (const String& d)
|
||||
{
|
||||
if (d == getLicenseStateValue (LicenseState::Type::gpl)) return LicenseState::Type::gpl;
|
||||
if (d == getLicenseStateValue (LicenseState::Type::personal)) return LicenseState::Type::personal;
|
||||
if (d == getLicenseStateValue (LicenseState::Type::educational)) return LicenseState::Type::educational;
|
||||
if (d == getLicenseStateValue (LicenseState::Type::indie)) return LicenseState::Type::indie;
|
||||
if (d == getLicenseStateValue (LicenseState::Type::pro)) return LicenseState::Type::pro;
|
||||
return LicenseState::Type::none;
|
||||
}
|
||||
|
||||
static LicenseState licenseStateFromSettings (PropertiesFile& props)
|
||||
{
|
||||
if (auto licenseXml = props.getXmlValue ("license"))
|
||||
{
|
||||
// this is here for backwards compatibility with old-style settings files using XML text elements
|
||||
if (licenseXml->getChildElementAllSubText ("type", {}).isNotEmpty())
|
||||
{
|
||||
auto stateFromOldSettings = [&licenseXml]() -> LicenseState
|
||||
{
|
||||
return { getLicenseTypeFromValue (licenseXml->getChildElementAllSubText ("type", {})),
|
||||
licenseXml->getChildElementAllSubText ("version", "-1").getIntValue(),
|
||||
licenseXml->getChildElementAllSubText ("username", {}),
|
||||
licenseXml->getChildElementAllSubText ("authToken", {}) };
|
||||
}();
|
||||
|
||||
licenseStateToSettings (stateFromOldSettings, props);
|
||||
|
||||
return stateFromOldSettings;
|
||||
}
|
||||
|
||||
return { getLicenseTypeFromValue (licenseXml->getStringAttribute ("type", {})),
|
||||
licenseXml->getIntAttribute ("version", -1),
|
||||
licenseXml->getStringAttribute ("username", {}),
|
||||
licenseXml->getStringAttribute ("authToken", {}) };
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static void licenseStateToSettings (const LicenseState& state, PropertiesFile& props)
|
||||
{
|
||||
props.removeValue ("license");
|
||||
|
||||
if (state.isSignedIn())
|
||||
{
|
||||
XmlElement licenseXml ("license");
|
||||
|
||||
if (auto* typeString = getLicenseStateValue (state.type))
|
||||
licenseXml.setAttribute ("type", typeString);
|
||||
|
||||
licenseXml.setAttribute ("version", state.version);
|
||||
licenseXml.setAttribute ("username", state.username);
|
||||
licenseXml.setAttribute ("authToken", state.authToken);
|
||||
|
||||
props.setValue ("license", &licenseXml);
|
||||
}
|
||||
|
||||
props.saveIfNeeded();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void checkLicense()
|
||||
{
|
||||
if (state.authToken.isNotEmpty() && ! state.isGPL())
|
||||
{
|
||||
auto completionCallback = [this] (LicenseQueryThread::ErrorMessageAndType error,
|
||||
LicenseState updatedState)
|
||||
{
|
||||
if (error == LicenseQueryThread::ErrorMessageAndType())
|
||||
{
|
||||
setState (updatedState);
|
||||
}
|
||||
else if ((error.second == LicenseQueryThread::ErrorType::busy
|
||||
|| error.second == LicenseQueryThread::ErrorType::cancelled
|
||||
|| error.second == LicenseQueryThread::ErrorType::connectionError)
|
||||
&& ! hasRetriedLicenseCheck)
|
||||
{
|
||||
hasRetriedLicenseCheck = true;
|
||||
startTimer (10000);
|
||||
}
|
||||
};
|
||||
|
||||
licenseQueryThread.checkLicenseValidity (state, std::move (completionCallback));
|
||||
}
|
||||
}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
stopTimer();
|
||||
checkLicense();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCER_ENABLE_GPL_MODE
|
||||
LicenseState state = getGPLState();
|
||||
#else
|
||||
LicenseState state = licenseStateFromSettings (getGlobalProperties());
|
||||
#endif
|
||||
|
||||
ListenerList<LicenseStateListener> stateListeners;
|
||||
LicenseQueryThread licenseQueryThread;
|
||||
bool hasRetriedLicenseCheck = false;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LicenseController)
|
||||
};
|
371
deps/juce/extras/Projucer/Source/Application/UserAccount/jucer_LicenseQueryThread.h
vendored
Normal file
371
deps/juce/extras/Projucer/Source/Application/UserAccount/jucer_LicenseQueryThread.h
vendored
Normal file
@ -0,0 +1,371 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//==============================================================================
|
||||
namespace LicenseHelpers
|
||||
{
|
||||
inline LicenseState::Type licenseTypeForString (const String& licenseString)
|
||||
{
|
||||
if (licenseString == "juce-pro") return LicenseState::Type::pro;
|
||||
if (licenseString == "juce-indie") return LicenseState::Type::indie;
|
||||
if (licenseString == "juce-edu") return LicenseState::Type::educational;
|
||||
if (licenseString == "juce-personal") return LicenseState::Type::personal;
|
||||
|
||||
jassertfalse; // unknown type
|
||||
return LicenseState::Type::none;
|
||||
}
|
||||
|
||||
using LicenseVersionAndType = std::pair<int, LicenseState::Type>;
|
||||
|
||||
inline LicenseVersionAndType findBestLicense (std::vector<LicenseVersionAndType>&& licenses)
|
||||
{
|
||||
if (licenses.size() == 1)
|
||||
return licenses[0];
|
||||
|
||||
auto getValueForLicenceType = [] (LicenseState::Type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LicenseState::Type::pro: return 4;
|
||||
case LicenseState::Type::indie: return 3;
|
||||
case LicenseState::Type::educational: return 2;
|
||||
case LicenseState::Type::personal: return 1;
|
||||
case LicenseState::Type::gpl:
|
||||
case LicenseState::Type::none:
|
||||
default: return -1;
|
||||
}
|
||||
};
|
||||
|
||||
std::sort (licenses.begin(), licenses.end(),
|
||||
[getValueForLicenceType] (const LicenseVersionAndType& l1, const LicenseVersionAndType& l2)
|
||||
{
|
||||
if (l1.first > l2.first)
|
||||
return true;
|
||||
|
||||
if (l1.first == l2.first)
|
||||
return getValueForLicenceType (l1.second) > getValueForLicenceType (l2.second);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
auto findFirstLicense = [&licenses] (bool isPaid)
|
||||
{
|
||||
auto iter = std::find_if (licenses.begin(), licenses.end(),
|
||||
[isPaid] (const LicenseVersionAndType& l)
|
||||
{
|
||||
auto proOrIndie = (l.second == LicenseState::Type::pro || l.second == LicenseState::Type::indie);
|
||||
return isPaid ? proOrIndie : ! proOrIndie;
|
||||
});
|
||||
|
||||
return iter != licenses.end() ? *iter
|
||||
: LicenseVersionAndType();
|
||||
};
|
||||
|
||||
auto newestPaid = findFirstLicense (true);
|
||||
auto newestFree = findFirstLicense (false);
|
||||
|
||||
if (newestPaid.first >= projucerMajorVersion || newestPaid.first >= newestFree.first)
|
||||
return newestPaid;
|
||||
|
||||
return newestFree;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class LicenseQueryThread
|
||||
{
|
||||
public:
|
||||
enum class ErrorType
|
||||
{
|
||||
busy,
|
||||
cancelled,
|
||||
connectionError,
|
||||
webResponseError
|
||||
};
|
||||
|
||||
using ErrorMessageAndType = std::pair<String, ErrorType>;
|
||||
using LicenseQueryCallback = std::function<void (ErrorMessageAndType, LicenseState)>;
|
||||
|
||||
//==============================================================================
|
||||
LicenseQueryThread() = default;
|
||||
|
||||
void checkLicenseValidity (const LicenseState& state, LicenseQueryCallback completionCallback)
|
||||
{
|
||||
if (jobPool.getNumJobs() > 0)
|
||||
{
|
||||
completionCallback ({ {}, ErrorType::busy }, {});
|
||||
return;
|
||||
}
|
||||
|
||||
jobPool.addJob ([this, state, completionCallback]
|
||||
{
|
||||
auto updatedState = state;
|
||||
|
||||
auto result = runTask (std::make_unique<UserLicenseQuery> (state.authToken), updatedState);
|
||||
|
||||
WeakReference<LicenseQueryThread> weakThis (this);
|
||||
MessageManager::callAsync ([weakThis, result, updatedState, completionCallback]
|
||||
{
|
||||
if (weakThis != nullptr)
|
||||
completionCallback (result, updatedState);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void doSignIn (const String& email, const String& password, LicenseQueryCallback completionCallback)
|
||||
{
|
||||
cancelRunningJobs();
|
||||
|
||||
jobPool.addJob ([this, email, password, completionCallback]
|
||||
{
|
||||
LicenseState state;
|
||||
|
||||
auto result = runTask (std::make_unique<UserLogin> (email, password), state);
|
||||
|
||||
if (result == ErrorMessageAndType())
|
||||
result = runTask (std::make_unique<UserLicenseQuery> (state.authToken), state);
|
||||
|
||||
if (result != ErrorMessageAndType())
|
||||
state = {};
|
||||
|
||||
WeakReference<LicenseQueryThread> weakThis (this);
|
||||
MessageManager::callAsync ([weakThis, result, state, completionCallback]
|
||||
{
|
||||
if (weakThis != nullptr)
|
||||
completionCallback (result, state);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void cancelRunningJobs()
|
||||
{
|
||||
jobPool.removeAllJobs (true, 500);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct AccountEnquiryBase
|
||||
{
|
||||
virtual ~AccountEnquiryBase() = default;
|
||||
|
||||
virtual bool isPOSTLikeRequest() const = 0;
|
||||
virtual String getEndpointURLSuffix() const = 0;
|
||||
virtual StringPairArray getParameterNamesAndValues() const = 0;
|
||||
virtual String getExtraHeaders() const = 0;
|
||||
virtual int getSuccessCode() const = 0;
|
||||
virtual String errorCodeToString (int) const = 0;
|
||||
virtual bool parseServerResponse (const String&, LicenseState&) = 0;
|
||||
};
|
||||
|
||||
struct UserLogin : public AccountEnquiryBase
|
||||
{
|
||||
UserLogin (const String& e, const String& p)
|
||||
: userEmail (e), userPassword (p)
|
||||
{
|
||||
}
|
||||
|
||||
bool isPOSTLikeRequest() const override { return true; }
|
||||
String getEndpointURLSuffix() const override { return "/authenticate/projucer"; }
|
||||
int getSuccessCode() const override { return 200; }
|
||||
|
||||
StringPairArray getParameterNamesAndValues() const override
|
||||
{
|
||||
StringPairArray namesAndValues;
|
||||
namesAndValues.set ("email", userEmail);
|
||||
namesAndValues.set ("password", userPassword);
|
||||
|
||||
return namesAndValues;
|
||||
}
|
||||
|
||||
String getExtraHeaders() const override
|
||||
{
|
||||
return "Content-Type: application/json";
|
||||
}
|
||||
|
||||
String errorCodeToString (int errorCode) const override
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case 400: return "Please enter your email and password to sign in.";
|
||||
case 401: return "Your email and password are incorrect.";
|
||||
case 451: return "Access denied.";
|
||||
default: return "Something went wrong, please try again.";
|
||||
}
|
||||
}
|
||||
|
||||
bool parseServerResponse (const String& serverResponse, LicenseState& licenseState) override
|
||||
{
|
||||
auto json = JSON::parse (serverResponse);
|
||||
|
||||
licenseState.authToken = json.getProperty ("token", {}).toString();
|
||||
licenseState.username = json.getProperty ("user", {}).getProperty ("username", {}).toString();
|
||||
|
||||
return (licenseState.authToken.isNotEmpty() && licenseState.username.isNotEmpty());
|
||||
}
|
||||
|
||||
String userEmail, userPassword;
|
||||
};
|
||||
|
||||
struct UserLicenseQuery : public AccountEnquiryBase
|
||||
{
|
||||
UserLicenseQuery (const String& authToken)
|
||||
: userAuthToken (authToken)
|
||||
{
|
||||
}
|
||||
|
||||
bool isPOSTLikeRequest() const override { return false; }
|
||||
String getEndpointURLSuffix() const override { return "/user/licences/projucer"; }
|
||||
int getSuccessCode() const override { return 200; }
|
||||
|
||||
StringPairArray getParameterNamesAndValues() const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
String getExtraHeaders() const override
|
||||
{
|
||||
return "x-access-token: " + userAuthToken;
|
||||
}
|
||||
|
||||
String errorCodeToString (int errorCode) const override
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case 401: return "User not found or could not be verified.";
|
||||
default: return "User licenses info fetch failed (unknown error).";
|
||||
}
|
||||
}
|
||||
|
||||
bool parseServerResponse (const String& serverResponse, LicenseState& licenseState) override
|
||||
{
|
||||
auto json = JSON::parse (serverResponse);
|
||||
|
||||
if (auto* licensesJson = json.getArray())
|
||||
{
|
||||
std::vector<LicenseHelpers::LicenseVersionAndType> licenses;
|
||||
|
||||
for (auto& license : *licensesJson)
|
||||
{
|
||||
auto version = license.getProperty ("product_version", {}).toString().trim();
|
||||
auto type = license.getProperty ("licence_type", {}).toString();
|
||||
auto status = license.getProperty ("status", {}).toString();
|
||||
|
||||
if (status == "active" && type.isNotEmpty() && version.isNotEmpty())
|
||||
licenses.push_back ({ version.getIntValue(), LicenseHelpers::licenseTypeForString (type) });
|
||||
}
|
||||
|
||||
if (! licenses.empty())
|
||||
{
|
||||
auto bestLicense = LicenseHelpers::findBestLicense (std::move (licenses));
|
||||
|
||||
licenseState.version = bestLicense.first;
|
||||
licenseState.type = bestLicense.second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String userAuthToken;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static String postDataStringAsJSON (const StringPairArray& parameters)
|
||||
{
|
||||
DynamicObject::Ptr d (new DynamicObject());
|
||||
|
||||
for (auto& key : parameters.getAllKeys())
|
||||
d->setProperty (key, parameters[key]);
|
||||
|
||||
return JSON::toString (var (d.get()));
|
||||
}
|
||||
|
||||
static ErrorMessageAndType runTask (std::unique_ptr<AccountEnquiryBase> accountEnquiryTask, LicenseState& state)
|
||||
{
|
||||
const ErrorMessageAndType cancelledError ("Cancelled.", ErrorType::cancelled);
|
||||
const String endpointURL ("https://api.juce.com/api/v1");
|
||||
|
||||
URL url (endpointURL + accountEnquiryTask->getEndpointURLSuffix());
|
||||
|
||||
auto isPOST = accountEnquiryTask->isPOSTLikeRequest();
|
||||
|
||||
if (isPOST)
|
||||
url = url.withPOSTData (postDataStringAsJSON (accountEnquiryTask->getParameterNamesAndValues()));
|
||||
|
||||
if (ThreadPoolJob::getCurrentThreadPoolJob()->shouldExit())
|
||||
return cancelledError;
|
||||
|
||||
int statusCode = 0;
|
||||
auto urlStream = url.createInputStream (URL::InputStreamOptions (isPOST ? URL::ParameterHandling::inPostData
|
||||
: URL::ParameterHandling::inAddress)
|
||||
.withExtraHeaders (accountEnquiryTask->getExtraHeaders())
|
||||
.withConnectionTimeoutMs (5000)
|
||||
.withStatusCode (&statusCode));
|
||||
|
||||
if (urlStream == nullptr)
|
||||
return { "Failed to connect to the web server.", ErrorType::connectionError };
|
||||
|
||||
if (statusCode != accountEnquiryTask->getSuccessCode())
|
||||
return { accountEnquiryTask->errorCodeToString (statusCode), ErrorType::webResponseError };
|
||||
|
||||
if (ThreadPoolJob::getCurrentThreadPoolJob()->shouldExit())
|
||||
return cancelledError;
|
||||
|
||||
String response;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char buffer [8192] = "";
|
||||
auto num = urlStream->read (buffer, sizeof (buffer));
|
||||
|
||||
if (ThreadPoolJob::getCurrentThreadPoolJob()->shouldExit())
|
||||
return cancelledError;
|
||||
|
||||
if (num <= 0)
|
||||
break;
|
||||
|
||||
response += buffer;
|
||||
}
|
||||
|
||||
if (ThreadPoolJob::getCurrentThreadPoolJob()->shouldExit())
|
||||
return cancelledError;
|
||||
|
||||
if (! accountEnquiryTask->parseServerResponse (response, state))
|
||||
return { "Failed to parse server response.", ErrorType::webResponseError };
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ThreadPool jobPool { 1 };
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (LicenseQueryThread)
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LicenseQueryThread)
|
||||
};
|
91
deps/juce/extras/Projucer/Source/Application/UserAccount/jucer_LicenseState.h
vendored
Normal file
91
deps/juce/extras/Projucer/Source/Application/UserAccount/jucer_LicenseState.h
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct LicenseState
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
none,
|
||||
gpl,
|
||||
personal,
|
||||
educational,
|
||||
indie,
|
||||
pro
|
||||
};
|
||||
|
||||
LicenseState() = default;
|
||||
|
||||
LicenseState (Type t, int v, String user, String token)
|
||||
: type (t), version (v), username (user), authToken (token)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator== (const LicenseState& other) const noexcept
|
||||
{
|
||||
return type == other.type
|
||||
&& version == other.version
|
||||
&& username == other.username
|
||||
&& authToken == other.authToken;
|
||||
}
|
||||
|
||||
bool operator != (const LicenseState& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
bool isSignedIn() const noexcept { return isGPL() || (version > 0 && username.isNotEmpty()); }
|
||||
bool isOldLicense() const noexcept { return isSignedIn() && version < projucerMajorVersion; }
|
||||
bool isGPL() const noexcept { return type == Type::gpl; }
|
||||
|
||||
bool canUnlockFullFeatures() const noexcept
|
||||
{
|
||||
return isGPL() || (isSignedIn() && ! isOldLicense() && (type == Type::indie || type == Type::pro));
|
||||
}
|
||||
|
||||
String getLicenseTypeString() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Type::none: return "No license";
|
||||
case Type::gpl: return "GPL";
|
||||
case Type::personal: return "Personal";
|
||||
case Type::educational: return "Educational";
|
||||
case Type::indie: return "Indie";
|
||||
case Type::pro: return "Pro";
|
||||
default: break;
|
||||
};
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
Type type = Type::none;
|
||||
int version = -1;
|
||||
String username, authToken;
|
||||
};
|
283
deps/juce/extras/Projucer/Source/Application/UserAccount/jucer_LoginFormComponent.h
vendored
Normal file
283
deps/juce/extras/Projucer/Source/Application/UserAccount/jucer_LoginFormComponent.h
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../../Project/UI/jucer_UserAvatarComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
class LoginFormComponent : public Component
|
||||
{
|
||||
public:
|
||||
LoginFormComponent (MainWindow& window)
|
||||
: mainWindow (window)
|
||||
{
|
||||
setTitle ("Login");
|
||||
setFocusContainerType (FocusContainerType::focusContainer);
|
||||
|
||||
addAndMakeVisible (emailBox);
|
||||
emailBox.setTextToShowWhenEmpty ("Email", Colours::black.withAlpha (0.2f));
|
||||
emailBox.setJustification (Justification::centredLeft);
|
||||
emailBox.onReturnKey = [this] { submitDetails(); };
|
||||
emailBox.setTitle ("Email");
|
||||
|
||||
addAndMakeVisible (passwordBox);
|
||||
passwordBox.setTextToShowWhenEmpty ("Password", Colours::black.withAlpha (0.2f));
|
||||
passwordBox.setPasswordCharacter ((juce_wchar) 0x2022);
|
||||
passwordBox.setJustification (Justification::centredLeft);
|
||||
passwordBox.onReturnKey = [this] { submitDetails(); };
|
||||
passwordBox.setTitle ("Password");
|
||||
|
||||
addAndMakeVisible (logInButton);
|
||||
logInButton.onClick = [this] { submitDetails(); };
|
||||
|
||||
addAndMakeVisible (enableGPLButton);
|
||||
enableGPLButton.onClick = [this]
|
||||
{
|
||||
ProjucerApplication::getApp().getLicenseController().setState (LicenseController::getGPLState());
|
||||
mainWindow.hideLoginFormOverlay();
|
||||
};
|
||||
|
||||
addAndMakeVisible (userAvatar);
|
||||
|
||||
addAndMakeVisible (createAccountLabel);
|
||||
createAccountLabel.setFont (Font (14.0f, Font::underlined));
|
||||
createAccountLabel.addMouseListener (this, false);
|
||||
createAccountLabel.setMouseCursor (MouseCursor::PointingHandCursor);
|
||||
|
||||
addAndMakeVisible (errorMessageLabel);
|
||||
errorMessageLabel.setMinimumHorizontalScale (1.0f);
|
||||
errorMessageLabel.setFont (12.0f);
|
||||
errorMessageLabel.setColour (Label::textColourId, Colours::red);
|
||||
errorMessageLabel.setVisible (false);
|
||||
|
||||
dismissButton.setShape (getLookAndFeel().getCrossShape (1.0f), false, true, false);
|
||||
addAndMakeVisible (dismissButton);
|
||||
dismissButton.onClick = [this] { mainWindow.hideLoginFormOverlay(); };
|
||||
dismissButton.setTitle ("Dismiss");
|
||||
|
||||
setWantsKeyboardFocus (true);
|
||||
setOpaque (true);
|
||||
|
||||
lookAndFeelChanged();
|
||||
|
||||
setSize (300, 350);
|
||||
}
|
||||
|
||||
~LoginFormComponent() override
|
||||
{
|
||||
ProjucerApplication::getApp().getLicenseController().cancelSignIn();
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (20);
|
||||
auto spacing = bounds.getHeight() / 20;
|
||||
|
||||
userAvatar.setBounds (bounds.removeFromTop (iconHeight).reduced ((bounds.getWidth() / 2) - (iconHeight / 2), 0));
|
||||
|
||||
errorMessageLabel.setBounds (bounds.removeFromTop (spacing));
|
||||
bounds.removeFromTop (spacing / 2);
|
||||
|
||||
auto textEditorHeight = bounds.getHeight() / 5;
|
||||
|
||||
emailBox.setBounds (bounds.removeFromTop (textEditorHeight));
|
||||
bounds.removeFromTop (spacing);
|
||||
|
||||
passwordBox.setBounds (bounds.removeFromTop (textEditorHeight));
|
||||
bounds.removeFromTop (spacing * 2);
|
||||
|
||||
emailBox.setFont (Font ((float) textEditorHeight / 2.5f));
|
||||
passwordBox.setFont (Font ((float) textEditorHeight / 2.5f));
|
||||
|
||||
logInButton.setBounds (bounds.removeFromTop (textEditorHeight));
|
||||
|
||||
auto slice = bounds.removeFromTop (textEditorHeight);
|
||||
createAccountLabel.setBounds (slice.removeFromLeft (createAccountLabel.getFont().getStringWidth (createAccountLabel.getText()) + 5));
|
||||
slice.removeFromLeft (15);
|
||||
enableGPLButton.setBounds (slice.reduced (0, 5));
|
||||
|
||||
dismissButton.setBounds (getLocalBounds().reduced (10).removeFromTop (20).removeFromRight (20));
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId).contrasting (0.1f));
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent& event) override
|
||||
{
|
||||
if (event.eventComponent == &createAccountLabel)
|
||||
URL ("https://juce.com/verification/register").launchInDefaultBrowser();
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
enableGPLButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
|
||||
}
|
||||
|
||||
private:
|
||||
class ProgressButton : public TextButton,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
ProgressButton (const String& buttonName)
|
||||
: TextButton (buttonName), text (buttonName)
|
||||
{
|
||||
}
|
||||
|
||||
void setBusy (bool shouldBeBusy)
|
||||
{
|
||||
isInProgress = shouldBeBusy;
|
||||
|
||||
if (isInProgress)
|
||||
{
|
||||
setEnabled (false);
|
||||
setButtonText ({});
|
||||
startTimerHz (30);
|
||||
}
|
||||
else
|
||||
{
|
||||
setEnabled (true);
|
||||
setButtonText (text);
|
||||
stopTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
TextButton::paint (g);
|
||||
|
||||
if (isInProgress)
|
||||
{
|
||||
auto size = getHeight() - 10;
|
||||
auto halfSize = size / 2;
|
||||
|
||||
getLookAndFeel().drawSpinningWaitAnimation (g, Colours::white,
|
||||
(getWidth() / 2) - halfSize, (getHeight() / 2) - halfSize,
|
||||
size, size);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void timerCallback() override
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
String text;
|
||||
bool isInProgress = false;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void updateLoginButtonStates (bool isLoggingIn)
|
||||
{
|
||||
logInButton.setBusy (isLoggingIn);
|
||||
|
||||
emailBox.setEnabled (! isLoggingIn);
|
||||
passwordBox.setEnabled (! isLoggingIn);
|
||||
}
|
||||
|
||||
void submitDetails()
|
||||
{
|
||||
auto loginFormError = checkLoginFormsAreValid();
|
||||
|
||||
if (loginFormError.isNotEmpty())
|
||||
{
|
||||
showErrorMessage (loginFormError);
|
||||
return;
|
||||
}
|
||||
|
||||
updateLoginButtonStates (true);
|
||||
|
||||
auto completionCallback = [weakThis = SafePointer<LoginFormComponent> { this }] (const String& errorMessage)
|
||||
{
|
||||
if (weakThis == nullptr)
|
||||
return;
|
||||
|
||||
weakThis->updateLoginButtonStates (false);
|
||||
|
||||
if (errorMessage.isNotEmpty())
|
||||
{
|
||||
weakThis->showErrorMessage (errorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
weakThis->hideErrorMessage();
|
||||
weakThis->mainWindow.hideLoginFormOverlay();
|
||||
ProjucerApplication::getApp().getCommandManager().commandStatusChanged();
|
||||
}
|
||||
};
|
||||
|
||||
ProjucerApplication::getApp().getLicenseController().signIn (emailBox.getText(), passwordBox.getText(),
|
||||
std::move (completionCallback));
|
||||
}
|
||||
|
||||
String checkLoginFormsAreValid() const
|
||||
{
|
||||
auto email = emailBox.getText();
|
||||
|
||||
if (email.isEmpty() || email.indexOfChar ('@') < 0)
|
||||
return "Please enter a valid email.";
|
||||
|
||||
auto password = passwordBox.getText();
|
||||
|
||||
if (password.isEmpty() || password.length() < 8)
|
||||
return "Please enter a valid password.";
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void showErrorMessage (const String& errorMessage)
|
||||
{
|
||||
errorMessageLabel.setText (errorMessage, dontSendNotification);
|
||||
errorMessageLabel.setVisible (true);
|
||||
}
|
||||
|
||||
void hideErrorMessage()
|
||||
{
|
||||
errorMessageLabel.setText ({}, dontSendNotification);
|
||||
errorMessageLabel.setVisible (false);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static constexpr int iconHeight = 50;
|
||||
|
||||
MainWindow& mainWindow;
|
||||
|
||||
TextEditor emailBox, passwordBox;
|
||||
ProgressButton logInButton { "Sign In" };
|
||||
TextButton enableGPLButton { "Enable GPL Mode" };
|
||||
ShapeButton dismissButton { {},
|
||||
findColour (treeIconColourId),
|
||||
findColour (treeIconColourId).overlaidWith (findColour (defaultHighlightedTextColourId).withAlpha (0.2f)),
|
||||
findColour (treeIconColourId).overlaidWith (findColour (defaultHighlightedTextColourId).withAlpha (0.4f)) };
|
||||
UserAvatarComponent userAvatar { false };
|
||||
Label createAccountLabel { {}, "Create an account" },
|
||||
errorMessageLabel { {}, {} };
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LoginFormComponent)
|
||||
};
|
103
deps/juce/extras/Projucer/Source/Application/Windows/jucer_AboutWindowComponent.h
vendored
Normal file
103
deps/juce/extras/Projucer/Source/Application/Windows/jucer_AboutWindowComponent.h
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class AboutWindowComponent : public Component
|
||||
{
|
||||
public:
|
||||
AboutWindowComponent()
|
||||
{
|
||||
addAndMakeVisible (titleLabel);
|
||||
titleLabel.setJustificationType (Justification::centred);
|
||||
titleLabel.setFont (Font (35.0f, Font::FontStyleFlags::bold));
|
||||
|
||||
auto buildDate = Time::getCompilationDate();
|
||||
addAndMakeVisible (versionLabel);
|
||||
versionLabel.setText ("JUCE v" + ProjucerApplication::getApp().getApplicationVersion()
|
||||
+ "\nBuild date: " + String (buildDate.getDayOfMonth())
|
||||
+ " " + Time::getMonthName (buildDate.getMonth(), true)
|
||||
+ " " + String (buildDate.getYear()),
|
||||
dontSendNotification);
|
||||
|
||||
versionLabel.setJustificationType (Justification::centred);
|
||||
addAndMakeVisible (copyrightLabel);
|
||||
copyrightLabel.setJustificationType (Justification::centred);
|
||||
|
||||
addAndMakeVisible (aboutButton);
|
||||
aboutButton.setTooltip ( {} );
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
bounds.removeFromBottom (20);
|
||||
|
||||
auto leftSlice = bounds.removeFromLeft (150);
|
||||
auto centreSlice = bounds.withTrimmedRight (150);
|
||||
|
||||
juceLogoBounds = leftSlice.removeFromTop (150).toFloat();
|
||||
juceLogoBounds.setWidth (juceLogoBounds.getWidth() + 100);
|
||||
juceLogoBounds.setHeight (juceLogoBounds.getHeight() + 100);
|
||||
|
||||
auto titleHeight = 40;
|
||||
|
||||
centreSlice.removeFromTop ((centreSlice.getHeight() / 2) - (titleHeight / 2));
|
||||
|
||||
titleLabel.setBounds (centreSlice.removeFromTop (titleHeight));
|
||||
|
||||
centreSlice.removeFromTop (10);
|
||||
versionLabel.setBounds (centreSlice.removeFromTop (40));
|
||||
|
||||
centreSlice.removeFromTop (10);
|
||||
aboutButton.setBounds (centreSlice.removeFromTop (20));
|
||||
|
||||
copyrightLabel.setBounds (getLocalBounds().removeFromBottom (50));
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (backgroundColourId));
|
||||
|
||||
if (juceLogo != nullptr)
|
||||
juceLogo->drawWithin (g, juceLogoBounds.translated (-75, -75), RectanglePlacement::centred, 1.0);
|
||||
}
|
||||
|
||||
private:
|
||||
Label titleLabel { "title", "PROJUCER" },
|
||||
versionLabel { "version" },
|
||||
copyrightLabel { "copyright", String (CharPointer_UTF8 ("\xc2\xa9")) + String (" 2020 Raw Material Software Limited") };
|
||||
|
||||
HyperlinkButton aboutButton { "About Us", URL ("https://juce.com") };
|
||||
|
||||
Rectangle<float> juceLogoBounds;
|
||||
|
||||
std::unique_ptr<Drawable> juceLogo { Drawable::createFromImageData (BinaryData::juce_icon_png,
|
||||
BinaryData::juce_icon_pngSize) };
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AboutWindowComponent)
|
||||
};
|
347
deps/juce/extras/Projucer/Source/Application/Windows/jucer_EditorColourSchemeWindowComponent.h
vendored
Normal file
347
deps/juce/extras/Projucer/Source/Application/Windows/jucer_EditorColourSchemeWindowComponent.h
vendored
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Utility/UI/PropertyComponents/jucer_ColourPropertyComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
class EditorColourSchemeWindowComponent : public Component
|
||||
{
|
||||
public:
|
||||
EditorColourSchemeWindowComponent()
|
||||
{
|
||||
if (getAppSettings().monospacedFontNames.size() == 0)
|
||||
changeContent (new AppearanceEditor::FontScanPanel());
|
||||
else
|
||||
changeContent (new AppearanceEditor::EditorPanel());
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (backgroundColourId));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
content->setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
void changeContent (Component* newContent)
|
||||
{
|
||||
content.reset (newContent);
|
||||
addAndMakeVisible (newContent);
|
||||
content->setBounds (getLocalBounds().reduced (10));
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Component> content;
|
||||
|
||||
//==============================================================================
|
||||
struct AppearanceEditor
|
||||
{
|
||||
struct FontScanPanel : public Component,
|
||||
private Timer
|
||||
{
|
||||
FontScanPanel()
|
||||
{
|
||||
fontsToScan = Font::findAllTypefaceNames();
|
||||
startTimer (1);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (backgroundColourId));
|
||||
|
||||
g.setFont (14.0f);
|
||||
g.setColour (findColour (defaultTextColourId));
|
||||
g.drawFittedText ("Scanning for fonts..", getLocalBounds(), Justification::centred, 2);
|
||||
|
||||
const auto size = 30;
|
||||
getLookAndFeel().drawSpinningWaitAnimation (g, Colours::white, (getWidth() - size) / 2, getHeight() / 2 - 50, size, size);
|
||||
}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
repaint();
|
||||
|
||||
if (fontsToScan.size() == 0)
|
||||
{
|
||||
getAppSettings().monospacedFontNames = fontsFound;
|
||||
|
||||
if (auto* owner = findParentComponentOfClass<EditorColourSchemeWindowComponent>())
|
||||
owner->changeContent (new EditorPanel());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isMonospacedTypeface (fontsToScan[0]))
|
||||
fontsFound.add (fontsToScan[0]);
|
||||
|
||||
fontsToScan.remove (0);
|
||||
}
|
||||
}
|
||||
|
||||
// A rather hacky trick to select only the fixed-pitch fonts..
|
||||
// This is unfortunately a bit slow, but will work on all platforms.
|
||||
static bool isMonospacedTypeface (const String& name)
|
||||
{
|
||||
const Font font (name, 20.0f, Font::plain);
|
||||
|
||||
const auto width = font.getStringWidth ("....");
|
||||
|
||||
return width == font.getStringWidth ("WWWW")
|
||||
&& width == font.getStringWidth ("0000")
|
||||
&& width == font.getStringWidth ("1111")
|
||||
&& width == font.getStringWidth ("iiii");
|
||||
}
|
||||
|
||||
StringArray fontsToScan, fontsFound;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct EditorPanel : public Component
|
||||
{
|
||||
EditorPanel()
|
||||
: loadButton ("Load Scheme..."),
|
||||
saveButton ("Save Scheme...")
|
||||
{
|
||||
rebuildProperties();
|
||||
addAndMakeVisible (panel);
|
||||
|
||||
addAndMakeVisible (loadButton);
|
||||
addAndMakeVisible (saveButton);
|
||||
|
||||
loadButton.onClick = [this] { loadScheme(); };
|
||||
saveButton.onClick = [this] { saveScheme (false); };
|
||||
|
||||
lookAndFeelChanged();
|
||||
|
||||
saveSchemeState();
|
||||
}
|
||||
|
||||
~EditorPanel() override
|
||||
{
|
||||
if (hasSchemeBeenModifiedSinceSave())
|
||||
saveScheme (true);
|
||||
}
|
||||
|
||||
void rebuildProperties()
|
||||
{
|
||||
auto& scheme = getAppSettings().appearance;
|
||||
|
||||
Array<PropertyComponent*> props;
|
||||
auto fontValue = scheme.getCodeFontValue();
|
||||
props.add (FontNameValueSource::createProperty ("Code Editor Font", fontValue));
|
||||
props.add (FontSizeValueSource::createProperty ("Font Size", fontValue));
|
||||
|
||||
const auto colourNames = scheme.getColourNames();
|
||||
|
||||
for (int i = 0; i < colourNames.size(); ++i)
|
||||
props.add (new ColourPropertyComponent (nullptr, colourNames[i],
|
||||
scheme.getColourValue (colourNames[i]),
|
||||
Colours::white, false));
|
||||
|
||||
panel.clear();
|
||||
panel.addProperties (props);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto r = getLocalBounds();
|
||||
panel.setBounds (r.removeFromTop (getHeight() - 28).reduced (10, 2));
|
||||
loadButton.setBounds (r.removeFromLeft (getWidth() / 2).reduced (10, 1));
|
||||
saveButton.setBounds (r.reduced (10, 1));
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyPanel panel;
|
||||
TextButton loadButton, saveButton;
|
||||
|
||||
Font codeFont;
|
||||
Array<var> colourValues;
|
||||
|
||||
void saveScheme (bool isExit)
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Select a file in which to save this colour-scheme...",
|
||||
getAppSettings().appearance.getSchemesFolder()
|
||||
.getNonexistentChildFile ("Scheme", AppearanceSettings::getSchemeFileSuffix()),
|
||||
AppearanceSettings::getSchemeFileWildCard());
|
||||
auto chooserFlags = FileBrowserComponent::saveMode
|
||||
| FileBrowserComponent::canSelectFiles
|
||||
| FileBrowserComponent::warnAboutOverwriting;
|
||||
|
||||
chooser->launchAsync (chooserFlags, [this, isExit] (const FileChooser& fc)
|
||||
{
|
||||
if (fc.getResult() == File{})
|
||||
{
|
||||
if (isExit)
|
||||
restorePreviousScheme();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
File file (fc.getResult().withFileExtension (AppearanceSettings::getSchemeFileSuffix()));
|
||||
getAppSettings().appearance.writeToFile (file);
|
||||
getAppSettings().appearance.refreshPresetSchemeList();
|
||||
|
||||
saveSchemeState();
|
||||
ProjucerApplication::getApp().selectEditorColourSchemeWithName (file.getFileNameWithoutExtension());
|
||||
});
|
||||
}
|
||||
|
||||
void loadScheme()
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Please select a colour-scheme file to load...",
|
||||
getAppSettings().appearance.getSchemesFolder(),
|
||||
AppearanceSettings::getSchemeFileWildCard());
|
||||
auto chooserFlags = FileBrowserComponent::openMode
|
||||
| FileBrowserComponent::canSelectFiles;
|
||||
|
||||
chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
|
||||
{
|
||||
if (fc.getResult() == File{})
|
||||
return;
|
||||
|
||||
if (getAppSettings().appearance.readFromFile (fc.getResult()))
|
||||
{
|
||||
rebuildProperties();
|
||||
saveSchemeState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
loadButton.setColour (TextButton::buttonColourId,
|
||||
findColour (secondaryButtonBackgroundColourId));
|
||||
}
|
||||
|
||||
void saveSchemeState()
|
||||
{
|
||||
auto& appearance = getAppSettings().appearance;
|
||||
const auto colourNames = appearance.getColourNames();
|
||||
|
||||
codeFont = appearance.getCodeFont();
|
||||
|
||||
colourValues.clear();
|
||||
for (int i = 0; i < colourNames.size(); ++i)
|
||||
colourValues.add (appearance.getColourValue (colourNames[i]).getValue());
|
||||
}
|
||||
|
||||
bool hasSchemeBeenModifiedSinceSave()
|
||||
{
|
||||
auto& appearance = getAppSettings().appearance;
|
||||
const auto colourNames = appearance.getColourNames();
|
||||
|
||||
if (codeFont != appearance.getCodeFont())
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < colourNames.size(); ++i)
|
||||
if (colourValues[i] != appearance.getColourValue (colourNames[i]).getValue())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void restorePreviousScheme()
|
||||
{
|
||||
auto& appearance = getAppSettings().appearance;
|
||||
const auto colourNames = appearance.getColourNames();
|
||||
|
||||
appearance.getCodeFontValue().setValue (codeFont.toString());
|
||||
|
||||
for (int i = 0; i < colourNames.size(); ++i)
|
||||
appearance.getColourValue (colourNames[i]).setValue (colourValues[i]);
|
||||
}
|
||||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (EditorPanel)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct FontNameValueSource : public ValueSourceFilter
|
||||
{
|
||||
FontNameValueSource (const Value& source) : ValueSourceFilter (source) {}
|
||||
|
||||
var getValue() const override
|
||||
{
|
||||
return Font::fromString (sourceValue.toString()).getTypefaceName();
|
||||
}
|
||||
|
||||
void setValue (const var& newValue) override
|
||||
{
|
||||
auto font = Font::fromString (sourceValue.toString());
|
||||
font.setTypefaceName (newValue.toString().isEmpty() ? Font::getDefaultMonospacedFontName()
|
||||
: newValue.toString());
|
||||
sourceValue = font.toString();
|
||||
}
|
||||
|
||||
static ChoicePropertyComponent* createProperty (const String& title, const Value& value)
|
||||
{
|
||||
auto fontNames = getAppSettings().monospacedFontNames;
|
||||
|
||||
Array<var> values;
|
||||
values.add (Font::getDefaultMonospacedFontName());
|
||||
values.add (var());
|
||||
|
||||
for (int i = 0; i < fontNames.size(); ++i)
|
||||
values.add (fontNames[i]);
|
||||
|
||||
StringArray names;
|
||||
names.add ("<Default Monospaced>");
|
||||
names.add (String());
|
||||
names.addArray (getAppSettings().monospacedFontNames);
|
||||
|
||||
return new ChoicePropertyComponent (Value (new FontNameValueSource (value)),
|
||||
title, names, values);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct FontSizeValueSource : public ValueSourceFilter
|
||||
{
|
||||
FontSizeValueSource (const Value& source) : ValueSourceFilter (source) {}
|
||||
|
||||
var getValue() const override
|
||||
{
|
||||
return Font::fromString (sourceValue.toString()).getHeight();
|
||||
}
|
||||
|
||||
void setValue (const var& newValue) override
|
||||
{
|
||||
sourceValue = Font::fromString (sourceValue.toString()).withHeight (newValue).toString();
|
||||
}
|
||||
|
||||
static PropertyComponent* createProperty (const String& title, const Value& value)
|
||||
{
|
||||
return new SliderPropertyComponent (Value (new FontSizeValueSource (value)),
|
||||
title, 5.0, 40.0, 0.1, 0.5);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EditorColourSchemeWindowComponent)
|
||||
};
|
89
deps/juce/extras/Projucer/Source/Application/Windows/jucer_FloatingToolWindow.h
vendored
Normal file
89
deps/juce/extras/Projucer/Source/Application/Windows/jucer_FloatingToolWindow.h
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct FloatingToolWindow : public DialogWindow
|
||||
{
|
||||
FloatingToolWindow (const String& title,
|
||||
const String& windowPosPropertyName,
|
||||
Component* content,
|
||||
std::unique_ptr<Component>& ownerPointer,
|
||||
bool shouldBeResizable,
|
||||
int defaultW, int defaultH,
|
||||
int minW, int minH,
|
||||
int maxW, int maxH)
|
||||
: DialogWindow (title, content->findColour (secondaryBackgroundColourId), true, true),
|
||||
windowPosProperty (windowPosPropertyName),
|
||||
owner (ownerPointer)
|
||||
{
|
||||
setUsingNativeTitleBar (true);
|
||||
setResizable (shouldBeResizable, shouldBeResizable);
|
||||
setResizeLimits (minW, minH, maxW, maxH);
|
||||
setContentOwned (content, false);
|
||||
|
||||
String windowState;
|
||||
if (windowPosProperty.isNotEmpty())
|
||||
windowState = getGlobalProperties().getValue (windowPosProperty);
|
||||
|
||||
if (windowState.isNotEmpty())
|
||||
restoreWindowStateFromString (windowState);
|
||||
else
|
||||
centreAroundComponent (Component::getCurrentlyFocusedComponent(), defaultW, defaultH);
|
||||
|
||||
setVisible (true);
|
||||
owner.reset (this);
|
||||
}
|
||||
|
||||
~FloatingToolWindow() override
|
||||
{
|
||||
if (windowPosProperty.isNotEmpty())
|
||||
getGlobalProperties().setValue (windowPosProperty, getWindowStateAsString());
|
||||
}
|
||||
|
||||
void closeButtonPressed() override
|
||||
{
|
||||
owner.reset();
|
||||
}
|
||||
|
||||
bool escapeKeyPressed() override
|
||||
{
|
||||
closeButtonPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
private:
|
||||
String windowPosProperty;
|
||||
std::unique_ptr<Component>& owner;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FloatingToolWindow)
|
||||
};
|
318
deps/juce/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h
vendored
Normal file
318
deps/juce/extras/Projucer/Source/Application/Windows/jucer_GlobalPathsWindowComponent.h
vendored
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Utility/UI/PropertyComponents/jucer_LabelPropertyComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
class GlobalPathsWindowComponent : public Component,
|
||||
private Timer,
|
||||
private Value::Listener,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
GlobalPathsWindowComponent()
|
||||
{
|
||||
addChildComponent (rescanJUCEPathButton);
|
||||
rescanJUCEPathButton.onClick = [this]
|
||||
{
|
||||
ProjucerApplication::getApp().rescanJUCEPathModules();
|
||||
lastJUCEModulePath = getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).get();
|
||||
};
|
||||
|
||||
addChildComponent (rescanUserPathButton);
|
||||
rescanUserPathButton.onClick = [this]
|
||||
{
|
||||
ProjucerApplication::getApp().rescanUserPathModules();
|
||||
lastUserModulePath = getAppSettings().getStoredPath (Ids::defaultUserModulePath, TargetOS::getThisOS()).get();
|
||||
};
|
||||
|
||||
addChildComponent (warnAboutJUCEPathButton);
|
||||
warnAboutJUCEPathButton.setToggleState (ProjucerApplication::getApp().shouldPromptUserAboutIncorrectJUCEPath(),
|
||||
dontSendNotification);
|
||||
warnAboutJUCEPathButton.onClick = [this]
|
||||
{
|
||||
ProjucerApplication::getApp().setShouldPromptUserAboutIncorrectJUCEPath (warnAboutJUCEPathButton.getToggleState());
|
||||
};
|
||||
|
||||
getGlobalProperties().addChangeListener (this);
|
||||
|
||||
addAndMakeVisible (resetToDefaultsButton);
|
||||
resetToDefaultsButton.onClick = [this] { resetCurrentOSPathsToDefaults(); };
|
||||
|
||||
addAndMakeVisible (propertyViewport);
|
||||
propertyViewport.setViewedComponent (&propertyGroup, false);
|
||||
|
||||
auto os = TargetOS::getThisOS();
|
||||
|
||||
if (os == TargetOS::osx) selectedOSValue = "osx";
|
||||
else if (os == TargetOS::windows) selectedOSValue = "windows";
|
||||
else if (os == TargetOS::linux) selectedOSValue = "linux";
|
||||
|
||||
selectedOSValue.addListener (this);
|
||||
|
||||
buildProps();
|
||||
|
||||
lastJUCEModulePath = getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()).get();
|
||||
lastUserModulePath = getAppSettings().getStoredPath (Ids::defaultUserModulePath, TargetOS::getThisOS()).get();
|
||||
}
|
||||
|
||||
~GlobalPathsWindowComponent() override
|
||||
{
|
||||
getGlobalProperties().removeChangeListener (this);
|
||||
|
||||
auto juceValue = getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS());
|
||||
auto userValue = getAppSettings().getStoredPath (Ids::defaultUserModulePath, TargetOS::getThisOS());
|
||||
|
||||
if (juceValue.get() != lastJUCEModulePath) ProjucerApplication::getApp().rescanJUCEPathModules();
|
||||
if (userValue.get() != lastUserModulePath) ProjucerApplication::getApp().rescanUserPathModules();
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
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);
|
||||
|
||||
auto bottomBounds = b.removeFromBottom (80);
|
||||
auto buttonBounds = bottomBounds.removeFromBottom (50);
|
||||
|
||||
rescanJUCEPathButton.setBounds (buttonBounds.removeFromLeft (150).reduced (5, 10));
|
||||
rescanUserPathButton.setBounds (buttonBounds.removeFromLeft (150).reduced (5, 10));
|
||||
|
||||
resetToDefaultsButton.setBounds (buttonBounds.removeFromRight (150).reduced (5, 10));
|
||||
warnAboutJUCEPathButton.setBounds (bottomBounds.reduced (0, 5));
|
||||
warnAboutJUCEPathButton.changeWidthToFitText();
|
||||
|
||||
propertyGroup.updateSize (0, 0, getWidth() - 20 - propertyViewport.getScrollBarThickness());
|
||||
propertyViewport.setBounds (b);
|
||||
}
|
||||
|
||||
void highlightJUCEPath()
|
||||
{
|
||||
if (isTimerRunning() || ! isSelectedOSThisOS())
|
||||
return;
|
||||
|
||||
const auto findJucePathPropertyComponent = [this]() -> PropertyComponent*
|
||||
{
|
||||
for (const auto& prop : propertyGroup.getProperties())
|
||||
if (prop->getName() == "Path to JUCE")
|
||||
return prop.get();
|
||||
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
if (auto* propComponent = findJucePathPropertyComponent())
|
||||
{
|
||||
boundsToHighlight = getLocalArea (nullptr, propComponent->getScreenBounds());
|
||||
flashAlpha = 0.0f;
|
||||
hasFlashed = false;
|
||||
|
||||
startTimer (25);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
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();
|
||||
}
|
||||
|
||||
void valueChanged (Value&) override
|
||||
{
|
||||
buildProps();
|
||||
resized();
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
warnAboutJUCEPathButton.setToggleState (ProjucerApplication::getApp().shouldPromptUserAboutIncorrectJUCEPath(),
|
||||
dontSendNotification);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isSelectedOSThisOS() { return TargetOS::getThisOS() == getSelectedOS(); }
|
||||
|
||||
TargetOS::OS getSelectedOS() const
|
||||
{
|
||||
auto val = selectedOSValue.getValue();
|
||||
|
||||
if (val == "osx") return TargetOS::osx;
|
||||
else if (val == "windows") return TargetOS::windows;
|
||||
else if (val == "linux") return TargetOS::linux;
|
||||
|
||||
jassertfalse;
|
||||
return TargetOS::unknown;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void buildProps()
|
||||
{
|
||||
updateValues();
|
||||
|
||||
PropertyListBuilder builder;
|
||||
auto isThisOS = isSelectedOSThisOS();
|
||||
|
||||
builder.add (new ChoicePropertyComponent (selectedOSValue, "OS", { "OSX", "Windows", "Linux" }, { "osx", "windows", "linux" }),
|
||||
"Use this dropdown to set the global paths for different OSes. "
|
||||
"\nN.B. These paths are stored locally and will only be used when "
|
||||
"saving a project on this machine. Other machines will have their own "
|
||||
"locally stored paths.");
|
||||
|
||||
builder.add (new LabelPropertyComponent ("JUCE"), {});
|
||||
|
||||
builder.add (new FilePathPropertyComponent (jucePathValue, "Path to JUCE", true, isThisOS),
|
||||
"This should be the path to the top-level directory of your JUCE folder. "
|
||||
"This path will be used when searching for the JUCE examples and DemoRunner application.");
|
||||
|
||||
builder.add (new FilePathPropertyComponent (juceModulePathValue, "JUCE Modules", true, isThisOS),
|
||||
String ("This should be the path to the folder containing the JUCE modules that you wish to use, typically the \"modules\" directory of your JUCE folder.")
|
||||
+ (isThisOS ? " Use the button below to re-scan a new path." : ""));
|
||||
builder.add (new FilePathPropertyComponent (userModulePathValue, "User Modules", true, isThisOS),
|
||||
String ("A path to a folder containing any custom modules that you wish to use.")
|
||||
+ (isThisOS ? " Use the button below to re-scan new paths." : ""));
|
||||
|
||||
builder.add (new LabelPropertyComponent ("SDKs"), {});
|
||||
|
||||
builder.add (new FilePathPropertyComponent (vstPathValue, "VST (Legacy) SDK", true, isThisOS),
|
||||
"If you are building a legacy VST plug-in then this path should point to a VST2 SDK. "
|
||||
"The VST2 SDK can be obtained from the vstsdk3610_11_06_2018_build_37 (or older) VST3 SDK or JUCE version 5.3.2. "
|
||||
"You also need a VST2 license from Steinberg to distribute VST2 plug-ins.");
|
||||
|
||||
if (getSelectedOS() != TargetOS::linux)
|
||||
{
|
||||
builder.add (new FilePathPropertyComponent (aaxPathValue, "AAX SDK", true, isThisOS),
|
||||
"If you are building AAX plug-ins, this should be the path to the AAX SDK folder.");
|
||||
builder.add (new FilePathPropertyComponent (rtasPathValue, "RTAS SDK (deprecated)", true, isThisOS),
|
||||
"If you are building RTAS plug-ins, this should be the path to the RTAS SDK folder.");
|
||||
}
|
||||
|
||||
builder.add (new FilePathPropertyComponent (androidSDKPathValue, "Android SDK", true, isThisOS),
|
||||
"This path will be used when writing the local.properties file of an Android project and should point to the Android SDK folder.");
|
||||
|
||||
if (isThisOS)
|
||||
{
|
||||
builder.add (new LabelPropertyComponent ("Other"), {});
|
||||
|
||||
#if JUCE_MAC
|
||||
String exeLabel ("app");
|
||||
#elif JUCE_WINDOWS
|
||||
String exeLabel ("executable");
|
||||
#else
|
||||
String exeLabel ("startup script");
|
||||
#endif
|
||||
|
||||
builder.add (new FilePathPropertyComponent (clionExePathValue, "CLion " + exeLabel, false, isThisOS),
|
||||
"This path will be used for the \"Save Project and Open in IDE...\" option of the CLion exporter.");
|
||||
builder.add (new FilePathPropertyComponent (androidStudioExePathValue, "Android Studio " + exeLabel, false, isThisOS),
|
||||
"This path will be used for the \"Save Project and Open in IDE...\" option of the Android Studio exporter.");
|
||||
}
|
||||
|
||||
rescanJUCEPathButton.setVisible (isThisOS);
|
||||
rescanUserPathButton.setVisible (isThisOS);
|
||||
warnAboutJUCEPathButton.setVisible (isThisOS);
|
||||
|
||||
propertyGroup.setProperties (builder);
|
||||
}
|
||||
|
||||
void updateValues()
|
||||
{
|
||||
auto& settings = getAppSettings();
|
||||
auto os = getSelectedOS();
|
||||
|
||||
jucePathValue = settings.getStoredPath (Ids::jucePath, os);
|
||||
juceModulePathValue = settings.getStoredPath (Ids::defaultJuceModulePath, os);
|
||||
userModulePathValue = settings.getStoredPath (Ids::defaultUserModulePath, os);
|
||||
vstPathValue = settings.getStoredPath (Ids::vstLegacyPath, os);
|
||||
rtasPathValue = settings.getStoredPath (Ids::rtasPath, os);
|
||||
aaxPathValue = settings.getStoredPath (Ids::aaxPath, os);
|
||||
androidSDKPathValue = settings.getStoredPath (Ids::androidSDKPath, os);
|
||||
clionExePathValue = settings.getStoredPath (Ids::clionExePath, os);
|
||||
androidStudioExePathValue = settings.getStoredPath (Ids::androidStudioExePath, os);
|
||||
}
|
||||
|
||||
void resetCurrentOSPathsToDefaults()
|
||||
{
|
||||
jucePathValue .resetToDefault();
|
||||
juceModulePathValue .resetToDefault();
|
||||
userModulePathValue .resetToDefault();
|
||||
vstPathValue .resetToDefault();
|
||||
rtasPathValue .resetToDefault();
|
||||
aaxPathValue .resetToDefault();
|
||||
androidSDKPathValue .resetToDefault();
|
||||
clionExePathValue .resetToDefault();
|
||||
androidStudioExePathValue.resetToDefault();
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Value selectedOSValue;
|
||||
|
||||
ValueWithDefault jucePathValue, juceModulePathValue, userModulePathValue,
|
||||
vstPathValue, rtasPathValue, aaxPathValue, androidSDKPathValue, clionExePathValue, androidStudioExePathValue;
|
||||
|
||||
Viewport propertyViewport;
|
||||
PropertyGroupComponent propertyGroup { "Global Paths", { getIcons().openFolder, Colours::transparentBlack } };
|
||||
|
||||
ToggleButton warnAboutJUCEPathButton { "Warn about incorrect JUCE path" };
|
||||
TextButton rescanJUCEPathButton { "Re-scan JUCE Modules" },
|
||||
rescanUserPathButton { "Re-scan User Modules" },
|
||||
resetToDefaultsButton { "Reset to Defaults" };
|
||||
|
||||
Rectangle<int> boundsToHighlight;
|
||||
float flashAlpha = 0.0f;
|
||||
bool hasFlashed = false;
|
||||
|
||||
var lastJUCEModulePath, lastUserModulePath;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlobalPathsWindowComponent)
|
||||
};
|
347
deps/juce/extras/Projucer/Source/Application/Windows/jucer_PIPCreatorWindowComponent.h
vendored
Normal file
347
deps/juce/extras/Projucer/Source/Application/Windows/jucer_PIPCreatorWindowComponent.h
vendored
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static String getWidthLimitedStringFromVarArray (const var& varArray) noexcept
|
||||
{
|
||||
if (! varArray.isArray())
|
||||
return {};
|
||||
|
||||
int numLines = 1;
|
||||
const int lineWidth = 100;
|
||||
const String indent (" ");
|
||||
|
||||
String str;
|
||||
if (auto* arr = varArray.getArray())
|
||||
{
|
||||
for (auto& v : *arr)
|
||||
{
|
||||
if ((str.length() + v.toString().length()) > (lineWidth * numLines))
|
||||
{
|
||||
str += newLine;
|
||||
str += indent;
|
||||
|
||||
++numLines;
|
||||
}
|
||||
|
||||
str += v.toString() + (arr->indexOf (v) != arr->size() - 1 ? ", " : "");
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class PIPCreatorWindowComponent : public Component,
|
||||
private ValueTree::Listener
|
||||
{
|
||||
public:
|
||||
PIPCreatorWindowComponent()
|
||||
{
|
||||
lf.reset (new PIPCreatorLookAndFeel());
|
||||
setLookAndFeel (lf.get());
|
||||
|
||||
addAndMakeVisible (propertyViewport);
|
||||
propertyViewport.setViewedComponent (&propertyGroup, false);
|
||||
buildProps();
|
||||
|
||||
addAndMakeVisible (createButton);
|
||||
createButton.onClick = [this]
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Save PIP File",
|
||||
File::getSpecialLocation (File::SpecialLocationType::userDesktopDirectory)
|
||||
.getChildFile (nameValue.get().toString() + ".h"));
|
||||
auto browserFlags = FileBrowserComponent::saveMode
|
||||
| FileBrowserComponent::canSelectFiles
|
||||
| FileBrowserComponent::warnAboutOverwriting;
|
||||
|
||||
chooser->launchAsync (browserFlags, [this] (const FileChooser& fc)
|
||||
{
|
||||
const auto result = fc.getResult();
|
||||
|
||||
if (result != File{})
|
||||
createPIPFile (result);
|
||||
});
|
||||
};
|
||||
|
||||
pipTree.addListener (this);
|
||||
}
|
||||
|
||||
~PIPCreatorWindowComponent() override
|
||||
{
|
||||
setLookAndFeel (nullptr);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
createButton.setBounds (bounds.removeFromBottom (50).reduced (100, 10));
|
||||
|
||||
propertyGroup.updateSize (0, 0, getWidth() - propertyViewport.getScrollBarThickness());
|
||||
propertyViewport.setBounds (bounds);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct PIPCreatorLookAndFeel : public ProjucerLookAndFeel
|
||||
{
|
||||
PIPCreatorLookAndFeel() {}
|
||||
|
||||
Rectangle<int> getPropertyComponentContentPosition (PropertyComponent& component)
|
||||
{
|
||||
auto textW = jmin (200, component.getWidth() / 3);
|
||||
return { textW, 0, component.getWidth() - textW, component.getHeight() - 1 };
|
||||
}
|
||||
};
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
lf->setColourScheme (ProjucerApplication::getApp().lookAndFeel.getCurrentColourScheme());
|
||||
lf->setupColours();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void buildProps()
|
||||
{
|
||||
PropertyListBuilder builder;
|
||||
|
||||
builder.add (new TextPropertyComponent (nameValue, "Name", 256, false),
|
||||
"The name of your JUCE project.");
|
||||
builder.add (new TextPropertyComponent (versionValue, "Version", 16, false),
|
||||
"This will be used for the \"Project Version\" field in the Projucer.");
|
||||
builder.add (new TextPropertyComponent (vendorValue, "Vendor", 2048, false),
|
||||
"This will be used for the \"Company Name\" field in the Projucer.");
|
||||
builder.add (new TextPropertyComponent (websiteValue, "Website", 2048, false),
|
||||
"This will be used for the \"Company Website\" field in the Projucer");
|
||||
builder.add (new TextPropertyComponent (descriptionValue, "Description", 2048, true),
|
||||
"A short description of your JUCE project.");
|
||||
|
||||
{
|
||||
Array<var> moduleVars;
|
||||
for (auto& m : getJUCEModules())
|
||||
moduleVars.add (m);
|
||||
|
||||
builder.add (new MultiChoicePropertyComponent (dependenciesValue, "Dependencies",
|
||||
getJUCEModules(), moduleVars),
|
||||
"The JUCE modules that should be added to your project.");
|
||||
}
|
||||
|
||||
{
|
||||
Array<var> exporterVars;
|
||||
StringArray exporterNames;
|
||||
|
||||
for (auto& exporterTypeInfo : ProjectExporter::getExporterTypeInfos())
|
||||
{
|
||||
exporterVars.add (exporterTypeInfo.identifier.toString());
|
||||
exporterNames.add (exporterTypeInfo.displayName);
|
||||
}
|
||||
|
||||
builder.add (new MultiChoicePropertyComponent (exportersValue, "Exporters", exporterNames, exporterVars),
|
||||
"The exporters that should be added to your project.");
|
||||
}
|
||||
|
||||
builder.add (new TextPropertyComponent (moduleFlagsValue, "Module Flags", 2048, true),
|
||||
"Use this to set one, or many, of the JUCE module flags");
|
||||
builder.add (new TextPropertyComponent (definesValue, "Defines", 2048, true),
|
||||
"This sets some global preprocessor definitions for your project. Used to populate the \"Preprocessor Definitions\" field in the Projucer.");
|
||||
builder.add (new ChoicePropertyComponent (typeValue, "Type",
|
||||
{ "Component", "Plugin", "Console Application" },
|
||||
{ "Component", "AudioProcessor", "Console" }),
|
||||
"The project type.");
|
||||
|
||||
builder.add (new TextPropertyComponent (mainClassValue, "Main Class", 2048, false),
|
||||
"The name of the main class that should be instantiated. "
|
||||
"There can only be one main class and it must have a default constructor. "
|
||||
"Depending on the type, this may need to inherit from a specific JUCE class");
|
||||
|
||||
builder.add (new ChoicePropertyComponent (useLocalCopyValue, "Use Local Copy"),
|
||||
"Enable this to specify that the PIP file should be copied to the generated project directory instead of just referred to.");
|
||||
|
||||
propertyGroup.setProperties (builder);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier& identifier) override
|
||||
{
|
||||
if (identifier == Ids::type)
|
||||
{
|
||||
auto type = typeValue.get().toString();
|
||||
|
||||
if (type == "Component")
|
||||
{
|
||||
nameValue.setDefault ("MyComponentPIP");
|
||||
dependenciesValue.setDefault (getModulesRequiredForComponent());
|
||||
mainClassValue.setDefault ("MyComponent");
|
||||
}
|
||||
else if (type == "AudioProcessor")
|
||||
{
|
||||
nameValue.setDefault ("MyPluginPIP");
|
||||
dependenciesValue.setDefault (getModulesRequiredForAudioProcessor());
|
||||
mainClassValue.setDefault ("MyPlugin");
|
||||
}
|
||||
else if (type == "Console")
|
||||
{
|
||||
nameValue.setDefault ("MyConsolePIP");
|
||||
dependenciesValue.setDefault (getModulesRequiredForConsole());
|
||||
mainClassValue.setDefault ({});
|
||||
}
|
||||
|
||||
MessageManager::callAsync ([this]
|
||||
{
|
||||
buildProps();
|
||||
resized();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String getFormattedMetadataString() const noexcept
|
||||
{
|
||||
StringArray metadata;
|
||||
|
||||
{
|
||||
StringArray section;
|
||||
|
||||
if (nameValue.get().toString().isNotEmpty()) section.add (" name: " + nameValue.get().toString());
|
||||
if (versionValue.get().toString().isNotEmpty()) section.add (" version: " + versionValue.get().toString());
|
||||
if (vendorValue.get().toString().isNotEmpty()) section.add (" vendor: " + vendorValue.get().toString());
|
||||
if (websiteValue.get().toString().isNotEmpty()) section.add (" website: " + websiteValue.get().toString());
|
||||
if (descriptionValue.get().toString().isNotEmpty()) section.add (" description: " + descriptionValue.get().toString());
|
||||
|
||||
if (! section.isEmpty())
|
||||
metadata.add (section.joinIntoString (getPreferredLineFeed()));
|
||||
}
|
||||
|
||||
{
|
||||
StringArray section;
|
||||
|
||||
auto dependenciesString = getWidthLimitedStringFromVarArray (dependenciesValue.get());
|
||||
if (dependenciesString.isNotEmpty()) section.add (" dependencies: " + dependenciesString);
|
||||
|
||||
auto exportersString = getWidthLimitedStringFromVarArray (exportersValue.get());
|
||||
if (exportersString.isNotEmpty()) section.add (" exporters: " + exportersString);
|
||||
|
||||
if (! section.isEmpty())
|
||||
metadata.add (section.joinIntoString (getPreferredLineFeed()));
|
||||
}
|
||||
|
||||
{
|
||||
StringArray section;
|
||||
|
||||
if (moduleFlagsValue.get().toString().isNotEmpty()) section.add (" moduleFlags: " + moduleFlagsValue.get().toString());
|
||||
if (definesValue.get().toString().isNotEmpty()) section.add (" defines: " + definesValue.get().toString());
|
||||
|
||||
if (! section.isEmpty())
|
||||
metadata.add (section.joinIntoString (getPreferredLineFeed()));
|
||||
}
|
||||
|
||||
{
|
||||
StringArray section;
|
||||
|
||||
if (typeValue.get().toString().isNotEmpty()) section.add (" type: " + typeValue.get().toString());
|
||||
if (mainClassValue.get().toString().isNotEmpty()) section.add (" mainClass: " + mainClassValue.get().toString());
|
||||
|
||||
if (! section.isEmpty())
|
||||
metadata.add (section.joinIntoString (getPreferredLineFeed()));
|
||||
}
|
||||
|
||||
{
|
||||
StringArray section;
|
||||
|
||||
if (useLocalCopyValue.get()) section.add (" useLocalCopy: " + useLocalCopyValue.get().toString());
|
||||
|
||||
if (! section.isEmpty())
|
||||
metadata.add (section.joinIntoString (getPreferredLineFeed()));
|
||||
}
|
||||
|
||||
return metadata.joinIntoString (String (getPreferredLineFeed()) + getPreferredLineFeed());
|
||||
}
|
||||
|
||||
void createPIPFile (File fileToSave)
|
||||
{
|
||||
String fileTemplate (BinaryData::jucer_PIPTemplate_h);
|
||||
fileTemplate = fileTemplate.replace ("%%pip_metadata%%", getFormattedMetadataString());
|
||||
|
||||
auto type = typeValue.get().toString();
|
||||
|
||||
if (type == "Component")
|
||||
{
|
||||
String componentCode (BinaryData::jucer_ContentCompSimpleTemplate_h);
|
||||
componentCode = componentCode.substring (componentCode.indexOf ("class %%content_component_class%%"))
|
||||
.replace ("%%content_component_class%%", mainClassValue.get().toString());
|
||||
|
||||
fileTemplate = fileTemplate.replace ("%%pip_code%%", componentCode);
|
||||
}
|
||||
else if (type == "AudioProcessor")
|
||||
{
|
||||
String audioProcessorCode (BinaryData::jucer_PIPAudioProcessorTemplate_h);
|
||||
audioProcessorCode = audioProcessorCode.replace ("%%class_name%%", mainClassValue.get().toString())
|
||||
.replace ("%%name%%", nameValue.get().toString());
|
||||
|
||||
fileTemplate = fileTemplate.replace ("%%pip_code%%", audioProcessorCode);
|
||||
}
|
||||
else if (type == "Console")
|
||||
{
|
||||
String consoleCode (BinaryData::jucer_MainConsoleAppTemplate_cpp);
|
||||
consoleCode = consoleCode.substring (consoleCode.indexOf ("int main (int argc, char* argv[])"));
|
||||
|
||||
fileTemplate = fileTemplate.replace ("%%pip_code%%", consoleCode);
|
||||
}
|
||||
|
||||
if (fileToSave.create())
|
||||
fileToSave.replaceWithText (fileTemplate);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ValueTree pipTree { "PIPSettings" };
|
||||
ValueWithDefault nameValue { pipTree, Ids::name, nullptr, "MyComponentPIP" },
|
||||
versionValue { pipTree, Ids::version, nullptr },
|
||||
vendorValue { pipTree, Ids::vendor, nullptr },
|
||||
websiteValue { pipTree, Ids::website, nullptr },
|
||||
descriptionValue { pipTree, Ids::description, nullptr },
|
||||
dependenciesValue { pipTree, Ids::dependencies_, nullptr, getModulesRequiredForComponent(), "," },
|
||||
exportersValue { pipTree, Ids::exporters, nullptr, StringArray (ProjectExporter::getCurrentPlatformExporterTypeInfo().identifier.toString()), "," },
|
||||
moduleFlagsValue { pipTree, Ids::moduleFlags, nullptr, "JUCE_STRICT_REFCOUNTEDPOINTER=1" },
|
||||
definesValue { pipTree, Ids::defines, nullptr },
|
||||
typeValue { pipTree, Ids::type, nullptr, "Component" },
|
||||
mainClassValue { pipTree, Ids::mainClass, nullptr, "MyComponent" },
|
||||
useLocalCopyValue { pipTree, Ids::useLocalCopy, nullptr, false };
|
||||
|
||||
std::unique_ptr<PIPCreatorLookAndFeel> lf;
|
||||
|
||||
Viewport propertyViewport;
|
||||
PropertyGroupComponent propertyGroup { "PIP Creator", {} };
|
||||
|
||||
TextButton createButton { "Create PIP" };
|
||||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PIPCreatorWindowComponent)
|
||||
};
|
218
deps/juce/extras/Projucer/Source/Application/Windows/jucer_SVGPathDataWindowComponent.h
vendored
Normal file
218
deps/juce/extras/Projucer/Source/Application/Windows/jucer_SVGPathDataWindowComponent.h
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class SVGPathDataComponent : public Component,
|
||||
public FileDragAndDropTarget
|
||||
|
||||
{
|
||||
public:
|
||||
SVGPathDataComponent()
|
||||
{
|
||||
desc.setJustificationType (Justification::centred);
|
||||
addAndMakeVisible (desc);
|
||||
|
||||
userText.setFont (getAppSettings().appearance.getCodeFont().withHeight (13.0f));
|
||||
userText.setMultiLine (true, true);
|
||||
userText.setReturnKeyStartsNewLine (true);
|
||||
addAndMakeVisible (userText);
|
||||
userText.onTextChange = [this] { update(); };
|
||||
userText.onEscapeKey = [this] { getTopLevelComponent()->exitModalState (0); };
|
||||
|
||||
resultText.setFont (getAppSettings().appearance.getCodeFont().withHeight (13.0f));
|
||||
resultText.setMultiLine (true, true);
|
||||
resultText.setReadOnly (true);
|
||||
resultText.setSelectAllWhenFocused (true);
|
||||
addAndMakeVisible (resultText);
|
||||
|
||||
userText.setText (getLastText());
|
||||
|
||||
addAndMakeVisible (copyButton);
|
||||
copyButton.onClick = [this] { SystemClipboard::copyTextToClipboard (resultText.getText()); };
|
||||
|
||||
addAndMakeVisible (closeSubPathButton);
|
||||
closeSubPathButton.onClick = [this] { update(); };
|
||||
closeSubPathButton.setToggleState (true, NotificationType::dontSendNotification);
|
||||
|
||||
addAndMakeVisible (fillPathButton);
|
||||
fillPathButton.onClick = [this] { update(); };
|
||||
fillPathButton.setToggleState (true, NotificationType::dontSendNotification);
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
getLastText() = userText.getText();
|
||||
auto text = getLastText().trim().unquoted().trim();
|
||||
|
||||
path = Drawable::parseSVGPath (text);
|
||||
|
||||
if (path.isEmpty())
|
||||
path = pathFromPoints (text);
|
||||
|
||||
String result = "No path generated.. Not a valid SVG path string?";
|
||||
|
||||
if (! path.isEmpty())
|
||||
{
|
||||
MemoryOutputStream data;
|
||||
path.writePathToStream (data);
|
||||
|
||||
MemoryOutputStream out;
|
||||
|
||||
out << "static const unsigned char pathData[] = ";
|
||||
build_tools::writeDataAsCppLiteral (data.getMemoryBlock(), out, false, true);
|
||||
out << newLine
|
||||
<< newLine
|
||||
<< "Path path;" << newLine
|
||||
<< "path.loadPathFromData (pathData, sizeof (pathData));" << newLine;
|
||||
|
||||
result = out.toString();
|
||||
}
|
||||
|
||||
resultText.setText (result, false);
|
||||
repaint (previewPathArea);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto r = getLocalBounds().reduced (8);
|
||||
|
||||
auto bottomSection = r.removeFromBottom (30);
|
||||
copyButton.setBounds (bottomSection.removeFromLeft (50));
|
||||
bottomSection.removeFromLeft (25);
|
||||
fillPathButton.setBounds (bottomSection.removeFromLeft (bottomSection.getWidth() / 2));
|
||||
closeSubPathButton.setBounds (bottomSection);
|
||||
|
||||
r.removeFromBottom (5);
|
||||
desc.setBounds (r.removeFromTop (44));
|
||||
r.removeFromTop (8);
|
||||
userText.setBounds (r.removeFromTop (r.getHeight() / 2));
|
||||
r.removeFromTop (8);
|
||||
previewPathArea = r.removeFromRight (r.getHeight());
|
||||
resultText.setBounds (r);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
if (dragOver)
|
||||
{
|
||||
g.setColour (findColour (secondaryBackgroundColourId).brighter());
|
||||
g.fillAll();
|
||||
}
|
||||
|
||||
g.setColour (findColour (defaultTextColourId));
|
||||
path.applyTransform (path.getTransformToScaleToFit (previewPathArea.reduced (4).toFloat(), true));
|
||||
|
||||
if (fillPathButton.getToggleState())
|
||||
g.fillPath (path);
|
||||
else
|
||||
g.strokePath (path, PathStrokeType (2.0f));
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
userText.applyFontToAllText (userText.getFont());
|
||||
resultText.applyFontToAllText (resultText.getFont());
|
||||
}
|
||||
|
||||
bool isInterestedInFileDrag (const StringArray& files) override
|
||||
{
|
||||
return files.size() == 1
|
||||
&& File (files[0]).hasFileExtension ("svg");
|
||||
}
|
||||
|
||||
void fileDragEnter (const StringArray&, int, int) override
|
||||
{
|
||||
dragOver = true;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void fileDragExit (const StringArray&) override
|
||||
{
|
||||
dragOver = false;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void filesDropped (const StringArray& files, int, int) override
|
||||
{
|
||||
dragOver = false;
|
||||
repaint();
|
||||
|
||||
if (auto element = parseXML (File (files[0])))
|
||||
{
|
||||
if (auto* ePath = element->getChildByName ("path"))
|
||||
userText.setText (ePath->getStringAttribute ("d"), true);
|
||||
else if (auto* ePolygon = element->getChildByName ("polygon"))
|
||||
userText.setText (ePolygon->getStringAttribute ("points"), true);
|
||||
}
|
||||
}
|
||||
|
||||
Path pathFromPoints (String pointsText)
|
||||
{
|
||||
auto points = StringArray::fromTokens (pointsText, " ,", "");
|
||||
points.removeEmptyStrings();
|
||||
|
||||
jassert (points.size() % 2 == 0);
|
||||
|
||||
Path p;
|
||||
|
||||
for (int i = 0; i < points.size() / 2; i++)
|
||||
{
|
||||
auto x = points[i * 2].getFloatValue();
|
||||
auto y = points[i * 2 + 1].getFloatValue();
|
||||
|
||||
if (i == 0)
|
||||
p.startNewSubPath ({ x, y });
|
||||
else
|
||||
p.lineTo ({ x, y });
|
||||
}
|
||||
|
||||
if (closeSubPathButton.getToggleState())
|
||||
p.closeSubPath();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
Label desc { {}, "Paste an SVG path string into the top box, and it'll be converted to some C++ "
|
||||
"code that will load it as a Path object.." };
|
||||
TextButton copyButton { "Copy" };
|
||||
TextEditor userText, resultText;
|
||||
|
||||
ToggleButton closeSubPathButton { "Close sub-path" };
|
||||
ToggleButton fillPathButton { "Fill path" };
|
||||
|
||||
Rectangle<int> previewPathArea;
|
||||
Path path;
|
||||
bool dragOver = false;
|
||||
|
||||
String& getLastText()
|
||||
{
|
||||
static String t;
|
||||
return t;
|
||||
}
|
||||
};
|
198
deps/juce/extras/Projucer/Source/Application/Windows/jucer_TranslationToolWindowComponent.h
vendored
Normal file
198
deps/juce/extras/Projucer/Source/Application/Windows/jucer_TranslationToolWindowComponent.h
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../Utility/Helpers/jucer_TranslationHelpers.h"
|
||||
|
||||
//==============================================================================
|
||||
class TranslationToolComponent : public Component
|
||||
{
|
||||
public:
|
||||
TranslationToolComponent()
|
||||
: editorOriginal (documentOriginal, nullptr),
|
||||
editorPre (documentPre, nullptr),
|
||||
editorPost (documentPost, nullptr),
|
||||
editorResult (documentResult, nullptr)
|
||||
{
|
||||
instructionsLabel.setText (
|
||||
"This utility converts translation files to/from a format that can be passed to automatic translation tools."
|
||||
"\n\n"
|
||||
"First, choose whether to scan the current project for all TRANS() macros, or "
|
||||
"pick an existing translation file to load:", dontSendNotification);
|
||||
addAndMakeVisible (instructionsLabel);
|
||||
|
||||
label1.setText ("..then copy-and-paste this annotated text into Google Translate or some other translator:", dontSendNotification);
|
||||
addAndMakeVisible (label1);
|
||||
|
||||
label2.setText ("...then, take the translated result and paste it into the box below:", dontSendNotification);
|
||||
addAndMakeVisible (label2);
|
||||
|
||||
label3.setText ("Finally, click the 'Generate' button, and a translation file will be created below. "
|
||||
"Remember to update its language code at the top!", dontSendNotification);
|
||||
addAndMakeVisible (label3);
|
||||
|
||||
label4.setText ("If you load an existing file the already translated strings will be removed. Ensure this box is empty to create a fresh translation", dontSendNotification);
|
||||
addAndMakeVisible (label4);
|
||||
|
||||
addAndMakeVisible (editorOriginal);
|
||||
addAndMakeVisible (editorPre);
|
||||
addAndMakeVisible (editorPost);
|
||||
addAndMakeVisible (editorResult);
|
||||
|
||||
addAndMakeVisible (generateButton);
|
||||
generateButton.onClick = [this] { generate(); };
|
||||
|
||||
addAndMakeVisible (scanProjectButton);
|
||||
scanProjectButton.onClick = [this] { scanProject(); };
|
||||
|
||||
addAndMakeVisible (scanFolderButton);
|
||||
scanFolderButton.onClick = [this] { scanFolder(); };
|
||||
|
||||
addAndMakeVisible (loadTranslationButton);
|
||||
loadTranslationButton.onClick = [this] { loadFile(); };
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (backgroundColourId));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
const int m = 6;
|
||||
const int textH = 44;
|
||||
const int extraH = (7 * textH);
|
||||
const int editorH = (getHeight() - extraH) / 4;
|
||||
const int numButtons = 3;
|
||||
|
||||
Rectangle<int> r (getLocalBounds().withTrimmedBottom (m));
|
||||
const int buttonWidth = r.getWidth() / numButtons;
|
||||
|
||||
instructionsLabel.setBounds (r.removeFromTop (textH * 2).reduced (m));
|
||||
r.removeFromTop (m);
|
||||
Rectangle<int> r2 (r.removeFromTop (textH - (2 * m)));
|
||||
scanProjectButton .setBounds (r2.removeFromLeft (buttonWidth).reduced (m, 0));
|
||||
scanFolderButton .setBounds (r2.removeFromLeft (buttonWidth).reduced (m, 0));
|
||||
loadTranslationButton.setBounds (r2.reduced (m, 0));
|
||||
|
||||
label1 .setBounds (r.removeFromTop (textH) .reduced (m));
|
||||
editorPre.setBounds (r.removeFromTop (editorH).reduced (m, 0));
|
||||
|
||||
label2 .setBounds (r.removeFromTop (textH) .reduced (m));
|
||||
editorPost.setBounds (r.removeFromTop (editorH).reduced (m, 0));
|
||||
|
||||
r2 = r.removeFromTop (textH);
|
||||
generateButton.setBounds (r2.removeFromRight (152).reduced (m));
|
||||
label3 .setBounds (r2.reduced (m));
|
||||
editorResult .setBounds (r.removeFromTop (editorH).reduced (m, 0));
|
||||
|
||||
label4 .setBounds (r.removeFromTop (textH).reduced (m));
|
||||
editorOriginal.setBounds (r.reduced (m, 0));
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void generate()
|
||||
{
|
||||
StringArray preStrings (TranslationHelpers::breakApart (documentPre.getAllContent()));
|
||||
StringArray postStrings (TranslationHelpers::breakApart (documentPost.getAllContent()));
|
||||
|
||||
if (postStrings.size() != preStrings.size())
|
||||
{
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
|
||||
TRANS("Error"),
|
||||
TRANS("The pre- and post-translation text doesn't match!\n\n"
|
||||
"Perhaps it got mangled by the translator?"));
|
||||
return;
|
||||
}
|
||||
|
||||
const LocalisedStrings originalTranslation (documentOriginal.getAllContent(), false);
|
||||
documentResult.replaceAllContent (TranslationHelpers::createFinishedTranslationFile (preStrings, postStrings, originalTranslation));
|
||||
}
|
||||
|
||||
void scanProject()
|
||||
{
|
||||
if (Project* project = ProjucerApplication::getApp().mainWindowList.getFrontmostProject())
|
||||
setPreTranslationText (TranslationHelpers::getPreTranslationText (*project));
|
||||
else
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Translation Tool",
|
||||
"This will only work when you have a project open!");
|
||||
}
|
||||
|
||||
void scanFolder()
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Choose the root folder to search for the TRANS macros",
|
||||
File(), "*");
|
||||
auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories;
|
||||
|
||||
chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
|
||||
{
|
||||
if (fc.getResult() == File{})
|
||||
return;
|
||||
|
||||
StringArray strings;
|
||||
TranslationHelpers::scanFolderForTranslations (strings, fc.getResult());
|
||||
setPreTranslationText (TranslationHelpers::mungeStrings(strings));
|
||||
});
|
||||
}
|
||||
|
||||
void loadFile()
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Choose a translation file to load", File(), "*");
|
||||
auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles;
|
||||
|
||||
chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
|
||||
{
|
||||
if (fc.getResult() == File{})
|
||||
return;
|
||||
|
||||
const LocalisedStrings loadedStrings (fc.getResult(), false);
|
||||
documentOriginal.replaceAllContent (fc.getResult().loadFileAsString().trim());
|
||||
setPreTranslationText (TranslationHelpers::getPreTranslationText (loadedStrings));
|
||||
});
|
||||
}
|
||||
|
||||
void setPreTranslationText (const String& text)
|
||||
{
|
||||
documentPre.replaceAllContent (text);
|
||||
editorPre.grabKeyboardFocus();
|
||||
editorPre.selectAll();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
CodeDocument documentOriginal, documentPre, documentPost, documentResult;
|
||||
CodeEditorComponent editorOriginal, editorPre, editorPost, editorResult;
|
||||
|
||||
Label label1, label2, label3, label4;
|
||||
Label instructionsLabel;
|
||||
|
||||
TextButton generateButton { TRANS("Generate") },
|
||||
scanProjectButton { "Scan project for TRANS macros" },
|
||||
scanFolderButton { "Scan folder for TRANS macros" },
|
||||
loadTranslationButton { "Load existing translation file..."};
|
||||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
};
|
87
deps/juce/extras/Projucer/Source/Application/Windows/jucer_UTF8WindowComponent.h
vendored
Normal file
87
deps/juce/extras/Projucer/Source/Application/Windows/jucer_UTF8WindowComponent.h
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class UTF8Component : public Component
|
||||
{
|
||||
public:
|
||||
UTF8Component()
|
||||
: desc (String(),
|
||||
"Type any string into the box, and it'll be shown below as a portable UTF-8 literal, "
|
||||
"ready to cut-and-paste into your source-code...")
|
||||
{
|
||||
desc.setJustificationType (Justification::centred);
|
||||
addAndMakeVisible (desc);
|
||||
|
||||
userText.setMultiLine (true, true);
|
||||
userText.setReturnKeyStartsNewLine (true);
|
||||
addAndMakeVisible (userText);
|
||||
userText.onTextChange = [this] { update(); };
|
||||
userText.onEscapeKey = [this] { getTopLevelComponent()->exitModalState (0); };
|
||||
|
||||
resultText.setFont (getAppSettings().appearance.getCodeFont().withHeight (13.0f));
|
||||
resultText.setMultiLine (true, true);
|
||||
resultText.setReadOnly (true);
|
||||
resultText.setSelectAllWhenFocused (true);
|
||||
addAndMakeVisible (resultText);
|
||||
|
||||
userText.setText (getLastText());
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
getLastText() = userText.getText();
|
||||
resultText.setText (CodeHelpers::stringLiteral (getLastText(), 100), false);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto r = getLocalBounds().reduced (8);
|
||||
desc.setBounds (r.removeFromTop (44));
|
||||
r.removeFromTop (8);
|
||||
userText.setBounds (r.removeFromTop (r.getHeight() / 2));
|
||||
r.removeFromTop (8);
|
||||
resultText.setBounds (r);
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
userText.applyFontToAllText (userText.getFont());
|
||||
resultText.applyFontToAllText (resultText.getFont());
|
||||
}
|
||||
|
||||
private:
|
||||
Label desc;
|
||||
TextEditor userText, resultText;
|
||||
|
||||
String& getLastText()
|
||||
{
|
||||
static String t;
|
||||
return t;
|
||||
}
|
||||
};
|
1521
deps/juce/extras/Projucer/Source/Application/jucer_Application.cpp
vendored
Normal file
1521
deps/juce/extras/Projucer/Source/Application/jucer_Application.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
224
deps/juce/extras/Projucer/Source/Application/jucer_Application.h
vendored
Normal file
224
deps/juce/extras/Projucer/Source/Application/jucer_Application.h
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UserAccount/jucer_LicenseController.h"
|
||||
#include "jucer_MainWindow.h"
|
||||
#include "../Project/Modules/jucer_Modules.h"
|
||||
#include "jucer_AutoUpdater.h"
|
||||
#include "../CodeEditor/jucer_SourceCodeEditor.h"
|
||||
#include "../Utility/UI/jucer_ProjucerLookAndFeel.h"
|
||||
|
||||
//==============================================================================
|
||||
class ProjucerApplication : public JUCEApplication,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
ProjucerApplication() = default;
|
||||
|
||||
static ProjucerApplication& getApp();
|
||||
static ApplicationCommandManager& getCommandManager();
|
||||
|
||||
//==============================================================================
|
||||
void initialise (const String& commandLine) override;
|
||||
void shutdown() override;
|
||||
void systemRequestedQuit() override;
|
||||
void deleteLogger();
|
||||
|
||||
const String getApplicationName() override { return "Projucer"; }
|
||||
const String getApplicationVersion() override { return ProjectInfo::versionString; }
|
||||
|
||||
String getVersionDescription() const;
|
||||
bool moreThanOneInstanceAllowed() override { return true; } // this is handled manually in initialise()
|
||||
|
||||
void anotherInstanceStarted (const String& commandLine) override;
|
||||
|
||||
//==============================================================================
|
||||
MenuBarModel* getMenuModel();
|
||||
|
||||
void getAllCommands (Array<CommandID>&) override;
|
||||
void getCommandInfo (CommandID commandID, ApplicationCommandInfo&) override;
|
||||
bool perform (const InvocationInfo&) override;
|
||||
|
||||
bool isGUIEditorEnabled() const;
|
||||
|
||||
//==============================================================================
|
||||
void openFile (const File&, std::function<void (bool)>);
|
||||
void showPathsWindow (bool highlightJUCEPath = false);
|
||||
PropertiesFile::Options getPropertyFileOptionsFor (const String& filename, bool isProjectSettings);
|
||||
void selectEditorColourSchemeWithName (const String& schemeName);
|
||||
|
||||
//==============================================================================
|
||||
void rescanJUCEPathModules();
|
||||
void rescanUserPathModules();
|
||||
|
||||
AvailableModulesList& getJUCEPathModulesList() { return jucePathModulesList; }
|
||||
AvailableModulesList& getUserPathsModulesList() { return userPathsModulesList; }
|
||||
|
||||
LicenseController& getLicenseController() { return *licenseController; }
|
||||
|
||||
bool isAutomaticVersionCheckingEnabled() const;
|
||||
void setAutomaticVersionCheckingEnabled (bool shouldBeEnabled);
|
||||
|
||||
bool shouldPromptUserAboutIncorrectJUCEPath() const;
|
||||
void setShouldPromptUserAboutIncorrectJUCEPath (bool shouldPrompt);
|
||||
|
||||
static File getJUCEExamplesDirectoryPathFromGlobal() noexcept;
|
||||
static Array<File> getSortedExampleDirectories() noexcept;
|
||||
static Array<File> getSortedExampleFilesInDirectory (const File&) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
ProjucerLookAndFeel lookAndFeel;
|
||||
|
||||
std::unique_ptr<StoredSettings> settings;
|
||||
std::unique_ptr<Icons> icons;
|
||||
|
||||
struct MainMenuModel;
|
||||
std::unique_ptr<MainMenuModel> menuModel;
|
||||
|
||||
MainWindowList mainWindowList;
|
||||
OpenDocumentManager openDocumentManager;
|
||||
std::unique_ptr<ApplicationCommandManager> commandManager;
|
||||
|
||||
bool isRunningCommandLine = false;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void handleAsyncUpdate() override;
|
||||
void doBasicApplicationSetup();
|
||||
|
||||
void initCommandManager();
|
||||
bool initialiseLogger (const char* filePrefix);
|
||||
void initialiseWindows (const String& commandLine);
|
||||
|
||||
void createNewProject();
|
||||
void createNewProjectFromClipboard();
|
||||
void createNewPIP();
|
||||
void askUserToOpenFile();
|
||||
void saveAllDocuments();
|
||||
void closeAllDocuments (OpenDocumentManager::SaveIfNeeded askUserToSave);
|
||||
void closeAllMainWindows (std::function<void (bool)>);
|
||||
void closeAllMainWindowsAndQuitIfNeeded();
|
||||
void clearRecentFiles();
|
||||
|
||||
StringArray getMenuNames();
|
||||
PopupMenu createMenu (const String& menuName);
|
||||
PopupMenu createFileMenu();
|
||||
PopupMenu createEditMenu();
|
||||
PopupMenu createViewMenu();
|
||||
void createColourSchemeItems (PopupMenu&);
|
||||
PopupMenu createWindowMenu();
|
||||
PopupMenu createDocumentMenu();
|
||||
PopupMenu createToolsMenu();
|
||||
PopupMenu createHelpMenu();
|
||||
PopupMenu createExtraAppleMenuItems();
|
||||
void handleMainMenuCommand (int menuItemID);
|
||||
PopupMenu createExamplesPopupMenu() noexcept;
|
||||
|
||||
void findAndLaunchExample (int);
|
||||
|
||||
void checkIfGlobalJUCEPathHasChanged();
|
||||
File tryToFindDemoRunnerExecutable();
|
||||
File tryToFindDemoRunnerProject();
|
||||
void launchDemoRunner();
|
||||
|
||||
void setColourScheme (int index, bool saveSetting);
|
||||
void setEditorColourScheme (int index, bool saveSetting);
|
||||
void updateEditorColourSchemeIfNeeded();
|
||||
|
||||
void showUTF8ToolWindow();
|
||||
void showSVGPathDataToolWindow();
|
||||
void showAboutWindow();
|
||||
void showEditorColourSchemeWindow();
|
||||
void showPIPCreatorWindow();
|
||||
|
||||
void launchForumBrowser();
|
||||
void launchModulesBrowser();
|
||||
void launchClassesBrowser();
|
||||
void launchTutorialsBrowser();
|
||||
|
||||
void doLoginOrLogout();
|
||||
void showLoginForm();
|
||||
|
||||
void enableOrDisableGUIEditor();
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC
|
||||
class AppleMenuRebuildListener : private MenuBarModel::Listener
|
||||
{
|
||||
public:
|
||||
AppleMenuRebuildListener()
|
||||
{
|
||||
if (auto* model = ProjucerApplication::getApp().getMenuModel())
|
||||
model->addListener (this);
|
||||
}
|
||||
|
||||
~AppleMenuRebuildListener() override
|
||||
{
|
||||
if (auto* model = ProjucerApplication::getApp().getMenuModel())
|
||||
model->removeListener (this);
|
||||
}
|
||||
|
||||
private:
|
||||
void menuBarItemsChanged (MenuBarModel*) override {}
|
||||
|
||||
void menuCommandInvoked (MenuBarModel*,
|
||||
const ApplicationCommandTarget::InvocationInfo& info) override
|
||||
{
|
||||
if (info.commandID == CommandIDs::enableNewVersionCheck)
|
||||
Timer::callAfterDelay (50, [] { ProjucerApplication::getApp().rebuildAppleMenu(); });
|
||||
}
|
||||
};
|
||||
|
||||
void rebuildAppleMenu();
|
||||
|
||||
std::unique_ptr<AppleMenuRebuildListener> appleMenuRebuildListener;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<LicenseController> licenseController;
|
||||
|
||||
std::unique_ptr<TooltipWindow> tooltipWindow;
|
||||
AvailableModulesList jucePathModulesList, userPathsModulesList;
|
||||
|
||||
std::unique_ptr<Component> utf8Window, svgPathWindow, aboutWindow, pathsWindow,
|
||||
editorColourSchemeWindow, pipCreatorWindow;
|
||||
|
||||
std::unique_ptr<FileLogger> logger;
|
||||
|
||||
int numExamples = 0;
|
||||
std::unique_ptr<AlertWindow> demoRunnerAlert;
|
||||
bool hasScannedForDemoRunnerExecutable = false, hasScannedForDemoRunnerProject = false;
|
||||
File lastJUCEPath, lastDemoRunnerExectuableFile, lastDemoRunnerProjectFile;
|
||||
|
||||
int selectedColourSchemeIndex = 0, selectedEditorColourSchemeIndex = 0;
|
||||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjucerApplication)
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (ProjucerApplication)
|
||||
};
|
560
deps/juce/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp
vendored
Normal file
560
deps/juce/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp
vendored
Normal file
@ -0,0 +1,560 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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 "../Application/jucer_Headers.h"
|
||||
#include "jucer_Application.h"
|
||||
#include "jucer_AutoUpdater.h"
|
||||
|
||||
//==============================================================================
|
||||
LatestVersionCheckerAndUpdater::LatestVersionCheckerAndUpdater()
|
||||
: Thread ("VersionChecker")
|
||||
{
|
||||
}
|
||||
|
||||
LatestVersionCheckerAndUpdater::~LatestVersionCheckerAndUpdater()
|
||||
{
|
||||
stopThread (6000);
|
||||
clearSingletonInstance();
|
||||
}
|
||||
|
||||
void LatestVersionCheckerAndUpdater::checkForNewVersion (bool background)
|
||||
{
|
||||
if (! isThreadRunning())
|
||||
{
|
||||
backgroundCheck = background;
|
||||
startThread (3);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void LatestVersionCheckerAndUpdater::run()
|
||||
{
|
||||
auto info = VersionInfo::fetchLatestFromUpdateServer();
|
||||
|
||||
if (info == nullptr)
|
||||
{
|
||||
if (! backgroundCheck)
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
|
||||
"Update Server Communication Error",
|
||||
"Failed to communicate with the JUCE update server.\n"
|
||||
"Please try again in a few minutes.\n\n"
|
||||
"If this problem persists you can download the latest version of JUCE from juce.com");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! info->isNewerVersionThanCurrent())
|
||||
{
|
||||
if (! backgroundCheck)
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon,
|
||||
"No New Version Available",
|
||||
"Your JUCE version is up to date.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto osString = []
|
||||
{
|
||||
#if JUCE_MAC
|
||||
return "osx";
|
||||
#elif JUCE_WINDOWS
|
||||
return "windows";
|
||||
#elif JUCE_LINUX
|
||||
return "linux";
|
||||
#elif JUCE_BSD
|
||||
return "bsd";
|
||||
#else
|
||||
jassertfalse;
|
||||
return "Unknown";
|
||||
#endif
|
||||
}();
|
||||
|
||||
String requiredFilename ("juce-" + info->versionString + "-" + osString + ".zip");
|
||||
|
||||
for (auto& asset : info->assets)
|
||||
{
|
||||
if (asset.name == requiredFilename)
|
||||
{
|
||||
auto versionString = info->versionString;
|
||||
auto releaseNotes = info->releaseNotes;
|
||||
|
||||
MessageManager::callAsync ([this, versionString, releaseNotes, asset]
|
||||
{
|
||||
askUserAboutNewVersion (versionString, releaseNotes, asset);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! backgroundCheck)
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
|
||||
"Failed to find any new downloads",
|
||||
"Please try again in a few minutes.");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class UpdateDialog : public Component
|
||||
{
|
||||
public:
|
||||
UpdateDialog (const String& newVersion, const String& releaseNotes)
|
||||
{
|
||||
titleLabel.setText ("JUCE version " + newVersion, dontSendNotification);
|
||||
titleLabel.setFont ({ 15.0f, Font::bold });
|
||||
titleLabel.setJustificationType (Justification::centred);
|
||||
addAndMakeVisible (titleLabel);
|
||||
|
||||
contentLabel.setText ("A new version of JUCE is available - would you like to download it?", dontSendNotification);
|
||||
contentLabel.setFont (15.0f);
|
||||
contentLabel.setJustificationType (Justification::topLeft);
|
||||
addAndMakeVisible (contentLabel);
|
||||
|
||||
releaseNotesLabel.setText ("Release notes:", dontSendNotification);
|
||||
releaseNotesLabel.setFont (15.0f);
|
||||
releaseNotesLabel.setJustificationType (Justification::topLeft);
|
||||
addAndMakeVisible (releaseNotesLabel);
|
||||
|
||||
releaseNotesEditor.setMultiLine (true);
|
||||
releaseNotesEditor.setReadOnly (true);
|
||||
releaseNotesEditor.setText (releaseNotes);
|
||||
addAndMakeVisible (releaseNotesEditor);
|
||||
|
||||
addAndMakeVisible (chooseButton);
|
||||
chooseButton.onClick = [this] { exitModalStateWithResult (1); };
|
||||
|
||||
addAndMakeVisible (cancelButton);
|
||||
cancelButton.onClick = [this]
|
||||
{
|
||||
ProjucerApplication::getApp().setAutomaticVersionCheckingEnabled (! dontAskAgainButton.getToggleState());
|
||||
exitModalStateWithResult (-1);
|
||||
};
|
||||
|
||||
dontAskAgainButton.setToggleState (! ProjucerApplication::getApp().isAutomaticVersionCheckingEnabled(), dontSendNotification);
|
||||
addAndMakeVisible (dontAskAgainButton);
|
||||
|
||||
juceIcon = Drawable::createFromImageData (BinaryData::juce_icon_png,
|
||||
BinaryData::juce_icon_pngSize);
|
||||
lookAndFeelChanged();
|
||||
|
||||
setSize (500, 280);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto b = getLocalBounds().reduced (10);
|
||||
|
||||
auto topSlice = b.removeFromTop (juceIconBounds.getHeight())
|
||||
.withTrimmedLeft (juceIconBounds.getWidth());
|
||||
|
||||
titleLabel.setBounds (topSlice.removeFromTop (25));
|
||||
topSlice.removeFromTop (5);
|
||||
contentLabel.setBounds (topSlice.removeFromTop (25));
|
||||
|
||||
auto buttonBounds = b.removeFromBottom (60);
|
||||
buttonBounds.removeFromBottom (25);
|
||||
chooseButton.setBounds (buttonBounds.removeFromLeft (buttonBounds.getWidth() / 2).reduced (20, 0));
|
||||
cancelButton.setBounds (buttonBounds.reduced (20, 0));
|
||||
dontAskAgainButton.setBounds (cancelButton.getBounds().withY (cancelButton.getBottom() + 5).withHeight (20));
|
||||
|
||||
releaseNotesEditor.setBounds (b.reduced (0, 10));
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (backgroundColourId));
|
||||
|
||||
if (juceIcon != nullptr)
|
||||
juceIcon->drawWithin (g, juceIconBounds.toFloat(),
|
||||
RectanglePlacement::stretchToFit, 1.0f);
|
||||
}
|
||||
|
||||
static std::unique_ptr<DialogWindow> launchDialog (const String& newVersionString,
|
||||
const String& releaseNotes)
|
||||
{
|
||||
DialogWindow::LaunchOptions options;
|
||||
|
||||
options.dialogTitle = "Download JUCE version " + newVersionString + "?";
|
||||
options.resizable = false;
|
||||
|
||||
auto* content = new UpdateDialog (newVersionString, releaseNotes);
|
||||
options.content.set (content, true);
|
||||
|
||||
std::unique_ptr<DialogWindow> dialog (options.create());
|
||||
|
||||
content->setParentWindow (dialog.get());
|
||||
dialog->enterModalState (true, nullptr, true);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private:
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
cancelButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
|
||||
releaseNotesEditor.applyFontToAllText (releaseNotesEditor.getFont());
|
||||
}
|
||||
|
||||
void setParentWindow (DialogWindow* parent)
|
||||
{
|
||||
parentWindow = parent;
|
||||
}
|
||||
|
||||
void exitModalStateWithResult (int result)
|
||||
{
|
||||
if (parentWindow != nullptr)
|
||||
parentWindow->exitModalState (result);
|
||||
}
|
||||
|
||||
Label titleLabel, contentLabel, releaseNotesLabel;
|
||||
TextEditor releaseNotesEditor;
|
||||
TextButton chooseButton { "Choose Location..." }, cancelButton { "Cancel" };
|
||||
ToggleButton dontAskAgainButton { "Don't ask again" };
|
||||
std::unique_ptr<Drawable> juceIcon;
|
||||
Rectangle<int> juceIconBounds { 10, 10, 64, 64 };
|
||||
|
||||
DialogWindow* parentWindow = nullptr;
|
||||
};
|
||||
|
||||
void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const VersionInfo::Asset& asset)
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> ("Please select the location into which you would like to install the new version",
|
||||
File { getAppSettings().getStoredPath (Ids::jucePath, TargetOS::getThisOS()).get() });
|
||||
|
||||
chooser->launchAsync (FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories,
|
||||
[weakThis = WeakReference<LatestVersionCheckerAndUpdater> { this }, asset] (const FileChooser& fc)
|
||||
{
|
||||
auto targetFolder = fc.getResult();
|
||||
|
||||
if (targetFolder == File{})
|
||||
return;
|
||||
|
||||
// By default we will install into 'targetFolder/JUCE', but we should install into
|
||||
// 'targetFolder' if that is an existing JUCE directory.
|
||||
bool willOverwriteJuceFolder = [&targetFolder]
|
||||
{
|
||||
if (isJUCEFolder (targetFolder))
|
||||
return true;
|
||||
|
||||
targetFolder = targetFolder.getChildFile ("JUCE");
|
||||
|
||||
return isJUCEFolder (targetFolder);
|
||||
}();
|
||||
|
||||
auto targetFolderPath = targetFolder.getFullPathName();
|
||||
|
||||
const auto onResult = [weakThis, asset, targetFolder] (int result)
|
||||
{
|
||||
if (weakThis == nullptr || result == 0)
|
||||
return;
|
||||
|
||||
weakThis->downloadAndInstall (asset, targetFolder);
|
||||
};
|
||||
|
||||
if (willOverwriteJuceFolder)
|
||||
{
|
||||
if (targetFolder.getChildFile (".git").isDirectory())
|
||||
{
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Downloading New JUCE Version",
|
||||
targetFolderPath + "\n\nis a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
|
||||
"Overwrite Existing JUCE Folder?",
|
||||
"Do you want to replace the folder\n\n" + targetFolderPath + "\n\nwith the latest version from juce.com?\n\n"
|
||||
"This will move the existing folder to " + targetFolderPath + "_old.\n\n"
|
||||
"Replacing the folder that contains the currently running Projucer executable may not work on Windows.",
|
||||
{},
|
||||
{},
|
||||
nullptr,
|
||||
ModalCallbackFunction::create (onResult));
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetFolder.exists())
|
||||
{
|
||||
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
|
||||
"Existing File Or Directory",
|
||||
"Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?",
|
||||
{},
|
||||
{},
|
||||
nullptr,
|
||||
ModalCallbackFunction::create (onResult));
|
||||
return;
|
||||
}
|
||||
|
||||
if (weakThis != nullptr)
|
||||
weakThis->downloadAndInstall (asset, targetFolder);
|
||||
});
|
||||
}
|
||||
|
||||
void LatestVersionCheckerAndUpdater::askUserAboutNewVersion (const String& newVersionString,
|
||||
const String& releaseNotes,
|
||||
const VersionInfo::Asset& asset)
|
||||
{
|
||||
if (backgroundCheck)
|
||||
addNotificationToOpenProjects (asset);
|
||||
else
|
||||
showDialogWindow (newVersionString, releaseNotes, asset);
|
||||
}
|
||||
|
||||
void LatestVersionCheckerAndUpdater::showDialogWindow (const String& newVersionString,
|
||||
const String& releaseNotes,
|
||||
const VersionInfo::Asset& asset)
|
||||
{
|
||||
dialogWindow = UpdateDialog::launchDialog (newVersionString, releaseNotes);
|
||||
|
||||
if (auto* mm = ModalComponentManager::getInstance())
|
||||
{
|
||||
mm->attachCallback (dialogWindow.get(),
|
||||
ModalCallbackFunction::create ([this, asset] (int result)
|
||||
{
|
||||
if (result == 1)
|
||||
askUserForLocationToDownload (asset);
|
||||
|
||||
dialogWindow.reset();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void LatestVersionCheckerAndUpdater::addNotificationToOpenProjects (const VersionInfo::Asset& asset)
|
||||
{
|
||||
for (auto* window : ProjucerApplication::getApp().mainWindowList.windows)
|
||||
{
|
||||
if (auto* project = window->getProject())
|
||||
{
|
||||
auto ignore = [safeWindow = Component::SafePointer<MainWindow> { window }]
|
||||
{
|
||||
if (safeWindow != nullptr)
|
||||
safeWindow->getProject()->removeProjectMessage (ProjectMessages::Ids::newVersionAvailable);
|
||||
};
|
||||
|
||||
auto dontAskAgain = [ignore]
|
||||
{
|
||||
ignore();
|
||||
ProjucerApplication::getApp().setAutomaticVersionCheckingEnabled (false);
|
||||
};
|
||||
|
||||
project->addProjectMessage (ProjectMessages::Ids::newVersionAvailable,
|
||||
{ { "Download", [this, asset] { askUserForLocationToDownload (asset); } },
|
||||
{ "Ignore", std::move (ignore) },
|
||||
{ "Don't ask again", std::move (dontAskAgain) } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DownloadAndInstallThread : private ThreadWithProgressWindow
|
||||
{
|
||||
public:
|
||||
DownloadAndInstallThread (const VersionInfo::Asset& a, const File& t, std::function<void()>&& cb)
|
||||
: ThreadWithProgressWindow ("Downloading New Version", true, true),
|
||||
asset (a), targetFolder (t), completionCallback (std::move (cb))
|
||||
{
|
||||
launchThread (3);
|
||||
}
|
||||
|
||||
private:
|
||||
void run() override
|
||||
{
|
||||
setProgress (-1.0);
|
||||
|
||||
MemoryBlock zipData;
|
||||
auto result = download (zipData);
|
||||
|
||||
if (result.wasOk() && ! threadShouldExit())
|
||||
result = install (zipData);
|
||||
|
||||
if (result.failed())
|
||||
MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
|
||||
"Installation Failed",
|
||||
result.getErrorMessage()); });
|
||||
else
|
||||
MessageManager::callAsync (completionCallback);
|
||||
}
|
||||
|
||||
Result download (MemoryBlock& dest)
|
||||
{
|
||||
setStatusMessage ("Downloading...");
|
||||
|
||||
int statusCode = 0;
|
||||
auto inStream = VersionInfo::createInputStreamForAsset (asset, statusCode);
|
||||
|
||||
if (inStream != nullptr && statusCode == 200)
|
||||
{
|
||||
int64 total = 0;
|
||||
MemoryOutputStream mo (dest, true);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (threadShouldExit())
|
||||
return Result::fail ("Cancelled");
|
||||
|
||||
auto written = mo.writeFromInputStream (*inStream, 8192);
|
||||
|
||||
if (written == 0)
|
||||
break;
|
||||
|
||||
total += written;
|
||||
|
||||
setStatusMessage ("Downloading... " + File::descriptionOfSizeInBytes (total));
|
||||
}
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
return Result::fail ("Failed to download from: " + asset.url);
|
||||
}
|
||||
|
||||
Result install (const MemoryBlock& data)
|
||||
{
|
||||
setStatusMessage ("Installing...");
|
||||
|
||||
MemoryInputStream input (data, false);
|
||||
ZipFile zip (input);
|
||||
|
||||
if (zip.getNumEntries() == 0)
|
||||
return Result::fail ("The downloaded file was not a valid JUCE file!");
|
||||
|
||||
struct ScopedDownloadFolder
|
||||
{
|
||||
explicit ScopedDownloadFolder (const File& installTargetFolder)
|
||||
{
|
||||
folder = installTargetFolder.getSiblingFile (installTargetFolder.getFileNameWithoutExtension() + "_download").getNonexistentSibling();
|
||||
jassert (folder.createDirectory());
|
||||
}
|
||||
|
||||
~ScopedDownloadFolder() { folder.deleteRecursively(); }
|
||||
|
||||
File folder;
|
||||
};
|
||||
|
||||
ScopedDownloadFolder unzipTarget (targetFolder);
|
||||
|
||||
if (! unzipTarget.folder.isDirectory())
|
||||
return Result::fail ("Couldn't create a temporary folder to unzip the new version!");
|
||||
|
||||
auto r = zip.uncompressTo (unzipTarget.folder);
|
||||
|
||||
if (r.failed())
|
||||
return r;
|
||||
|
||||
if (threadShouldExit())
|
||||
return Result::fail ("Cancelled");
|
||||
|
||||
#if JUCE_LINUX || JUCE_BSD || JUCE_MAC
|
||||
r = setFilePermissions (unzipTarget.folder, zip);
|
||||
|
||||
if (r.failed())
|
||||
return r;
|
||||
|
||||
if (threadShouldExit())
|
||||
return Result::fail ("Cancelled");
|
||||
#endif
|
||||
|
||||
if (targetFolder.exists())
|
||||
{
|
||||
auto oldFolder = targetFolder.getSiblingFile (targetFolder.getFileNameWithoutExtension() + "_old").getNonexistentSibling();
|
||||
|
||||
if (! targetFolder.moveFileTo (oldFolder))
|
||||
return Result::fail ("Could not remove the existing folder!\n\n"
|
||||
"This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n"
|
||||
"Please select a folder that is writable by the current user.");
|
||||
}
|
||||
|
||||
if (! unzipTarget.folder.getChildFile ("JUCE").moveFileTo (targetFolder))
|
||||
return Result::fail ("Could not overwrite the existing folder!\n\n"
|
||||
"This may happen if you are trying to download into a directory that requires administrator privileges to modify.\n"
|
||||
"Please select a folder that is writable by the current user.");
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
Result setFilePermissions (const File& root, const ZipFile& zip)
|
||||
{
|
||||
constexpr uint32 executableFlag = (1 << 22);
|
||||
|
||||
for (int i = 0; i < zip.getNumEntries(); ++i)
|
||||
{
|
||||
auto* entry = zip.getEntry (i);
|
||||
|
||||
if ((entry->externalFileAttributes & executableFlag) != 0 && entry->filename.getLastCharacter() != '/')
|
||||
{
|
||||
auto exeFile = root.getChildFile (entry->filename);
|
||||
|
||||
if (! exeFile.exists())
|
||||
return Result::fail ("Failed to find executable file when setting permissions " + exeFile.getFileName());
|
||||
|
||||
if (! exeFile.setExecutePermission (true))
|
||||
return Result::fail ("Failed to set executable file permission for " + exeFile.getFileName());
|
||||
}
|
||||
}
|
||||
|
||||
return Result::ok();
|
||||
}
|
||||
|
||||
VersionInfo::Asset asset;
|
||||
File targetFolder;
|
||||
std::function<void()> completionCallback;
|
||||
};
|
||||
|
||||
static void restartProcess (const File& targetFolder)
|
||||
{
|
||||
#if JUCE_MAC || JUCE_LINUX || JUCE_BSD
|
||||
#if JUCE_MAC
|
||||
auto newProcess = targetFolder.getChildFile ("Projucer.app").getChildFile ("Contents").getChildFile ("MacOS").getChildFile ("Projucer");
|
||||
#elif JUCE_LINUX || JUCE_BSD
|
||||
auto newProcess = targetFolder.getChildFile ("Projucer");
|
||||
#endif
|
||||
|
||||
StringArray command ("/bin/sh", "-c", "while killall -0 Projucer; do sleep 5; done; " + newProcess.getFullPathName().quoted());
|
||||
#elif JUCE_WINDOWS
|
||||
auto newProcess = targetFolder.getChildFile ("Projucer.exe");
|
||||
|
||||
auto command = "cmd.exe /c\"@echo off & for /l %a in (0) do ( tasklist | find \"Projucer\" >nul & ( if errorlevel 1 ( "
|
||||
+ targetFolder.getChildFile ("Projucer.exe").getFullPathName().quoted() + " & exit /b ) else ( timeout /t 10 >nul ) ) )\"";
|
||||
#endif
|
||||
|
||||
if (newProcess.existsAsFile())
|
||||
{
|
||||
ChildProcess restartProcess;
|
||||
restartProcess.start (command, 0);
|
||||
|
||||
ProjucerApplication::getApp().systemRequestedQuit();
|
||||
}
|
||||
}
|
||||
|
||||
void LatestVersionCheckerAndUpdater::downloadAndInstall (const VersionInfo::Asset& asset, const File& targetFolder)
|
||||
{
|
||||
installer.reset (new DownloadAndInstallThread (asset, targetFolder,
|
||||
[this, targetFolder]
|
||||
{
|
||||
installer.reset();
|
||||
restartProcess (targetFolder);
|
||||
}));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
JUCE_IMPLEMENT_SINGLETON (LatestVersionCheckerAndUpdater)
|
62
deps/juce/extras/Projucer/Source/Application/jucer_AutoUpdater.h
vendored
Normal file
62
deps/juce/extras/Projucer/Source/Application/jucer_AutoUpdater.h
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Utility/Helpers/jucer_VersionInfo.h"
|
||||
|
||||
class DownloadAndInstallThread;
|
||||
|
||||
class LatestVersionCheckerAndUpdater : public DeletedAtShutdown,
|
||||
private Thread
|
||||
{
|
||||
public:
|
||||
LatestVersionCheckerAndUpdater();
|
||||
~LatestVersionCheckerAndUpdater() override;
|
||||
|
||||
void checkForNewVersion (bool isBackgroundCheck);
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (LatestVersionCheckerAndUpdater)
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void run() override;
|
||||
void askUserAboutNewVersion (const String&, const String&, const VersionInfo::Asset&);
|
||||
void askUserForLocationToDownload (const VersionInfo::Asset&);
|
||||
void downloadAndInstall (const VersionInfo::Asset&, const File&);
|
||||
|
||||
void showDialogWindow (const String&, const String&, const VersionInfo::Asset&);
|
||||
void addNotificationToOpenProjects (const VersionInfo::Asset&);
|
||||
|
||||
//==============================================================================
|
||||
bool backgroundCheck = false;
|
||||
|
||||
std::unique_ptr<DownloadAndInstallThread> installer;
|
||||
std::unique_ptr<Component> dialogWindow;
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (LatestVersionCheckerAndUpdater)
|
||||
};
|
108
deps/juce/extras/Projucer/Source/Application/jucer_CommandIDs.h
vendored
Normal file
108
deps/juce/extras/Projucer/Source/Application/jucer_CommandIDs.h
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
A namespace to hold all the possible command IDs.
|
||||
*/
|
||||
namespace CommandIDs
|
||||
{
|
||||
enum
|
||||
{
|
||||
newProject = 0x300000,
|
||||
newProjectFromClipboard = 0x300001,
|
||||
newPIP = 0x300002,
|
||||
open = 0x300003,
|
||||
closeDocument = 0x300004,
|
||||
saveDocument = 0x300005,
|
||||
saveDocumentAs = 0x300006,
|
||||
|
||||
launchDemoRunner = 0x300007,
|
||||
|
||||
closeProject = 0x300010,
|
||||
saveProject = 0x300011,
|
||||
saveAll = 0x300012,
|
||||
openInIDE = 0x300013,
|
||||
saveAndOpenInIDE = 0x300014,
|
||||
createNewExporter = 0x300015,
|
||||
|
||||
showUTF8Tool = 0x300020,
|
||||
showGlobalPathsWindow = 0x300021,
|
||||
showTranslationTool = 0x300022,
|
||||
showSVGPathTool = 0x300023,
|
||||
showAboutWindow = 0x300024,
|
||||
checkForNewVersion = 0x300025,
|
||||
enableNewVersionCheck = 0x300026,
|
||||
enableGUIEditor = 0x300027,
|
||||
|
||||
showProjectSettings = 0x300030,
|
||||
showFileExplorerPanel = 0x300033,
|
||||
showModulesPanel = 0x300034,
|
||||
showExportersPanel = 0x300035,
|
||||
showExporterSettings = 0x300036,
|
||||
|
||||
closeWindow = 0x300040,
|
||||
closeAllWindows = 0x300041,
|
||||
closeAllDocuments = 0x300042,
|
||||
goToPreviousDoc = 0x300043,
|
||||
goToNextDoc = 0x300044,
|
||||
goToCounterpart = 0x300045,
|
||||
deleteSelectedItem = 0x300046,
|
||||
goToPreviousWindow = 0x300047,
|
||||
goToNextWindow = 0x300048,
|
||||
clearRecentFiles = 0x300049,
|
||||
|
||||
showFindPanel = 0x300050,
|
||||
findSelection = 0x300051,
|
||||
findNext = 0x300052,
|
||||
findPrevious = 0x300053,
|
||||
|
||||
enableSnapToGrid = 0x300070,
|
||||
zoomIn = 0x300071,
|
||||
zoomOut = 0x300072,
|
||||
zoomNormal = 0x300073,
|
||||
spaceBarDrag = 0x300074,
|
||||
|
||||
loginLogout = 0x300090,
|
||||
|
||||
showForum = 0x300100,
|
||||
showAPIModules = 0x300101,
|
||||
showAPIClasses = 0x300102,
|
||||
showTutorials = 0x300103,
|
||||
|
||||
addNewGUIFile = 0x300200,
|
||||
|
||||
lastCommandIDEntry
|
||||
};
|
||||
}
|
||||
|
||||
namespace CommandCategories
|
||||
{
|
||||
static const char* const general = "General";
|
||||
static const char* const editing = "Editing";
|
||||
static const char* const view = "View";
|
||||
static const char* const windows = "Windows";
|
||||
}
|
933
deps/juce/extras/Projucer/Source/Application/jucer_CommandLine.cpp
vendored
Normal file
933
deps/juce/extras/Projucer/Source/Application/jucer_CommandLine.cpp
vendored
Normal file
@ -0,0 +1,933 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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_Headers.h"
|
||||
#include "jucer_Application.h"
|
||||
#include "../Utility/Helpers/jucer_TranslationHelpers.h"
|
||||
|
||||
#include "jucer_CommandLine.h"
|
||||
|
||||
//==============================================================================
|
||||
const char* preferredLineFeed = "\r\n";
|
||||
const char* getPreferredLineFeed() { return preferredLineFeed; }
|
||||
|
||||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
static void hideDockIcon()
|
||||
{
|
||||
#if JUCE_MAC
|
||||
Process::setDockIconVisible (false);
|
||||
#endif
|
||||
}
|
||||
|
||||
static Array<File> findAllSourceFiles (const File& folder)
|
||||
{
|
||||
Array<File> files;
|
||||
|
||||
for (const auto& di : RangedDirectoryIterator (folder, true, "*.cpp;*.cxx;*.cc;*.c;*.h;*.hpp;*.hxx;*.hpp;*.mm;*.m;*.java;*.dox;*.soul;*.js", File::findFiles))
|
||||
if (! di.getFile().isSymbolicLink())
|
||||
files.add (di.getFile());
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
static void replaceFile (const File& file, const String& newText, const String& message)
|
||||
{
|
||||
std::cout << message << file.getFullPathName() << std::endl;
|
||||
|
||||
TemporaryFile temp (file);
|
||||
|
||||
if (! temp.getFile().replaceWithText (newText, false, false, nullptr))
|
||||
ConsoleApplication::fail ("!!! ERROR Couldn't write to temp file!");
|
||||
|
||||
if (! temp.overwriteTargetFileWithTemporary())
|
||||
ConsoleApplication::fail ("!!! ERROR Couldn't write to file!");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct LoadedProject
|
||||
{
|
||||
explicit LoadedProject (const ArgumentList::Argument& fileToLoad)
|
||||
{
|
||||
hideDockIcon();
|
||||
|
||||
auto projectFile = fileToLoad.resolveAsExistingFile();
|
||||
|
||||
if (! projectFile.hasFileExtension (Project::projectFileExtension))
|
||||
ConsoleApplication::fail (projectFile.getFullPathName() + " isn't a valid jucer project file!");
|
||||
|
||||
project.reset (new Project (projectFile));
|
||||
|
||||
if (! project->loadFrom (projectFile, true, false))
|
||||
{
|
||||
project.reset();
|
||||
ConsoleApplication::fail ("Failed to load the project file: " + projectFile.getFullPathName());
|
||||
}
|
||||
|
||||
preferredLineFeed = project->getProjectLineFeed().toRawUTF8();
|
||||
}
|
||||
|
||||
void save (bool justSaveResources, bool fixMissingDependencies)
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
if (! justSaveResources)
|
||||
rescanModulePathsIfNecessary();
|
||||
|
||||
if (fixMissingDependencies)
|
||||
tryToFixMissingModuleDependencies();
|
||||
|
||||
const auto onCompletion = [this] (Result result)
|
||||
{
|
||||
project.reset();
|
||||
|
||||
if (result.failed())
|
||||
ConsoleApplication::fail ("Error when saving: " + result.getErrorMessage());
|
||||
};
|
||||
|
||||
if (justSaveResources)
|
||||
onCompletion (project->saveResourcesOnly());
|
||||
else
|
||||
project->saveProject (Async::no, nullptr, onCompletion);
|
||||
}
|
||||
}
|
||||
|
||||
void rescanModulePathsIfNecessary()
|
||||
{
|
||||
bool scanJUCEPath = false, scanUserPaths = false;
|
||||
|
||||
const auto& modules = project->getEnabledModules();
|
||||
|
||||
for (auto i = modules.getNumModules(); --i >= 0;)
|
||||
{
|
||||
const auto& id = modules.getModuleID (i);
|
||||
|
||||
if (isJUCEModule (id) && ! scanJUCEPath)
|
||||
{
|
||||
if (modules.shouldUseGlobalPath (id))
|
||||
scanJUCEPath = true;
|
||||
}
|
||||
else if (! scanUserPaths)
|
||||
{
|
||||
if (modules.shouldUseGlobalPath (id))
|
||||
scanUserPaths = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (scanJUCEPath)
|
||||
ProjucerApplication::getApp().rescanJUCEPathModules();
|
||||
|
||||
if (scanUserPaths)
|
||||
ProjucerApplication::getApp().rescanUserPathModules();
|
||||
}
|
||||
|
||||
void tryToFixMissingModuleDependencies()
|
||||
{
|
||||
auto& modules = project->getEnabledModules();
|
||||
|
||||
for (const auto& m : modules.getModulesWithMissingDependencies())
|
||||
modules.tryToFixMissingDependencies (m);
|
||||
}
|
||||
|
||||
std::unique_ptr<Project> project;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/* Running a command-line of the form "projucer --resave foobar.jucer" will try to load
|
||||
that project and re-export all of its targets.
|
||||
*/
|
||||
static void resaveProject (const ArgumentList& args, bool justSaveResources)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
std::cout << (justSaveResources ? "Re-saving project resources: "
|
||||
: "Re-saving file: ")
|
||||
<< proj.project->getFile().getFullPathName() << std::endl;
|
||||
|
||||
proj.save (justSaveResources, args.containsOption ("--fix-missing-dependencies"));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void getVersion (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
std::cout << proj.project->getVersionString() << std::endl;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void setVersion (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[2]);
|
||||
|
||||
String version (args[1].text.trim());
|
||||
|
||||
std::cout << "Setting project version: " << version << std::endl;
|
||||
|
||||
proj.project->setProjectVersion (version);
|
||||
proj.save (false, false);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void bumpVersion (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
String version = proj.project->getVersionString();
|
||||
|
||||
version = version.upToLastOccurrenceOf (".", true, false)
|
||||
+ String (version.getTrailingIntValue() + 1);
|
||||
|
||||
std::cout << "Bumping project version to: " << version << std::endl;
|
||||
|
||||
proj.project->setProjectVersion (version);
|
||||
proj.save (false, false);
|
||||
}
|
||||
|
||||
static void gitTag (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
String version (proj.project->getVersionString());
|
||||
|
||||
if (version.trim().isEmpty())
|
||||
ConsoleApplication::fail ("Cannot read version number from project!");
|
||||
|
||||
StringArray command;
|
||||
command.add ("git");
|
||||
command.add ("tag");
|
||||
command.add ("-a");
|
||||
command.add (version);
|
||||
command.add ("-m");
|
||||
command.add (version.quoted());
|
||||
|
||||
std::cout << "Performing command: " << command.joinIntoString(" ") << std::endl;
|
||||
|
||||
ChildProcess c;
|
||||
|
||||
if (! c.start (command, 0))
|
||||
ConsoleApplication::fail ("Cannot run git!");
|
||||
|
||||
c.waitForProcessToFinish (10000);
|
||||
|
||||
if (c.getExitCode() != 0)
|
||||
ConsoleApplication::fail ("git command failed!");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void showStatus (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
std::cout << "Project file: " << proj.project->getFile().getFullPathName() << std::endl
|
||||
<< "Name: " << proj.project->getProjectNameString() << std::endl
|
||||
<< "UID: " << proj.project->getProjectUIDString() << std::endl;
|
||||
|
||||
auto& modules = proj.project->getEnabledModules();
|
||||
|
||||
if (int numModules = modules.getNumModules())
|
||||
{
|
||||
std::cout << "Modules:" << std::endl;
|
||||
|
||||
for (int i = 0; i < numModules; ++i)
|
||||
std::cout << " " << modules.getModuleID (i) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static String getModulePackageName (const LibraryModule& module)
|
||||
{
|
||||
return module.getID() + ".jucemodule";
|
||||
}
|
||||
|
||||
static void zipModule (const File& targetFolder, const File& moduleFolder)
|
||||
{
|
||||
jassert (targetFolder.isDirectory());
|
||||
|
||||
auto moduleFolderParent = moduleFolder.getParentDirectory();
|
||||
LibraryModule module (moduleFolder);
|
||||
|
||||
if (! module.isValid())
|
||||
ConsoleApplication::fail (moduleFolder.getFullPathName() + " is not a valid module folder!");
|
||||
|
||||
auto targetFile = targetFolder.getChildFile (getModulePackageName (module));
|
||||
|
||||
ZipFile::Builder zip;
|
||||
|
||||
{
|
||||
for (const auto& i : RangedDirectoryIterator (moduleFolder, true, "*", File::findFiles))
|
||||
if (! i.getFile().isHidden())
|
||||
zip.addFile (i.getFile(), 9, i.getFile().getRelativePathFrom (moduleFolderParent));
|
||||
}
|
||||
|
||||
std::cout << "Writing: " << targetFile.getFullPathName() << std::endl;
|
||||
|
||||
TemporaryFile temp (targetFile);
|
||||
|
||||
{
|
||||
FileOutputStream out (temp.getFile());
|
||||
|
||||
if (! (out.openedOk() && zip.writeToStream (out, nullptr)))
|
||||
ConsoleApplication::fail ("Failed to write to the target file: " + targetFile.getFullPathName());
|
||||
}
|
||||
|
||||
if (! temp.overwriteTargetFileWithTemporary())
|
||||
ConsoleApplication::fail ("Failed to write to the target file: " + targetFile.getFullPathName());
|
||||
}
|
||||
|
||||
static void buildModules (const ArgumentList& args, const bool buildAllWithIndex)
|
||||
{
|
||||
hideDockIcon();
|
||||
args.checkMinNumArguments (3);
|
||||
|
||||
auto targetFolder = args[1].resolveAsFile();
|
||||
|
||||
if (! targetFolder.isDirectory())
|
||||
ConsoleApplication::fail ("The first argument must be the directory to put the result.");
|
||||
|
||||
if (buildAllWithIndex)
|
||||
{
|
||||
auto folderToSearch = args[2].resolveAsFile();
|
||||
var infoList;
|
||||
|
||||
for (const auto& i : RangedDirectoryIterator (folderToSearch, false, "*", File::findDirectories))
|
||||
{
|
||||
LibraryModule module (i.getFile());
|
||||
|
||||
if (module.isValid())
|
||||
{
|
||||
zipModule (targetFolder, i.getFile());
|
||||
|
||||
var moduleInfo (new DynamicObject());
|
||||
moduleInfo.getDynamicObject()->setProperty ("file", getModulePackageName (module));
|
||||
moduleInfo.getDynamicObject()->setProperty ("info", module.moduleInfo.getModuleInfo());
|
||||
infoList.append (moduleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
auto indexFile = targetFolder.getChildFile ("modulelist");
|
||||
std::cout << "Writing: " << indexFile.getFullPathName() << std::endl;
|
||||
indexFile.replaceWithText (JSON::toString (infoList), false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 2; i < args.size(); ++i)
|
||||
zipModule (targetFolder, args[i].resolveAsFile());
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct CleanupOptions
|
||||
{
|
||||
bool removeTabs;
|
||||
bool fixDividerComments;
|
||||
};
|
||||
|
||||
static void cleanWhitespace (const File& file, CleanupOptions options)
|
||||
{
|
||||
auto content = file.loadFileAsString();
|
||||
|
||||
auto isProjucerTemplateFile = [file, content]
|
||||
{
|
||||
return file.getFullPathName().contains ("Templates")
|
||||
&& content.contains ("%""%") && content.contains ("//[");
|
||||
}();
|
||||
|
||||
if (isProjucerTemplateFile)
|
||||
return;
|
||||
|
||||
StringArray lines;
|
||||
lines.addLines (content);
|
||||
bool anyTabsRemoved = false;
|
||||
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
String& line = lines.getReference (i);
|
||||
|
||||
if (options.removeTabs && line.containsChar ('\t'))
|
||||
{
|
||||
anyTabsRemoved = true;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const int tabPos = line.indexOfChar ('\t');
|
||||
|
||||
if (tabPos < 0)
|
||||
break;
|
||||
|
||||
const int spacesPerTab = 4;
|
||||
const int spacesNeeded = spacesPerTab - (tabPos % spacesPerTab);
|
||||
line = line.replaceSection (tabPos, 1, String::repeatedString (" ", spacesNeeded));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.fixDividerComments)
|
||||
{
|
||||
auto afterIndent = line.trim();
|
||||
|
||||
if (afterIndent.startsWith ("//") && afterIndent.length() > 20)
|
||||
{
|
||||
afterIndent = afterIndent.substring (2);
|
||||
|
||||
if (afterIndent.containsOnly ("=")
|
||||
|| afterIndent.containsOnly ("/")
|
||||
|| afterIndent.containsOnly ("-"))
|
||||
{
|
||||
line = line.substring (0, line.indexOfChar ('/'))
|
||||
+ "//" + String::repeatedString ("=", 78);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line = line.trimEnd();
|
||||
}
|
||||
|
||||
if (options.removeTabs && ! anyTabsRemoved)
|
||||
return;
|
||||
|
||||
auto newText = joinLinesIntoSourceFile (lines);
|
||||
|
||||
if (newText != content && newText != content + getPreferredLineFeed())
|
||||
replaceFile (file, newText, options.removeTabs ? "Removing tabs in: "
|
||||
: "Cleaning file: ");
|
||||
}
|
||||
|
||||
static void scanFilesForCleanup (const ArgumentList& args, CleanupOptions options)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
|
||||
for (auto it = args.arguments.begin() + 1; it < args.arguments.end(); ++it)
|
||||
{
|
||||
auto target = it->resolveAsFile();
|
||||
|
||||
Array<File> files;
|
||||
|
||||
if (target.isDirectory())
|
||||
files = findAllSourceFiles (target);
|
||||
else
|
||||
files.add (target);
|
||||
|
||||
for (int i = 0; i < files.size(); ++i)
|
||||
cleanWhitespace (files.getReference (i), options);
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanWhitespace (const ArgumentList& args, bool replaceTabs)
|
||||
{
|
||||
CleanupOptions options = { replaceTabs, false };
|
||||
scanFilesForCleanup (args, options);
|
||||
}
|
||||
|
||||
static void tidyDividerComments (const ArgumentList& args)
|
||||
{
|
||||
CleanupOptions options = { false, true };
|
||||
scanFilesForCleanup (args, options);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static File findSimilarlyNamedHeader (const Array<File>& allFiles, const String& name, const File& sourceFile)
|
||||
{
|
||||
File result;
|
||||
|
||||
for (auto& f : allFiles)
|
||||
{
|
||||
if (f.getFileName().equalsIgnoreCase (name) && f != sourceFile)
|
||||
{
|
||||
if (result.exists())
|
||||
return {}; // multiple possible results, so don't change it!
|
||||
|
||||
result = f;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void fixIncludes (const File& file, const Array<File>& allFiles)
|
||||
{
|
||||
const String content (file.loadFileAsString());
|
||||
|
||||
StringArray lines;
|
||||
lines.addLines (content);
|
||||
bool hasChanged = false;
|
||||
|
||||
for (auto& line : lines)
|
||||
{
|
||||
if (line.trimStart().startsWith ("#include \""))
|
||||
{
|
||||
auto includedFile = line.fromFirstOccurrenceOf ("\"", true, false)
|
||||
.upToLastOccurrenceOf ("\"", true, false)
|
||||
.trim()
|
||||
.unquoted();
|
||||
|
||||
auto target = file.getSiblingFile (includedFile);
|
||||
|
||||
if (! target.exists())
|
||||
{
|
||||
auto header = findSimilarlyNamedHeader (allFiles, target.getFileName(), file);
|
||||
|
||||
if (header.exists())
|
||||
{
|
||||
line = line.upToFirstOccurrenceOf ("#include \"", true, false)
|
||||
+ header.getRelativePathFrom (file.getParentDirectory())
|
||||
.replaceCharacter ('\\', '/')
|
||||
+ "\"";
|
||||
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
auto newText = joinLinesIntoSourceFile (lines);
|
||||
|
||||
if (newText != content && newText != content + getPreferredLineFeed())
|
||||
replaceFile (file, newText, "Fixing includes in: ");
|
||||
}
|
||||
}
|
||||
|
||||
static void fixRelativeIncludePaths (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
auto target = args[1].resolveAsExistingFolder();
|
||||
auto files = findAllSourceFiles (target);
|
||||
|
||||
for (int i = 0; i < files.size(); ++i)
|
||||
fixIncludes (files.getReference(i), files);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static String getStringConcatenationExpression (Random& rng, int start, int length)
|
||||
{
|
||||
jassert (length > 0);
|
||||
|
||||
if (length == 1)
|
||||
return "s" + String (start);
|
||||
|
||||
int breakPos = jlimit (1, length - 1, (length / 3) + rng.nextInt (jmax (1, length / 3)));
|
||||
|
||||
return "(" + getStringConcatenationExpression (rng, start, breakPos)
|
||||
+ " + " + getStringConcatenationExpression (rng, start + breakPos, length - breakPos) + ")";
|
||||
}
|
||||
|
||||
static void generateObfuscatedStringCode (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
auto originalText = args[1].text.unquoted();
|
||||
|
||||
struct Section
|
||||
{
|
||||
String text;
|
||||
int position, index;
|
||||
|
||||
void writeGenerator (MemoryOutputStream& out) const
|
||||
{
|
||||
String name ("s" + String (index));
|
||||
|
||||
out << " String " << name << "; " << name;
|
||||
|
||||
auto escapeIfSingleQuote = [] (const String& s) -> String
|
||||
{
|
||||
if (s == "\'")
|
||||
return "\\'";
|
||||
|
||||
return s;
|
||||
};
|
||||
|
||||
for (int i = 0; i < text.length(); ++i)
|
||||
out << " << '" << escapeIfSingleQuote (String::charToString (text[i])) << "'";
|
||||
|
||||
out << ";" << preferredLineFeed;
|
||||
}
|
||||
};
|
||||
|
||||
Array<Section> sections;
|
||||
String text = originalText;
|
||||
Random rng;
|
||||
|
||||
while (text.isNotEmpty())
|
||||
{
|
||||
int pos = jmax (0, text.length() - (1 + rng.nextInt (6)));
|
||||
Section s = { text.substring (pos), pos, 0 };
|
||||
sections.insert (0, s);
|
||||
text = text.substring (0, pos);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sections.size(); ++i)
|
||||
sections.getReference(i).index = i;
|
||||
|
||||
for (int i = 0; i < sections.size(); ++i)
|
||||
sections.swap (i, rng.nextInt (sections.size()));
|
||||
|
||||
MemoryOutputStream out;
|
||||
|
||||
out << "String createString()" << preferredLineFeed
|
||||
<< "{" << preferredLineFeed;
|
||||
|
||||
for (int i = 0; i < sections.size(); ++i)
|
||||
sections.getReference(i).writeGenerator (out);
|
||||
|
||||
out << preferredLineFeed
|
||||
<< " String result = " << getStringConcatenationExpression (rng, 0, sections.size()) << ";" << preferredLineFeed
|
||||
<< preferredLineFeed
|
||||
<< " jassert (result == " << originalText.quoted() << ");" << preferredLineFeed
|
||||
<< " return result;" << preferredLineFeed
|
||||
<< "}" << preferredLineFeed;
|
||||
|
||||
std::cout << out.toString() << std::endl;
|
||||
}
|
||||
|
||||
static void scanFoldersForTranslationFiles (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (2);
|
||||
|
||||
StringArray translations;
|
||||
|
||||
for (auto it = args.arguments.begin() + 1; it != args.arguments.end(); ++it)
|
||||
{
|
||||
auto directoryToSearch = it->resolveAsExistingFolder();
|
||||
TranslationHelpers::scanFolderForTranslations (translations, directoryToSearch);
|
||||
}
|
||||
|
||||
std::cout << TranslationHelpers::mungeStrings (translations) << std::endl;
|
||||
}
|
||||
|
||||
static void createFinishedTranslationFile (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (3);
|
||||
|
||||
auto preTranslated = args[1].resolveAsExistingFile().loadFileAsString();
|
||||
auto postTranslated = args[2].resolveAsExistingFile().loadFileAsString();
|
||||
|
||||
auto localisedContent = (args.size() > 3 ? args[3].resolveAsExistingFile().loadFileAsString() : String());
|
||||
auto localised = LocalisedStrings (localisedContent, false);
|
||||
|
||||
using TH = TranslationHelpers;
|
||||
std::cout << TH::createFinishedTranslationFile (TH::withTrimmedEnds (TH::breakApart (preTranslated)),
|
||||
TH::withTrimmedEnds (TH::breakApart (postTranslated)),
|
||||
localised) << std::endl;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void encodeBinary (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (3);
|
||||
auto source = args[1].resolveAsExistingFile();
|
||||
auto target = args[2].resolveAsExistingFile();
|
||||
|
||||
MemoryOutputStream literal;
|
||||
size_t dataSize = 0;
|
||||
|
||||
{
|
||||
MemoryBlock data;
|
||||
FileInputStream input (source);
|
||||
input.readIntoMemoryBlock (data);
|
||||
build_tools::writeDataAsCppLiteral (data, literal, true, true);
|
||||
dataSize = data.getSize();
|
||||
}
|
||||
|
||||
auto variableName = build_tools::makeBinaryDataIdentifierName (source);
|
||||
|
||||
MemoryOutputStream header, cpp;
|
||||
|
||||
header << "// Auto-generated binary data by the Projucer" << preferredLineFeed
|
||||
<< "// Source file: " << source.getRelativePathFrom (target.getParentDirectory()) << preferredLineFeed
|
||||
<< preferredLineFeed;
|
||||
|
||||
cpp << header.toString();
|
||||
|
||||
if (target.hasFileExtension (headerFileExtensions))
|
||||
{
|
||||
header << "static constexpr unsigned char " << variableName << "[] =" << preferredLineFeed
|
||||
<< literal.toString() << preferredLineFeed
|
||||
<< preferredLineFeed;
|
||||
|
||||
replaceFile (target, header.toString(), "Writing: ");
|
||||
}
|
||||
else if (target.hasFileExtension (cppFileExtensions))
|
||||
{
|
||||
header << "extern const char* " << variableName << ";" << preferredLineFeed
|
||||
<< "const unsigned int " << variableName << "Size = " << (int) dataSize << ";" << preferredLineFeed
|
||||
<< preferredLineFeed;
|
||||
|
||||
cpp << CodeHelpers::createIncludeStatement (target.withFileExtension (".h").getFileName()) << preferredLineFeed
|
||||
<< preferredLineFeed
|
||||
<< "static constexpr unsigned char " << variableName << "_local[] =" << preferredLineFeed
|
||||
<< literal.toString() << preferredLineFeed
|
||||
<< preferredLineFeed
|
||||
<< "const char* " << variableName << " = (const char*) " << variableName << "_local;" << preferredLineFeed;
|
||||
|
||||
replaceFile (target, cpp.toString(), "Writing: ");
|
||||
replaceFile (target.withFileExtension (".h"), header.toString(), "Writing: ");
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsoleApplication::fail ("You need to specify a .h or .cpp file as the target");
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static bool isThisOS (const String& os)
|
||||
{
|
||||
auto targetOS = TargetOS::unknown;
|
||||
|
||||
if (os == "osx") targetOS = TargetOS::osx;
|
||||
else if (os == "windows") targetOS = TargetOS::windows;
|
||||
else if (os == "linux") targetOS = TargetOS::linux;
|
||||
|
||||
if (targetOS == TargetOS::unknown)
|
||||
ConsoleApplication::fail ("You need to specify a valid OS! Use osx, windows or linux");
|
||||
|
||||
return targetOS == TargetOS::getThisOS();
|
||||
}
|
||||
|
||||
static bool isValidPathIdentifier (const String& id, const String& os)
|
||||
{
|
||||
return id == "vstLegacyPath" || (id == "aaxPath" && os != "linux") || (id == "rtasPath" && os != "linux")
|
||||
|| id == "androidSDKPath" || id == "defaultJuceModulePath" || id == "defaultUserModulePath";
|
||||
}
|
||||
|
||||
static void setGlobalPath (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (3);
|
||||
|
||||
if (! isValidPathIdentifier (args[2].text, args[1].text))
|
||||
ConsoleApplication::fail ("Identifier " + args[2].text + " is not valid for the OS " + args[1].text);
|
||||
|
||||
auto userAppData = File::getSpecialLocation (File::userApplicationDataDirectory);
|
||||
|
||||
#if JUCE_MAC
|
||||
userAppData = userAppData.getChildFile ("Application Support");
|
||||
#endif
|
||||
|
||||
auto settingsFile = userAppData.getChildFile ("Projucer").getChildFile ("Projucer.settings");
|
||||
auto xml = parseXML (settingsFile);
|
||||
|
||||
if (xml == nullptr)
|
||||
ConsoleApplication::fail ("Settings file not valid!");
|
||||
|
||||
auto settingsTree = ValueTree::fromXml (*xml);
|
||||
|
||||
if (! settingsTree.isValid())
|
||||
ConsoleApplication::fail ("Settings file not valid!");
|
||||
|
||||
ValueTree childToSet;
|
||||
|
||||
if (isThisOS (args[1].text))
|
||||
{
|
||||
childToSet = settingsTree.getChildWithProperty (Ids::name, "PROJECT_DEFAULT_SETTINGS")
|
||||
.getOrCreateChildWithName ("PROJECT_DEFAULT_SETTINGS", nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
childToSet = settingsTree.getChildWithProperty (Ids::name, "FALLBACK_PATHS")
|
||||
.getOrCreateChildWithName ("FALLBACK_PATHS", nullptr)
|
||||
.getOrCreateChildWithName (args[1].text + "Fallback", nullptr);
|
||||
}
|
||||
|
||||
if (! childToSet.isValid())
|
||||
ConsoleApplication::fail ("Failed to set the requested setting!");
|
||||
|
||||
childToSet.setProperty (args[2].text, args[3].resolveAsFile().getFullPathName(), nullptr);
|
||||
|
||||
settingsFile.replaceWithText (settingsTree.toXmlString());
|
||||
}
|
||||
|
||||
static void createProjectFromPIP (const ArgumentList& args)
|
||||
{
|
||||
args.checkMinNumArguments (3);
|
||||
|
||||
auto pipFile = args[1].resolveAsFile();
|
||||
|
||||
if (! pipFile.existsAsFile())
|
||||
ConsoleApplication::fail ("PIP file doesn't exist.");
|
||||
|
||||
auto outputDir = args[2].resolveAsFile();
|
||||
|
||||
if (! outputDir.exists())
|
||||
{
|
||||
auto res = outputDir.createDirectory();
|
||||
std::cout << "Creating directory " << outputDir.getFullPathName() << std::endl;
|
||||
}
|
||||
|
||||
File juceModulesPath, userModulesPath;
|
||||
|
||||
if (args.size() > 3)
|
||||
{
|
||||
juceModulesPath = args[3].resolveAsFile();
|
||||
|
||||
if (! juceModulesPath.exists())
|
||||
ConsoleApplication::fail ("Specified JUCE modules directory doesn't exist.");
|
||||
|
||||
if (args.size() == 5)
|
||||
{
|
||||
userModulesPath = args[4].resolveAsFile();
|
||||
|
||||
if (! userModulesPath.exists())
|
||||
ConsoleApplication::fail ("Specified JUCE modules directory doesn't exist.");
|
||||
}
|
||||
}
|
||||
|
||||
PIPGenerator generator (pipFile, outputDir, juceModulesPath, userModulesPath);
|
||||
|
||||
auto createJucerFileResult = generator.createJucerFile();
|
||||
|
||||
if (! createJucerFileResult)
|
||||
ConsoleApplication::fail (createJucerFileResult.getErrorMessage());
|
||||
|
||||
auto createMainCppResult = generator.createMainCpp();
|
||||
|
||||
if (! createMainCppResult)
|
||||
ConsoleApplication::fail (createMainCppResult.getErrorMessage());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void showHelp()
|
||||
{
|
||||
hideDockIcon();
|
||||
|
||||
auto appName = JUCEApplication::getInstance()->getApplicationName();
|
||||
|
||||
std::cout << appName << std::endl
|
||||
<< std::endl
|
||||
<< "Usage: " << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --resave project_file" << std::endl
|
||||
<< " Resaves all files and resources in a project. Add the \"--fix-missing-dependencies\" option to automatically fix any missing module dependencies." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --resave-resources project_file" << std::endl
|
||||
<< " Resaves just the binary resources for a project." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --get-version project_file" << std::endl
|
||||
<< " Returns the version number of a project." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --set-version version_number project_file" << std::endl
|
||||
<< " Updates the version number in a project." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --bump-version project_file" << std::endl
|
||||
<< " Updates the minor version number in a project by 1." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --git-tag-version project_file" << std::endl
|
||||
<< " Invokes 'git tag' to attach the project's version number to the current git repository." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --status project_file" << std::endl
|
||||
<< " Displays information about a project." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --buildmodule target_folder module_folder" << std::endl
|
||||
<< " Zips a module into a downloadable file format." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --buildallmodules target_folder module_folder" << std::endl
|
||||
<< " Zips all modules in a given folder and creates an index for them." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --trim-whitespace target_folder" << std::endl
|
||||
<< " Scans the given folder for C/C++ source files (recursively), and trims any trailing whitespace from their lines, as well as normalising their line-endings to CR-LF." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --remove-tabs target_folder" << std::endl
|
||||
<< " Scans the given folder for C/C++ source files (recursively), and replaces any tab characters with 4 spaces." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --tidy-divider-comments target_folder" << std::endl
|
||||
<< " Scans the given folder for C/C++ source files (recursively), and normalises any juce-style comment division lines (i.e. any lines that look like //===== or //------- or /////////// will be replaced)." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --fix-broken-include-paths target_folder" << std::endl
|
||||
<< " Scans the given folder for C/C++ source files (recursively). Where a file contains an #include of one of the other filenames, it changes it to use the optimum relative path. Helpful for auto-fixing includes when re-arranging files and folders in a project." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --obfuscated-string-code string_to_obfuscate" << std::endl
|
||||
<< " Generates a C++ function which returns the given string, but in an obfuscated way." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --encode-binary source_binary_file target_cpp_file" << std::endl
|
||||
<< " Converts a binary file to a C++ file containing its contents as a block of data. Provide a .h file as the target if you want a single output file, or a .cpp file if you want a pair of .h/.cpp files." << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --trans target_folders..." << std::endl
|
||||
<< " Scans each of the given folders (recursively) for any NEEDS_TRANS macros, and generates a translation file that can be used with Projucer's translation file builder" << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --trans-finish pre_translated_file post_translated_file optional_existing_translation_file" << std::endl
|
||||
<< " Creates a completed translations mapping file, that can be used to initialise a LocalisedStrings object. This allows you to localise the strings in your project" << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --set-global-search-path os identifier_to_set new_path" << std::endl
|
||||
<< " 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, vstLegacyPath, aaxPath (not valid on linux), rtasPath (not valid on linux), or androidSDKPath. " << std::endl
|
||||
<< std::endl
|
||||
<< " " << appName << " --create-project-from-pip path/to/PIP path/to/output path/to/JUCE/modules (optional) path/to/user/modules (optional)" << std::endl
|
||||
<< " Generates a folder containing a JUCE project in the specified output path using the specified PIP file. Use the optional JUCE and user module paths to override "
|
||||
"the global module paths." << std::endl
|
||||
<< std::endl
|
||||
<< "Note that for any of the file-rewriting commands, add the option \"--lf\" if you want it to use LF linefeeds instead of CRLF" << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int performCommandLine (const ArgumentList& args)
|
||||
{
|
||||
return ConsoleApplication::invokeCatchingFailures ([&]() -> int
|
||||
{
|
||||
if (args.containsOption ("--lf"))
|
||||
preferredLineFeed = "\n";
|
||||
|
||||
auto command = args[0];
|
||||
|
||||
auto matchCommand = [&] (StringRef name) -> bool
|
||||
{
|
||||
return command == name || command.isLongOption (name);
|
||||
};
|
||||
|
||||
if (matchCommand ("help")) { showHelp(); return 0; }
|
||||
if (matchCommand ("h")) { showHelp(); return 0; }
|
||||
if (matchCommand ("resave")) { resaveProject (args, false); return 0; }
|
||||
if (matchCommand ("resave-resources")) { resaveProject (args, true); return 0; }
|
||||
if (matchCommand ("get-version")) { getVersion (args); return 0; }
|
||||
if (matchCommand ("set-version")) { setVersion (args); return 0; }
|
||||
if (matchCommand ("bump-version")) { bumpVersion (args); return 0; }
|
||||
if (matchCommand ("git-tag-version")) { gitTag (args); return 0; }
|
||||
if (matchCommand ("buildmodule")) { buildModules (args, false); return 0; }
|
||||
if (matchCommand ("buildallmodules")) { buildModules (args, true); return 0; }
|
||||
if (matchCommand ("status")) { showStatus (args); return 0; }
|
||||
if (matchCommand ("trim-whitespace")) { cleanWhitespace (args, false); return 0; }
|
||||
if (matchCommand ("remove-tabs")) { cleanWhitespace (args, true); return 0; }
|
||||
if (matchCommand ("tidy-divider-comments")) { tidyDividerComments (args); return 0; }
|
||||
if (matchCommand ("fix-broken-include-paths")) { fixRelativeIncludePaths (args); return 0; }
|
||||
if (matchCommand ("obfuscated-string-code")) { generateObfuscatedStringCode (args); return 0; }
|
||||
if (matchCommand ("encode-binary")) { encodeBinary (args); return 0; }
|
||||
if (matchCommand ("trans")) { scanFoldersForTranslationFiles (args); return 0; }
|
||||
if (matchCommand ("trans-finish")) { createFinishedTranslationFile (args); return 0; }
|
||||
if (matchCommand ("set-global-search-path")) { setGlobalPath (args); return 0; }
|
||||
if (matchCommand ("create-project-from-pip")) { createProjectFromPIP (args); return 0; }
|
||||
|
||||
if (command.isLongOption() || command.isShortOption())
|
||||
ConsoleApplication::fail ("Unrecognised command: " + command.text.quoted());
|
||||
|
||||
return commandLineNotPerformed;
|
||||
});
|
||||
}
|
30
deps/juce/extras/Projucer/Source/Application/jucer_CommandLine.h
vendored
Normal file
30
deps/juce/extras/Projucer/Source/Application/jucer_CommandLine.h
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
int performCommandLine (const ArgumentList&);
|
||||
|
||||
enum { commandLineNotPerformed = 0x72346231 };
|
99
deps/juce/extras/Projucer/Source/Application/jucer_CommonHeaders.h
vendored
Normal file
99
deps/juce/extras/Projucer/Source/Application/jucer_CommonHeaders.h
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// The GCC extensions define linux somewhere in the headers, so undef it here...
|
||||
#if JUCE_GCC
|
||||
#undef linux
|
||||
#endif
|
||||
|
||||
struct TargetOS
|
||||
{
|
||||
enum OS
|
||||
{
|
||||
windows = 0,
|
||||
osx,
|
||||
linux,
|
||||
unknown
|
||||
};
|
||||
|
||||
static OS getThisOS() noexcept
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
return windows;
|
||||
#elif JUCE_MAC
|
||||
return osx;
|
||||
#elif JUCE_LINUX || JUCE_BSD
|
||||
return linux;
|
||||
#else
|
||||
return unknown;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
typedef TargetOS::OS DependencyPathOS;
|
||||
|
||||
//==============================================================================
|
||||
#include "../Settings/jucer_StoredSettings.h"
|
||||
#include "../Utility/UI/jucer_Icons.h"
|
||||
#include "../Utility/Helpers/jucer_MiscUtilities.h"
|
||||
#include "../Utility/Helpers/jucer_CodeHelpers.h"
|
||||
#include "../Utility/Helpers/jucer_FileHelpers.h"
|
||||
#include "../Utility/Helpers/jucer_ValueSourceHelpers.h"
|
||||
#include "../Utility/Helpers/jucer_PresetIDs.h"
|
||||
#include "jucer_CommandIDs.h"
|
||||
|
||||
//==============================================================================
|
||||
const char* const projectItemDragType = "Project Items";
|
||||
const char* const drawableItemDragType = "Drawable Items";
|
||||
const char* const componentItemDragType = "Components";
|
||||
|
||||
enum ColourIds
|
||||
{
|
||||
backgroundColourId = 0x2340000,
|
||||
secondaryBackgroundColourId = 0x2340001,
|
||||
defaultTextColourId = 0x2340002,
|
||||
widgetTextColourId = 0x2340003,
|
||||
defaultButtonBackgroundColourId = 0x2340004,
|
||||
secondaryButtonBackgroundColourId = 0x2340005,
|
||||
userButtonBackgroundColourId = 0x2340006,
|
||||
defaultIconColourId = 0x2340007,
|
||||
treeIconColourId = 0x2340008,
|
||||
defaultHighlightColourId = 0x2340009,
|
||||
defaultHighlightedTextColourId = 0x234000a,
|
||||
codeEditorLineNumberColourId = 0x234000b,
|
||||
activeTabIconColourId = 0x234000c,
|
||||
inactiveTabBackgroundColourId = 0x234000d,
|
||||
inactiveTabIconColourId = 0x234000e,
|
||||
contentHeaderBackgroundColourId = 0x234000f,
|
||||
widgetBackgroundColourId = 0x2340010,
|
||||
secondaryWidgetBackgroundColourId = 0x2340011,
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static constexpr int projucerMajorVersion = ProjectInfo::versionNumber >> 16;
|
29
deps/juce/extras/Projucer/Source/Application/jucer_Headers.h
vendored
Normal file
29
deps/juce/extras/Projucer/Source/Application/jucer_Headers.h
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "jucer_CommonHeaders.h"
|
48
deps/juce/extras/Projucer/Source/Application/jucer_Main.cpp
vendored
Normal file
48
deps/juce/extras/Projucer/Source/Application/jucer_Main.cpp
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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_Headers.h"
|
||||
|
||||
#include "jucer_Application.h"
|
||||
#include "../CodeEditor/jucer_OpenDocumentManager.h"
|
||||
#include "../CodeEditor/jucer_SourceCodeEditor.h"
|
||||
#include "../Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h"
|
||||
#include "../Project/UI/jucer_ProjectContentComponent.h"
|
||||
#include "../Project/UI/Sidebar/jucer_TreeItemTypes.h"
|
||||
#include "Windows/jucer_UTF8WindowComponent.h"
|
||||
#include "Windows/jucer_SVGPathDataWindowComponent.h"
|
||||
#include "Windows/jucer_AboutWindowComponent.h"
|
||||
#include "Windows/jucer_EditorColourSchemeWindowComponent.h"
|
||||
#include "Windows/jucer_GlobalPathsWindowComponent.h"
|
||||
#include "Windows/jucer_PIPCreatorWindowComponent.h"
|
||||
#include "Windows/jucer_FloatingToolWindow.h"
|
||||
|
||||
#include "jucer_CommandLine.h"
|
||||
|
||||
#include "../Project/UI/jucer_ProjectContentComponent.cpp"
|
||||
#include "jucer_Application.cpp"
|
||||
|
||||
|
||||
START_JUCE_APPLICATION (ProjucerApplication)
|
1051
deps/juce/extras/Projucer/Source/Application/jucer_MainWindow.cpp
vendored
Normal file
1051
deps/juce/extras/Projucer/Source/Application/jucer_MainWindow.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
146
deps/juce/extras/Projucer/Source/Application/jucer_MainWindow.h
vendored
Normal file
146
deps/juce/extras/Projucer/Source/Application/jucer_MainWindow.h
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Utility/PIPs/jucer_PIPGenerator.h"
|
||||
#include "../Project/jucer_Project.h"
|
||||
#include "../CodeEditor/jucer_OpenDocumentManager.h"
|
||||
|
||||
class ProjectContentComponent;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
The big top-level window where everything happens.
|
||||
*/
|
||||
class MainWindow : public DocumentWindow,
|
||||
public ApplicationCommandTarget,
|
||||
public FileDragAndDropTarget,
|
||||
public DragAndDropContainer,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
MainWindow();
|
||||
~MainWindow() override;
|
||||
|
||||
enum class OpenInIDE { no, yes };
|
||||
|
||||
//==============================================================================
|
||||
void closeButtonPressed() override;
|
||||
|
||||
//==============================================================================
|
||||
bool canOpenFile (const File& file) const;
|
||||
void openFile (const File& file, std::function<void (bool)> callback);
|
||||
|
||||
void setProject (std::unique_ptr<Project> newProject);
|
||||
Project* getProject() const { return currentProject.get(); }
|
||||
|
||||
void makeVisible();
|
||||
void restoreWindowPosition();
|
||||
void updateTitleBarIcon();
|
||||
void closeCurrentProject (OpenDocumentManager::SaveIfNeeded askToSave, std::function<void (bool)> callback);
|
||||
void moveProject (File newProjectFile, OpenInIDE openInIDE);
|
||||
|
||||
void showStartPage();
|
||||
|
||||
void showLoginFormOverlay();
|
||||
void hideLoginFormOverlay();
|
||||
bool isShowingLoginForm() const noexcept { return loginFormOpen; }
|
||||
|
||||
bool isInterestedInFileDrag (const StringArray& files) override;
|
||||
void filesDropped (const StringArray& filenames, int mouseX, int mouseY) override;
|
||||
|
||||
void activeWindowStatusChanged() override;
|
||||
|
||||
ProjectContentComponent* getProjectContentComponent() const;
|
||||
|
||||
//==============================================================================
|
||||
ApplicationCommandTarget* getNextCommandTarget() override;
|
||||
void getAllCommands (Array <CommandID>& commands) override;
|
||||
void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) override;
|
||||
bool perform (const InvocationInfo& info) override;
|
||||
|
||||
bool shouldDropFilesWhenDraggedExternally (const DragAndDropTarget::SourceDetails& sourceDetails,
|
||||
StringArray& files, bool& canMoveFiles) override;
|
||||
private:
|
||||
void valueChanged (Value&) override;
|
||||
|
||||
static const char* getProjectWindowPosName() { return "projectWindowPos"; }
|
||||
void createProjectContentCompIfNeeded();
|
||||
|
||||
void openPIP (const File&, std::function<void (bool)> callback);
|
||||
void setupTemporaryPIPProject (PIPGenerator&);
|
||||
|
||||
void initialiseProjectWindow();
|
||||
|
||||
std::unique_ptr<Project> currentProject;
|
||||
Value projectNameValue;
|
||||
|
||||
std::unique_ptr<Component> blurOverlayComponent;
|
||||
bool loginFormOpen = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class MainWindowList
|
||||
{
|
||||
public:
|
||||
MainWindowList();
|
||||
|
||||
void forceCloseAllWindows();
|
||||
void askAllWindowsToClose (std::function<void (bool)> callback);
|
||||
void closeWindow (MainWindow*);
|
||||
|
||||
void goToSiblingWindow (MainWindow*, int delta);
|
||||
|
||||
void createWindowIfNoneAreOpen();
|
||||
void openDocument (OpenDocumentManager::Document*, bool grabFocus);
|
||||
void openFile (const File& file, std::function<void (bool)> callback, bool openInBackground = false);
|
||||
|
||||
MainWindow* createNewMainWindow();
|
||||
MainWindow* getFrontmostWindow (bool createIfNotFound = true);
|
||||
MainWindow* getOrCreateEmptyWindow();
|
||||
MainWindow* getMainWindowForFile (const File&);
|
||||
MainWindow* getMainWindowWithLoginFormOpen();
|
||||
|
||||
Project* getFrontmostProject();
|
||||
|
||||
void reopenLastProjects();
|
||||
void saveCurrentlyOpenProjectList();
|
||||
|
||||
void checkWindowBounds (MainWindow&);
|
||||
|
||||
void sendLookAndFeelChange();
|
||||
|
||||
OwnedArray<MainWindow> windows;
|
||||
|
||||
private:
|
||||
bool isInReopenLastProjects = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindowList)
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (MainWindowList)
|
||||
};
|
Reference in New Issue
Block a user