migrating to the latest JUCE version
This commit is contained in:
@ -1,215 +1,179 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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_ModuleDescription.h"
|
||||
|
||||
//==============================================================================
|
||||
class AvailableModulesList : private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
using ModuleIDAndFolder = std::pair<String, File>;
|
||||
using ModuleIDAndFolderList = std::vector<ModuleIDAndFolder>;
|
||||
|
||||
AvailableModulesList() = default;
|
||||
|
||||
//==============================================================================
|
||||
void scanPaths (const Array<File>& paths)
|
||||
{
|
||||
auto job = createScannerJob (paths);
|
||||
auto& ref = *job;
|
||||
|
||||
removePendingAndAddJob (std::move (job));
|
||||
scanPool.waitForJobToFinish (&ref, -1);
|
||||
}
|
||||
|
||||
void scanPathsAsync (const Array<File>& paths)
|
||||
{
|
||||
removePendingAndAddJob (createScannerJob (paths));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ModuleIDAndFolderList getAllModules() const
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
return modulesList;
|
||||
}
|
||||
|
||||
ModuleIDAndFolder getModuleWithID (const String& id) const
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
|
||||
for (auto& mod : modulesList)
|
||||
if (mod.first == id)
|
||||
return mod;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void removeDuplicates (const ModuleIDAndFolderList& other)
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
|
||||
const auto predicate = [&] (const ModuleIDAndFolder& entry)
|
||||
{
|
||||
return std::find (other.begin(), other.end(), entry) != other.end();
|
||||
};
|
||||
|
||||
modulesList.erase (std::remove_if (modulesList.begin(), modulesList.end(), predicate),
|
||||
modulesList.end());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct Listener
|
||||
{
|
||||
virtual ~Listener() = default;
|
||||
virtual void availableModulesChanged (AvailableModulesList* listThatHasChanged) = 0;
|
||||
};
|
||||
|
||||
void addListener (Listener* listenerToAdd) { listeners.add (listenerToAdd); }
|
||||
void removeListener (Listener* listenerToRemove) { listeners.remove (listenerToRemove); }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct ModuleScannerJob : public ThreadPoolJob
|
||||
{
|
||||
ModuleScannerJob (const Array<File>& paths,
|
||||
std::function<void (const ModuleIDAndFolderList&)>&& callback)
|
||||
: ThreadPoolJob ("ModuleScannerJob"),
|
||||
pathsToScan (paths),
|
||||
completionCallback (std::move (callback))
|
||||
{
|
||||
}
|
||||
|
||||
JobStatus runJob() override
|
||||
{
|
||||
ModuleIDAndFolderList list;
|
||||
|
||||
for (auto& p : pathsToScan)
|
||||
addAllModulesInFolder (p, list);
|
||||
|
||||
if (! shouldExit())
|
||||
{
|
||||
std::sort (list.begin(), list.end(), [] (const ModuleIDAndFolder& m1,
|
||||
const ModuleIDAndFolder& m2)
|
||||
{
|
||||
return m1.first.compareIgnoreCase (m2.first) < 0;
|
||||
});
|
||||
|
||||
completionCallback (list);
|
||||
}
|
||||
|
||||
return jobHasFinished;
|
||||
}
|
||||
|
||||
static bool tryToAddModuleFromFolder (const File& path, ModuleIDAndFolderList& list)
|
||||
{
|
||||
ModuleDescription m (path);
|
||||
|
||||
if (m.isValid()
|
||||
&& std::find_if (list.begin(), list.end(),
|
||||
[&m] (const ModuleIDAndFolder& element) { return element.first == m.getID(); }) == std::end (list))
|
||||
{
|
||||
list.push_back ({ m.getID(), path });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void addAllModulesInFolder (const File& topLevelPath, ModuleIDAndFolderList& list)
|
||||
{
|
||||
struct FileAndDepth
|
||||
{
|
||||
File file;
|
||||
int depth;
|
||||
};
|
||||
|
||||
std::queue<FileAndDepth> pathsToCheck;
|
||||
pathsToCheck.push ({ topLevelPath, 0 });
|
||||
|
||||
while (! pathsToCheck.empty())
|
||||
{
|
||||
const auto path = pathsToCheck.front();
|
||||
pathsToCheck.pop();
|
||||
|
||||
if (tryToAddModuleFromFolder (path.file, list) || path.depth == 3)
|
||||
continue;
|
||||
|
||||
for (const auto& iter : RangedDirectoryIterator (path.file, false, "*", File::findDirectories))
|
||||
{
|
||||
if (auto* job = ThreadPoolJob::getCurrentThreadPoolJob())
|
||||
if (job->shouldExit())
|
||||
return;
|
||||
|
||||
pathsToCheck.push({ iter.getFile(), path.depth + 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array<File> pathsToScan;
|
||||
std::function<void (const ModuleIDAndFolderList&)> completionCallback;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
listeners.call ([this] (Listener& l) { l.availableModulesChanged (this); });
|
||||
}
|
||||
|
||||
std::unique_ptr<ThreadPoolJob> createScannerJob (const Array<File>& paths)
|
||||
{
|
||||
return std::make_unique<ModuleScannerJob> (paths, [this] (ModuleIDAndFolderList scannedModulesList)
|
||||
{
|
||||
if (scannedModulesList == modulesList)
|
||||
return;
|
||||
|
||||
{
|
||||
const ScopedLock swapLock (lock);
|
||||
modulesList.swap (scannedModulesList);
|
||||
}
|
||||
|
||||
triggerAsyncUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
void removePendingAndAddJob (std::unique_ptr<ThreadPoolJob> jobToAdd)
|
||||
{
|
||||
scanPool.removeAllJobs (false, 100);
|
||||
scanPool.addJob (jobToAdd.release(), true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ThreadPool scanPool { 1 };
|
||||
|
||||
ModuleIDAndFolderList modulesList;
|
||||
ListenerList<Listener> listeners;
|
||||
CriticalSection lock;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AvailableModulesList)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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_ModuleDescription.h"
|
||||
|
||||
#include <future>
|
||||
|
||||
//==============================================================================
|
||||
class AvailableModulesList : private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
using ModuleIDAndFolder = std::pair<String, File>;
|
||||
using ModuleIDAndFolderList = std::vector<ModuleIDAndFolder>;
|
||||
|
||||
AvailableModulesList() = default;
|
||||
|
||||
//==============================================================================
|
||||
void scanPaths (const Array<File>& paths)
|
||||
{
|
||||
scanPathsAsync (paths);
|
||||
scanner = {};
|
||||
}
|
||||
|
||||
void scanPathsAsync (const Array<File>& paths)
|
||||
{
|
||||
scanner = std::async (std::launch::async, [this, paths]
|
||||
{
|
||||
ModuleIDAndFolderList list;
|
||||
|
||||
for (auto& p : paths)
|
||||
addAllModulesInFolder (p, list);
|
||||
|
||||
std::sort (list.begin(), list.end(), [] (const ModuleIDAndFolder& m1,
|
||||
const ModuleIDAndFolder& m2)
|
||||
{
|
||||
return m1.first.compareIgnoreCase (m2.first) < 0;
|
||||
});
|
||||
|
||||
{
|
||||
const ScopedLock swapLock (lock);
|
||||
|
||||
if (list == modulesList)
|
||||
return;
|
||||
|
||||
modulesList.swap (list);
|
||||
}
|
||||
|
||||
triggerAsyncUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ModuleIDAndFolderList getAllModules() const
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
return modulesList;
|
||||
}
|
||||
|
||||
ModuleIDAndFolder getModuleWithID (const String& id) const
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
|
||||
for (auto& mod : modulesList)
|
||||
if (mod.first == id)
|
||||
return mod;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void removeDuplicates (const ModuleIDAndFolderList& other)
|
||||
{
|
||||
const ScopedLock readLock (lock);
|
||||
|
||||
const auto predicate = [&] (const ModuleIDAndFolder& entry)
|
||||
{
|
||||
return std::find (other.begin(), other.end(), entry) != other.end();
|
||||
};
|
||||
|
||||
modulesList.erase (std::remove_if (modulesList.begin(), modulesList.end(), predicate),
|
||||
modulesList.end());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct Listener
|
||||
{
|
||||
virtual ~Listener() = default;
|
||||
virtual void availableModulesChanged (AvailableModulesList* listThatHasChanged) = 0;
|
||||
};
|
||||
|
||||
void addListener (Listener* listenerToAdd) { listeners.add (listenerToAdd); }
|
||||
void removeListener (Listener* listenerToRemove) { listeners.remove (listenerToRemove); }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
static bool tryToAddModuleFromFolder (const File& path, ModuleIDAndFolderList& list)
|
||||
{
|
||||
ModuleDescription m (path);
|
||||
|
||||
if (m.isValid()
|
||||
&& std::none_of (list.begin(), list.end(),
|
||||
[&m] (const ModuleIDAndFolder& element) { return element.first == m.getID(); }))
|
||||
{
|
||||
list.push_back ({ m.getID(), path });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void addAllModulesInFolder (const File& topLevelPath, ModuleIDAndFolderList& list)
|
||||
{
|
||||
struct FileAndDepth
|
||||
{
|
||||
File file;
|
||||
int depth;
|
||||
};
|
||||
|
||||
std::queue<FileAndDepth> pathsToCheck;
|
||||
pathsToCheck.push ({ topLevelPath, 0 });
|
||||
|
||||
while (! pathsToCheck.empty())
|
||||
{
|
||||
const auto path = pathsToCheck.front();
|
||||
pathsToCheck.pop();
|
||||
|
||||
if (tryToAddModuleFromFolder (path.file, list) || path.depth == 3)
|
||||
continue;
|
||||
|
||||
for (const auto& iter : RangedDirectoryIterator (path.file, false, "*", File::findDirectories))
|
||||
{
|
||||
if (auto* job = ThreadPoolJob::getCurrentThreadPoolJob())
|
||||
if (job->shouldExit())
|
||||
return;
|
||||
|
||||
pathsToCheck.push({ iter.getFile(), path.depth + 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
listeners.call ([this] (Listener& l) { l.availableModulesChanged (this); });
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ModuleIDAndFolderList modulesList;
|
||||
ListenerList<Listener> listeners;
|
||||
CriticalSection lock;
|
||||
std::future<void> scanner;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AvailableModulesList)
|
||||
};
|
||||
|
@ -1,93 +1,93 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ModuleDescription
|
||||
{
|
||||
public:
|
||||
ModuleDescription() = default;
|
||||
|
||||
ModuleDescription (const File& folder)
|
||||
: moduleFolder (folder),
|
||||
moduleInfo (parseJUCEHeaderMetadata (getHeader()))
|
||||
{
|
||||
}
|
||||
|
||||
bool isValid() const { return getID().isNotEmpty(); }
|
||||
|
||||
String getID() const { return moduleInfo [Ids::ID_uppercase].toString(); }
|
||||
String getVendor() const { return moduleInfo [Ids::vendor].toString(); }
|
||||
String getVersion() const { return moduleInfo [Ids::version].toString(); }
|
||||
String getName() const { return moduleInfo [Ids::name].toString(); }
|
||||
String getDescription() const { return moduleInfo [Ids::description].toString(); }
|
||||
String getLicense() const { return moduleInfo [Ids::license].toString(); }
|
||||
String getMinimumCppStandard() const { return moduleInfo [Ids::minimumCppStandard].toString(); }
|
||||
String getPreprocessorDefs() const { return moduleInfo [Ids::defines].toString(); }
|
||||
String getExtraSearchPaths() const { return moduleInfo [Ids::searchpaths].toString(); }
|
||||
var getModuleInfo() const { return moduleInfo; }
|
||||
File getModuleFolder() const { return moduleFolder; }
|
||||
|
||||
File getFolder() const
|
||||
{
|
||||
jassert (moduleFolder != File());
|
||||
|
||||
return moduleFolder;
|
||||
}
|
||||
|
||||
File getHeader() const
|
||||
{
|
||||
if (moduleFolder != File())
|
||||
{
|
||||
static const char* extensions[] = { ".h", ".hpp", ".hxx" };
|
||||
|
||||
for (auto e : extensions)
|
||||
{
|
||||
auto header = moduleFolder.getChildFile (moduleFolder.getFileName() + e);
|
||||
|
||||
if (header.existsAsFile())
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
StringArray getDependencies() const
|
||||
{
|
||||
auto moduleDependencies = StringArray::fromTokens (moduleInfo ["dependencies"].toString(), " \t;,", "\"'");
|
||||
moduleDependencies.trim();
|
||||
moduleDependencies.removeEmptyStrings();
|
||||
|
||||
return moduleDependencies;
|
||||
}
|
||||
|
||||
private:
|
||||
File moduleFolder;
|
||||
var moduleInfo;
|
||||
URL url;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 ModuleDescription
|
||||
{
|
||||
public:
|
||||
ModuleDescription() = default;
|
||||
|
||||
ModuleDescription (const File& folder)
|
||||
: moduleFolder (folder),
|
||||
moduleInfo (parseJUCEHeaderMetadata (getHeader()))
|
||||
{
|
||||
}
|
||||
|
||||
bool isValid() const { return getID().isNotEmpty(); }
|
||||
|
||||
String getID() const { return moduleInfo [Ids::ID_uppercase].toString(); }
|
||||
String getVendor() const { return moduleInfo [Ids::vendor].toString(); }
|
||||
String getVersion() const { return moduleInfo [Ids::version].toString(); }
|
||||
String getName() const { return moduleInfo [Ids::name].toString(); }
|
||||
String getDescription() const { return moduleInfo [Ids::description].toString(); }
|
||||
String getLicense() const { return moduleInfo [Ids::license].toString(); }
|
||||
String getMinimumCppStandard() const { return moduleInfo [Ids::minimumCppStandard].toString(); }
|
||||
String getPreprocessorDefs() const { return moduleInfo [Ids::defines].toString(); }
|
||||
String getExtraSearchPaths() const { return moduleInfo [Ids::searchpaths].toString(); }
|
||||
var getModuleInfo() const { return moduleInfo; }
|
||||
File getModuleFolder() const { return moduleFolder; }
|
||||
|
||||
File getFolder() const
|
||||
{
|
||||
jassert (moduleFolder != File());
|
||||
|
||||
return moduleFolder;
|
||||
}
|
||||
|
||||
File getHeader() const
|
||||
{
|
||||
if (moduleFolder != File())
|
||||
{
|
||||
static const char* extensions[] = { ".h", ".hpp", ".hxx" };
|
||||
|
||||
for (auto e : extensions)
|
||||
{
|
||||
auto header = moduleFolder.getChildFile (moduleFolder.getFileName() + e);
|
||||
|
||||
if (header.existsAsFile())
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
StringArray getDependencies() const
|
||||
{
|
||||
auto moduleDependencies = StringArray::fromTokens (moduleInfo ["dependencies"].toString(), " \t;,", "\"'");
|
||||
moduleDependencies.trim();
|
||||
moduleDependencies.removeEmptyStrings();
|
||||
|
||||
return moduleDependencies;
|
||||
}
|
||||
|
||||
private:
|
||||
File moduleFolder;
|
||||
var moduleInfo;
|
||||
URL url;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,148 +1,148 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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_Project.h"
|
||||
|
||||
class ProjectExporter;
|
||||
class ProjectSaver;
|
||||
|
||||
//==============================================================================
|
||||
class LibraryModule
|
||||
{
|
||||
public:
|
||||
LibraryModule (const ModuleDescription&);
|
||||
|
||||
bool isValid() const { return moduleInfo.isValid(); }
|
||||
String getID() const { return moduleInfo.getID(); }
|
||||
String getVendor() const { return moduleInfo.getVendor(); }
|
||||
String getVersion() const { return moduleInfo.getVersion(); }
|
||||
String getName() const { return moduleInfo.getName(); }
|
||||
String getDescription() const { return moduleInfo.getDescription(); }
|
||||
String getLicense() const { return moduleInfo.getLicense(); }
|
||||
String getMinimumCppStandard() const { return moduleInfo.getMinimumCppStandard(); }
|
||||
|
||||
File getFolder() const { return moduleInfo.getFolder(); }
|
||||
|
||||
void writeIncludes (ProjectSaver&, OutputStream&);
|
||||
void addSettingsForModuleToExporter (ProjectExporter&, ProjectSaver&) const;
|
||||
void getConfigFlags (Project&, OwnedArray<Project::ConfigFlag>& flags) const;
|
||||
void findBrowseableFiles (const File& localModuleFolder, Array<File>& files) const;
|
||||
|
||||
struct CompileUnit
|
||||
{
|
||||
File file;
|
||||
bool isCompiledForObjC = false, isCompiledForNonObjC = false;
|
||||
|
||||
bool isNeededForExporter (ProjectExporter&) const;
|
||||
String getFilenameForProxyFile() const;
|
||||
static bool hasSuffix (const File&, const char*);
|
||||
};
|
||||
|
||||
Array<CompileUnit> getAllCompileUnits (build_tools::ProjectType::Target::Type forTarget =
|
||||
build_tools::ProjectType::Target::unspecified) const;
|
||||
void findAndAddCompiledUnits (ProjectExporter&, ProjectSaver*, Array<File>& result,
|
||||
build_tools::ProjectType::Target::Type forTarget =
|
||||
build_tools::ProjectType::Target::unspecified) const;
|
||||
|
||||
ModuleDescription moduleInfo;
|
||||
|
||||
private:
|
||||
void addSearchPathsToExporter (ProjectExporter&) const;
|
||||
void addDefinesToExporter (ProjectExporter&) const;
|
||||
void addCompileUnitsToExporter (ProjectExporter&, ProjectSaver&) const;
|
||||
void addLibsToExporter (ProjectExporter&) const;
|
||||
|
||||
void addBrowseableCode (ProjectExporter&, const Array<File>& compiled, const File& localModuleFolder) const;
|
||||
|
||||
mutable Array<File> sourceFiles;
|
||||
OwnedArray<Project::ConfigFlag> configFlags;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class EnabledModulesList
|
||||
{
|
||||
public:
|
||||
EnabledModulesList (Project&, const ValueTree&);
|
||||
|
||||
//==============================================================================
|
||||
ValueTree getState() const { return state; }
|
||||
|
||||
StringArray getAllModules() const;
|
||||
void createRequiredModules (OwnedArray<LibraryModule>& modules);
|
||||
void sortAlphabetically();
|
||||
|
||||
File getDefaultModulesFolder() const;
|
||||
|
||||
int getNumModules() const { return state.getNumChildren(); }
|
||||
String getModuleID (int index) const { return state.getChild (index) [Ids::ID].toString(); }
|
||||
|
||||
ModuleDescription getModuleInfo (const String& moduleID) const;
|
||||
|
||||
bool isModuleEnabled (const String& moduleID) const;
|
||||
|
||||
StringArray getExtraDependenciesNeeded (const String& moduleID) const;
|
||||
bool tryToFixMissingDependencies (const String& moduleID);
|
||||
|
||||
bool doesModuleHaveHigherCppStandardThanProject (const String& moduleID) const;
|
||||
|
||||
bool shouldUseGlobalPath (const String& moduleID) const;
|
||||
Value shouldUseGlobalPathValue (const String& moduleID) const;
|
||||
|
||||
bool shouldShowAllModuleFilesInProject (const String& moduleID) const;
|
||||
Value shouldShowAllModuleFilesInProjectValue (const String& moduleID) const;
|
||||
|
||||
bool shouldCopyModuleFilesLocally (const String& moduleID) const;
|
||||
Value shouldCopyModuleFilesLocallyValue (const String& moduleID) const;
|
||||
|
||||
bool areMostModulesUsingGlobalPath() const;
|
||||
bool areMostModulesCopiedLocally() const;
|
||||
|
||||
StringArray getModulesWithHigherCppStandardThanProject() const;
|
||||
StringArray getModulesWithMissingDependencies() const;
|
||||
|
||||
String getHighestModuleCppStandard() const;
|
||||
|
||||
//==============================================================================
|
||||
void addModule (const File& moduleManifestFile, bool copyLocally, bool useGlobalPath);
|
||||
void addModuleInteractive (const String& moduleID);
|
||||
void addModuleFromUserSelectedFile();
|
||||
void addModuleOfferingToCopy (const File&, bool isFromUserSpecifiedFolder);
|
||||
|
||||
void removeModule (String moduleID);
|
||||
|
||||
private:
|
||||
UndoManager* getUndoManager() const { return project.getUndoManagerFor (state); }
|
||||
|
||||
Project& project;
|
||||
|
||||
CriticalSection stateLock;
|
||||
ValueTree state;
|
||||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EnabledModulesList)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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_Project.h"
|
||||
|
||||
class ProjectExporter;
|
||||
class ProjectSaver;
|
||||
|
||||
//==============================================================================
|
||||
class LibraryModule
|
||||
{
|
||||
public:
|
||||
LibraryModule (const ModuleDescription&);
|
||||
|
||||
bool isValid() const { return moduleDescription.isValid(); }
|
||||
String getID() const { return moduleDescription.getID(); }
|
||||
String getVendor() const { return moduleDescription.getVendor(); }
|
||||
String getVersion() const { return moduleDescription.getVersion(); }
|
||||
String getName() const { return moduleDescription.getName(); }
|
||||
String getDescription() const { return moduleDescription.getDescription(); }
|
||||
String getLicense() const { return moduleDescription.getLicense(); }
|
||||
String getMinimumCppStandard() const { return moduleDescription.getMinimumCppStandard(); }
|
||||
|
||||
File getFolder() const { return moduleDescription.getFolder(); }
|
||||
|
||||
void writeIncludes (ProjectSaver&, OutputStream&);
|
||||
void addSettingsForModuleToExporter (ProjectExporter&, ProjectSaver&) const;
|
||||
void getConfigFlags (Project&, OwnedArray<Project::ConfigFlag>& flags) const;
|
||||
void findBrowseableFiles (const File& localModuleFolder, Array<File>& files) const;
|
||||
|
||||
struct CompileUnit
|
||||
{
|
||||
File file;
|
||||
bool isCompiledForObjC = false, isCompiledForNonObjC = false;
|
||||
|
||||
bool isNeededForExporter (ProjectExporter&) const;
|
||||
String getFilenameForProxyFile() const;
|
||||
static bool hasSuffix (const File&, const char*);
|
||||
};
|
||||
|
||||
Array<CompileUnit> getAllCompileUnits (build_tools::ProjectType::Target::Type forTarget =
|
||||
build_tools::ProjectType::Target::unspecified) const;
|
||||
void findAndAddCompiledUnits (ProjectExporter&, ProjectSaver*, Array<File>& result,
|
||||
build_tools::ProjectType::Target::Type forTarget =
|
||||
build_tools::ProjectType::Target::unspecified) const;
|
||||
|
||||
ModuleDescription moduleDescription;
|
||||
|
||||
private:
|
||||
void addSearchPathsToExporter (ProjectExporter&) const;
|
||||
void addDefinesToExporter (ProjectExporter&) const;
|
||||
void addCompileUnitsToExporter (ProjectExporter&, ProjectSaver&) const;
|
||||
void addLibsToExporter (ProjectExporter&) const;
|
||||
|
||||
void addBrowseableCode (ProjectExporter&, const Array<File>& compiled, const File& localModuleFolder) const;
|
||||
|
||||
mutable Array<File> sourceFiles;
|
||||
OwnedArray<Project::ConfigFlag> configFlags;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class EnabledModulesList
|
||||
{
|
||||
public:
|
||||
EnabledModulesList (Project&, const ValueTree&);
|
||||
|
||||
//==============================================================================
|
||||
ValueTree getState() const { return state; }
|
||||
|
||||
StringArray getAllModules() const;
|
||||
void createRequiredModules (OwnedArray<LibraryModule>& modules);
|
||||
void sortAlphabetically();
|
||||
|
||||
File getDefaultModulesFolder() const;
|
||||
|
||||
int getNumModules() const { return state.getNumChildren(); }
|
||||
String getModuleID (int index) const { return state.getChild (index) [Ids::ID].toString(); }
|
||||
|
||||
ModuleDescription getModuleInfo (const String& moduleID) const;
|
||||
|
||||
bool isModuleEnabled (const String& moduleID) const;
|
||||
|
||||
StringArray getExtraDependenciesNeeded (const String& moduleID) const;
|
||||
bool tryToFixMissingDependencies (const String& moduleID);
|
||||
|
||||
bool doesModuleHaveHigherCppStandardThanProject (const String& moduleID) const;
|
||||
|
||||
bool shouldUseGlobalPath (const String& moduleID) const;
|
||||
Value shouldUseGlobalPathValue (const String& moduleID) const;
|
||||
|
||||
bool shouldShowAllModuleFilesInProject (const String& moduleID) const;
|
||||
Value shouldShowAllModuleFilesInProjectValue (const String& moduleID) const;
|
||||
|
||||
bool shouldCopyModuleFilesLocally (const String& moduleID) const;
|
||||
Value shouldCopyModuleFilesLocallyValue (const String& moduleID) const;
|
||||
|
||||
bool areMostModulesUsingGlobalPath() const;
|
||||
bool areMostModulesCopiedLocally() const;
|
||||
|
||||
StringArray getModulesWithHigherCppStandardThanProject() const;
|
||||
StringArray getModulesWithMissingDependencies() const;
|
||||
|
||||
String getHighestModuleCppStandard() const;
|
||||
|
||||
//==============================================================================
|
||||
void addModule (const File& moduleManifestFile, bool copyLocally, bool useGlobalPath);
|
||||
void addModuleInteractive (const String& moduleID);
|
||||
void addModuleFromUserSelectedFile();
|
||||
void addModuleOfferingToCopy (const File&, bool isFromUserSpecifiedFolder);
|
||||
|
||||
void removeModule (String moduleID);
|
||||
|
||||
private:
|
||||
UndoManager* getUndoManager() const { return project.getUndoManagerFor (state); }
|
||||
|
||||
Project& project;
|
||||
|
||||
CriticalSection stateLock;
|
||||
ValueTree state;
|
||||
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EnabledModulesList)
|
||||
};
|
||||
|
@ -1,401 +1,400 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ExporterItem : public ProjectTreeItemBase,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
ExporterItem (Project& p, ProjectExporter* e, int index)
|
||||
: project (p), exporter (e), configListTree (exporter->getConfigurations()),
|
||||
exporterIndex (index)
|
||||
{
|
||||
exporter->initialiseDependencyPathValues();
|
||||
configListTree.addListener (this);
|
||||
targetLocationValue.referTo (exporter->getTargetLocationValue());
|
||||
targetLocationValue.addListener (this);
|
||||
}
|
||||
|
||||
int getItemHeight() const override { return 25; }
|
||||
bool canBeSelected() const override { return true; }
|
||||
bool mightContainSubItems() override { return exporter->getNumConfigurations() > 0; }
|
||||
String getUniqueName() const override { return "exporter_" + String (exporterIndex); }
|
||||
String getRenamingName() const override { return getDisplayName(); }
|
||||
String getDisplayName() const override { return exporter->getUniqueName(); }
|
||||
void setName (const String&) override {}
|
||||
bool isMissing() const override { return false; }
|
||||
String getTooltip() override { return getDisplayName(); }
|
||||
|
||||
static Icon getIconForExporter (ProjectExporter* e)
|
||||
{
|
||||
if (e != nullptr)
|
||||
{
|
||||
if (e->isXcode()) return Icon (getIcons().xcode, Colours::transparentBlack);
|
||||
else if (e->isVisualStudio()) return Icon (getIcons().visualStudio, Colours::transparentBlack);
|
||||
else if (e->isAndroid()) return Icon (getIcons().android, Colours::transparentBlack);
|
||||
else if (e->isCodeBlocks()) return Icon (getIcons().codeBlocks, Colours::transparentBlack);
|
||||
else if (e->isMakefile()) return Icon (getIcons().linux, Colours::transparentBlack);
|
||||
else if (e->isCLion()) return Icon (getIcons().clion, Colours::transparentBlack);
|
||||
}
|
||||
|
||||
return Icon();
|
||||
}
|
||||
|
||||
Icon getIcon() const override
|
||||
{
|
||||
return getIconForExporter (exporter.get()).withColour (getContentColour (true));
|
||||
}
|
||||
|
||||
void showDocument() override
|
||||
{
|
||||
showSettingsPage (new SettingsComp (*exporter));
|
||||
}
|
||||
|
||||
void deleteItem() override
|
||||
{
|
||||
auto resultCallback = [safeThis = WeakReference<ExporterItem> { this }] (int result)
|
||||
{
|
||||
if (safeThis == nullptr || result == 0)
|
||||
return;
|
||||
|
||||
safeThis->closeSettingsPage();
|
||||
|
||||
auto parent = safeThis->exporter->settings.getParent();
|
||||
parent.removeChild (safeThis->exporter->settings,
|
||||
safeThis->project.getUndoManagerFor (parent));
|
||||
};
|
||||
|
||||
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
|
||||
"Delete Exporter",
|
||||
"Are you sure you want to delete this export target?",
|
||||
"",
|
||||
"",
|
||||
nullptr,
|
||||
ModalCallbackFunction::create (std::move (resultCallback)));
|
||||
}
|
||||
|
||||
void addSubItems() override
|
||||
{
|
||||
for (ProjectExporter::ConfigIterator config (*exporter); config.next();)
|
||||
addSubItem (new ConfigItem (config.config, *exporter));
|
||||
}
|
||||
|
||||
void showPopupMenu (Point<int> p) override
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addItem (1, "Add a new configuration", exporter->supportsUserDefinedConfigurations());
|
||||
menu.addItem (2, "Save this exporter");
|
||||
menu.addSeparator();
|
||||
menu.addItem (3, "Delete this exporter");
|
||||
|
||||
launchPopupMenu (menu, p);
|
||||
}
|
||||
|
||||
void showAddMenu (Point<int> p) override
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addItem (1, "Add a new configuration", exporter->supportsUserDefinedConfigurations());
|
||||
|
||||
launchPopupMenu (menu, p);
|
||||
}
|
||||
|
||||
void handlePopupMenuResult (int resultCode) override
|
||||
{
|
||||
if (resultCode == 1)
|
||||
exporter->addNewConfiguration (false);
|
||||
else if (resultCode == 2)
|
||||
project.saveProject (Async::yes, exporter.get(), nullptr);
|
||||
else if (resultCode == 3)
|
||||
deleteAllSelectedItems();
|
||||
}
|
||||
|
||||
var getDragSourceDescription() override
|
||||
{
|
||||
return getParentItem()->getUniqueName() + "/" + String (exporterIndex);
|
||||
}
|
||||
|
||||
bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails) override
|
||||
{
|
||||
return dragSourceDetails.description.toString().startsWith (getUniqueName());
|
||||
}
|
||||
|
||||
void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex) override
|
||||
{
|
||||
auto oldIndex = indexOfConfig (dragSourceDetails.description.toString().fromLastOccurrenceOf ("||", false, false));
|
||||
|
||||
if (oldIndex >= 0)
|
||||
configListTree.moveChild (oldIndex, insertIndex, project.getUndoManagerFor (configListTree));
|
||||
}
|
||||
|
||||
int indexOfConfig (const String& configName)
|
||||
{
|
||||
int i = 0;
|
||||
for (ProjectExporter::ConfigIterator config (*exporter); config.next(); ++i)
|
||||
if (config->getName() == configName)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) override { refreshIfNeeded (parentTree); }
|
||||
void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { refreshIfNeeded (parentTree); }
|
||||
void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { refreshIfNeeded (parentTree); }
|
||||
|
||||
void refreshIfNeeded (ValueTree& changedTree)
|
||||
{
|
||||
if (changedTree == configListTree)
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
private:
|
||||
Project& project;
|
||||
std::unique_ptr<ProjectExporter> exporter;
|
||||
ValueTree configListTree;
|
||||
int exporterIndex;
|
||||
|
||||
Value targetLocationValue;
|
||||
|
||||
void valueChanged (Value& value) override
|
||||
{
|
||||
if (value == exporter->getTargetLocationValue())
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct SettingsComp : public Component
|
||||
{
|
||||
SettingsComp (ProjectExporter& exp)
|
||||
: group (exp.getUniqueName(),
|
||||
ExporterItem::getIconForExporter (&exp),
|
||||
exp.getDescription())
|
||||
{
|
||||
addAndMakeVisible (group);
|
||||
|
||||
PropertyListBuilder props;
|
||||
exp.createPropertyEditors (props);
|
||||
group.setProperties (props);
|
||||
parentSizeChanged();
|
||||
}
|
||||
|
||||
void parentSizeChanged() override { updateSize (*this, group); }
|
||||
void resized() override { group.setBounds (getLocalBounds().withTrimmedLeft (12)); }
|
||||
|
||||
PropertyGroupComponent group;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp)
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExporterItem)
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (ExporterItem)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ConfigItem : public ProjectTreeItemBase
|
||||
{
|
||||
public:
|
||||
ConfigItem (const ProjectExporter::BuildConfiguration::Ptr& conf, ProjectExporter& e)
|
||||
: config (conf), exporter (e), configTree (config->config)
|
||||
{
|
||||
jassert (config != nullptr);
|
||||
configTree.addListener (this);
|
||||
}
|
||||
|
||||
bool isMissing() const override { return false; }
|
||||
bool canBeSelected() const override { return true; }
|
||||
bool mightContainSubItems() override { return false; }
|
||||
String getUniqueName() const override { return "config_" + config->getName(); }
|
||||
String getRenamingName() const override { return getDisplayName(); }
|
||||
String getDisplayName() const override { return config->getName(); }
|
||||
void setName (const String&) override {}
|
||||
Icon getIcon() const override { return Icon (getIcons().config, getContentColour (true)); }
|
||||
void itemOpennessChanged (bool) override {}
|
||||
|
||||
void showDocument() override
|
||||
{
|
||||
showSettingsPage (new SettingsComp (*config));
|
||||
}
|
||||
|
||||
void deleteItem() override
|
||||
{
|
||||
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
|
||||
"Delete Configuration",
|
||||
"Are you sure you want to delete this configuration?",
|
||||
"",
|
||||
"",
|
||||
nullptr,
|
||||
ModalCallbackFunction::create ([parent = WeakReference<ConfigItem> { this }] (int result)
|
||||
{
|
||||
if (parent == nullptr)
|
||||
return;
|
||||
|
||||
if (result == 0)
|
||||
return;
|
||||
|
||||
parent->closeSettingsPage();
|
||||
parent->config->removeFromExporter();
|
||||
}));
|
||||
}
|
||||
|
||||
void showPopupMenu (Point<int> p) override
|
||||
{
|
||||
bool enabled = exporter.supportsUserDefinedConfigurations();
|
||||
|
||||
PopupMenu menu;
|
||||
menu.addItem (1, "Create a copy of this configuration", enabled);
|
||||
menu.addSeparator();
|
||||
menu.addItem (2, "Delete this configuration", enabled);
|
||||
|
||||
launchPopupMenu (menu, p);
|
||||
}
|
||||
|
||||
void handlePopupMenuResult (int resultCode) override
|
||||
{
|
||||
if (resultCode == 1)
|
||||
exporter.addNewConfigurationFromExisting (*config);
|
||||
else if (resultCode == 2)
|
||||
deleteAllSelectedItems();
|
||||
}
|
||||
|
||||
var getDragSourceDescription() override
|
||||
{
|
||||
return getParentItem()->getUniqueName() + "||" + config->getName();
|
||||
}
|
||||
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) override { repaintItem(); }
|
||||
|
||||
private:
|
||||
ProjectExporter::BuildConfiguration::Ptr config;
|
||||
ProjectExporter& exporter;
|
||||
ValueTree configTree;
|
||||
|
||||
//==============================================================================
|
||||
class SettingsComp : public Component
|
||||
{
|
||||
public:
|
||||
SettingsComp (ProjectExporter::BuildConfiguration& conf)
|
||||
: group (conf.exporter.getUniqueName() + " - " + conf.getName(), Icon (getIcons().config, Colours::transparentBlack))
|
||||
{
|
||||
addAndMakeVisible (group);
|
||||
|
||||
PropertyListBuilder props;
|
||||
conf.createPropertyEditors (props);
|
||||
group.setProperties (props);
|
||||
parentSizeChanged();
|
||||
}
|
||||
|
||||
void parentSizeChanged() override { updateSize (*this, group); }
|
||||
|
||||
void resized() override { group.setBounds (getLocalBounds().withTrimmedLeft (12)); }
|
||||
|
||||
private:
|
||||
PropertyGroupComponent group;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp)
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConfigItem)
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (ConfigItem)
|
||||
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ExportersTreeRoot : public ProjectTreeItemBase
|
||||
{
|
||||
public:
|
||||
ExportersTreeRoot (Project& p)
|
||||
: project (p),
|
||||
exportersTree (project.getExporters())
|
||||
{
|
||||
exportersTree.addListener (this);
|
||||
}
|
||||
|
||||
bool isRoot() const override { return true; }
|
||||
bool canBeSelected() const override { return true; }
|
||||
bool isMissing() const override { return false; }
|
||||
bool mightContainSubItems() override { return project.getNumExporters() > 0; }
|
||||
String getUniqueName() const override { return "exporters"; }
|
||||
String getRenamingName() const override { return getDisplayName(); }
|
||||
String getDisplayName() const override { return "Exporters"; }
|
||||
void setName (const String&) override {}
|
||||
Icon getIcon() const override { return project.getMainGroup().getIcon (isOpen()).withColour (getContentColour (true)); }
|
||||
|
||||
void showPopupMenu (Point<int>) override
|
||||
{
|
||||
if (auto* pcc = getProjectContentComponent())
|
||||
pcc->showNewExporterMenu();
|
||||
}
|
||||
|
||||
void addSubItems() override
|
||||
{
|
||||
int i = 0;
|
||||
for (Project::ExporterIterator exporter (project); exporter.next(); ++i)
|
||||
addSubItem (new TreeItemTypes::ExporterItem (project, exporter.exporter.release(), i));
|
||||
}
|
||||
|
||||
bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails) override
|
||||
{
|
||||
return dragSourceDetails.description.toString().startsWith (getUniqueName());
|
||||
}
|
||||
|
||||
void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex) override
|
||||
{
|
||||
int oldIndex = dragSourceDetails.description.toString().getTrailingIntValue();
|
||||
exportersTree.moveChild (oldIndex, jmax (0, insertIndex), project.getUndoManagerFor (exportersTree));
|
||||
}
|
||||
|
||||
void itemOpennessChanged (bool isNowOpen) override
|
||||
{
|
||||
if (isNowOpen)
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
void removeExporter (int index)
|
||||
{
|
||||
if (auto* exporter = dynamic_cast<TreeItemTypes::ExporterItem*> (getSubItem (index)))
|
||||
exporter->deleteItem();
|
||||
}
|
||||
|
||||
private:
|
||||
Project& project;
|
||||
ValueTree exportersTree;
|
||||
|
||||
//==============================================================================
|
||||
void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) override { refreshIfNeeded (parentTree); }
|
||||
void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { refreshIfNeeded (parentTree); }
|
||||
void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { refreshIfNeeded (parentTree); }
|
||||
|
||||
void refreshIfNeeded (ValueTree& changedTree)
|
||||
{
|
||||
if (changedTree == exportersTree)
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExportersTreeRoot)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 ExporterItem : public ProjectTreeItemBase,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
ExporterItem (Project& p, ProjectExporter* e, int index)
|
||||
: project (p), exporter (e), configListTree (exporter->getConfigurations()),
|
||||
exporterIndex (index)
|
||||
{
|
||||
exporter->initialiseDependencyPathValues();
|
||||
configListTree.addListener (this);
|
||||
targetLocationValue.referTo (exporter->getTargetLocationValue());
|
||||
targetLocationValue.addListener (this);
|
||||
}
|
||||
|
||||
int getItemHeight() const override { return 25; }
|
||||
bool canBeSelected() const override { return true; }
|
||||
bool mightContainSubItems() override { return exporter->getNumConfigurations() > 0; }
|
||||
String getUniqueName() const override { return "exporter_" + String (exporterIndex); }
|
||||
String getRenamingName() const override { return getDisplayName(); }
|
||||
String getDisplayName() const override { return exporter->getUniqueName(); }
|
||||
void setName (const String&) override {}
|
||||
bool isMissing() const override { return false; }
|
||||
String getTooltip() override { return getDisplayName(); }
|
||||
|
||||
static Icon getIconForExporter (ProjectExporter* e)
|
||||
{
|
||||
if (e != nullptr)
|
||||
{
|
||||
if (e->isXcode()) return Icon (getIcons().xcode, Colours::transparentBlack);
|
||||
else if (e->isVisualStudio()) return Icon (getIcons().visualStudio, Colours::transparentBlack);
|
||||
else if (e->isAndroid()) return Icon (getIcons().android, Colours::transparentBlack);
|
||||
else if (e->isCodeBlocks()) return Icon (getIcons().codeBlocks, Colours::transparentBlack);
|
||||
else if (e->isMakefile()) return Icon (getIcons().linux, Colours::transparentBlack);
|
||||
}
|
||||
|
||||
return Icon();
|
||||
}
|
||||
|
||||
Icon getIcon() const override
|
||||
{
|
||||
return getIconForExporter (exporter.get()).withColour (getContentColour (true));
|
||||
}
|
||||
|
||||
void showDocument() override
|
||||
{
|
||||
showSettingsPage (new SettingsComp (*exporter));
|
||||
}
|
||||
|
||||
void deleteItem() override
|
||||
{
|
||||
auto resultCallback = [safeThis = WeakReference<ExporterItem> { this }] (int result)
|
||||
{
|
||||
if (safeThis == nullptr || result == 0)
|
||||
return;
|
||||
|
||||
safeThis->closeSettingsPage();
|
||||
|
||||
auto parent = safeThis->exporter->settings.getParent();
|
||||
parent.removeChild (safeThis->exporter->settings,
|
||||
safeThis->project.getUndoManagerFor (parent));
|
||||
};
|
||||
|
||||
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
|
||||
"Delete Exporter",
|
||||
"Are you sure you want to delete this export target?",
|
||||
"",
|
||||
"",
|
||||
nullptr,
|
||||
ModalCallbackFunction::create (std::move (resultCallback)));
|
||||
}
|
||||
|
||||
void addSubItems() override
|
||||
{
|
||||
for (ProjectExporter::ConfigIterator config (*exporter); config.next();)
|
||||
addSubItem (new ConfigItem (config.config, *exporter));
|
||||
}
|
||||
|
||||
void showPopupMenu (Point<int> p) override
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addItem (1, "Add a new configuration", exporter->supportsUserDefinedConfigurations());
|
||||
menu.addItem (2, "Save this exporter");
|
||||
menu.addSeparator();
|
||||
menu.addItem (3, "Delete this exporter");
|
||||
|
||||
launchPopupMenu (menu, p);
|
||||
}
|
||||
|
||||
void showAddMenu (Point<int> p) override
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addItem (1, "Add a new configuration", exporter->supportsUserDefinedConfigurations());
|
||||
|
||||
launchPopupMenu (menu, p);
|
||||
}
|
||||
|
||||
void handlePopupMenuResult (int resultCode) override
|
||||
{
|
||||
if (resultCode == 1)
|
||||
exporter->addNewConfiguration (false);
|
||||
else if (resultCode == 2)
|
||||
project.saveProject (Async::yes, exporter.get(), nullptr);
|
||||
else if (resultCode == 3)
|
||||
deleteAllSelectedItems();
|
||||
}
|
||||
|
||||
var getDragSourceDescription() override
|
||||
{
|
||||
return getParentItem()->getUniqueName() + "/" + String (exporterIndex);
|
||||
}
|
||||
|
||||
bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails) override
|
||||
{
|
||||
return dragSourceDetails.description.toString().startsWith (getUniqueName());
|
||||
}
|
||||
|
||||
void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex) override
|
||||
{
|
||||
auto oldIndex = indexOfConfig (dragSourceDetails.description.toString().fromLastOccurrenceOf ("||", false, false));
|
||||
|
||||
if (oldIndex >= 0)
|
||||
configListTree.moveChild (oldIndex, insertIndex, project.getUndoManagerFor (configListTree));
|
||||
}
|
||||
|
||||
int indexOfConfig (const String& configName)
|
||||
{
|
||||
int i = 0;
|
||||
for (ProjectExporter::ConfigIterator config (*exporter); config.next(); ++i)
|
||||
if (config->getName() == configName)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) override { refreshIfNeeded (parentTree); }
|
||||
void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { refreshIfNeeded (parentTree); }
|
||||
void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { refreshIfNeeded (parentTree); }
|
||||
|
||||
void refreshIfNeeded (ValueTree& changedTree)
|
||||
{
|
||||
if (changedTree == configListTree)
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
private:
|
||||
Project& project;
|
||||
std::unique_ptr<ProjectExporter> exporter;
|
||||
ValueTree configListTree;
|
||||
int exporterIndex;
|
||||
|
||||
Value targetLocationValue;
|
||||
|
||||
void valueChanged (Value& value) override
|
||||
{
|
||||
if (value == exporter->getTargetLocationValue())
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct SettingsComp : public Component
|
||||
{
|
||||
SettingsComp (ProjectExporter& exp)
|
||||
: group (exp.getUniqueName(),
|
||||
ExporterItem::getIconForExporter (&exp),
|
||||
exp.getDescription())
|
||||
{
|
||||
addAndMakeVisible (group);
|
||||
|
||||
PropertyListBuilder props;
|
||||
exp.createPropertyEditors (props);
|
||||
group.setProperties (props);
|
||||
parentSizeChanged();
|
||||
}
|
||||
|
||||
void parentSizeChanged() override { updateSize (*this, group); }
|
||||
void resized() override { group.setBounds (getLocalBounds().withTrimmedLeft (12)); }
|
||||
|
||||
PropertyGroupComponent group;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp)
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExporterItem)
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (ExporterItem)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ConfigItem : public ProjectTreeItemBase
|
||||
{
|
||||
public:
|
||||
ConfigItem (const ProjectExporter::BuildConfiguration::Ptr& conf, ProjectExporter& e)
|
||||
: config (conf), exporter (e), configTree (config->config)
|
||||
{
|
||||
jassert (config != nullptr);
|
||||
configTree.addListener (this);
|
||||
}
|
||||
|
||||
bool isMissing() const override { return false; }
|
||||
bool canBeSelected() const override { return true; }
|
||||
bool mightContainSubItems() override { return false; }
|
||||
String getUniqueName() const override { return "config_" + config->getName(); }
|
||||
String getRenamingName() const override { return getDisplayName(); }
|
||||
String getDisplayName() const override { return config->getName(); }
|
||||
void setName (const String&) override {}
|
||||
Icon getIcon() const override { return Icon (getIcons().config, getContentColour (true)); }
|
||||
void itemOpennessChanged (bool) override {}
|
||||
|
||||
void showDocument() override
|
||||
{
|
||||
showSettingsPage (new SettingsComp (*config));
|
||||
}
|
||||
|
||||
void deleteItem() override
|
||||
{
|
||||
AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
|
||||
"Delete Configuration",
|
||||
"Are you sure you want to delete this configuration?",
|
||||
"",
|
||||
"",
|
||||
nullptr,
|
||||
ModalCallbackFunction::create ([parent = WeakReference<ConfigItem> { this }] (int result)
|
||||
{
|
||||
if (parent == nullptr)
|
||||
return;
|
||||
|
||||
if (result == 0)
|
||||
return;
|
||||
|
||||
parent->closeSettingsPage();
|
||||
parent->config->removeFromExporter();
|
||||
}));
|
||||
}
|
||||
|
||||
void showPopupMenu (Point<int> p) override
|
||||
{
|
||||
bool enabled = exporter.supportsUserDefinedConfigurations();
|
||||
|
||||
PopupMenu menu;
|
||||
menu.addItem (1, "Create a copy of this configuration", enabled);
|
||||
menu.addSeparator();
|
||||
menu.addItem (2, "Delete this configuration", enabled);
|
||||
|
||||
launchPopupMenu (menu, p);
|
||||
}
|
||||
|
||||
void handlePopupMenuResult (int resultCode) override
|
||||
{
|
||||
if (resultCode == 1)
|
||||
exporter.addNewConfigurationFromExisting (*config);
|
||||
else if (resultCode == 2)
|
||||
deleteAllSelectedItems();
|
||||
}
|
||||
|
||||
var getDragSourceDescription() override
|
||||
{
|
||||
return getParentItem()->getUniqueName() + "||" + config->getName();
|
||||
}
|
||||
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) override { repaintItem(); }
|
||||
|
||||
private:
|
||||
ProjectExporter::BuildConfiguration::Ptr config;
|
||||
ProjectExporter& exporter;
|
||||
ValueTree configTree;
|
||||
|
||||
//==============================================================================
|
||||
class SettingsComp : public Component
|
||||
{
|
||||
public:
|
||||
SettingsComp (ProjectExporter::BuildConfiguration& conf)
|
||||
: group (conf.exporter.getUniqueName() + " - " + conf.getName(), Icon (getIcons().config, Colours::transparentBlack))
|
||||
{
|
||||
addAndMakeVisible (group);
|
||||
|
||||
PropertyListBuilder props;
|
||||
conf.createPropertyEditors (props);
|
||||
group.setProperties (props);
|
||||
parentSizeChanged();
|
||||
}
|
||||
|
||||
void parentSizeChanged() override { updateSize (*this, group); }
|
||||
|
||||
void resized() override { group.setBounds (getLocalBounds().withTrimmedLeft (12)); }
|
||||
|
||||
private:
|
||||
PropertyGroupComponent group;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SettingsComp)
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConfigItem)
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (ConfigItem)
|
||||
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ExportersTreeRoot : public ProjectTreeItemBase
|
||||
{
|
||||
public:
|
||||
ExportersTreeRoot (Project& p)
|
||||
: project (p),
|
||||
exportersTree (project.getExporters())
|
||||
{
|
||||
exportersTree.addListener (this);
|
||||
}
|
||||
|
||||
bool isRoot() const override { return true; }
|
||||
bool canBeSelected() const override { return true; }
|
||||
bool isMissing() const override { return false; }
|
||||
bool mightContainSubItems() override { return project.getNumExporters() > 0; }
|
||||
String getUniqueName() const override { return "exporters"; }
|
||||
String getRenamingName() const override { return getDisplayName(); }
|
||||
String getDisplayName() const override { return "Exporters"; }
|
||||
void setName (const String&) override {}
|
||||
Icon getIcon() const override { return project.getMainGroup().getIcon (isOpen()).withColour (getContentColour (true)); }
|
||||
|
||||
void showPopupMenu (Point<int>) override
|
||||
{
|
||||
if (auto* pcc = getProjectContentComponent())
|
||||
pcc->showNewExporterMenu();
|
||||
}
|
||||
|
||||
void addSubItems() override
|
||||
{
|
||||
int i = 0;
|
||||
for (Project::ExporterIterator exporter (project); exporter.next(); ++i)
|
||||
addSubItem (new TreeItemTypes::ExporterItem (project, exporter.exporter.release(), i));
|
||||
}
|
||||
|
||||
bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails) override
|
||||
{
|
||||
return dragSourceDetails.description.toString().startsWith (getUniqueName());
|
||||
}
|
||||
|
||||
void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex) override
|
||||
{
|
||||
int oldIndex = dragSourceDetails.description.toString().getTrailingIntValue();
|
||||
exportersTree.moveChild (oldIndex, jmax (0, insertIndex), project.getUndoManagerFor (exportersTree));
|
||||
}
|
||||
|
||||
void itemOpennessChanged (bool isNowOpen) override
|
||||
{
|
||||
if (isNowOpen)
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
void removeExporter (int index)
|
||||
{
|
||||
if (auto* exporter = dynamic_cast<TreeItemTypes::ExporterItem*> (getSubItem (index)))
|
||||
exporter->deleteItem();
|
||||
}
|
||||
|
||||
private:
|
||||
Project& project;
|
||||
ValueTree exportersTree;
|
||||
|
||||
//==============================================================================
|
||||
void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) override { refreshIfNeeded (parentTree); }
|
||||
void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { refreshIfNeeded (parentTree); }
|
||||
void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { refreshIfNeeded (parentTree); }
|
||||
|
||||
void refreshIfNeeded (ValueTree& changedTree)
|
||||
{
|
||||
if (changedTree == exportersTree)
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExportersTreeRoot)
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,81 +1,81 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ProjectTreeItemBase : public JucerTreeViewBase,
|
||||
public ValueTree::Listener
|
||||
{
|
||||
ProjectTreeItemBase() {}
|
||||
|
||||
void showSettingsPage (Component* content)
|
||||
{
|
||||
content->setComponentID (getUniqueName());
|
||||
std::unique_ptr<Component> comp (content);
|
||||
|
||||
if (auto* pcc = getProjectContentComponent())
|
||||
pcc->setScrollableEditorComponent (std::move (comp));
|
||||
}
|
||||
|
||||
void closeSettingsPage()
|
||||
{
|
||||
if (auto* pcc = getProjectContentComponent())
|
||||
if (auto* content = pcc->getEditorComponent())
|
||||
if (content->getComponentID() == getUniqueName())
|
||||
pcc->hideEditor();
|
||||
}
|
||||
|
||||
void deleteAllSelectedItems() override
|
||||
{
|
||||
auto* tree = getOwnerView();
|
||||
jassert (tree->getNumSelectedItems() <= 1); // multi-select should be disabled
|
||||
|
||||
if (auto* s = dynamic_cast<ProjectTreeItemBase*> (tree->getSelectedItem (0)))
|
||||
s->deleteItem();
|
||||
}
|
||||
|
||||
void itemOpennessChanged (bool isNowOpen) override
|
||||
{
|
||||
if (isNowOpen)
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
virtual bool isProjectSettings() const { return false; }
|
||||
virtual bool isModulesList() const { return false; }
|
||||
|
||||
static void updateSize (Component& comp, PropertyGroupComponent& group)
|
||||
{
|
||||
auto width = jmax (550, comp.getParentWidth() - 12);
|
||||
|
||||
auto y = 0;
|
||||
y += group.updateSize (12, y, width - 12);
|
||||
|
||||
y = jmax (comp.getParentHeight(), y);
|
||||
|
||||
comp.setSize (width, y);
|
||||
}
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 ProjectTreeItemBase : public JucerTreeViewBase,
|
||||
public ValueTree::Listener
|
||||
{
|
||||
ProjectTreeItemBase() {}
|
||||
|
||||
void showSettingsPage (Component* content)
|
||||
{
|
||||
content->setComponentID (getUniqueName());
|
||||
std::unique_ptr<Component> comp (content);
|
||||
|
||||
if (auto* pcc = getProjectContentComponent())
|
||||
pcc->setScrollableEditorComponent (std::move (comp));
|
||||
}
|
||||
|
||||
void closeSettingsPage()
|
||||
{
|
||||
if (auto* pcc = getProjectContentComponent())
|
||||
if (auto* content = pcc->getEditorComponent())
|
||||
if (content->getComponentID() == getUniqueName())
|
||||
pcc->hideEditor();
|
||||
}
|
||||
|
||||
void deleteAllSelectedItems() override
|
||||
{
|
||||
auto* tree = getOwnerView();
|
||||
jassert (tree->getNumSelectedItems() <= 1); // multi-select should be disabled
|
||||
|
||||
if (auto* s = dynamic_cast<ProjectTreeItemBase*> (tree->getSelectedItem (0)))
|
||||
s->deleteItem();
|
||||
}
|
||||
|
||||
void itemOpennessChanged (bool isNowOpen) override
|
||||
{
|
||||
if (isNowOpen)
|
||||
refreshSubItems();
|
||||
}
|
||||
|
||||
virtual bool isProjectSettings() const { return false; }
|
||||
virtual bool isModulesList() const { return false; }
|
||||
|
||||
static void updateSize (Component& comp, PropertyGroupComponent& group)
|
||||
{
|
||||
auto width = jmax (550, comp.getParentWidth() - 12);
|
||||
|
||||
auto y = 0;
|
||||
y += group.updateSize (12, y, width - 12);
|
||||
|
||||
y = jmax (comp.getParentHeight(), y);
|
||||
|
||||
comp.setSize (width, y);
|
||||
}
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,42 +1,42 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 "../../../Application/Windows/jucer_TranslationToolWindowComponent.h"
|
||||
#include "../../../Utility/UI/jucer_JucerTreeViewBase.h"
|
||||
#include "../../../Utility/Helpers/jucer_NewFileWizard.h"
|
||||
#include "../jucer_ContentViewComponents.h"
|
||||
#include "../jucer_FileGroupInformationComponent.h"
|
||||
#include "../jucer_ModulesInformationComponent.h"
|
||||
|
||||
struct TreeItemTypes
|
||||
{
|
||||
#include "jucer_ProjectTreeItemBase.h"
|
||||
#include "jucer_ExporterTreeItems.h"
|
||||
#include "jucer_ModuleTreeItems.h"
|
||||
#include "jucer_FileTreeItems.h"
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 "../../../Application/Windows/jucer_TranslationToolWindowComponent.h"
|
||||
#include "../../../Utility/UI/jucer_JucerTreeViewBase.h"
|
||||
#include "../../../Utility/Helpers/jucer_NewFileWizard.h"
|
||||
#include "../jucer_ContentViewComponents.h"
|
||||
#include "../jucer_FileGroupInformationComponent.h"
|
||||
#include "../jucer_ModulesInformationComponent.h"
|
||||
|
||||
struct TreeItemTypes
|
||||
{
|
||||
#include "jucer_ProjectTreeItemBase.h"
|
||||
#include "jucer_ExporterTreeItems.h"
|
||||
#include "jucer_ModuleTreeItems.h"
|
||||
#include "jucer_FileTreeItems.h"
|
||||
};
|
||||
|
@ -1,112 +1,112 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ContentViewComponent : public Component
|
||||
{
|
||||
public:
|
||||
ContentViewComponent()
|
||||
{
|
||||
setTitle ("Content");
|
||||
setFocusContainerType (Component::FocusContainerType::focusContainer);
|
||||
|
||||
addAndMakeVisible (logoComponent);
|
||||
|
||||
addAndMakeVisible (fileNameLabel);
|
||||
fileNameLabel.setJustificationType (Justification::centred);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
fileNameLabel.setBounds (bounds.removeFromTop (15));
|
||||
|
||||
if (content != nullptr)
|
||||
content->setBounds (bounds);
|
||||
else
|
||||
logoComponent.setBounds (bounds);
|
||||
}
|
||||
|
||||
Component* getCurrentComponent() noexcept
|
||||
{
|
||||
return content.get();
|
||||
}
|
||||
|
||||
void setContent (std::unique_ptr<Component> newContent,
|
||||
const String& labelText)
|
||||
{
|
||||
content = std::move (newContent);
|
||||
addAndMakeVisible (content.get());
|
||||
|
||||
fileNameLabel.setVisible (labelText.isNotEmpty());
|
||||
fileNameLabel.setText (labelText, dontSendNotification);
|
||||
|
||||
resized();
|
||||
}
|
||||
|
||||
private:
|
||||
class LogoComponent : public Component
|
||||
{
|
||||
public:
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.setColour (findColour (defaultTextColourId));
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
bounds.reduce (bounds.getWidth() / 6, bounds.getHeight() / 6);
|
||||
|
||||
g.setFont (15.0f);
|
||||
g.drawFittedText (versionInfo, bounds.removeFromBottom (50), Justification::centredBottom, 3);
|
||||
|
||||
if (logo != nullptr)
|
||||
logo->drawWithin (g, bounds.withTrimmedBottom (bounds.getHeight() / 4).toFloat(),
|
||||
RectanglePlacement (RectanglePlacement::centred), 1.0f);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Drawable> logo = []() -> std::unique_ptr<Drawable>
|
||||
{
|
||||
if (auto svg = parseXML (BinaryData::background_logo_svg))
|
||||
return Drawable::createFromSVG (*svg);
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}();
|
||||
|
||||
String versionInfo = SystemStats::getJUCEVersion()
|
||||
+ newLine
|
||||
+ ProjucerApplication::getApp().getVersionDescription();
|
||||
};
|
||||
|
||||
std::unique_ptr<Component> content;
|
||||
LogoComponent logoComponent;
|
||||
Label fileNameLabel;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentViewComponent)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 ContentViewComponent : public Component
|
||||
{
|
||||
public:
|
||||
ContentViewComponent()
|
||||
{
|
||||
setTitle ("Content");
|
||||
setFocusContainerType (Component::FocusContainerType::focusContainer);
|
||||
|
||||
addAndMakeVisible (logoComponent);
|
||||
|
||||
addAndMakeVisible (fileNameLabel);
|
||||
fileNameLabel.setJustificationType (Justification::centred);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
fileNameLabel.setBounds (bounds.removeFromTop (15));
|
||||
|
||||
if (content != nullptr)
|
||||
content->setBounds (bounds);
|
||||
else
|
||||
logoComponent.setBounds (bounds);
|
||||
}
|
||||
|
||||
Component* getCurrentComponent() noexcept
|
||||
{
|
||||
return content.get();
|
||||
}
|
||||
|
||||
void setContent (std::unique_ptr<Component> newContent,
|
||||
const String& labelText)
|
||||
{
|
||||
content = std::move (newContent);
|
||||
addAndMakeVisible (content.get());
|
||||
|
||||
fileNameLabel.setVisible (labelText.isNotEmpty());
|
||||
fileNameLabel.setText (labelText, dontSendNotification);
|
||||
|
||||
resized();
|
||||
}
|
||||
|
||||
private:
|
||||
class LogoComponent : public Component
|
||||
{
|
||||
public:
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.setColour (findColour (defaultTextColourId));
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
bounds.reduce (bounds.getWidth() / 6, bounds.getHeight() / 6);
|
||||
|
||||
g.setFont (15.0f);
|
||||
g.drawFittedText (versionInfo, bounds.removeFromBottom (50), Justification::centredBottom, 3);
|
||||
|
||||
if (logo != nullptr)
|
||||
logo->drawWithin (g, bounds.withTrimmedBottom (bounds.getHeight() / 4).toFloat(),
|
||||
RectanglePlacement (RectanglePlacement::centred), 1.0f);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Drawable> logo = []() -> std::unique_ptr<Drawable>
|
||||
{
|
||||
if (auto svg = parseXML (BinaryData::background_logo_svg))
|
||||
return Drawable::createFromSVG (*svg);
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}();
|
||||
|
||||
String versionInfo = SystemStats::getJUCEVersion()
|
||||
+ newLine
|
||||
+ ProjucerApplication::getApp().getVersionDescription();
|
||||
};
|
||||
|
||||
std::unique_ptr<Component> content;
|
||||
LogoComponent logoComponent;
|
||||
Label fileNameLabel;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentViewComponent)
|
||||
};
|
||||
|
@ -1,446 +1,445 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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"
|
||||
|
||||
//==============================================================================
|
||||
struct ContentViewHeader : public Component
|
||||
{
|
||||
ContentViewHeader (String headerName, Icon headerIcon)
|
||||
: name (headerName), icon (headerIcon)
|
||||
{
|
||||
setTitle (name);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (contentHeaderBackgroundColourId));
|
||||
|
||||
auto bounds = getLocalBounds().reduced (20, 0);
|
||||
|
||||
icon.withColour (Colours::white).draw (g, bounds.toFloat().removeFromRight (30), false);
|
||||
|
||||
g.setColour (Colours::white);
|
||||
g.setFont (Font (18.0f));
|
||||
g.drawFittedText (name, bounds, Justification::centredLeft, 1);
|
||||
}
|
||||
|
||||
String name;
|
||||
Icon icon;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ListBoxHeader : public Component
|
||||
{
|
||||
public:
|
||||
ListBoxHeader (Array<String> columnHeaders)
|
||||
{
|
||||
for (auto s : columnHeaders)
|
||||
{
|
||||
addAndMakeVisible (headers.add (new Label (s, s)));
|
||||
widths.add (1.0f / (float) columnHeaders.size());
|
||||
}
|
||||
|
||||
setSize (200, 40);
|
||||
}
|
||||
|
||||
ListBoxHeader (Array<String> columnHeaders, Array<float> columnWidths)
|
||||
{
|
||||
jassert (columnHeaders.size() == columnWidths.size());
|
||||
|
||||
auto index = 0;
|
||||
for (auto s : columnHeaders)
|
||||
{
|
||||
addAndMakeVisible (headers.add (new Label (s, s)));
|
||||
widths.add (columnWidths.getUnchecked (index++));
|
||||
}
|
||||
|
||||
recalculateWidths();
|
||||
|
||||
setSize (200, 40);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
auto width = bounds.getWidth();
|
||||
|
||||
auto index = 0;
|
||||
for (auto h : headers)
|
||||
{
|
||||
auto headerWidth = roundToInt ((float) width * widths.getUnchecked (index));
|
||||
h->setBounds (bounds.removeFromLeft (headerWidth));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
void setColumnHeaderWidth (int index, float proportionOfWidth)
|
||||
{
|
||||
if (! (isPositiveAndBelow (index, headers.size()) && isPositiveAndNotGreaterThan (proportionOfWidth, 1.0f)))
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
widths.set (index, proportionOfWidth);
|
||||
recalculateWidths (index);
|
||||
}
|
||||
|
||||
int getColumnX (int index)
|
||||
{
|
||||
auto prop = 0.0f;
|
||||
for (int i = 0; i < index; ++i)
|
||||
prop += widths.getUnchecked (i);
|
||||
|
||||
return roundToInt (prop * (float) getWidth());
|
||||
}
|
||||
|
||||
float getProportionAtIndex (int index)
|
||||
{
|
||||
jassert (isPositiveAndBelow (index, widths.size()));
|
||||
return widths.getUnchecked (index);
|
||||
}
|
||||
|
||||
private:
|
||||
OwnedArray<Label> headers;
|
||||
Array<float> widths;
|
||||
|
||||
void recalculateWidths (int indexToIgnore = -1)
|
||||
{
|
||||
auto total = 0.0f;
|
||||
|
||||
for (auto w : widths)
|
||||
total += w;
|
||||
|
||||
if (total == 1.0f)
|
||||
return;
|
||||
|
||||
auto diff = 1.0f - total;
|
||||
auto amount = diff / static_cast<float> (indexToIgnore == -1 ? widths.size() : widths.size() - 1);
|
||||
|
||||
for (int i = 0; i < widths.size(); ++i)
|
||||
{
|
||||
if (i != indexToIgnore)
|
||||
{
|
||||
auto val = widths.getUnchecked (i);
|
||||
widths.set (i, val + amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class InfoButton : public Button
|
||||
{
|
||||
public:
|
||||
InfoButton (const String& infoToDisplay = {})
|
||||
: Button ({})
|
||||
{
|
||||
setTitle ("Info");
|
||||
|
||||
if (infoToDisplay.isNotEmpty())
|
||||
setInfoToDisplay (infoToDisplay);
|
||||
|
||||
setSize (20, 20);
|
||||
}
|
||||
|
||||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override
|
||||
{
|
||||
auto bounds = getLocalBounds().toFloat().reduced (2);
|
||||
auto& icon = getIcons().info;
|
||||
|
||||
g.setColour (findColour (treeIconColourId).withMultipliedAlpha (isMouseOverButton || isButtonDown ? 1.0f : 0.5f));
|
||||
|
||||
if (isButtonDown)
|
||||
g.fillEllipse (bounds);
|
||||
else
|
||||
g.fillPath (icon, RectanglePlacement (RectanglePlacement::centred)
|
||||
.getTransformToFit (icon.getBounds(), bounds));
|
||||
}
|
||||
|
||||
void clicked() override
|
||||
{
|
||||
auto w = std::make_unique<InfoWindow> (info);
|
||||
w->setSize (width, w->getHeight() * numLines + 10);
|
||||
|
||||
CallOutBox::launchAsynchronously (std::move (w), getScreenBounds(), nullptr);
|
||||
}
|
||||
|
||||
using Button::clicked;
|
||||
|
||||
void setInfoToDisplay (const String& infoToDisplay)
|
||||
{
|
||||
if (infoToDisplay.isNotEmpty())
|
||||
{
|
||||
info = infoToDisplay;
|
||||
|
||||
auto stringWidth = roundToInt (Font (14.0f).getStringWidthFloat (info));
|
||||
width = jmin (300, stringWidth);
|
||||
|
||||
numLines += static_cast<int> (stringWidth / width);
|
||||
|
||||
setHelpText (info);
|
||||
}
|
||||
}
|
||||
|
||||
void setAssociatedComponent (Component* comp) { associatedComponent = comp; }
|
||||
Component* getAssociatedComponent() { return associatedComponent; }
|
||||
|
||||
private:
|
||||
String info;
|
||||
Component* associatedComponent = nullptr;
|
||||
int width;
|
||||
int numLines = 1;
|
||||
|
||||
//==============================================================================
|
||||
struct InfoWindow : public Component
|
||||
{
|
||||
InfoWindow (const String& s)
|
||||
: stringToDisplay (s)
|
||||
{
|
||||
setSize (150, 14);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
|
||||
g.setColour (findColour (defaultTextColourId));
|
||||
g.setFont (Font (14.0f));
|
||||
g.drawFittedText (stringToDisplay, getLocalBounds(), Justification::centred, 15, 0.75f);
|
||||
}
|
||||
|
||||
String stringToDisplay;
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InfoButton)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class PropertyGroupComponent : public Component,
|
||||
private TextPropertyComponent::Listener
|
||||
{
|
||||
public:
|
||||
PropertyGroupComponent (String name, Icon icon, String desc = {})
|
||||
: header (name, icon),
|
||||
description (desc)
|
||||
{
|
||||
addAndMakeVisible (header);
|
||||
}
|
||||
|
||||
void setProperties (const PropertyListBuilder& newProps)
|
||||
{
|
||||
clearProperties();
|
||||
|
||||
if (description.isNotEmpty())
|
||||
properties.push_back (std::make_unique<LabelPropertyComponent> (description, 16, Font (16.0f),
|
||||
Justification::centredLeft));
|
||||
|
||||
for (auto* comp : newProps.components)
|
||||
properties.push_back (std::unique_ptr<PropertyComponent> (comp));
|
||||
|
||||
for (auto& prop : properties)
|
||||
{
|
||||
const auto propertyTooltip = prop->getTooltip();
|
||||
|
||||
if (propertyTooltip.isNotEmpty())
|
||||
{
|
||||
// set the tooltip to empty so it only displays when its button is clicked
|
||||
prop->setTooltip ({});
|
||||
|
||||
auto infoButton = std::make_unique<InfoButton> (propertyTooltip);
|
||||
infoButton->setAssociatedComponent (prop.get());
|
||||
|
||||
auto propertyAndInfoWrapper = std::make_unique<PropertyAndInfoWrapper> (*prop, *infoButton.get());
|
||||
addAndMakeVisible (propertyAndInfoWrapper.get());
|
||||
propertyComponentsWithInfo.push_back (std::move (propertyAndInfoWrapper));
|
||||
|
||||
infoButtons.push_back (std::move (infoButton));
|
||||
}
|
||||
else
|
||||
{
|
||||
addAndMakeVisible (prop.get());
|
||||
}
|
||||
|
||||
if (auto* multiChoice = dynamic_cast<MultiChoicePropertyComponent*> (prop.get()))
|
||||
multiChoice->onHeightChange = [this] { updateSize(); };
|
||||
|
||||
if (auto* text = dynamic_cast<TextPropertyComponent*> (prop.get()))
|
||||
if (text->isTextEditorMultiLine())
|
||||
text->addListener (this);
|
||||
}
|
||||
}
|
||||
|
||||
int updateSize (int x, int y, int width)
|
||||
{
|
||||
header.setBounds (0, 0, width, headerSize);
|
||||
auto height = header.getBottom() + 10;
|
||||
|
||||
for (auto& pp : properties)
|
||||
{
|
||||
const auto propertyHeight = pp->getPreferredHeight()
|
||||
+ (getHeightMultiplier (pp.get()) * pp->getPreferredHeight());
|
||||
|
||||
auto iter = std::find_if (propertyComponentsWithInfo.begin(), propertyComponentsWithInfo.end(),
|
||||
[&pp] (const std::unique_ptr<PropertyAndInfoWrapper>& w) { return &w->propertyComponent == pp.get(); });
|
||||
|
||||
if (iter != propertyComponentsWithInfo.end())
|
||||
(*iter)->setBounds (0, height, width - 10, propertyHeight);
|
||||
else
|
||||
pp->setBounds (40, height, width - 50, propertyHeight);
|
||||
|
||||
if (shouldResizePropertyComponent (pp.get()))
|
||||
resizePropertyComponent (pp.get());
|
||||
|
||||
height += pp->getHeight() + 10;
|
||||
}
|
||||
|
||||
height += 16;
|
||||
|
||||
setBounds (x, y, width, jmax (height, getParentHeight()));
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<PropertyComponent>>& getProperties() const noexcept
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
|
||||
void clearProperties()
|
||||
{
|
||||
propertyComponentsWithInfo.clear();
|
||||
infoButtons.clear();
|
||||
properties.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct PropertyAndInfoWrapper : public Component
|
||||
{
|
||||
PropertyAndInfoWrapper (PropertyComponent& c, InfoButton& i)
|
||||
: propertyComponent (c),
|
||||
infoButton (i)
|
||||
{
|
||||
setFocusContainerType (FocusContainerType::focusContainer);
|
||||
setTitle (propertyComponent.getName());
|
||||
|
||||
addAndMakeVisible (propertyComponent);
|
||||
addAndMakeVisible (infoButton);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
bounds.removeFromLeft (40);
|
||||
bounds.removeFromRight (10);
|
||||
|
||||
propertyComponent.setBounds (bounds);
|
||||
infoButton.setCentrePosition (20, bounds.getHeight() / 2);
|
||||
}
|
||||
|
||||
PropertyComponent& propertyComponent;
|
||||
InfoButton& infoButton;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void textPropertyComponentChanged (TextPropertyComponent* comp) override
|
||||
{
|
||||
auto fontHeight = [comp]
|
||||
{
|
||||
Label tmpLabel;
|
||||
return comp->getLookAndFeel().getLabelFont (tmpLabel).getHeight();
|
||||
}();
|
||||
|
||||
auto lines = StringArray::fromLines (comp->getText());
|
||||
|
||||
comp->setPreferredHeight (jmax (100, 10 + roundToInt (fontHeight * (float) lines.size())));
|
||||
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void updateSize()
|
||||
{
|
||||
updateSize (getX(), getY(), getWidth());
|
||||
|
||||
if (auto* parent = getParentComponent())
|
||||
parent->parentSizeChanged();
|
||||
}
|
||||
|
||||
bool shouldResizePropertyComponent (PropertyComponent* p)
|
||||
{
|
||||
if (auto* textComp = dynamic_cast<TextPropertyComponent*> (p))
|
||||
return ! textComp->isTextEditorMultiLine();
|
||||
|
||||
return (dynamic_cast<ChoicePropertyComponent*> (p) != nullptr
|
||||
|| dynamic_cast<ButtonPropertyComponent*> (p) != nullptr
|
||||
|| dynamic_cast<BooleanPropertyComponent*> (p) != nullptr);
|
||||
}
|
||||
|
||||
void resizePropertyComponent (PropertyComponent* pp)
|
||||
{
|
||||
for (auto i = pp->getNumChildComponents() - 1; i >= 0; --i)
|
||||
{
|
||||
auto* child = pp->getChildComponent (i);
|
||||
|
||||
auto bounds = child->getBounds();
|
||||
child->setBounds (bounds.withSizeKeepingCentre (child->getWidth(), pp->getPreferredHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
int getHeightMultiplier (PropertyComponent* pp)
|
||||
{
|
||||
auto availableTextWidth = ProjucerLookAndFeel::getTextWidthForPropertyComponent (pp);
|
||||
|
||||
auto font = ProjucerLookAndFeel::getPropertyComponentFont();
|
||||
auto nameWidth = font.getStringWidthFloat (pp->getName());
|
||||
|
||||
if (availableTextWidth == 0)
|
||||
return 0;
|
||||
|
||||
return static_cast<int> (nameWidth / (float) availableTextWidth);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static constexpr int headerSize = 40;
|
||||
|
||||
std::vector<std::unique_ptr<PropertyComponent>> properties;
|
||||
std::vector<std::unique_ptr<InfoButton>> infoButtons;
|
||||
std::vector<std::unique_ptr<PropertyAndInfoWrapper>> propertyComponentsWithInfo;
|
||||
|
||||
ContentViewHeader header;
|
||||
String description;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyGroupComponent)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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"
|
||||
|
||||
//==============================================================================
|
||||
struct ContentViewHeader : public Component
|
||||
{
|
||||
ContentViewHeader (String headerName, Icon headerIcon)
|
||||
: name (headerName), icon (headerIcon)
|
||||
{
|
||||
setTitle (name);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (contentHeaderBackgroundColourId));
|
||||
|
||||
auto bounds = getLocalBounds().reduced (20, 0);
|
||||
|
||||
icon.withColour (Colours::white).draw (g, bounds.toFloat().removeFromRight (30), false);
|
||||
|
||||
g.setColour (Colours::white);
|
||||
g.setFont (Font (18.0f));
|
||||
g.drawFittedText (name, bounds, Justification::centredLeft, 1);
|
||||
}
|
||||
|
||||
String name;
|
||||
Icon icon;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ListBoxHeader : public Component
|
||||
{
|
||||
public:
|
||||
ListBoxHeader (Array<String> columnHeaders)
|
||||
{
|
||||
for (auto s : columnHeaders)
|
||||
{
|
||||
addAndMakeVisible (headers.add (new Label (s, s)));
|
||||
widths.add (1.0f / (float) columnHeaders.size());
|
||||
}
|
||||
|
||||
setSize (200, 40);
|
||||
}
|
||||
|
||||
ListBoxHeader (Array<String> columnHeaders, Array<float> columnWidths)
|
||||
{
|
||||
jassert (columnHeaders.size() == columnWidths.size());
|
||||
|
||||
auto index = 0;
|
||||
for (auto s : columnHeaders)
|
||||
{
|
||||
addAndMakeVisible (headers.add (new Label (s, s)));
|
||||
widths.add (columnWidths.getUnchecked (index++));
|
||||
}
|
||||
|
||||
recalculateWidths();
|
||||
|
||||
setSize (200, 40);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
auto width = bounds.getWidth();
|
||||
|
||||
auto index = 0;
|
||||
for (auto h : headers)
|
||||
{
|
||||
auto headerWidth = roundToInt ((float) width * widths.getUnchecked (index));
|
||||
h->setBounds (bounds.removeFromLeft (headerWidth));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
void setColumnHeaderWidth (int index, float proportionOfWidth)
|
||||
{
|
||||
if (! (isPositiveAndBelow (index, headers.size()) && isPositiveAndNotGreaterThan (proportionOfWidth, 1.0f)))
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
widths.set (index, proportionOfWidth);
|
||||
recalculateWidths (index);
|
||||
}
|
||||
|
||||
int getColumnX (int index)
|
||||
{
|
||||
auto prop = 0.0f;
|
||||
for (int i = 0; i < index; ++i)
|
||||
prop += widths.getUnchecked (i);
|
||||
|
||||
return roundToInt (prop * (float) getWidth());
|
||||
}
|
||||
|
||||
float getProportionAtIndex (int index)
|
||||
{
|
||||
jassert (isPositiveAndBelow (index, widths.size()));
|
||||
return widths.getUnchecked (index);
|
||||
}
|
||||
|
||||
private:
|
||||
OwnedArray<Label> headers;
|
||||
Array<float> widths;
|
||||
|
||||
void recalculateWidths (int indexToIgnore = -1)
|
||||
{
|
||||
auto total = 0.0f;
|
||||
|
||||
for (auto w : widths)
|
||||
total += w;
|
||||
|
||||
if (total == 1.0f)
|
||||
return;
|
||||
|
||||
auto diff = 1.0f - total;
|
||||
auto amount = diff / static_cast<float> (indexToIgnore == -1 ? widths.size() : widths.size() - 1);
|
||||
|
||||
for (int i = 0; i < widths.size(); ++i)
|
||||
{
|
||||
if (i != indexToIgnore)
|
||||
{
|
||||
auto val = widths.getUnchecked (i);
|
||||
widths.set (i, val + amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class InfoButton : public Button
|
||||
{
|
||||
public:
|
||||
InfoButton (const String& infoToDisplay = {})
|
||||
: Button ({})
|
||||
{
|
||||
setTitle ("Info");
|
||||
|
||||
if (infoToDisplay.isNotEmpty())
|
||||
setInfoToDisplay (infoToDisplay);
|
||||
|
||||
setSize (20, 20);
|
||||
}
|
||||
|
||||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override
|
||||
{
|
||||
auto bounds = getLocalBounds().toFloat().reduced (2);
|
||||
auto& icon = getIcons().info;
|
||||
|
||||
g.setColour (findColour (treeIconColourId).withMultipliedAlpha (isMouseOverButton || isButtonDown ? 1.0f : 0.5f));
|
||||
|
||||
if (isButtonDown)
|
||||
g.fillEllipse (bounds);
|
||||
else
|
||||
g.fillPath (icon, RectanglePlacement (RectanglePlacement::centred)
|
||||
.getTransformToFit (icon.getBounds(), bounds));
|
||||
}
|
||||
|
||||
void clicked() override
|
||||
{
|
||||
auto w = std::make_unique<InfoWindow> (info);
|
||||
w->setSize (width, w->getHeight() * numLines + 10);
|
||||
|
||||
CallOutBox::launchAsynchronously (std::move (w), getScreenBounds(), nullptr);
|
||||
}
|
||||
|
||||
using Button::clicked;
|
||||
|
||||
void setInfoToDisplay (const String& infoToDisplay)
|
||||
{
|
||||
if (infoToDisplay.isNotEmpty())
|
||||
{
|
||||
info = infoToDisplay;
|
||||
|
||||
auto stringWidth = roundToInt (Font (14.0f).getStringWidthFloat (info));
|
||||
width = jmin (300, stringWidth);
|
||||
|
||||
numLines += static_cast<int> (stringWidth / width);
|
||||
|
||||
setHelpText (info);
|
||||
}
|
||||
}
|
||||
|
||||
void setAssociatedComponent (Component* comp) { associatedComponent = comp; }
|
||||
Component* getAssociatedComponent() { return associatedComponent; }
|
||||
|
||||
private:
|
||||
String info;
|
||||
Component* associatedComponent = nullptr;
|
||||
int width;
|
||||
int numLines = 1;
|
||||
|
||||
//==============================================================================
|
||||
struct InfoWindow : public Component
|
||||
{
|
||||
InfoWindow (const String& s)
|
||||
: stringToDisplay (s)
|
||||
{
|
||||
setSize (150, 14);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
|
||||
g.setColour (findColour (defaultTextColourId));
|
||||
g.setFont (Font (14.0f));
|
||||
g.drawFittedText (stringToDisplay, getLocalBounds(), Justification::centred, 15, 0.75f);
|
||||
}
|
||||
|
||||
String stringToDisplay;
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InfoButton)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class PropertyGroupComponent : public Component,
|
||||
private TextPropertyComponent::Listener
|
||||
{
|
||||
public:
|
||||
PropertyGroupComponent (String name, Icon icon, String desc = {})
|
||||
: header (name, icon),
|
||||
description (desc)
|
||||
{
|
||||
addAndMakeVisible (header);
|
||||
}
|
||||
|
||||
void setProperties (const PropertyListBuilder& newProps)
|
||||
{
|
||||
clearProperties();
|
||||
|
||||
if (description.isNotEmpty())
|
||||
properties.push_back (std::make_unique<LabelPropertyComponent> (description, 16, Font (16.0f),
|
||||
Justification::centredLeft));
|
||||
|
||||
for (auto* comp : newProps.components)
|
||||
properties.push_back (std::unique_ptr<PropertyComponent> (comp));
|
||||
|
||||
for (auto& prop : properties)
|
||||
{
|
||||
const auto propertyTooltip = prop->getTooltip();
|
||||
|
||||
if (propertyTooltip.isNotEmpty())
|
||||
{
|
||||
// set the tooltip to empty so it only displays when its button is clicked
|
||||
prop->setTooltip ({});
|
||||
|
||||
auto infoButton = std::make_unique<InfoButton> (propertyTooltip);
|
||||
infoButton->setAssociatedComponent (prop.get());
|
||||
|
||||
auto propertyAndInfoWrapper = std::make_unique<PropertyAndInfoWrapper> (*prop, *infoButton.get());
|
||||
addAndMakeVisible (propertyAndInfoWrapper.get());
|
||||
propertyComponentsWithInfo.push_back (std::move (propertyAndInfoWrapper));
|
||||
|
||||
infoButtons.push_back (std::move (infoButton));
|
||||
}
|
||||
else
|
||||
{
|
||||
addAndMakeVisible (prop.get());
|
||||
}
|
||||
|
||||
if (auto* multiChoice = dynamic_cast<MultiChoicePropertyComponent*> (prop.get()))
|
||||
multiChoice->onHeightChange = [this] { updateSize(); };
|
||||
|
||||
if (auto* text = dynamic_cast<TextPropertyComponent*> (prop.get()))
|
||||
if (text->isTextEditorMultiLine())
|
||||
text->addListener (this);
|
||||
}
|
||||
}
|
||||
|
||||
int updateSize (int x, int y, int width)
|
||||
{
|
||||
header.setBounds (0, 0, width, headerSize);
|
||||
auto height = header.getBottom() + 10;
|
||||
|
||||
for (auto& pp : properties)
|
||||
{
|
||||
const auto propertyHeight = jmax (pp->getPreferredHeight(), getApproximateLabelHeight (*pp));
|
||||
|
||||
auto iter = std::find_if (propertyComponentsWithInfo.begin(), propertyComponentsWithInfo.end(),
|
||||
[&pp] (const std::unique_ptr<PropertyAndInfoWrapper>& w) { return &w->propertyComponent == pp.get(); });
|
||||
|
||||
if (iter != propertyComponentsWithInfo.end())
|
||||
(*iter)->setBounds (0, height, width - 10, propertyHeight);
|
||||
else
|
||||
pp->setBounds (40, height, width - 50, propertyHeight);
|
||||
|
||||
if (shouldResizePropertyComponent (pp.get()))
|
||||
resizePropertyComponent (pp.get());
|
||||
|
||||
height += pp->getHeight() + 10;
|
||||
}
|
||||
|
||||
height += 16;
|
||||
|
||||
setBounds (x, y, width, jmax (height, getParentHeight()));
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<PropertyComponent>>& getProperties() const noexcept
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
|
||||
void clearProperties()
|
||||
{
|
||||
propertyComponentsWithInfo.clear();
|
||||
infoButtons.clear();
|
||||
properties.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct PropertyAndInfoWrapper : public Component
|
||||
{
|
||||
PropertyAndInfoWrapper (PropertyComponent& c, InfoButton& i)
|
||||
: propertyComponent (c),
|
||||
infoButton (i)
|
||||
{
|
||||
setFocusContainerType (FocusContainerType::focusContainer);
|
||||
setTitle (propertyComponent.getName());
|
||||
|
||||
addAndMakeVisible (propertyComponent);
|
||||
addAndMakeVisible (infoButton);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
bounds.removeFromLeft (40);
|
||||
bounds.removeFromRight (10);
|
||||
|
||||
propertyComponent.setBounds (bounds);
|
||||
infoButton.setCentrePosition (20, bounds.getHeight() / 2);
|
||||
}
|
||||
|
||||
PropertyComponent& propertyComponent;
|
||||
InfoButton& infoButton;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void textPropertyComponentChanged (TextPropertyComponent* comp) override
|
||||
{
|
||||
auto fontHeight = [comp]
|
||||
{
|
||||
Label tmpLabel;
|
||||
return comp->getLookAndFeel().getLabelFont (tmpLabel).getHeight();
|
||||
}();
|
||||
|
||||
auto lines = StringArray::fromLines (comp->getText());
|
||||
|
||||
comp->setPreferredHeight (jmax (100, 10 + roundToInt (fontHeight * (float) lines.size())));
|
||||
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void updateSize()
|
||||
{
|
||||
updateSize (getX(), getY(), getWidth());
|
||||
|
||||
if (auto* parent = getParentComponent())
|
||||
parent->parentSizeChanged();
|
||||
}
|
||||
|
||||
bool shouldResizePropertyComponent (PropertyComponent* p)
|
||||
{
|
||||
if (auto* textComp = dynamic_cast<TextPropertyComponent*> (p))
|
||||
return ! textComp->isTextEditorMultiLine();
|
||||
|
||||
return (dynamic_cast<ChoicePropertyComponent*> (p) != nullptr
|
||||
|| dynamic_cast<ButtonPropertyComponent*> (p) != nullptr
|
||||
|| dynamic_cast<BooleanPropertyComponent*> (p) != nullptr);
|
||||
}
|
||||
|
||||
void resizePropertyComponent (PropertyComponent* pp)
|
||||
{
|
||||
for (auto i = pp->getNumChildComponents() - 1; i >= 0; --i)
|
||||
{
|
||||
auto* child = pp->getChildComponent (i);
|
||||
|
||||
auto bounds = child->getBounds();
|
||||
child->setBounds (bounds.withSizeKeepingCentre (child->getWidth(), pp->getPreferredHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
static int getApproximateLabelHeight (const PropertyComponent& pp)
|
||||
{
|
||||
auto availableTextWidth = ProjucerLookAndFeel::getTextWidthForPropertyComponent (pp);
|
||||
|
||||
if (availableTextWidth == 0)
|
||||
return 0;
|
||||
|
||||
const auto font = ProjucerLookAndFeel::getPropertyComponentFont();
|
||||
const auto labelWidth = font.getStringWidthFloat (pp.getName());
|
||||
const auto numLines = (int) (labelWidth / (float) availableTextWidth) + 1;
|
||||
return (int) std::round ((float) numLines * font.getHeight() * 1.1f);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static constexpr int headerSize = 40;
|
||||
|
||||
std::vector<std::unique_ptr<PropertyComponent>> properties;
|
||||
std::vector<std::unique_ptr<InfoButton>> infoButtons;
|
||||
std::vector<std::unique_ptr<PropertyAndInfoWrapper>> propertyComponentsWithInfo;
|
||||
|
||||
ContentViewHeader header;
|
||||
String description;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyGroupComponent)
|
||||
};
|
||||
|
@ -1,363 +1,363 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 FileGroupInformationComponent : public Component,
|
||||
private ListBoxModel,
|
||||
private ValueTree::Listener
|
||||
{
|
||||
public:
|
||||
FileGroupInformationComponent (const Project::Item& group)
|
||||
: item (group),
|
||||
header (item.getName(), { getIcons().openFolder, Colours::transparentBlack })
|
||||
{
|
||||
list.setHeaderComponent (std::make_unique<ListBoxHeader> (Array<String> { "File", "Binary Resource", "Xcode Resource", "Compile", "Skip PCH", "Compiler Flag Scheme" },
|
||||
Array<float> { 0.25f, 0.125f, 0.125f, 0.125f, 0.125f, 0.25f }));
|
||||
list.setModel (this);
|
||||
list.setColour (ListBox::backgroundColourId, Colours::transparentBlack);
|
||||
addAndMakeVisible (list);
|
||||
list.updateContent();
|
||||
list.setRowHeight (30);
|
||||
item.state.addListener (this);
|
||||
lookAndFeelChanged();
|
||||
|
||||
addAndMakeVisible (header);
|
||||
}
|
||||
|
||||
~FileGroupInformationComponent() override
|
||||
{
|
||||
item.state.removeListener (this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.setColour (findColour (secondaryBackgroundColourId));
|
||||
g.fillRect (getLocalBounds().reduced (12, 0));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (12, 0);
|
||||
|
||||
header.setBounds (bounds.removeFromTop (40));
|
||||
list.setBounds (bounds.reduced (10, 4));
|
||||
}
|
||||
|
||||
void parentSizeChanged() override
|
||||
{
|
||||
setSize (jmax (550, getParentWidth()), getParentHeight());
|
||||
}
|
||||
|
||||
int getNumRows() override
|
||||
{
|
||||
return item.getNumChildren();
|
||||
}
|
||||
|
||||
void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool /*rowIsSelected*/) override
|
||||
{
|
||||
g.setColour (findColour (rowNumber % 2 == 0 ? widgetBackgroundColourId
|
||||
: secondaryWidgetBackgroundColourId));
|
||||
g.fillRect (0, 0, width, height - 1);
|
||||
}
|
||||
|
||||
Component* refreshComponentForRow (int rowNumber, bool /*isRowSelected*/, Component* existingComponentToUpdate) override
|
||||
{
|
||||
std::unique_ptr<Component> existing (existingComponentToUpdate);
|
||||
|
||||
if (rowNumber < getNumRows())
|
||||
{
|
||||
auto child = item.getChild (rowNumber);
|
||||
|
||||
if (existingComponentToUpdate == nullptr
|
||||
|| dynamic_cast<FileOptionComponent*> (existing.get())->item != child)
|
||||
{
|
||||
existing.reset();
|
||||
existing.reset (new FileOptionComponent (child, dynamic_cast<ListBoxHeader*> (list.getHeaderComponent())));
|
||||
}
|
||||
}
|
||||
|
||||
return existing.release();
|
||||
}
|
||||
|
||||
String getGroupPath() const { return item.getFile().getFullPathName(); }
|
||||
|
||||
//==============================================================================
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) override { itemChanged(); }
|
||||
void valueTreeChildAdded (ValueTree&, ValueTree&) override { itemChanged(); }
|
||||
void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { itemChanged(); }
|
||||
void valueTreeChildOrderChanged (ValueTree&, int, int) override { itemChanged(); }
|
||||
void valueTreeParentChanged (ValueTree&) override { itemChanged(); }
|
||||
|
||||
private:
|
||||
Project::Item item;
|
||||
ListBox list;
|
||||
ContentViewHeader header;
|
||||
|
||||
void itemChanged()
|
||||
{
|
||||
list.updateContent();
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class FileOptionComponent : public Component
|
||||
{
|
||||
public:
|
||||
FileOptionComponent (const Project::Item& fileItem, ListBoxHeader* listBoxHeader)
|
||||
: item (fileItem),
|
||||
header (listBoxHeader),
|
||||
compilerFlagSchemeSelector (item)
|
||||
{
|
||||
if (item.isFile())
|
||||
{
|
||||
auto isSourceFile = item.isSourceFile();
|
||||
|
||||
if (isSourceFile)
|
||||
{
|
||||
addAndMakeVisible (compileButton);
|
||||
compileButton.getToggleStateValue().referTo (item.getShouldCompileValue());
|
||||
compileButton.onStateChange = [this] { compileEnablementChanged(); };
|
||||
}
|
||||
|
||||
addAndMakeVisible (binaryResourceButton);
|
||||
binaryResourceButton.getToggleStateValue().referTo (item.getShouldAddToBinaryResourcesValue());
|
||||
|
||||
addAndMakeVisible (xcodeResourceButton);
|
||||
xcodeResourceButton.getToggleStateValue().referTo (item.getShouldAddToXcodeResourcesValue());
|
||||
|
||||
if (isSourceFile)
|
||||
{
|
||||
addChildComponent (skipPCHButton);
|
||||
skipPCHButton.getToggleStateValue().referTo (item.getShouldSkipPCHValue());
|
||||
|
||||
addChildComponent (compilerFlagSchemeSelector);
|
||||
|
||||
compileEnablementChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
if (header != nullptr)
|
||||
{
|
||||
auto textBounds = getLocalBounds().removeFromLeft (roundToInt (header->getProportionAtIndex (0) * (float) getWidth()));
|
||||
|
||||
auto iconBounds = textBounds.removeFromLeft (25);
|
||||
|
||||
if (item.isImageFile())
|
||||
iconBounds.reduce (5, 5);
|
||||
|
||||
item.getIcon().withColour (findColour (treeIconColourId)).draw (g, iconBounds.toFloat(), item.isIconCrossedOut());
|
||||
|
||||
g.setColour (findColour (widgetTextColourId));
|
||||
|
||||
g.drawText (item.getName(), textBounds, Justification::centredLeft);
|
||||
}
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
if (header != nullptr)
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
auto width = (float) getWidth();
|
||||
|
||||
bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (0) * width));
|
||||
|
||||
binaryResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (1) * width)));
|
||||
xcodeResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (2) * width)));
|
||||
compileButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (3) * width)));
|
||||
skipPCHButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (4) * width)));
|
||||
compilerFlagSchemeSelector.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (5) * width)));
|
||||
}
|
||||
}
|
||||
|
||||
Project::Item item;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class CompilerFlagSchemeSelector : public Component,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
CompilerFlagSchemeSelector (Project::Item& it)
|
||||
: item (it)
|
||||
{
|
||||
schemeBox.setTextWhenNothingSelected ("None");
|
||||
updateCompilerFlagSchemeComboBox();
|
||||
schemeBox.onChange = [this] { handleComboBoxSelection(); };
|
||||
|
||||
addAndMakeVisible (schemeBox);
|
||||
addChildComponent (newSchemeLabel);
|
||||
|
||||
newSchemeLabel.setEditable (true);
|
||||
newSchemeLabel.setJustificationType (Justification::centredLeft);
|
||||
newSchemeLabel.onEditorHide = [this]
|
||||
{
|
||||
newSchemeLabel.setVisible (false);
|
||||
schemeBox.setVisible (true);
|
||||
|
||||
auto newScheme = newSchemeLabel.getText();
|
||||
|
||||
item.project.addCompilerFlagScheme (newScheme);
|
||||
|
||||
if (item.getCompilerFlagSchemeString().isEmpty())
|
||||
item.setCompilerFlagScheme (newScheme);
|
||||
|
||||
updateCompilerFlagSchemeComboBox();
|
||||
};
|
||||
|
||||
selectScheme (item.getCompilerFlagSchemeString());
|
||||
|
||||
projectCompilerFlagSchemesValue = item.project.getProjectValue (Ids::compilerFlagSchemes);
|
||||
projectCompilerFlagSchemesValue.addListener (this);
|
||||
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto b = getLocalBounds();
|
||||
|
||||
schemeBox.setBounds (b);
|
||||
newSchemeLabel.setBounds (b);
|
||||
}
|
||||
|
||||
private:
|
||||
void valueChanged (Value&) override { updateCompilerFlagSchemeComboBox(); }
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
schemeBox.setColour (ComboBox::outlineColourId, Colours::transparentBlack);
|
||||
schemeBox.setColour (ComboBox::textColourId, findColour (defaultTextColourId));
|
||||
}
|
||||
|
||||
void updateCompilerFlagSchemeComboBox()
|
||||
{
|
||||
auto itemScheme = item.getCompilerFlagSchemeString();
|
||||
auto allSchemes = item.project.getCompilerFlagSchemes();
|
||||
|
||||
if (itemScheme.isNotEmpty() && ! allSchemes.contains (itemScheme))
|
||||
{
|
||||
item.clearCurrentCompilerFlagScheme();
|
||||
itemScheme = {};
|
||||
}
|
||||
|
||||
schemeBox.clear();
|
||||
|
||||
schemeBox.addItemList (allSchemes, 1);
|
||||
schemeBox.addSeparator();
|
||||
schemeBox.addItem ("Add a new scheme...", -1);
|
||||
schemeBox.addItem ("Delete selected scheme", -2);
|
||||
schemeBox.addItem ("Clear", -3);
|
||||
|
||||
selectScheme (itemScheme);
|
||||
}
|
||||
|
||||
void handleComboBoxSelection()
|
||||
{
|
||||
auto selectedID = schemeBox.getSelectedId();
|
||||
|
||||
if (selectedID > 0)
|
||||
{
|
||||
item.setCompilerFlagScheme (schemeBox.getItemText (selectedID - 1));
|
||||
}
|
||||
else if (selectedID == -1)
|
||||
{
|
||||
newSchemeLabel.setText ("NewScheme", dontSendNotification);
|
||||
|
||||
schemeBox.setVisible (false);
|
||||
newSchemeLabel.setVisible (true);
|
||||
|
||||
newSchemeLabel.showEditor();
|
||||
|
||||
if (auto* ed = newSchemeLabel.getCurrentTextEditor())
|
||||
ed->setInputRestrictions (64, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_");
|
||||
}
|
||||
else if (selectedID == -2)
|
||||
{
|
||||
auto currentScheme = item.getCompilerFlagSchemeString();
|
||||
|
||||
if (currentScheme.isNotEmpty())
|
||||
{
|
||||
item.project.removeCompilerFlagScheme (currentScheme);
|
||||
item.clearCurrentCompilerFlagScheme();
|
||||
}
|
||||
|
||||
updateCompilerFlagSchemeComboBox();
|
||||
}
|
||||
else if (selectedID == -3)
|
||||
{
|
||||
schemeBox.setSelectedId (0);
|
||||
item.clearCurrentCompilerFlagScheme();
|
||||
}
|
||||
}
|
||||
|
||||
void selectScheme (const String& schemeToSelect)
|
||||
{
|
||||
if (schemeToSelect.isNotEmpty())
|
||||
{
|
||||
for (int i = 0; i < schemeBox.getNumItems(); ++i)
|
||||
{
|
||||
if (schemeBox.getItemText (i) == schemeToSelect)
|
||||
{
|
||||
schemeBox.setSelectedItemIndex (i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schemeBox.setSelectedId (0);
|
||||
}
|
||||
|
||||
Project::Item& item;
|
||||
Value projectCompilerFlagSchemesValue;
|
||||
|
||||
ComboBox schemeBox;
|
||||
Label newSchemeLabel;
|
||||
};
|
||||
|
||||
void compileEnablementChanged()
|
||||
{
|
||||
auto shouldBeCompiled = compileButton.getToggleState();
|
||||
|
||||
skipPCHButton.setVisible (shouldBeCompiled);
|
||||
compilerFlagSchemeSelector.setVisible (shouldBeCompiled);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ListBoxHeader* header;
|
||||
|
||||
ToggleButton compileButton, binaryResourceButton, xcodeResourceButton, skipPCHButton;
|
||||
CompilerFlagSchemeSelector compilerFlagSchemeSelector;
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileGroupInformationComponent)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 FileGroupInformationComponent : public Component,
|
||||
private ListBoxModel,
|
||||
private ValueTree::Listener
|
||||
{
|
||||
public:
|
||||
FileGroupInformationComponent (const Project::Item& group)
|
||||
: item (group),
|
||||
header (item.getName(), { getIcons().openFolder, Colours::transparentBlack })
|
||||
{
|
||||
list.setHeaderComponent (std::make_unique<ListBoxHeader> (Array<String> { "File", "Binary Resource", "Xcode Resource", "Compile", "Skip PCH", "Compiler Flag Scheme" },
|
||||
Array<float> { 0.25f, 0.125f, 0.125f, 0.125f, 0.125f, 0.25f }));
|
||||
list.setModel (this);
|
||||
list.setColour (ListBox::backgroundColourId, Colours::transparentBlack);
|
||||
addAndMakeVisible (list);
|
||||
list.updateContent();
|
||||
list.setRowHeight (30);
|
||||
item.state.addListener (this);
|
||||
lookAndFeelChanged();
|
||||
|
||||
addAndMakeVisible (header);
|
||||
}
|
||||
|
||||
~FileGroupInformationComponent() override
|
||||
{
|
||||
item.state.removeListener (this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.setColour (findColour (secondaryBackgroundColourId));
|
||||
g.fillRect (getLocalBounds().reduced (12, 0));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (12, 0);
|
||||
|
||||
header.setBounds (bounds.removeFromTop (40));
|
||||
list.setBounds (bounds.reduced (10, 4));
|
||||
}
|
||||
|
||||
void parentSizeChanged() override
|
||||
{
|
||||
setSize (jmax (550, getParentWidth()), getParentHeight());
|
||||
}
|
||||
|
||||
int getNumRows() override
|
||||
{
|
||||
return item.getNumChildren();
|
||||
}
|
||||
|
||||
void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool /*rowIsSelected*/) override
|
||||
{
|
||||
g.setColour (findColour (rowNumber % 2 == 0 ? widgetBackgroundColourId
|
||||
: secondaryWidgetBackgroundColourId));
|
||||
g.fillRect (0, 0, width, height - 1);
|
||||
}
|
||||
|
||||
Component* refreshComponentForRow (int rowNumber, bool /*isRowSelected*/, Component* existingComponentToUpdate) override
|
||||
{
|
||||
std::unique_ptr<Component> existing (existingComponentToUpdate);
|
||||
|
||||
if (rowNumber < getNumRows())
|
||||
{
|
||||
auto child = item.getChild (rowNumber);
|
||||
|
||||
if (existingComponentToUpdate == nullptr
|
||||
|| dynamic_cast<FileOptionComponent*> (existing.get())->item != child)
|
||||
{
|
||||
existing.reset();
|
||||
existing.reset (new FileOptionComponent (child, dynamic_cast<ListBoxHeader*> (list.getHeaderComponent())));
|
||||
}
|
||||
}
|
||||
|
||||
return existing.release();
|
||||
}
|
||||
|
||||
String getGroupPath() const { return item.getFile().getFullPathName(); }
|
||||
|
||||
//==============================================================================
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) override { itemChanged(); }
|
||||
void valueTreeChildAdded (ValueTree&, ValueTree&) override { itemChanged(); }
|
||||
void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { itemChanged(); }
|
||||
void valueTreeChildOrderChanged (ValueTree&, int, int) override { itemChanged(); }
|
||||
void valueTreeParentChanged (ValueTree&) override { itemChanged(); }
|
||||
|
||||
private:
|
||||
Project::Item item;
|
||||
ListBox list;
|
||||
ContentViewHeader header;
|
||||
|
||||
void itemChanged()
|
||||
{
|
||||
list.updateContent();
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class FileOptionComponent : public Component
|
||||
{
|
||||
public:
|
||||
FileOptionComponent (const Project::Item& fileItem, ListBoxHeader* listBoxHeader)
|
||||
: item (fileItem),
|
||||
header (listBoxHeader),
|
||||
compilerFlagSchemeSelector (item)
|
||||
{
|
||||
if (item.isFile())
|
||||
{
|
||||
auto isSourceFile = item.isSourceFile();
|
||||
|
||||
if (isSourceFile)
|
||||
{
|
||||
addAndMakeVisible (compileButton);
|
||||
compileButton.getToggleStateValue().referTo (item.getShouldCompileValue());
|
||||
compileButton.onStateChange = [this] { compileEnablementChanged(); };
|
||||
}
|
||||
|
||||
addAndMakeVisible (binaryResourceButton);
|
||||
binaryResourceButton.getToggleStateValue().referTo (item.getShouldAddToBinaryResourcesValue());
|
||||
|
||||
addAndMakeVisible (xcodeResourceButton);
|
||||
xcodeResourceButton.getToggleStateValue().referTo (item.getShouldAddToXcodeResourcesValue());
|
||||
|
||||
if (isSourceFile)
|
||||
{
|
||||
addChildComponent (skipPCHButton);
|
||||
skipPCHButton.getToggleStateValue().referTo (item.getShouldSkipPCHValue());
|
||||
|
||||
addChildComponent (compilerFlagSchemeSelector);
|
||||
|
||||
compileEnablementChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
if (header != nullptr)
|
||||
{
|
||||
auto textBounds = getLocalBounds().removeFromLeft (roundToInt (header->getProportionAtIndex (0) * (float) getWidth()));
|
||||
|
||||
auto iconBounds = textBounds.removeFromLeft (25);
|
||||
|
||||
if (item.isImageFile())
|
||||
iconBounds.reduce (5, 5);
|
||||
|
||||
item.getIcon().withColour (findColour (treeIconColourId)).draw (g, iconBounds.toFloat(), item.isIconCrossedOut());
|
||||
|
||||
g.setColour (findColour (widgetTextColourId));
|
||||
|
||||
g.drawText (item.getName(), textBounds, Justification::centredLeft);
|
||||
}
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
if (header != nullptr)
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
auto width = (float) getWidth();
|
||||
|
||||
bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (0) * width));
|
||||
|
||||
binaryResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (1) * width)));
|
||||
xcodeResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (2) * width)));
|
||||
compileButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (3) * width)));
|
||||
skipPCHButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (4) * width)));
|
||||
compilerFlagSchemeSelector.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (5) * width)));
|
||||
}
|
||||
}
|
||||
|
||||
Project::Item item;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class CompilerFlagSchemeSelector : public Component,
|
||||
private Value::Listener
|
||||
{
|
||||
public:
|
||||
CompilerFlagSchemeSelector (Project::Item& it)
|
||||
: item (it)
|
||||
{
|
||||
schemeBox.setTextWhenNothingSelected ("None");
|
||||
updateCompilerFlagSchemeComboBox();
|
||||
schemeBox.onChange = [this] { handleComboBoxSelection(); };
|
||||
|
||||
addAndMakeVisible (schemeBox);
|
||||
addChildComponent (newSchemeLabel);
|
||||
|
||||
newSchemeLabel.setEditable (true);
|
||||
newSchemeLabel.setJustificationType (Justification::centredLeft);
|
||||
newSchemeLabel.onEditorHide = [this]
|
||||
{
|
||||
newSchemeLabel.setVisible (false);
|
||||
schemeBox.setVisible (true);
|
||||
|
||||
auto newScheme = newSchemeLabel.getText();
|
||||
|
||||
item.project.addCompilerFlagScheme (newScheme);
|
||||
|
||||
if (item.getCompilerFlagSchemeString().isEmpty())
|
||||
item.setCompilerFlagScheme (newScheme);
|
||||
|
||||
updateCompilerFlagSchemeComboBox();
|
||||
};
|
||||
|
||||
selectScheme (item.getCompilerFlagSchemeString());
|
||||
|
||||
projectCompilerFlagSchemesValue = item.project.getProjectValue (Ids::compilerFlagSchemes);
|
||||
projectCompilerFlagSchemesValue.addListener (this);
|
||||
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto b = getLocalBounds();
|
||||
|
||||
schemeBox.setBounds (b);
|
||||
newSchemeLabel.setBounds (b);
|
||||
}
|
||||
|
||||
private:
|
||||
void valueChanged (Value&) override { updateCompilerFlagSchemeComboBox(); }
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
schemeBox.setColour (ComboBox::outlineColourId, Colours::transparentBlack);
|
||||
schemeBox.setColour (ComboBox::textColourId, findColour (defaultTextColourId));
|
||||
}
|
||||
|
||||
void updateCompilerFlagSchemeComboBox()
|
||||
{
|
||||
auto itemScheme = item.getCompilerFlagSchemeString();
|
||||
auto allSchemes = item.project.getCompilerFlagSchemes();
|
||||
|
||||
if (itemScheme.isNotEmpty() && ! allSchemes.contains (itemScheme))
|
||||
{
|
||||
item.clearCurrentCompilerFlagScheme();
|
||||
itemScheme = {};
|
||||
}
|
||||
|
||||
schemeBox.clear();
|
||||
|
||||
schemeBox.addItemList (allSchemes, 1);
|
||||
schemeBox.addSeparator();
|
||||
schemeBox.addItem ("Add a new scheme...", -1);
|
||||
schemeBox.addItem ("Delete selected scheme", -2);
|
||||
schemeBox.addItem ("Clear", -3);
|
||||
|
||||
selectScheme (itemScheme);
|
||||
}
|
||||
|
||||
void handleComboBoxSelection()
|
||||
{
|
||||
auto selectedID = schemeBox.getSelectedId();
|
||||
|
||||
if (selectedID > 0)
|
||||
{
|
||||
item.setCompilerFlagScheme (schemeBox.getItemText (selectedID - 1));
|
||||
}
|
||||
else if (selectedID == -1)
|
||||
{
|
||||
newSchemeLabel.setText ("NewScheme", dontSendNotification);
|
||||
|
||||
schemeBox.setVisible (false);
|
||||
newSchemeLabel.setVisible (true);
|
||||
|
||||
newSchemeLabel.showEditor();
|
||||
|
||||
if (auto* ed = newSchemeLabel.getCurrentTextEditor())
|
||||
ed->setInputRestrictions (64, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_");
|
||||
}
|
||||
else if (selectedID == -2)
|
||||
{
|
||||
auto currentScheme = item.getCompilerFlagSchemeString();
|
||||
|
||||
if (currentScheme.isNotEmpty())
|
||||
{
|
||||
item.project.removeCompilerFlagScheme (currentScheme);
|
||||
item.clearCurrentCompilerFlagScheme();
|
||||
}
|
||||
|
||||
updateCompilerFlagSchemeComboBox();
|
||||
}
|
||||
else if (selectedID == -3)
|
||||
{
|
||||
schemeBox.setSelectedId (0);
|
||||
item.clearCurrentCompilerFlagScheme();
|
||||
}
|
||||
}
|
||||
|
||||
void selectScheme (const String& schemeToSelect)
|
||||
{
|
||||
if (schemeToSelect.isNotEmpty())
|
||||
{
|
||||
for (int i = 0; i < schemeBox.getNumItems(); ++i)
|
||||
{
|
||||
if (schemeBox.getItemText (i) == schemeToSelect)
|
||||
{
|
||||
schemeBox.setSelectedItemIndex (i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schemeBox.setSelectedId (0);
|
||||
}
|
||||
|
||||
Project::Item& item;
|
||||
Value projectCompilerFlagSchemesValue;
|
||||
|
||||
ComboBox schemeBox;
|
||||
Label newSchemeLabel;
|
||||
};
|
||||
|
||||
void compileEnablementChanged()
|
||||
{
|
||||
auto shouldBeCompiled = compileButton.getToggleState();
|
||||
|
||||
skipPCHButton.setVisible (shouldBeCompiled);
|
||||
compilerFlagSchemeSelector.setVisible (shouldBeCompiled);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ListBoxHeader* header;
|
||||
|
||||
ToggleButton compileButton, binaryResourceButton, xcodeResourceButton, skipPCHButton;
|
||||
CompilerFlagSchemeSelector compilerFlagSchemeSelector;
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileGroupInformationComponent)
|
||||
};
|
||||
|
@ -1,279 +1,279 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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_HeaderComponent.h"
|
||||
|
||||
#include "../../Application/jucer_Application.h"
|
||||
|
||||
#include "../../ProjectSaving/jucer_ProjectExporter.h"
|
||||
#include "../../Project/UI/jucer_ProjectContentComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
HeaderComponent::HeaderComponent (ProjectContentComponent* pcc)
|
||||
: projectContentComponent (pcc)
|
||||
{
|
||||
setTitle ("Header");
|
||||
setFocusContainerType (FocusContainerType::focusContainer);
|
||||
|
||||
addAndMakeVisible (configLabel);
|
||||
addAndMakeVisible (exporterBox);
|
||||
|
||||
exporterBox.onChange = [this] { updateExporterButton(); };
|
||||
|
||||
juceIcon.setImage (ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize), RectanglePlacement::centred);
|
||||
addAndMakeVisible (juceIcon);
|
||||
|
||||
addAndMakeVisible (userAvatar);
|
||||
userAvatar.addChangeListener (this);
|
||||
|
||||
projectNameLabel.setText ({}, dontSendNotification);
|
||||
addAndMakeVisible (projectNameLabel);
|
||||
|
||||
initialiseButtons();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::resized()
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
configLabel.setFont ({ (float) bounds.getHeight() / 3.0f });
|
||||
|
||||
{
|
||||
auto headerBounds = bounds.removeFromLeft (tabsWidth);
|
||||
|
||||
const int buttonSize = 25;
|
||||
auto buttonBounds = headerBounds.removeFromRight (buttonSize);
|
||||
|
||||
projectSettingsButton.setBounds (buttonBounds.removeFromBottom (buttonSize).reduced (2));
|
||||
|
||||
juceIcon.setBounds (headerBounds.removeFromLeft (headerBounds.getHeight()).reduced (2));
|
||||
|
||||
headerBounds.removeFromRight (5);
|
||||
projectNameLabel.setBounds (headerBounds);
|
||||
}
|
||||
|
||||
{
|
||||
auto exporterWidth = jmin (400, bounds.getWidth() / 2);
|
||||
Rectangle<int> exporterBounds (0, 0, exporterWidth, bounds.getHeight());
|
||||
|
||||
exporterBounds.setCentre (bounds.getCentre());
|
||||
|
||||
saveAndOpenInIDEButton.setBounds (exporterBounds.removeFromRight (exporterBounds.getHeight()).reduced (2));
|
||||
|
||||
exporterBounds.removeFromRight (5);
|
||||
exporterBox.setBounds (exporterBounds.removeFromBottom (roundToInt ((float) exporterBounds.getHeight() / 1.8f)));
|
||||
configLabel.setBounds (exporterBounds);
|
||||
}
|
||||
|
||||
userAvatar.setBounds (bounds.removeFromRight (userAvatar.isDisplaingGPLLogo() ? roundToInt ((float) bounds.getHeight() * 1.9f)
|
||||
: bounds.getHeight()).reduced (2));
|
||||
}
|
||||
|
||||
void HeaderComponent::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (findColour (backgroundColourId));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::setCurrentProject (Project* newProject)
|
||||
{
|
||||
stopTimer();
|
||||
repaint();
|
||||
|
||||
projectNameLabel.setText ({}, dontSendNotification);
|
||||
|
||||
project = newProject;
|
||||
|
||||
if (project != nullptr)
|
||||
{
|
||||
exportersTree = project->getExporters();
|
||||
exportersTree.addListener (this);
|
||||
updateExporters();
|
||||
|
||||
projectNameValue.referTo (project->getProjectValue (Ids::name));
|
||||
projectNameValue.addListener (this);
|
||||
updateName();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::updateExporters()
|
||||
{
|
||||
auto selectedExporter = getSelectedExporter();
|
||||
|
||||
exporterBox.clear();
|
||||
auto preferredExporterIndex = -1;
|
||||
|
||||
int i = 0;
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next(); ++i)
|
||||
{
|
||||
auto exporterName = exporter->getUniqueName();
|
||||
|
||||
exporterBox.addItem (exporterName, i + 1);
|
||||
|
||||
if (selectedExporter != nullptr && exporterName == selectedExporter->getUniqueName())
|
||||
exporterBox.setSelectedId (i + 1);
|
||||
|
||||
if (exporterName.contains (ProjectExporter::getCurrentPlatformExporterTypeInfo().displayName) && preferredExporterIndex == -1)
|
||||
preferredExporterIndex = i;
|
||||
}
|
||||
|
||||
if (exporterBox.getSelectedItemIndex() == -1)
|
||||
{
|
||||
if (preferredExporterIndex == -1)
|
||||
{
|
||||
i = 0;
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next(); ++i)
|
||||
{
|
||||
if (exporter->canLaunchProject())
|
||||
{
|
||||
preferredExporterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exporterBox.setSelectedItemIndex (preferredExporterIndex != -1 ? preferredExporterIndex : 0);
|
||||
}
|
||||
|
||||
updateExporterButton();
|
||||
}
|
||||
|
||||
std::unique_ptr<ProjectExporter> HeaderComponent::getSelectedExporter() const
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
int i = 0;
|
||||
auto selectedIndex = exporterBox.getSelectedItemIndex();
|
||||
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next();)
|
||||
if (i++ == selectedIndex)
|
||||
return std::move (exporter.exporter);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool HeaderComponent::canCurrentExporterLaunchProject() const
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
if (auto selectedExporter = getSelectedExporter())
|
||||
{
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next();)
|
||||
if (exporter->canLaunchProject() && exporter->getUniqueName() == selectedExporter->getUniqueName())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::sidebarTabsWidthChanged (int newWidth)
|
||||
{
|
||||
tabsWidth = newWidth;
|
||||
resized();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::changeListenerCallback (ChangeBroadcaster* source)
|
||||
{
|
||||
if (source == &userAvatar)
|
||||
resized();
|
||||
}
|
||||
|
||||
void HeaderComponent::valueChanged (Value&)
|
||||
{
|
||||
updateName();
|
||||
}
|
||||
|
||||
void HeaderComponent::timerCallback()
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::initialiseButtons()
|
||||
{
|
||||
addAndMakeVisible (projectSettingsButton);
|
||||
projectSettingsButton.onClick = [this] { projectContentComponent->showProjectSettings(); };
|
||||
|
||||
addAndMakeVisible (saveAndOpenInIDEButton);
|
||||
saveAndOpenInIDEButton.setBackgroundColour (Colours::white);
|
||||
saveAndOpenInIDEButton.setIconInset (7);
|
||||
saveAndOpenInIDEButton.onClick = [this]
|
||||
{
|
||||
if (project == nullptr)
|
||||
return;
|
||||
|
||||
if (! project->isSaveAndExportDisabled())
|
||||
{
|
||||
projectContentComponent->openInSelectedIDE (true);
|
||||
return;
|
||||
}
|
||||
|
||||
auto setWarningVisible = [this] (const Identifier& identifier)
|
||||
{
|
||||
auto child = project->getProjectMessages().getChildWithName (ProjectMessages::Ids::warning)
|
||||
.getChildWithName (identifier);
|
||||
|
||||
if (child.isValid())
|
||||
child.setProperty (ProjectMessages::Ids::isVisible, true, nullptr);
|
||||
};
|
||||
|
||||
if (project->hasIncompatibleLicenseTypeAndSplashScreenSetting())
|
||||
setWarningVisible (ProjectMessages::Ids::incompatibleLicense);
|
||||
|
||||
if (project->isFileModificationCheckPending())
|
||||
setWarningVisible (ProjectMessages::Ids::jucerFileModified);
|
||||
};
|
||||
|
||||
updateExporterButton();
|
||||
}
|
||||
|
||||
void HeaderComponent::updateName()
|
||||
{
|
||||
if (project != nullptr)
|
||||
projectNameLabel.setText (project->getDocumentTitle(), dontSendNotification);
|
||||
}
|
||||
|
||||
void HeaderComponent::updateExporterButton()
|
||||
{
|
||||
if (auto selectedExporter = getSelectedExporter())
|
||||
{
|
||||
auto selectedName = selectedExporter->getUniqueName();
|
||||
|
||||
for (auto info : ProjectExporter::getExporterTypeInfos())
|
||||
{
|
||||
if (selectedName.contains (info.displayName))
|
||||
{
|
||||
saveAndOpenInIDEButton.setImage (info.icon);
|
||||
saveAndOpenInIDEButton.repaint();
|
||||
saveAndOpenInIDEButton.setEnabled (canCurrentExporterLaunchProject());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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_HeaderComponent.h"
|
||||
|
||||
#include "../../Application/jucer_Application.h"
|
||||
|
||||
#include "../../ProjectSaving/jucer_ProjectExporter.h"
|
||||
#include "../../Project/UI/jucer_ProjectContentComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
HeaderComponent::HeaderComponent (ProjectContentComponent* pcc)
|
||||
: projectContentComponent (pcc)
|
||||
{
|
||||
setTitle ("Header");
|
||||
setFocusContainerType (FocusContainerType::focusContainer);
|
||||
|
||||
addAndMakeVisible (configLabel);
|
||||
addAndMakeVisible (exporterBox);
|
||||
|
||||
exporterBox.onChange = [this] { updateExporterButton(); };
|
||||
|
||||
juceIcon.setImage (ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize), RectanglePlacement::centred);
|
||||
addAndMakeVisible (juceIcon);
|
||||
|
||||
addAndMakeVisible (userAvatar);
|
||||
userAvatar.addChangeListener (this);
|
||||
|
||||
projectNameLabel.setText ({}, dontSendNotification);
|
||||
addAndMakeVisible (projectNameLabel);
|
||||
|
||||
initialiseButtons();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::resized()
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
configLabel.setFont ({ (float) bounds.getHeight() / 3.0f });
|
||||
|
||||
{
|
||||
auto headerBounds = bounds.removeFromLeft (tabsWidth);
|
||||
|
||||
const int buttonSize = 25;
|
||||
auto buttonBounds = headerBounds.removeFromRight (buttonSize);
|
||||
|
||||
projectSettingsButton.setBounds (buttonBounds.removeFromBottom (buttonSize).reduced (2));
|
||||
|
||||
juceIcon.setBounds (headerBounds.removeFromLeft (headerBounds.getHeight()).reduced (2));
|
||||
|
||||
headerBounds.removeFromRight (5);
|
||||
projectNameLabel.setBounds (headerBounds);
|
||||
}
|
||||
|
||||
{
|
||||
auto exporterWidth = jmin (400, bounds.getWidth() / 2);
|
||||
Rectangle<int> exporterBounds (0, 0, exporterWidth, bounds.getHeight());
|
||||
|
||||
exporterBounds.setCentre (bounds.getCentre());
|
||||
|
||||
saveAndOpenInIDEButton.setBounds (exporterBounds.removeFromRight (exporterBounds.getHeight()).reduced (2));
|
||||
|
||||
exporterBounds.removeFromRight (5);
|
||||
exporterBox.setBounds (exporterBounds.removeFromBottom (roundToInt ((float) exporterBounds.getHeight() / 1.8f)));
|
||||
configLabel.setBounds (exporterBounds);
|
||||
}
|
||||
|
||||
userAvatar.setBounds (bounds.removeFromRight (userAvatar.isDisplaingGPLLogo() ? roundToInt ((float) bounds.getHeight() * 1.9f)
|
||||
: bounds.getHeight()).reduced (2));
|
||||
}
|
||||
|
||||
void HeaderComponent::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (findColour (backgroundColourId));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::setCurrentProject (Project* newProject)
|
||||
{
|
||||
stopTimer();
|
||||
repaint();
|
||||
|
||||
projectNameLabel.setText ({}, dontSendNotification);
|
||||
|
||||
project = newProject;
|
||||
|
||||
if (project != nullptr)
|
||||
{
|
||||
exportersTree = project->getExporters();
|
||||
exportersTree.addListener (this);
|
||||
updateExporters();
|
||||
|
||||
projectNameValue.referTo (project->getProjectValue (Ids::name));
|
||||
projectNameValue.addListener (this);
|
||||
updateName();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::updateExporters()
|
||||
{
|
||||
auto selectedExporter = getSelectedExporter();
|
||||
|
||||
exporterBox.clear();
|
||||
auto preferredExporterIndex = -1;
|
||||
|
||||
int i = 0;
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next(); ++i)
|
||||
{
|
||||
auto exporterName = exporter->getUniqueName();
|
||||
|
||||
exporterBox.addItem (exporterName, i + 1);
|
||||
|
||||
if (selectedExporter != nullptr && exporterName == selectedExporter->getUniqueName())
|
||||
exporterBox.setSelectedId (i + 1);
|
||||
|
||||
if (exporterName.contains (ProjectExporter::getCurrentPlatformExporterTypeInfo().displayName) && preferredExporterIndex == -1)
|
||||
preferredExporterIndex = i;
|
||||
}
|
||||
|
||||
if (exporterBox.getSelectedItemIndex() == -1)
|
||||
{
|
||||
if (preferredExporterIndex == -1)
|
||||
{
|
||||
i = 0;
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next(); ++i)
|
||||
{
|
||||
if (exporter->canLaunchProject())
|
||||
{
|
||||
preferredExporterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exporterBox.setSelectedItemIndex (preferredExporterIndex != -1 ? preferredExporterIndex : 0);
|
||||
}
|
||||
|
||||
updateExporterButton();
|
||||
}
|
||||
|
||||
std::unique_ptr<ProjectExporter> HeaderComponent::getSelectedExporter() const
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
int i = 0;
|
||||
auto selectedIndex = exporterBox.getSelectedItemIndex();
|
||||
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next();)
|
||||
if (i++ == selectedIndex)
|
||||
return std::move (exporter.exporter);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool HeaderComponent::canCurrentExporterLaunchProject() const
|
||||
{
|
||||
if (project != nullptr)
|
||||
{
|
||||
if (auto selectedExporter = getSelectedExporter())
|
||||
{
|
||||
for (Project::ExporterIterator exporter (*project); exporter.next();)
|
||||
if (exporter->canLaunchProject() && exporter->getUniqueName() == selectedExporter->getUniqueName())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::sidebarTabsWidthChanged (int newWidth)
|
||||
{
|
||||
tabsWidth = newWidth;
|
||||
resized();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::changeListenerCallback (ChangeBroadcaster* source)
|
||||
{
|
||||
if (source == &userAvatar)
|
||||
resized();
|
||||
}
|
||||
|
||||
void HeaderComponent::valueChanged (Value&)
|
||||
{
|
||||
updateName();
|
||||
}
|
||||
|
||||
void HeaderComponent::timerCallback()
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void HeaderComponent::initialiseButtons()
|
||||
{
|
||||
addAndMakeVisible (projectSettingsButton);
|
||||
projectSettingsButton.onClick = [this] { projectContentComponent->showProjectSettings(); };
|
||||
|
||||
addAndMakeVisible (saveAndOpenInIDEButton);
|
||||
saveAndOpenInIDEButton.setBackgroundColour (Colours::white);
|
||||
saveAndOpenInIDEButton.setIconInset (7);
|
||||
saveAndOpenInIDEButton.onClick = [this]
|
||||
{
|
||||
if (project == nullptr)
|
||||
return;
|
||||
|
||||
if (! project->isSaveAndExportDisabled())
|
||||
{
|
||||
projectContentComponent->openInSelectedIDE (true);
|
||||
return;
|
||||
}
|
||||
|
||||
auto setWarningVisible = [this] (const Identifier& identifier)
|
||||
{
|
||||
auto child = project->getProjectMessages().getChildWithName (ProjectMessages::Ids::warning)
|
||||
.getChildWithName (identifier);
|
||||
|
||||
if (child.isValid())
|
||||
child.setProperty (ProjectMessages::Ids::isVisible, true, nullptr);
|
||||
};
|
||||
|
||||
if (project->hasIncompatibleLicenseTypeAndSplashScreenSetting())
|
||||
setWarningVisible (ProjectMessages::Ids::incompatibleLicense);
|
||||
|
||||
if (project->isFileModificationCheckPending())
|
||||
setWarningVisible (ProjectMessages::Ids::jucerFileModified);
|
||||
};
|
||||
|
||||
updateExporterButton();
|
||||
}
|
||||
|
||||
void HeaderComponent::updateName()
|
||||
{
|
||||
if (project != nullptr)
|
||||
projectNameLabel.setText (project->getDocumentTitle(), dontSendNotification);
|
||||
}
|
||||
|
||||
void HeaderComponent::updateExporterButton()
|
||||
{
|
||||
if (auto selectedExporter = getSelectedExporter())
|
||||
{
|
||||
auto selectedName = selectedExporter->getUniqueName();
|
||||
|
||||
for (auto info : ProjectExporter::getExporterTypeInfos())
|
||||
{
|
||||
if (selectedName.contains (info.displayName))
|
||||
{
|
||||
saveAndOpenInIDEButton.setImage (info.icon);
|
||||
saveAndOpenInIDEButton.repaint();
|
||||
saveAndOpenInIDEButton.setEnabled (canCurrentExporterLaunchProject());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,101 +1,101 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 "../../Application/jucer_Headers.h"
|
||||
#include "../../Utility/UI/jucer_IconButton.h"
|
||||
#include "jucer_UserAvatarComponent.h"
|
||||
|
||||
class Project;
|
||||
class ProjectContentComponent;
|
||||
class ProjectExporter;
|
||||
|
||||
//==============================================================================
|
||||
class HeaderComponent : public Component,
|
||||
private ValueTree::Listener,
|
||||
private ChangeListener,
|
||||
private Value::Listener,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
HeaderComponent (ProjectContentComponent* projectContentComponent);
|
||||
|
||||
//==============================================================================
|
||||
void resized() override;
|
||||
void paint (Graphics&) override;
|
||||
|
||||
//==============================================================================
|
||||
void setCurrentProject (Project*);
|
||||
|
||||
void updateExporters();
|
||||
std::unique_ptr<ProjectExporter> getSelectedExporter() const;
|
||||
bool canCurrentExporterLaunchProject() const;
|
||||
|
||||
void sidebarTabsWidthChanged (int newWidth);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void changeListenerCallback (ChangeBroadcaster* source) override;
|
||||
void valueChanged (Value&) override;
|
||||
void timerCallback() override;
|
||||
|
||||
//==============================================================================
|
||||
void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) override { updateIfNeeded (parentTree); }
|
||||
void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { updateIfNeeded (parentTree); }
|
||||
void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { updateIfNeeded (parentTree); }
|
||||
|
||||
void updateIfNeeded (ValueTree tree)
|
||||
{
|
||||
if (tree == exportersTree)
|
||||
updateExporters();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void initialiseButtons();
|
||||
|
||||
void updateName();
|
||||
void updateExporterButton();
|
||||
|
||||
//==============================================================================
|
||||
int tabsWidth = 200;
|
||||
|
||||
ProjectContentComponent* projectContentComponent = nullptr;
|
||||
Project* project = nullptr;
|
||||
ValueTree exportersTree;
|
||||
|
||||
Value projectNameValue;
|
||||
|
||||
ComboBox exporterBox;
|
||||
Label configLabel { "Config Label", "Selected exporter" }, projectNameLabel;
|
||||
|
||||
ImageComponent juceIcon;
|
||||
UserAvatarComponent userAvatar { true };
|
||||
|
||||
IconButton projectSettingsButton { "Project Settings", getIcons().settings },
|
||||
saveAndOpenInIDEButton { "Save and Open in IDE", Image() };
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HeaderComponent)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 "../../Application/jucer_Headers.h"
|
||||
#include "../../Utility/UI/jucer_IconButton.h"
|
||||
#include "jucer_UserAvatarComponent.h"
|
||||
|
||||
class Project;
|
||||
class ProjectContentComponent;
|
||||
class ProjectExporter;
|
||||
|
||||
//==============================================================================
|
||||
class HeaderComponent : public Component,
|
||||
private ValueTree::Listener,
|
||||
private ChangeListener,
|
||||
private Value::Listener,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
HeaderComponent (ProjectContentComponent* projectContentComponent);
|
||||
|
||||
//==============================================================================
|
||||
void resized() override;
|
||||
void paint (Graphics&) override;
|
||||
|
||||
//==============================================================================
|
||||
void setCurrentProject (Project*);
|
||||
|
||||
void updateExporters();
|
||||
std::unique_ptr<ProjectExporter> getSelectedExporter() const;
|
||||
bool canCurrentExporterLaunchProject() const;
|
||||
|
||||
void sidebarTabsWidthChanged (int newWidth);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void changeListenerCallback (ChangeBroadcaster* source) override;
|
||||
void valueChanged (Value&) override;
|
||||
void timerCallback() override;
|
||||
|
||||
//==============================================================================
|
||||
void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) override { updateIfNeeded (parentTree); }
|
||||
void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { updateIfNeeded (parentTree); }
|
||||
void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { updateIfNeeded (parentTree); }
|
||||
|
||||
void updateIfNeeded (ValueTree tree)
|
||||
{
|
||||
if (tree == exportersTree)
|
||||
updateExporters();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void initialiseButtons();
|
||||
|
||||
void updateName();
|
||||
void updateExporterButton();
|
||||
|
||||
//==============================================================================
|
||||
int tabsWidth = 200;
|
||||
|
||||
ProjectContentComponent* projectContentComponent = nullptr;
|
||||
Project* project = nullptr;
|
||||
ValueTree exportersTree;
|
||||
|
||||
Value projectNameValue;
|
||||
|
||||
ComboBox exporterBox;
|
||||
Label configLabel { "Config Label", "Selected exporter" }, projectNameLabel;
|
||||
|
||||
ImageComponent juceIcon;
|
||||
UserAvatarComponent userAvatar { true };
|
||||
|
||||
IconButton projectSettingsButton { "Project Settings", getIcons().settings },
|
||||
saveAndOpenInIDEButton { "Save and Open in IDE", Image() };
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HeaderComponent)
|
||||
};
|
||||
|
@ -1,341 +1,344 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 ModulesInformationComponent : public Component,
|
||||
private ListBoxModel,
|
||||
private ValueTree::Listener
|
||||
{
|
||||
public:
|
||||
ModulesInformationComponent (Project& p)
|
||||
: project (p),
|
||||
modulesValueTree (project.getEnabledModules().getState())
|
||||
{
|
||||
auto tempHeader = std::make_unique<ListBoxHeader> (Array<String> { "Module", "Version", "Make Local Copy", "Paths" },
|
||||
Array<float> { 0.25f, 0.2f, 0.2f, 0.35f });
|
||||
listHeader = tempHeader.get();
|
||||
list.setHeaderComponent (std::move (tempHeader));
|
||||
list.setModel (this);
|
||||
list.setColour (ListBox::backgroundColourId, Colours::transparentBlack);
|
||||
addAndMakeVisible (list);
|
||||
list.updateContent();
|
||||
list.setRowHeight (30);
|
||||
list.setMultipleSelectionEnabled (true);
|
||||
|
||||
addAndMakeVisible (header);
|
||||
|
||||
addAndMakeVisible (setCopyModeButton);
|
||||
setCopyModeButton.setTriggeredOnMouseDown (true);
|
||||
setCopyModeButton.onClick = [this] { showCopyModeMenu(); };
|
||||
|
||||
addAndMakeVisible (copyPathButton);
|
||||
copyPathButton.setTriggeredOnMouseDown (true);
|
||||
copyPathButton.onClick = [this] { showSetPathsMenu(); };
|
||||
|
||||
addAndMakeVisible (globalPathsButton);
|
||||
globalPathsButton.onClick = [this] { showGlobalPathsMenu(); };
|
||||
|
||||
modulesValueTree.addListener (this);
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.setColour (findColour (secondaryBackgroundColourId));
|
||||
g.fillRect (getLocalBounds().reduced (12, 0));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (12, 0);
|
||||
|
||||
header.setBounds (bounds.removeFromTop (40));
|
||||
|
||||
bounds.reduce (10, 0);
|
||||
list.setBounds (bounds.removeFromTop (list.getRowPosition (getNumRows() - 1, true).getBottom() + 20));
|
||||
|
||||
if (bounds.getHeight() < 35)
|
||||
{
|
||||
parentSizeChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto buttonRow = bounds.removeFromTop (35);
|
||||
setCopyModeButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
|
||||
buttonRow.removeFromLeft (8);
|
||||
copyPathButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
|
||||
buttonRow.removeFromLeft (8);
|
||||
globalPathsButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
|
||||
}
|
||||
}
|
||||
|
||||
void parentSizeChanged() override
|
||||
{
|
||||
auto width = jmax (550, getParentWidth());
|
||||
auto y = list.getRowPosition (getNumRows() - 1, true).getBottom() + 200;
|
||||
|
||||
y = jmax (getParentHeight(), y);
|
||||
|
||||
setSize (width, y);
|
||||
}
|
||||
|
||||
int getNumRows() override
|
||||
{
|
||||
return project.getEnabledModules().getNumModules();
|
||||
}
|
||||
|
||||
void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) override
|
||||
{
|
||||
ignoreUnused (height);
|
||||
|
||||
Rectangle<int> bounds (0, 0, width, height);
|
||||
|
||||
g.setColour (rowIsSelected ? findColour (defaultHighlightColourId) : findColour (rowNumber % 2 == 0 ? widgetBackgroundColourId
|
||||
: secondaryWidgetBackgroundColourId));
|
||||
g.fillRect (bounds.withTrimmedBottom (1));
|
||||
|
||||
bounds.removeFromLeft (5);
|
||||
g.setColour (rowIsSelected ? findColour (defaultHighlightedTextColourId) : findColour (widgetTextColourId));
|
||||
|
||||
//==============================================================================
|
||||
auto moduleID = project.getEnabledModules().getModuleID (rowNumber);
|
||||
|
||||
g.drawFittedText (moduleID, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (0) * (float) width)), Justification::centredLeft, 1);
|
||||
|
||||
//==============================================================================
|
||||
auto version = project.getEnabledModules().getModuleInfo (moduleID).getVersion();
|
||||
if (version.isEmpty())
|
||||
version = "?";
|
||||
|
||||
g.drawFittedText (version, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (1) * (float) width)), Justification::centredLeft, 1);
|
||||
|
||||
//==============================================================================
|
||||
g.drawFittedText (String (project.getEnabledModules().shouldCopyModuleFilesLocally (moduleID) ? "Yes" : "No"),
|
||||
bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (2) * (float) width)), Justification::centredLeft, 1);
|
||||
|
||||
//==============================================================================
|
||||
String pathText;
|
||||
|
||||
if (project.getEnabledModules().shouldUseGlobalPath (moduleID))
|
||||
{
|
||||
pathText = "Global";
|
||||
}
|
||||
else
|
||||
{
|
||||
StringArray paths;
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
paths.addIfNotAlreadyThere (exporter->getPathForModuleString (moduleID).trim());
|
||||
|
||||
pathText = paths.joinIntoString (", ");
|
||||
}
|
||||
|
||||
g.drawFittedText (pathText, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (3) * (float) width)), Justification::centredLeft, 1);
|
||||
}
|
||||
|
||||
void listBoxItemDoubleClicked (int row, const MouseEvent&) override
|
||||
{
|
||||
auto moduleID = project.getEnabledModules().getModuleID (row);
|
||||
|
||||
if (moduleID.isNotEmpty())
|
||||
if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>())
|
||||
pcc->showModule (moduleID);
|
||||
}
|
||||
|
||||
void deleteKeyPressed (int row) override
|
||||
{
|
||||
project.getEnabledModules().removeModule (project.getEnabledModules().getModuleID (row));
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
setCopyModeButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
|
||||
copyPathButton.setColour (TextButton::buttonColourId, findColour (defaultButtonBackgroundColourId));
|
||||
globalPathsButton.setColour (TextButton::buttonColourId, findColour (defaultButtonBackgroundColourId));
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
nameCol = 1,
|
||||
versionCol,
|
||||
copyCol,
|
||||
pathCol
|
||||
};
|
||||
|
||||
Project& project;
|
||||
ValueTree modulesValueTree;
|
||||
|
||||
ContentViewHeader header { "Modules", { getIcons().modules, Colours::transparentBlack } };
|
||||
ListBox list;
|
||||
ListBoxHeader* listHeader;
|
||||
|
||||
TextButton setCopyModeButton { "Set copy-mode for all modules..." };
|
||||
TextButton copyPathButton { "Set paths for all modules..." };
|
||||
TextButton globalPathsButton { "Enable/disable global path for modules..." };
|
||||
|
||||
std::map<String, var> modulePathClipboard;
|
||||
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) override { itemChanged(); }
|
||||
void valueTreeChildAdded (ValueTree&, ValueTree&) override { itemChanged(); }
|
||||
void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { itemChanged(); }
|
||||
void valueTreeChildOrderChanged (ValueTree&, int, int) override { itemChanged(); }
|
||||
void valueTreeParentChanged (ValueTree&) override { itemChanged(); }
|
||||
|
||||
void itemChanged()
|
||||
{
|
||||
list.updateContent();
|
||||
resized();
|
||||
repaint();
|
||||
}
|
||||
|
||||
static void setLocalCopyModeForAllModules (Project& project, bool copyLocally)
|
||||
{
|
||||
auto& modules = project.getEnabledModules();
|
||||
|
||||
for (auto i = modules.getNumModules(); --i >= 0;)
|
||||
modules.shouldCopyModuleFilesLocallyValue (modules.getModuleID (i)) = copyLocally;
|
||||
}
|
||||
|
||||
void showCopyModeMenu()
|
||||
{
|
||||
PopupMenu m;
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set all modules to copy locally")
|
||||
.setAction ([&] { setLocalCopyModeForAllModules (project, true); }));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set all modules to not copy locally")
|
||||
.setAction ([&] { setLocalCopyModeForAllModules (project, false); }));
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options().withTargetComponent (setCopyModeButton));
|
||||
}
|
||||
|
||||
static void setAllModulesToUseGlobalPaths (Project& project, bool useGlobal)
|
||||
{
|
||||
auto& modules = project.getEnabledModules();
|
||||
|
||||
for (auto moduleID : modules.getAllModules())
|
||||
modules.shouldUseGlobalPathValue (moduleID) = useGlobal;
|
||||
}
|
||||
|
||||
static void setSelectedModulesToUseGlobalPaths (Project& project, SparseSet<int> selected, bool useGlobal)
|
||||
{
|
||||
auto& modules = project.getEnabledModules();
|
||||
|
||||
for (int i = 0; i < selected.size(); ++i)
|
||||
modules.shouldUseGlobalPathValue (modules.getModuleID (selected[i])) = useGlobal;
|
||||
}
|
||||
|
||||
void showGlobalPathsMenu()
|
||||
{
|
||||
PopupMenu m;
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set all modules to use global paths")
|
||||
.setAction ([&] { setAllModulesToUseGlobalPaths (project, true); }));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set all modules to not use global paths")
|
||||
.setAction ([&] { setAllModulesToUseGlobalPaths (project, false); }));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set selected modules to use global paths")
|
||||
.setEnabled (list.getNumSelectedRows() > 0)
|
||||
.setAction ([&] { setSelectedModulesToUseGlobalPaths (project, list.getSelectedRows(), true); }));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set selected modules to not use global paths")
|
||||
.setEnabled (list.getNumSelectedRows() > 0)
|
||||
.setAction ([&] { setSelectedModulesToUseGlobalPaths (project, list.getSelectedRows(), false); }));
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options().withTargetComponent (globalPathsButton));
|
||||
}
|
||||
|
||||
void showSetPathsMenu()
|
||||
{
|
||||
PopupMenu m;
|
||||
auto moduleToCopy = project.getEnabledModules().getModuleID (list.getSelectedRow());
|
||||
|
||||
if (moduleToCopy.isNotEmpty())
|
||||
{
|
||||
m.addItem (PopupMenu::Item ("Copy the paths from the module '" + moduleToCopy + "' to all other modules")
|
||||
.setAction ([this, moduleToCopy]
|
||||
{
|
||||
auto& modulesList = project.getEnabledModules();
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
{
|
||||
for (int i = 0; i < modulesList.getNumModules(); ++i)
|
||||
{
|
||||
auto modID = modulesList.getModuleID (i);
|
||||
|
||||
if (modID != moduleToCopy)
|
||||
exporter->getPathForModuleValue (modID) = exporter->getPathForModuleValue (moduleToCopy).get();
|
||||
}
|
||||
}
|
||||
|
||||
list.repaint();
|
||||
}));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Copy paths from selected module")
|
||||
.setEnabled (list.getNumSelectedRows() == 1)
|
||||
.setAction ([this, moduleToCopy]
|
||||
{
|
||||
modulePathClipboard.clear();
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
modulePathClipboard[exporter->getUniqueName()] = exporter->getPathForModuleValue (moduleToCopy).get();
|
||||
|
||||
list.repaint();
|
||||
}));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Paste paths to selected modules")
|
||||
.setEnabled (! modulePathClipboard.empty())
|
||||
.setAction ([this]
|
||||
{
|
||||
for (int selectionId = 0; selectionId < list.getNumSelectedRows(); ++selectionId)
|
||||
{
|
||||
auto rowNumber = list.getSelectedRow (selectionId);
|
||||
auto modID = project.getEnabledModules().getModuleID (rowNumber);
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
exporter->getPathForModuleValue (modID) = modulePathClipboard[exporter->getUniqueName()];
|
||||
}
|
||||
|
||||
list.repaint();
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
m.addItem (PopupMenu::Item ("(Select a module in the list above to use this option)")
|
||||
.setEnabled (false));
|
||||
}
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options()
|
||||
.withDeletionCheck (*this)
|
||||
.withTargetComponent (copyPathButton));
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesInformationComponent)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 ModulesInformationComponent : public Component,
|
||||
private ListBoxModel,
|
||||
private ValueTree::Listener
|
||||
{
|
||||
public:
|
||||
ModulesInformationComponent (Project& p)
|
||||
: project (p),
|
||||
modulesValueTree (project.getEnabledModules().getState())
|
||||
{
|
||||
auto tempHeader = std::make_unique<ListBoxHeader> (Array<String> { "Module", "Version", "Make Local Copy", "Paths" },
|
||||
Array<float> { 0.25f, 0.2f, 0.2f, 0.35f });
|
||||
listHeader = tempHeader.get();
|
||||
list.setHeaderComponent (std::move (tempHeader));
|
||||
list.setModel (this);
|
||||
list.setColour (ListBox::backgroundColourId, Colours::transparentBlack);
|
||||
addAndMakeVisible (list);
|
||||
list.updateContent();
|
||||
list.setRowHeight (30);
|
||||
list.setMultipleSelectionEnabled (true);
|
||||
|
||||
addAndMakeVisible (header);
|
||||
|
||||
addAndMakeVisible (setCopyModeButton);
|
||||
setCopyModeButton.setTriggeredOnMouseDown (true);
|
||||
setCopyModeButton.onClick = [this] { showCopyModeMenu(); };
|
||||
|
||||
addAndMakeVisible (copyPathButton);
|
||||
copyPathButton.setTriggeredOnMouseDown (true);
|
||||
copyPathButton.onClick = [this] { showSetPathsMenu(); };
|
||||
|
||||
addAndMakeVisible (globalPathsButton);
|
||||
globalPathsButton.onClick = [this] { showGlobalPathsMenu(); };
|
||||
|
||||
modulesValueTree.addListener (this);
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.setColour (findColour (secondaryBackgroundColourId));
|
||||
g.fillRect (getLocalBounds().reduced (12, 0));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (12, 0);
|
||||
|
||||
header.setBounds (bounds.removeFromTop (40));
|
||||
|
||||
bounds.reduce (10, 0);
|
||||
list.setBounds (bounds.removeFromTop (list.getRowPosition (getNumRows() - 1, true).getBottom() + 20));
|
||||
|
||||
if (bounds.getHeight() < 35)
|
||||
{
|
||||
parentSizeChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto buttonRow = bounds.removeFromTop (35);
|
||||
setCopyModeButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
|
||||
buttonRow.removeFromLeft (8);
|
||||
copyPathButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
|
||||
buttonRow.removeFromLeft (8);
|
||||
globalPathsButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
|
||||
}
|
||||
}
|
||||
|
||||
void parentSizeChanged() override
|
||||
{
|
||||
auto width = jmax (550, getParentWidth());
|
||||
auto y = list.getRowPosition (getNumRows() - 1, true).getBottom() + 200;
|
||||
|
||||
y = jmax (getParentHeight(), y);
|
||||
|
||||
setSize (width, y);
|
||||
}
|
||||
|
||||
int getNumRows() override
|
||||
{
|
||||
return project.getEnabledModules().getNumModules();
|
||||
}
|
||||
|
||||
void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) override
|
||||
{
|
||||
ignoreUnused (height);
|
||||
|
||||
Rectangle<int> bounds (0, 0, width, height);
|
||||
|
||||
g.setColour (rowIsSelected ? findColour (defaultHighlightColourId) : findColour (rowNumber % 2 == 0 ? widgetBackgroundColourId
|
||||
: secondaryWidgetBackgroundColourId));
|
||||
g.fillRect (bounds.withTrimmedBottom (1));
|
||||
|
||||
bounds.removeFromLeft (5);
|
||||
g.setColour (rowIsSelected ? findColour (defaultHighlightedTextColourId) : findColour (widgetTextColourId));
|
||||
|
||||
//==============================================================================
|
||||
auto moduleID = project.getEnabledModules().getModuleID (rowNumber);
|
||||
|
||||
g.drawFittedText (moduleID, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (0) * (float) width)), Justification::centredLeft, 1);
|
||||
|
||||
//==============================================================================
|
||||
auto version = project.getEnabledModules().getModuleInfo (moduleID).getVersion();
|
||||
if (version.isEmpty())
|
||||
version = "?";
|
||||
|
||||
g.drawFittedText (version, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (1) * (float) width)), Justification::centredLeft, 1);
|
||||
|
||||
//==============================================================================
|
||||
g.drawFittedText (String (project.getEnabledModules().shouldCopyModuleFilesLocally (moduleID) ? "Yes" : "No"),
|
||||
bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (2) * (float) width)), Justification::centredLeft, 1);
|
||||
|
||||
//==============================================================================
|
||||
String pathText;
|
||||
|
||||
if (project.getEnabledModules().shouldUseGlobalPath (moduleID))
|
||||
{
|
||||
pathText = "Global";
|
||||
}
|
||||
else
|
||||
{
|
||||
StringArray paths;
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
paths.addIfNotAlreadyThere (exporter->getPathForModuleString (moduleID).trim());
|
||||
|
||||
paths.removeEmptyStrings();
|
||||
paths.removeDuplicates (true);
|
||||
|
||||
pathText = paths.joinIntoString (", ");
|
||||
}
|
||||
|
||||
g.drawFittedText (pathText, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (3) * (float) width)), Justification::centredLeft, 1);
|
||||
}
|
||||
|
||||
void listBoxItemDoubleClicked (int row, const MouseEvent&) override
|
||||
{
|
||||
auto moduleID = project.getEnabledModules().getModuleID (row);
|
||||
|
||||
if (moduleID.isNotEmpty())
|
||||
if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>())
|
||||
pcc->showModule (moduleID);
|
||||
}
|
||||
|
||||
void deleteKeyPressed (int row) override
|
||||
{
|
||||
project.getEnabledModules().removeModule (project.getEnabledModules().getModuleID (row));
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
setCopyModeButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
|
||||
copyPathButton.setColour (TextButton::buttonColourId, findColour (defaultButtonBackgroundColourId));
|
||||
globalPathsButton.setColour (TextButton::buttonColourId, findColour (defaultButtonBackgroundColourId));
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
nameCol = 1,
|
||||
versionCol,
|
||||
copyCol,
|
||||
pathCol
|
||||
};
|
||||
|
||||
Project& project;
|
||||
ValueTree modulesValueTree;
|
||||
|
||||
ContentViewHeader header { "Modules", { getIcons().modules, Colours::transparentBlack } };
|
||||
ListBox list;
|
||||
ListBoxHeader* listHeader;
|
||||
|
||||
TextButton setCopyModeButton { "Set copy-mode for all modules..." };
|
||||
TextButton copyPathButton { "Set paths for all modules..." };
|
||||
TextButton globalPathsButton { "Enable/disable global path for modules..." };
|
||||
|
||||
std::map<String, var> modulePathClipboard;
|
||||
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) override { itemChanged(); }
|
||||
void valueTreeChildAdded (ValueTree&, ValueTree&) override { itemChanged(); }
|
||||
void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { itemChanged(); }
|
||||
void valueTreeChildOrderChanged (ValueTree&, int, int) override { itemChanged(); }
|
||||
void valueTreeParentChanged (ValueTree&) override { itemChanged(); }
|
||||
|
||||
void itemChanged()
|
||||
{
|
||||
list.updateContent();
|
||||
resized();
|
||||
repaint();
|
||||
}
|
||||
|
||||
static void setLocalCopyModeForAllModules (Project& project, bool copyLocally)
|
||||
{
|
||||
auto& modules = project.getEnabledModules();
|
||||
|
||||
for (auto i = modules.getNumModules(); --i >= 0;)
|
||||
modules.shouldCopyModuleFilesLocallyValue (modules.getModuleID (i)) = copyLocally;
|
||||
}
|
||||
|
||||
void showCopyModeMenu()
|
||||
{
|
||||
PopupMenu m;
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set all modules to copy locally")
|
||||
.setAction ([&] { setLocalCopyModeForAllModules (project, true); }));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set all modules to not copy locally")
|
||||
.setAction ([&] { setLocalCopyModeForAllModules (project, false); }));
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options().withTargetComponent (setCopyModeButton));
|
||||
}
|
||||
|
||||
static void setAllModulesToUseGlobalPaths (Project& project, bool useGlobal)
|
||||
{
|
||||
auto& modules = project.getEnabledModules();
|
||||
|
||||
for (auto moduleID : modules.getAllModules())
|
||||
modules.shouldUseGlobalPathValue (moduleID) = useGlobal;
|
||||
}
|
||||
|
||||
static void setSelectedModulesToUseGlobalPaths (Project& project, SparseSet<int> selected, bool useGlobal)
|
||||
{
|
||||
auto& modules = project.getEnabledModules();
|
||||
|
||||
for (int i = 0; i < selected.size(); ++i)
|
||||
modules.shouldUseGlobalPathValue (modules.getModuleID (selected[i])) = useGlobal;
|
||||
}
|
||||
|
||||
void showGlobalPathsMenu()
|
||||
{
|
||||
PopupMenu m;
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set all modules to use global paths")
|
||||
.setAction ([&] { setAllModulesToUseGlobalPaths (project, true); }));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set all modules to not use global paths")
|
||||
.setAction ([&] { setAllModulesToUseGlobalPaths (project, false); }));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set selected modules to use global paths")
|
||||
.setEnabled (list.getNumSelectedRows() > 0)
|
||||
.setAction ([&] { setSelectedModulesToUseGlobalPaths (project, list.getSelectedRows(), true); }));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Set selected modules to not use global paths")
|
||||
.setEnabled (list.getNumSelectedRows() > 0)
|
||||
.setAction ([&] { setSelectedModulesToUseGlobalPaths (project, list.getSelectedRows(), false); }));
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options().withTargetComponent (globalPathsButton));
|
||||
}
|
||||
|
||||
void showSetPathsMenu()
|
||||
{
|
||||
PopupMenu m;
|
||||
auto moduleToCopy = project.getEnabledModules().getModuleID (list.getSelectedRow());
|
||||
|
||||
if (moduleToCopy.isNotEmpty())
|
||||
{
|
||||
m.addItem (PopupMenu::Item ("Copy the paths from the module '" + moduleToCopy + "' to all other modules")
|
||||
.setAction ([this, moduleToCopy]
|
||||
{
|
||||
auto& modulesList = project.getEnabledModules();
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
{
|
||||
for (int i = 0; i < modulesList.getNumModules(); ++i)
|
||||
{
|
||||
auto modID = modulesList.getModuleID (i);
|
||||
|
||||
if (modID != moduleToCopy)
|
||||
exporter->getPathForModuleValue (modID) = exporter->getPathForModuleValue (moduleToCopy).get();
|
||||
}
|
||||
}
|
||||
|
||||
list.repaint();
|
||||
}));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Copy paths from selected module")
|
||||
.setEnabled (list.getNumSelectedRows() == 1)
|
||||
.setAction ([this, moduleToCopy]
|
||||
{
|
||||
modulePathClipboard.clear();
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
modulePathClipboard[exporter->getUniqueName()] = exporter->getPathForModuleValue (moduleToCopy).get();
|
||||
|
||||
list.repaint();
|
||||
}));
|
||||
|
||||
m.addItem (PopupMenu::Item ("Paste paths to selected modules")
|
||||
.setEnabled (! modulePathClipboard.empty())
|
||||
.setAction ([this]
|
||||
{
|
||||
for (int selectionId = 0; selectionId < list.getNumSelectedRows(); ++selectionId)
|
||||
{
|
||||
auto rowNumber = list.getSelectedRow (selectionId);
|
||||
auto modID = project.getEnabledModules().getModuleID (rowNumber);
|
||||
|
||||
for (Project::ExporterIterator exporter (project); exporter.next();)
|
||||
exporter->getPathForModuleValue (modID) = modulePathClipboard[exporter->getUniqueName()];
|
||||
}
|
||||
|
||||
list.repaint();
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
m.addItem (PopupMenu::Item ("(Select a module in the list above to use this option)")
|
||||
.setEnabled (false));
|
||||
}
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options()
|
||||
.withDeletionCheck (*this)
|
||||
.withTargetComponent (copyPathButton));
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesInformationComponent)
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,153 +1,153 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 "../../CodeEditor/jucer_OpenDocumentManager.h"
|
||||
#include "jucer_HeaderComponent.h"
|
||||
#include "jucer_ProjectMessagesComponent.h"
|
||||
#include "jucer_ContentViewComponent.h"
|
||||
|
||||
class Sidebar;
|
||||
struct WizardHolder;
|
||||
|
||||
//==============================================================================
|
||||
class ProjectContentComponent : public Component,
|
||||
public ApplicationCommandTarget,
|
||||
private ChangeListener,
|
||||
private OpenDocumentManager::DocumentCloseListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ProjectContentComponent();
|
||||
~ProjectContentComponent() override;
|
||||
|
||||
Project* getProject() const noexcept { return project; }
|
||||
void setProject (Project*);
|
||||
|
||||
void saveOpenDocumentList();
|
||||
void reloadLastOpenDocuments();
|
||||
|
||||
bool showEditorForFile (const File&, bool grabFocus);
|
||||
bool hasFileInRecentList (const File&) const;
|
||||
File getCurrentFile() const;
|
||||
|
||||
bool showDocument (OpenDocumentManager::Document*, bool grabFocus);
|
||||
void hideDocument (OpenDocumentManager::Document*);
|
||||
OpenDocumentManager::Document* getCurrentDocument() const { return currentDocument; }
|
||||
void closeDocument();
|
||||
void saveDocumentAsync();
|
||||
void saveAsAsync();
|
||||
|
||||
void hideEditor();
|
||||
void setScrollableEditorComponent (std::unique_ptr<Component> component);
|
||||
void setEditorDocument (std::unique_ptr<Component> component, OpenDocumentManager::Document* doc);
|
||||
Component* getEditorComponent();
|
||||
|
||||
Component& getSidebarComponent();
|
||||
|
||||
bool goToPreviousFile();
|
||||
bool goToNextFile();
|
||||
bool canGoToCounterpart() const;
|
||||
bool goToCounterpart();
|
||||
|
||||
void saveProjectAsync();
|
||||
void closeProject();
|
||||
void openInSelectedIDE (bool saveFirst);
|
||||
void showNewExporterMenu();
|
||||
|
||||
void showFilesPanel() { showProjectPanel (0); }
|
||||
void showModulesPanel() { showProjectPanel (1); }
|
||||
void showExportersPanel() { showProjectPanel (2); }
|
||||
|
||||
void showProjectSettings();
|
||||
void showCurrentExporterSettings();
|
||||
void showExporterSettings (const String& exporterName);
|
||||
void showModule (const String& moduleID);
|
||||
void showUserSettings();
|
||||
|
||||
void deleteSelectedTreeItems();
|
||||
|
||||
void refreshProjectTreeFileStatuses();
|
||||
void updateMissingFileStatuses();
|
||||
void addNewGUIFile();
|
||||
|
||||
void showBubbleMessage (Rectangle<int>, const String&);
|
||||
|
||||
StringArray getExportersWhichCanLaunch() const;
|
||||
|
||||
static void getSelectedProjectItemsBeingDragged (const DragAndDropTarget::SourceDetails&,
|
||||
OwnedArray<Project::Item>& selectedNodes);
|
||||
|
||||
//==============================================================================
|
||||
ApplicationCommandTarget* getNextCommandTarget() override;
|
||||
void getAllCommands (Array<CommandID>&) override;
|
||||
void getCommandInfo (CommandID, ApplicationCommandInfo&) override;
|
||||
bool perform (const InvocationInfo&) override;
|
||||
|
||||
bool isSaveCommand (const CommandID id);
|
||||
|
||||
void paint (Graphics&) override;
|
||||
void resized() override;
|
||||
void childBoundsChanged (Component*) override;
|
||||
void lookAndFeelChanged() override;
|
||||
|
||||
ProjectMessagesComponent& getProjectMessagesComponent() { return projectMessagesComponent; }
|
||||
|
||||
static String getProjectTabName() { return "Project"; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
bool documentAboutToClose (OpenDocumentManager::Document*) override;
|
||||
void changeListenerCallback (ChangeBroadcaster*) override;
|
||||
void showTranslationTool();
|
||||
|
||||
//==============================================================================
|
||||
void showProjectPanel (const int index);
|
||||
bool canSelectedProjectBeLaunch();
|
||||
|
||||
//==============================================================================
|
||||
Project* project = nullptr;
|
||||
OpenDocumentManager::Document* currentDocument = nullptr;
|
||||
RecentDocumentList recentDocumentList;
|
||||
|
||||
HeaderComponent headerComponent { this };
|
||||
std::unique_ptr<Sidebar> sidebar;
|
||||
ProjectMessagesComponent projectMessagesComponent;
|
||||
ContentViewComponent contentViewComponent;
|
||||
|
||||
std::unique_ptr<ResizableEdgeComponent> resizerBar;
|
||||
ComponentBoundsConstrainer sidebarSizeConstrainer;
|
||||
std::unique_ptr<Component> translationTool;
|
||||
BubbleMessageComponent bubbleMessage;
|
||||
|
||||
bool isForeground = false;
|
||||
int lastViewedTab = 0;
|
||||
|
||||
std::unique_ptr<WizardHolder> wizardHolder;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectContentComponent)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 "../../CodeEditor/jucer_OpenDocumentManager.h"
|
||||
#include "jucer_HeaderComponent.h"
|
||||
#include "jucer_ProjectMessagesComponent.h"
|
||||
#include "jucer_ContentViewComponent.h"
|
||||
|
||||
class Sidebar;
|
||||
struct WizardHolder;
|
||||
|
||||
//==============================================================================
|
||||
class ProjectContentComponent : public Component,
|
||||
public ApplicationCommandTarget,
|
||||
private ChangeListener,
|
||||
private OpenDocumentManager::DocumentCloseListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ProjectContentComponent();
|
||||
~ProjectContentComponent() override;
|
||||
|
||||
Project* getProject() const noexcept { return project; }
|
||||
void setProject (Project*);
|
||||
|
||||
void saveOpenDocumentList();
|
||||
void reloadLastOpenDocuments();
|
||||
|
||||
bool showEditorForFile (const File&, bool grabFocus);
|
||||
bool hasFileInRecentList (const File&) const;
|
||||
File getCurrentFile() const;
|
||||
|
||||
bool showDocument (OpenDocumentManager::Document*, bool grabFocus);
|
||||
void hideDocument (OpenDocumentManager::Document*);
|
||||
OpenDocumentManager::Document* getCurrentDocument() const { return currentDocument; }
|
||||
void closeDocument();
|
||||
void saveDocumentAsync();
|
||||
void saveAsAsync();
|
||||
|
||||
void hideEditor();
|
||||
void setScrollableEditorComponent (std::unique_ptr<Component> component);
|
||||
void setEditorDocument (std::unique_ptr<Component> component, OpenDocumentManager::Document* doc);
|
||||
Component* getEditorComponent();
|
||||
|
||||
Component& getSidebarComponent();
|
||||
|
||||
bool goToPreviousFile();
|
||||
bool goToNextFile();
|
||||
bool canGoToCounterpart() const;
|
||||
bool goToCounterpart();
|
||||
|
||||
void saveProjectAsync();
|
||||
void closeProject();
|
||||
void openInSelectedIDE (bool saveFirst);
|
||||
void showNewExporterMenu();
|
||||
|
||||
void showFilesPanel() { showProjectPanel (0); }
|
||||
void showModulesPanel() { showProjectPanel (1); }
|
||||
void showExportersPanel() { showProjectPanel (2); }
|
||||
|
||||
void showProjectSettings();
|
||||
void showCurrentExporterSettings();
|
||||
void showExporterSettings (const String& exporterName);
|
||||
void showModule (const String& moduleID);
|
||||
void showUserSettings();
|
||||
|
||||
void deleteSelectedTreeItems();
|
||||
|
||||
void refreshProjectTreeFileStatuses();
|
||||
void updateMissingFileStatuses();
|
||||
void addNewGUIFile();
|
||||
|
||||
void showBubbleMessage (Rectangle<int>, const String&);
|
||||
|
||||
StringArray getExportersWhichCanLaunch() const;
|
||||
|
||||
static void getSelectedProjectItemsBeingDragged (const DragAndDropTarget::SourceDetails&,
|
||||
OwnedArray<Project::Item>& selectedNodes);
|
||||
|
||||
//==============================================================================
|
||||
ApplicationCommandTarget* getNextCommandTarget() override;
|
||||
void getAllCommands (Array<CommandID>&) override;
|
||||
void getCommandInfo (CommandID, ApplicationCommandInfo&) override;
|
||||
bool perform (const InvocationInfo&) override;
|
||||
|
||||
bool isSaveCommand (const CommandID id);
|
||||
|
||||
void paint (Graphics&) override;
|
||||
void resized() override;
|
||||
void childBoundsChanged (Component*) override;
|
||||
void lookAndFeelChanged() override;
|
||||
|
||||
ProjectMessagesComponent& getProjectMessagesComponent() { return projectMessagesComponent; }
|
||||
|
||||
static String getProjectTabName() { return "Project"; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
bool documentAboutToClose (OpenDocumentManager::Document*) override;
|
||||
void changeListenerCallback (ChangeBroadcaster*) override;
|
||||
void showTranslationTool();
|
||||
|
||||
//==============================================================================
|
||||
void showProjectPanel (const int index);
|
||||
bool canSelectedProjectBeLaunch();
|
||||
|
||||
//==============================================================================
|
||||
Project* project = nullptr;
|
||||
OpenDocumentManager::Document* currentDocument = nullptr;
|
||||
RecentDocumentList recentDocumentList;
|
||||
|
||||
HeaderComponent headerComponent { this };
|
||||
std::unique_ptr<Sidebar> sidebar;
|
||||
ProjectMessagesComponent projectMessagesComponent;
|
||||
ContentViewComponent contentViewComponent;
|
||||
|
||||
std::unique_ptr<ResizableEdgeComponent> resizerBar;
|
||||
ComponentBoundsConstrainer sidebarSizeConstrainer;
|
||||
std::unique_ptr<Component> translationTool;
|
||||
BubbleMessageComponent bubbleMessage;
|
||||
|
||||
bool isForeground = false;
|
||||
int lastViewedTab = 0;
|
||||
|
||||
std::unique_ptr<WizardHolder> wizardHolder;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectContentComponent)
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,171 +1,171 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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 "../../Application/jucer_Application.h"
|
||||
|
||||
//==============================================================================
|
||||
class UserAvatarComponent : public Component,
|
||||
public SettableTooltipClient,
|
||||
public ChangeBroadcaster,
|
||||
private LicenseController::LicenseStateListener
|
||||
{
|
||||
public:
|
||||
UserAvatarComponent (bool isInteractive)
|
||||
: interactive (isInteractive)
|
||||
{
|
||||
ProjucerApplication::getApp().getLicenseController().addListener (this);
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
~UserAvatarComponent() override
|
||||
{
|
||||
ProjucerApplication::getApp().getLicenseController().removeListener (this);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
if (! isGPL)
|
||||
{
|
||||
bounds = bounds.removeFromRight (bounds.getHeight());
|
||||
|
||||
Path ellipse;
|
||||
ellipse.addEllipse (bounds.toFloat());
|
||||
|
||||
g.reduceClipRegion (ellipse);
|
||||
}
|
||||
|
||||
g.drawImage (currentAvatar, bounds.toFloat(), RectanglePlacement::fillDestination);
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent&) override
|
||||
{
|
||||
triggerClick();
|
||||
}
|
||||
|
||||
void triggerClick()
|
||||
{
|
||||
if (interactive)
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (ProjucerApplication::getApp().commandManager.get(), CommandIDs::loginLogout);
|
||||
|
||||
menu.showMenuAsync (PopupMenu::Options().withTargetComponent (this));
|
||||
}
|
||||
}
|
||||
|
||||
bool isDisplaingGPLLogo() const noexcept { return isGPL; }
|
||||
|
||||
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
|
||||
{
|
||||
return interactive ? std::make_unique<AccessibilityHandler> (*this,
|
||||
AccessibilityRole::button,
|
||||
AccessibilityActions().addAction (AccessibilityActionType::press,
|
||||
[this] { triggerClick(); }))
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
static Image createGPLAvatarImage()
|
||||
{
|
||||
if (auto logo = Drawable::createFromImageData (BinaryData::gpl_logo_svg, BinaryData::gpl_logo_svgSize))
|
||||
{
|
||||
auto bounds = logo->getDrawableBounds();
|
||||
|
||||
Image image (Image::ARGB, roundToInt (bounds.getWidth()), roundToInt (bounds.getHeight()), true);
|
||||
Graphics g (image);
|
||||
logo->draw (g, 1.0f);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
Image createStandardAvatarImage()
|
||||
{
|
||||
Image image (Image::ARGB, 250, 250, true);
|
||||
Graphics g (image);
|
||||
|
||||
g.setColour (findColour (defaultButtonBackgroundColourId));
|
||||
g.fillAll();
|
||||
|
||||
g.setColour (findColour (defaultIconColourId));
|
||||
|
||||
auto path = getIcons().user;
|
||||
g.fillPath (path, RectanglePlacement (RectanglePlacement::centred)
|
||||
.getTransformToFit (path.getBounds(), image.getBounds().reduced (image.getHeight() / 5).toFloat()));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void licenseStateChanged() override
|
||||
{
|
||||
auto state = ProjucerApplication::getApp().getLicenseController().getCurrentState();
|
||||
|
||||
isGPL = ProjucerApplication::getApp().getLicenseController().getCurrentState().isGPL();
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
auto formattedUserString = [state]() -> String
|
||||
{
|
||||
if (state.isSignedIn())
|
||||
return (state.isGPL() ? "" : (state.username + " - ")) + state.getLicenseTypeString();
|
||||
|
||||
return "Not logged in";
|
||||
}();
|
||||
|
||||
setTooltip (formattedUserString);
|
||||
}
|
||||
|
||||
currentAvatar = isGPL ? gplAvatarImage
|
||||
: state.isSignedIn() ? standardAvatarImage : signedOutAvatarImage;
|
||||
|
||||
repaint();
|
||||
sendChangeMessage();
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
standardAvatarImage = createStandardAvatarImage();
|
||||
signedOutAvatarImage = createStandardAvatarImage();
|
||||
|
||||
if (interactive)
|
||||
signedOutAvatarImage.multiplyAllAlphas (0.4f);
|
||||
|
||||
licenseStateChanged();
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Image standardAvatarImage, signedOutAvatarImage, gplAvatarImage { createGPLAvatarImage() }, currentAvatar;
|
||||
bool isGPL = false, interactive = false;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 "../../Application/jucer_Application.h"
|
||||
|
||||
//==============================================================================
|
||||
class UserAvatarComponent : public Component,
|
||||
public SettableTooltipClient,
|
||||
public ChangeBroadcaster,
|
||||
private LicenseController::LicenseStateListener
|
||||
{
|
||||
public:
|
||||
UserAvatarComponent (bool isInteractive)
|
||||
: interactive (isInteractive)
|
||||
{
|
||||
ProjucerApplication::getApp().getLicenseController().addListener (this);
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
~UserAvatarComponent() override
|
||||
{
|
||||
ProjucerApplication::getApp().getLicenseController().removeListener (this);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
if (! isGPL)
|
||||
{
|
||||
bounds = bounds.removeFromRight (bounds.getHeight());
|
||||
|
||||
Path ellipse;
|
||||
ellipse.addEllipse (bounds.toFloat());
|
||||
|
||||
g.reduceClipRegion (ellipse);
|
||||
}
|
||||
|
||||
g.drawImage (currentAvatar, bounds.toFloat(), RectanglePlacement::fillDestination);
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent&) override
|
||||
{
|
||||
triggerClick();
|
||||
}
|
||||
|
||||
void triggerClick()
|
||||
{
|
||||
if (interactive)
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addCommandItem (ProjucerApplication::getApp().commandManager.get(), CommandIDs::loginLogout);
|
||||
|
||||
menu.showMenuAsync (PopupMenu::Options().withTargetComponent (this));
|
||||
}
|
||||
}
|
||||
|
||||
bool isDisplaingGPLLogo() const noexcept { return isGPL; }
|
||||
|
||||
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
|
||||
{
|
||||
return interactive ? std::make_unique<AccessibilityHandler> (*this,
|
||||
AccessibilityRole::button,
|
||||
AccessibilityActions().addAction (AccessibilityActionType::press,
|
||||
[this] { triggerClick(); }))
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
static Image createGPLAvatarImage()
|
||||
{
|
||||
if (auto logo = Drawable::createFromImageData (BinaryData::gpl_logo_svg, BinaryData::gpl_logo_svgSize))
|
||||
{
|
||||
auto bounds = logo->getDrawableBounds();
|
||||
|
||||
Image image (Image::ARGB, roundToInt (bounds.getWidth()), roundToInt (bounds.getHeight()), true);
|
||||
Graphics g (image);
|
||||
logo->draw (g, 1.0f);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
Image createStandardAvatarImage()
|
||||
{
|
||||
Image image (Image::ARGB, 250, 250, true);
|
||||
Graphics g (image);
|
||||
|
||||
g.setColour (findColour (defaultButtonBackgroundColourId));
|
||||
g.fillAll();
|
||||
|
||||
g.setColour (findColour (defaultIconColourId));
|
||||
|
||||
auto path = getIcons().user;
|
||||
g.fillPath (path, RectanglePlacement (RectanglePlacement::centred)
|
||||
.getTransformToFit (path.getBounds(), image.getBounds().reduced (image.getHeight() / 5).toFloat()));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void licenseStateChanged() override
|
||||
{
|
||||
auto state = ProjucerApplication::getApp().getLicenseController().getCurrentState();
|
||||
|
||||
isGPL = ProjucerApplication::getApp().getLicenseController().getCurrentState().isGPL();
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
auto formattedUserString = [state]() -> String
|
||||
{
|
||||
if (state.isSignedIn())
|
||||
return (state.isGPL() ? "" : (state.username + " - ")) + state.getLicenseTypeString();
|
||||
|
||||
return "Not logged in";
|
||||
}();
|
||||
|
||||
setTooltip (formattedUserString);
|
||||
}
|
||||
|
||||
currentAvatar = isGPL ? gplAvatarImage
|
||||
: state.isSignedIn() ? standardAvatarImage : signedOutAvatarImage;
|
||||
|
||||
repaint();
|
||||
sendChangeMessage();
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
standardAvatarImage = createStandardAvatarImage();
|
||||
signedOutAvatarImage = createStandardAvatarImage();
|
||||
|
||||
if (interactive)
|
||||
signedOutAvatarImage.multiplyAllAlphas (0.4f);
|
||||
|
||||
licenseStateChanged();
|
||||
repaint();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Image standardAvatarImage, signedOutAvatarImage, gplAvatarImage { createGPLAvatarImage() }, currentAvatar;
|
||||
bool isGPL = false, interactive = false;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
1294
deps/juce/extras/Projucer/Source/Project/jucer_Project.h
vendored
1294
deps/juce/extras/Projucer/Source/Project/jucer_Project.h
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user