327 lines
12 KiB
C
327 lines
12 KiB
C
|
/*
|
||
|
==============================================================================
|
||
|
|
||
|
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)
|
||
|
};
|