mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-22 01:34:21 +00:00
Added some flexibility to PluginListComponent to make it easier to customise, and added some right-click popup menu options for the items
This commit is contained in:
parent
bec0c2661d
commit
4599496a42
4 changed files with 128 additions and 58 deletions
|
|
@ -53,6 +53,17 @@ Array<PluginDescription> KnownPluginList::getTypes() const
|
|||
return types;
|
||||
}
|
||||
|
||||
Array<PluginDescription> KnownPluginList::getTypesForFormat (AudioPluginFormat& format) const
|
||||
{
|
||||
Array<PluginDescription> result;
|
||||
|
||||
for (auto& d : getTypes())
|
||||
if (d.pluginFormatName == format.getName())
|
||||
result.add (d);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<PluginDescription> KnownPluginList::getTypeForFile (const String& fileOrIdentifier) const
|
||||
{
|
||||
ScopedLock lock (typesArrayLock);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ public:
|
|||
/** Returns a copy of the current list. */
|
||||
Array<PluginDescription> getTypes() const;
|
||||
|
||||
/** Returns the subset of plugin types for a given format. */
|
||||
Array<PluginDescription> getTypesForFormat (AudioPluginFormat&) const;
|
||||
|
||||
/** Looks for a type in the list which comes from this file. */
|
||||
std::unique_ptr<PluginDescription> getTypeForFile (const String& fileOrIdentifier) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void cellClicked (int rowNumber, int columnId, const juce::MouseEvent& e) override
|
||||
{
|
||||
TableListBoxModel::cellClicked (rowNumber, columnId, e);
|
||||
|
||||
if (rowNumber >= 0 && rowNumber < getNumRows() && e.mods.isPopupMenu())
|
||||
owner.createMenuForRow (rowNumber).showMenuAsync (PopupMenu::Options().withDeletionCheck (owner));
|
||||
}
|
||||
|
||||
void deleteKeyPressed (int) override
|
||||
{
|
||||
owner.removeSelectedPlugins();
|
||||
|
|
@ -161,7 +169,13 @@ PluginListComponent::PluginListComponent (AudioPluginFormatManager& manager, Kno
|
|||
addAndMakeVisible (table);
|
||||
|
||||
addAndMakeVisible (optionsButton);
|
||||
optionsButton.onClick = [this] { showOptionsMenu(); };
|
||||
optionsButton.onClick = [this]
|
||||
{
|
||||
createOptionsMenu().showMenuAsync (PopupMenu::Options()
|
||||
.withDeletionCheck (*this)
|
||||
.withTargetComponent (optionsButton));
|
||||
};
|
||||
|
||||
optionsButton.setTriggeredOnMouseDown (true);
|
||||
|
||||
setSize (400, 600);
|
||||
|
|
@ -199,10 +213,13 @@ void PluginListComponent::resized()
|
|||
{
|
||||
auto r = getLocalBounds().reduced (2);
|
||||
|
||||
optionsButton.setBounds (r.removeFromBottom (24));
|
||||
optionsButton.changeWidthToFitText (24);
|
||||
if (optionsButton.isVisible())
|
||||
{
|
||||
optionsButton.setBounds (r.removeFromBottom (24));
|
||||
optionsButton.changeWidthToFitText (24);
|
||||
r.removeFromBottom (3);
|
||||
}
|
||||
|
||||
r.removeFromBottom (3);
|
||||
table.setBounds (r);
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +237,7 @@ void PluginListComponent::updateList()
|
|||
|
||||
void PluginListComponent::removeSelectedPlugins()
|
||||
{
|
||||
const SparseSet<int> selected (table.getSelectedRows());
|
||||
auto selected = table.getSelectedRows();
|
||||
|
||||
for (int i = table.getNumRows(); --i >= 0;)
|
||||
if (selected.contains (i))
|
||||
|
|
@ -238,15 +255,15 @@ void PluginListComponent::setTableModel (TableListBoxModel* model)
|
|||
table.repaint();
|
||||
}
|
||||
|
||||
bool PluginListComponent::canShowSelectedFolder() const
|
||||
static bool canShowFolderForPlugin (KnownPluginList& list, int index)
|
||||
{
|
||||
return File::createFileWithoutCheckingPath (list.getTypes()[table.getSelectedRow()].fileOrIdentifier).exists();
|
||||
return File::createFileWithoutCheckingPath (list.getTypes()[index].fileOrIdentifier).exists();
|
||||
}
|
||||
|
||||
void PluginListComponent::showSelectedFolder()
|
||||
static void showFolderForPlugin (KnownPluginList& list, int index)
|
||||
{
|
||||
if (canShowSelectedFolder())
|
||||
File (list.getTypes()[table.getSelectedRow()].fileOrIdentifier).getParentDirectory().startAsProcess();
|
||||
if (canShowFolderForPlugin (list, index))
|
||||
File (list.getTypes()[index].fileOrIdentifier).getParentDirectory().startAsProcess();
|
||||
}
|
||||
|
||||
void PluginListComponent::removeMissingPlugins()
|
||||
|
|
@ -270,49 +287,81 @@ void PluginListComponent::removePluginItem (int index)
|
|||
list.removeFromBlacklist (list.getBlacklistedFiles() [index - list.getNumTypes()]);
|
||||
}
|
||||
|
||||
void PluginListComponent::optionsMenuStaticCallback (int result, PluginListComponent* pluginList)
|
||||
{
|
||||
if (pluginList != nullptr)
|
||||
pluginList->optionsMenuCallback (result);
|
||||
}
|
||||
|
||||
void PluginListComponent::optionsMenuCallback (int result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: list.clear(); break;
|
||||
case 2: removeSelectedPlugins(); break;
|
||||
case 3: showSelectedFolder(); break;
|
||||
case 4: removeMissingPlugins(); break;
|
||||
|
||||
default:
|
||||
if (AudioPluginFormat* format = formatManager.getFormat (result - 10))
|
||||
scanFor (*format);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PluginListComponent::showOptionsMenu()
|
||||
PopupMenu PluginListComponent::createOptionsMenu()
|
||||
{
|
||||
PopupMenu menu;
|
||||
menu.addItem (1, TRANS("Clear list"));
|
||||
menu.addItem (2, TRANS("Remove selected plug-in from list"), table.getNumSelectedRows() > 0);
|
||||
menu.addItem (3, TRANS("Show folder containing selected plug-in"), canShowSelectedFolder());
|
||||
menu.addItem (4, TRANS("Remove any plug-ins whose files no longer exist"));
|
||||
menu.addItem (PopupMenu::Item (TRANS("Clear list"))
|
||||
.setAction ([this] { list.clear(); }));
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
for (int i = 0; i < formatManager.getNumFormats(); ++i)
|
||||
{
|
||||
auto* format = formatManager.getFormat (i);
|
||||
|
||||
if (format->canScanForPlugins())
|
||||
menu.addItem (10 + i, "Scan for new or updated " + format->getName() + " plug-ins");
|
||||
if (auto format = formatManager.getFormat(i))
|
||||
{
|
||||
if (format->canScanForPlugins())
|
||||
{
|
||||
menu.addItem (PopupMenu::Item ("Remove all " + format->getName() + " plug-ins")
|
||||
.setEnabled (! list.getTypesForFormat (*format).isEmpty())
|
||||
.setAction ([this, i]
|
||||
{
|
||||
if (auto f = formatManager.getFormat (i))
|
||||
for (auto& pd : list.getTypesForFormat (*f))
|
||||
list.removeType (pd);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu.showMenuAsync (PopupMenu::Options().withTargetComponent (optionsButton),
|
||||
ModalCallbackFunction::forComponent (optionsMenuStaticCallback, this));
|
||||
menu.addSeparator();
|
||||
|
||||
menu.addItem (PopupMenu::Item (TRANS("Remove selected plug-in from list"))
|
||||
.setEnabled (table.getNumSelectedRows() > 0)
|
||||
.setAction ([this] { removeSelectedPlugins(); }));
|
||||
|
||||
menu.addItem (PopupMenu::Item (TRANS("Remove any plug-ins whose files no longer exist"))
|
||||
.setAction ([this] { removeMissingPlugins(); }));
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
auto selectedRow = table.getSelectedRow();
|
||||
|
||||
menu.addItem (PopupMenu::Item (TRANS("Show folder containing selected plug-in"))
|
||||
.setEnabled (canShowFolderForPlugin (list, selectedRow))
|
||||
.setAction ([this, selectedRow] { showFolderForPlugin (list, selectedRow); }));
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
for (int i = 0; i < formatManager.getNumFormats(); ++i)
|
||||
{
|
||||
if (auto format = formatManager.getFormat(i))
|
||||
if (format->canScanForPlugins())
|
||||
menu.addItem (PopupMenu::Item ("Scan for new or updated " + format->getName() + " plug-ins")
|
||||
.setAction ([this, i]
|
||||
{
|
||||
if (auto f = formatManager.getFormat (i))
|
||||
scanFor (*f);
|
||||
}));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
PopupMenu PluginListComponent::createMenuForRow (int rowNumber)
|
||||
{
|
||||
PopupMenu menu;
|
||||
|
||||
if (rowNumber >= 0 && rowNumber < tableModel->getNumRows())
|
||||
{
|
||||
menu.addItem (PopupMenu::Item (TRANS("Remove plug-in from list"))
|
||||
.setAction ([this, rowNumber] { removePluginItem (rowNumber); }));
|
||||
|
||||
menu.addItem (PopupMenu::Item (TRANS("Show folder containing plug-in"))
|
||||
.setEnabled (canShowFolderForPlugin (list, rowNumber))
|
||||
.setAction ([this, rowNumber] { showFolderForPlugin (list, rowNumber); }));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
bool PluginListComponent::isInterestedInFileDrag (const StringArray& /*files*/)
|
||||
|
|
@ -357,8 +406,7 @@ public:
|
|||
: owner (plc), formatToScan (format), filesOrIdentifiersToScan (filesOrIdentifiers), propertiesToUse (properties),
|
||||
pathChooserWindow (TRANS("Select folders to scan..."), String(), AlertWindow::NoIcon),
|
||||
progressWindow (title, text, AlertWindow::NoIcon),
|
||||
progress (0.0), numThreads (threads), allowAsync (allowPluginsWhichRequireAsynchronousInstantiation),
|
||||
finished (false)
|
||||
numThreads (threads), allowAsync (allowPluginsWhichRequireAsynchronousInstantiation)
|
||||
{
|
||||
FileSearchPath path (formatToScan.getDefaultLocationsToSearch());
|
||||
|
||||
|
|
@ -410,9 +458,9 @@ private:
|
|||
AlertWindow pathChooserWindow, progressWindow;
|
||||
FileSearchPathListComponent pathList;
|
||||
String pluginBeingScanned;
|
||||
double progress;
|
||||
double progress = 0;
|
||||
int numThreads;
|
||||
bool allowAsync, finished, timerReentrancyCheck = false;
|
||||
bool allowAsync, finished = false, timerReentrancyCheck = false;
|
||||
std::unique_ptr<ThreadPool> pool;
|
||||
|
||||
static void startScanCallback (int result, AlertWindow* alert, Scanner* scanner)
|
||||
|
|
@ -431,7 +479,7 @@ private:
|
|||
{
|
||||
for (int i = 0; i < pathList.getPath().getNumPaths(); ++i)
|
||||
{
|
||||
const File f (pathList.getPath()[i]);
|
||||
auto f = pathList.getPath()[i];
|
||||
|
||||
if (isStupidPath (f))
|
||||
{
|
||||
|
|
@ -472,9 +520,9 @@ private:
|
|||
File::userMoviesDirectory,
|
||||
File::userPicturesDirectory };
|
||||
|
||||
for (int i = 0; i < numElementsInArray (pathsThatWouldBeStupidToScan); ++i)
|
||||
for (auto location : pathsThatWouldBeStupidToScan)
|
||||
{
|
||||
const File sillyFolder (File::getSpecialLocation (pathsThatWouldBeStupidToScan[i]));
|
||||
auto sillyFolder = File::getSpecialLocation (location);
|
||||
|
||||
if (f == sillyFolder || sillyFolder.isAChildOf (f))
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -58,6 +58,14 @@ public:
|
|||
/** Changes the text in the panel's options button. */
|
||||
void setOptionsButtonText (const String& newText);
|
||||
|
||||
/** Returns a pop-up menu that contains all the options for scanning and updating the list. */
|
||||
PopupMenu createOptionsMenu();
|
||||
|
||||
/** Returns a menu that can be shown if a row is right-clicked, containing actions
|
||||
like "remove plugin" or "show folder" etc.
|
||||
*/
|
||||
PopupMenu createMenuForRow (int rowNumber);
|
||||
|
||||
/** Changes the text in the progress dialog box that is shown when scanning. */
|
||||
void setScanDialogText (const String& textForProgressWindowTitle,
|
||||
const String& textForProgressWindowDescription);
|
||||
|
|
@ -92,11 +100,16 @@ public:
|
|||
/** Sets a custom table model to be used.
|
||||
This will take ownership of the model and delete it when no longer needed.
|
||||
*/
|
||||
void setTableModel (TableListBoxModel* model);
|
||||
void setTableModel (TableListBoxModel*);
|
||||
|
||||
/** Returns the table used to display the plugin list. */
|
||||
TableListBox& getTableListBox() noexcept { return table; }
|
||||
|
||||
/** Returns the button used to display the options menu - you can make this invisible
|
||||
if you want to hide it and use some other method for showing the menu.
|
||||
*/
|
||||
TextButton& getOptionsButton() { return optionsButton; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
AudioPluginFormatManager& formatManager;
|
||||
|
|
@ -116,14 +129,9 @@ private:
|
|||
std::unique_ptr<Scanner> currentScanner;
|
||||
|
||||
void scanFinished (const StringArray&);
|
||||
static void optionsMenuStaticCallback (int, PluginListComponent*);
|
||||
void optionsMenuCallback (int);
|
||||
void updateList();
|
||||
void showSelectedFolder();
|
||||
bool canShowSelectedFolder() const;
|
||||
void removeMissingPlugins();
|
||||
void removePluginItem (int index);
|
||||
void showOptionsMenu();
|
||||
|
||||
void resized() override;
|
||||
bool isInterestedInFileDrag (const StringArray&) override;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue