Mema
Memory Matrix — multi-channel audio matrix monitor and router
Loading...
Searching...
No Matches
PluginControlComponent.h
Go to the documentation of this file.
1/* Copyright (c) 2024, Christian Ahrens
2 *
3 * This file is part of Mema <https://github.com/ChristianAhrens/Mema>
4 *
5 * This tool is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License version 3.0 as published
7 * by the Free Software Foundation.
8 *
9 * This tool is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this tool; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#pragma once
20
21#include <JuceHeader.h>
22
23#include "../MemaProcessor/MemaPluginParameterInfo.h"
24
25#include <FixedFontTextEditor.h>
26
27
28namespace Mema
29{
30
35class CustomPluginListComponentTableModel : public juce::TableListBoxModel
36{
37public:
38 CustomPluginListComponentTableModel(juce::PluginListComponent& c, juce::KnownPluginList& l) : m_owner(c), m_list(l) {}
39
40 int getNumRows() override
41 {
42 return m_list.getNumTypes() + m_list.getBlacklistedFiles().size();
43 }
44
45 void paintRowBackground(juce::Graphics& g, int /*rowNumber*/, int /*width*/, int /*height*/, bool rowIsSelected) override
46 {
47 const auto defaultColour = m_owner.findColour(ListBox::backgroundColourId);
48 const auto c = rowIsSelected ? defaultColour.interpolatedWith(m_owner.findColour(ListBox::textColourId), 0.5f)
49 : defaultColour;
50
51 g.fillAll(c);
52 }
53
54 enum
55 {
60 descCol = 5
61 };
62
63 void paintCell(juce::Graphics& g, int row, int columnId, int width, int height, bool /*rowIsSelected*/) override
64 {
65 juce::String text;
66 bool isBlacklisted = row >= m_list.getNumTypes();
67
68 if (isBlacklisted)
69 {
70 if (columnId == nameCol)
71 text = m_list.getBlacklistedFiles()[row - m_list.getNumTypes()];
72 else if (columnId == descCol)
73 text = TRANS("Deactivated after failing to initialise correctly");
74 }
75 else
76 {
77 auto desc = m_list.getTypes()[row];
78
79 switch (columnId)
80 {
81 case nameCol: text = desc.name; break;
82 case typeCol: text = desc.pluginFormatName; break;
83 case categoryCol: text = desc.category.isNotEmpty() ? desc.category : "-"; break;
84 case manufacturerCol: text = desc.manufacturerName; break;
85 case descCol: text = getPluginDescription(desc); break;
86
87 default: jassertfalse; break;
88 }
89 }
90
91 if (text.isNotEmpty())
92 {
93 const auto defaultTextColour = m_owner.findColour(ListBox::textColourId);
94 g.setColour(isBlacklisted ? Colours::red
95 : columnId == nameCol ? defaultTextColour
96 : defaultTextColour.interpolatedWith(Colours::transparentBlack, 0.3f));
97 g.setFont(m_owner.withDefaultMetrics(juce::FontOptions((float)height * 0.7f, Font::bold)));
98 g.drawFittedText(text, 4, 0, width - 6, height, juce::Justification::centredLeft, 1, 0.9f);
99 }
100 }
101
102 void cellClicked(int rowNumber, int columnId, const juce::MouseEvent& e) override
103 {
104 juce::TableListBoxModel::cellClicked(rowNumber, columnId, e);
105
106 if (rowNumber >= 0 && rowNumber < getNumRows() && e.mods.isPopupMenu())
107 m_owner.createMenuForRow(rowNumber).showMenuAsync(juce::PopupMenu::Options().withDeletionCheck(m_owner));
108 }
109
110 void deleteKeyPressed(int) override
111 {
112 m_owner.removeSelectedPlugins();
113 }
114
115 void sortOrderChanged(int newSortColumnId, bool isForwards) override
116 {
117 switch (newSortColumnId)
118 {
119 case nameCol: m_list.sort(juce::KnownPluginList::sortAlphabetically, isForwards); break;
120 case typeCol: m_list.sort(juce::KnownPluginList::sortByFormat, isForwards); break;
121 case categoryCol: m_list.sort(juce::KnownPluginList::sortByCategory, isForwards); break;
122 case manufacturerCol: m_list.sort(juce::KnownPluginList::sortByManufacturer, isForwards); break;
123 case descCol: break;
124
125 default: jassertfalse; break;
126 }
127 }
128
129 void selectedRowsChanged(int lastRowSelected) override
130 {
131 m_lastRowSelected = lastRowSelected;
132
133 juce::TableListBoxModel::selectedRowsChanged(lastRowSelected);
134
137 }
138
139 static juce::String getPluginDescription(const juce::PluginDescription& desc)
140 {
141 juce::StringArray items;
142
143 if (desc.descriptiveName != desc.name)
144 items.add(desc.descriptiveName);
145
146 items.add(desc.version);
147
148 items.removeEmptyStrings();
149 return items.joinIntoString(" - ");
150 }
151
152 juce::PluginDescription getPluginDescriptionOfSelectedRow()
153 {
154 if (m_lastRowSelected != -1)
155 {
156 auto currentPluginDescriptionListContents = m_list.getTypes();
157 if (currentPluginDescriptionListContents.size() > m_lastRowSelected)
158 return currentPluginDescriptionListContents[m_lastRowSelected];
159 }
160
161 return {};
162 }
163
164 std::function<void(int)> onSelectionChanged;
165
166 //==============================================================================
167 juce::PluginListComponent& m_owner;
168 juce::KnownPluginList& m_list;
170
171
172 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CustomPluginListComponentTableModel)
173};
174
175//==============================================================================
176class Spacing : public juce::Component
177{
178public:
179 Spacing() = default;
180 ~Spacing() = default;
181
182 //==============================================================================
183 void paint(Graphics& g) override
184 {
185 g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
186 };
187
188
189 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Spacing)
190};
191
192//==============================================================================
193class PluginListAndSelectComponent : public juce::Component
194{
195public:
197 {
198 addDefaultFormatsToManager(m_formatManager);
199 juce::File deadMansPedalFile;
200 m_pluginListComponent = std::make_unique<juce::PluginListComponent>(m_formatManager, m_pluginList, deadMansPedalFile, nullptr);
201 m_pluginListComponent->getTableListBox().setMultipleSelectionEnabled(false);
202 auto customTableModel = std::make_unique<CustomPluginListComponentTableModel>(*m_pluginListComponent, m_pluginList);
203 customTableModel->onSelectionChanged = [=](int lastRowSelected) {
204 if (m_selectButton)
205 m_selectButton->setEnabled(-1 != lastRowSelected);
206 };
207 m_pluginListComponent->setTableModel(dynamic_cast<juce::TableListBoxModel*>(customTableModel.release()));
208 addAndMakeVisible(m_pluginListComponent.get());
209
210 m_selectButton = std::make_unique<juce::TextButton>("Select", "Accept the current plugin selection as new type to instantiate and close.");
211 m_selectButton->onClick = [=]() {
212 if (m_pluginListComponent)
213 {
214 auto customTableModel = dynamic_cast<CustomPluginListComponentTableModel*>(m_pluginListComponent->getTableListBox().getTableListBoxModel());
215 if (customTableModel && onPluginSelected)
216 onPluginSelected(customTableModel->getPluginDescriptionOfSelectedRow());
217 }
218 removeFromDesktop();
219 };
220 m_selectButton->setEnabled(false);
221 addAndMakeVisible(m_selectButton.get());
222
223 m_cancelButton = std::make_unique<juce::TextButton>("Cancel", "Discard the current plugin selection and close.");
224 m_cancelButton->onClick = [=]() {
225 removeFromDesktop();
226 };
227 addAndMakeVisible(m_cancelButton.get());
228
229 setSize(885, 600);
230 };
232
233 //==============================================================================
234 void paint(Graphics& g) override
235 {
236 // (Our component is opaque, so we must completely fill the background with a solid colour)
237 g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
238 };
239 void resized() override
240 {
241 auto bounds = getLocalBounds();
242 m_pluginListComponent->setBounds(bounds);
243
244 bounds = bounds.removeFromBottom(28);
245 m_cancelButton->setBounds(bounds.removeFromRight(80).reduced(2));
246 m_selectButton->setBounds(bounds.removeFromRight(80).reduced(2));
247 };
248
249 //==============================================================================
250 std::function<void(const juce::PluginDescription&)> onPluginSelected;
251
252private:
253 //==============================================================================
254 juce::AudioPluginFormatManager m_formatManager;
255 juce::KnownPluginList m_pluginList;
256
257 std::unique_ptr<juce::PluginListComponent> m_pluginListComponent;
258 std::unique_ptr<juce::TextButton> m_selectButton;
259 std::unique_ptr<juce::TextButton> m_cancelButton;
260
261
262 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginListAndSelectComponent)
263};
264
266class PluginControlComponent : public juce::Component
267{
268public:
271
272 void showPluginsList(juce::Point<int> showPosition);
273 void setPluginEnabled(bool enabled = true);
274 void setPluginPrePost(bool post = false);
275 void setSelectedPlugin(const juce::PluginDescription& pluginDescription);
276 void setParameterInfos(const std::vector<PluginParameterInfo>& infos);
277 const std::map<int, Mema::PluginParameterInfo>& getParameterInfos();
278 void showParameterConfig();
279
280 //==============================================================================
281 void paint (Graphics&) override;
282 void resized() override;
283 void lookAndFeelChanged() override;
284
285 //==============================================================================
286 std::function<void(const juce::PluginDescription&)> onPluginSelected;
287 std::function<void()> onShowPluginEditor;
288 std::function<void(bool)> onPluginEnabledChange;
289 std::function<void(bool)> onPluginPrePostChange;
290 std::function<void()> onPluginParametersStatusChanged;
291 std::function<void()> onClearPlugin;
292
293private:
294 //==============================================================================
295 std::unique_ptr<juce::DrawableButton> m_enableButton;
296 std::unique_ptr<Spacing> m_spacing1;
297 std::unique_ptr<juce::TextButton> m_postButton;
298 std::unique_ptr<Spacing> m_spacing2;
299 std::unique_ptr<juce::TextButton> m_showEditorButton;
300 std::unique_ptr<juce::DrawableButton> m_triggerSelectButton;
301 std::unique_ptr<Spacing> m_spacing3;
302 std::unique_ptr<juce::DrawableButton> m_parameterConfigButton;
303 std::unique_ptr<Spacing> m_spacing4;
304 std::unique_ptr<juce::DrawableButton> m_clearButton;
305
306 std::unique_ptr<PluginListAndSelectComponent> m_pluginSelectionComponent;
307 juce::PluginDescription m_selectedPluginDescription;
308
309 std::map<int, Mema::PluginParameterInfo> m_parameterInfos;
310
311 std::map<int, std::unique_ptr<juce::ToggleButton>> m_messageBoxParameterToggles;
312 std::map<int, std::unique_ptr<juce::ComboBox>> m_messageBoxParameterCtrlTypess;
313 std::map<int, std::unique_ptr<JUCEAppBasics::FixedFontTextEditor>> m_messageBoxParameterCtrlStepsEdit;
314 std::unique_ptr<juce::Component> m_messageBoxParameterTogglesContainer;
315 juce::FlexBox m_messageBoxParameterTogglesFlexBox;
316 std::unique_ptr<juce::AlertWindow> m_messageBox;
317
318
319 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginControlComponent)
320};
321
322} // namespace Mema
CustomPluginListComponentTableModel(juce::PluginListComponent &c, juce::KnownPluginList &l)
void cellClicked(int rowNumber, int columnId, const juce::MouseEvent &e) override
void paintCell(juce::Graphics &g, int row, int columnId, int width, int height, bool) override
static juce::String getPluginDescription(const juce::PluginDescription &desc)
void sortOrderChanged(int newSortColumnId, bool isForwards) override
void selectedRowsChanged(int lastRowSelected) override
void paintRowBackground(juce::Graphics &g, int, int, int, bool rowIsSelected) override
juce::PluginDescription getPluginDescriptionOfSelectedRow()
void setParameterInfos(const std::vector< PluginParameterInfo > &infos)
void lookAndFeelChanged() override
void setSelectedPlugin(const juce::PluginDescription &pluginDescription)
std::function< void()> onShowPluginEditor
std::function< void(bool)> onPluginPrePostChange
void setPluginEnabled(bool enabled=true)
std::function< void()> onPluginParametersStatusChanged
const std::map< int, Mema::PluginParameterInfo > & getParameterInfos()
std::function< void(bool)> onPluginEnabledChange
std::function< void(const juce::PluginDescription &)> onPluginSelected
void showPluginsList(juce::Point< int > showPosition)
void paint(Graphics &) override
std::function< void(const juce::PluginDescription &)> onPluginSelected
Spacing()=default
void paint(Graphics &g) override
~Spacing()=default
Definition Mema.cpp:27