|  | /*
  ==============================================================================
   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]
        {
            FileChooser fc ("Save Project", NewProjectWizard::getLastWizardFolder());
            if (fc.browseForDirectory())
            {
                auto dir = fc.getResult();
                if (auto project = NewProjectWizard::createNewProject (projectTemplate,
                                                                       dir.getChildFile (projectNameValue.get().toString()),
                                                                       projectNameValue.get(),
                                                                       modulesValue.get(),
                                                                       exportersValue.get(),
                                                                       fileOptionsValue.get(),
                                                                       modulePathValue.getCurrentValue(),
                                                                       modulePathValue.getWrappedValueWithDefault().isUsingDefault()))
                {
                    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());
        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::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)
    {
        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);
        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)
};
 |