33 m_parameterControlsGrid = std::make_unique<juce::Grid>();
35 auto noconfigui = juce::JUCEApplication::getInstance()->getCommandLineParameters().contains(
"--noconfigui");
37 m_enableButton = std::make_unique<juce::DrawableButton>(
"pluginEnable", juce::DrawableButton::ImageOnButtonBackground);
38 m_enableButton->setClickingTogglesState(
true);
39 m_enableButton->setTooltip(
"Toggle plugin processing on/off");
40 m_enableButton->onStateChange = [=]() {
45 addChildComponent(m_enableButton.get());
47 addAndMakeVisible(m_enableButton.get());
49 m_prePostButton = std::make_unique<juce::TextButton>(
"Post",
"Toggle plugin pre/post matrix insertion");
50 m_prePostButton->setClickingTogglesState(
true);
51 m_prePostButton->onStateChange = [=]() {
56 addChildComponent(m_prePostButton.get());
58 addAndMakeVisible(m_prePostButton.get());
60 m_pluginNameLabel = std::make_unique<juce::Label>(
"pluginName");
61 m_pluginNameLabel->setFont(m_pluginNameLabel->getFont().withHeight(25));
62 m_pluginNameLabel->setJustificationType(juce::Justification::centredLeft);
63 addAndMakeVisible(m_pluginNameLabel.get());
79 auto bounds = getLocalBounds();
80 auto headerRow = bounds.removeFromTop(margin);
82 const bool enableVisible = m_enableButton && m_enableButton->isVisible();
83 const bool prePostVisible = m_prePostButton && m_prePostButton->isVisible();
85 if (enableVisible || prePostVisible)
88 const int enableBtnWidth = margin;
89 const int prePostBtnWidth = 2 * margin;
91 int totalBtnsWidth = 0;
92 if (enableVisible) totalBtnsWidth += enableBtnWidth;
93 if (prePostVisible) totalBtnsWidth += prePostBtnWidth;
96 const int labelWidth = juce::jmax(80, headerRow.getWidth() / 2);
97 const int groupWidth = totalBtnsWidth + labelWidth;
100 const int groupX = headerRow.getX() + juce::jmax(0, (headerRow.getWidth() - groupWidth) / 2);
101 auto groupBounds = juce::Rectangle<int>(groupX, headerRow.getY(),
102 juce::jmin(groupWidth, headerRow.getWidth()),
103 headerRow.getHeight());
106 m_enableButton->setBounds(groupBounds.removeFromLeft(enableBtnWidth).reduced(2));
108 m_prePostButton->setBounds(groupBounds.removeFromLeft(prePostBtnWidth).reduced(2));
109 if (m_pluginNameLabel)
110 m_pluginNameLabel->setBounds(groupBounds);
114 if (m_pluginNameLabel)
115 m_pluginNameLabel->setBounds(headerRow);
118 bounds.removeFromLeft(margin);
119 bounds.removeFromRight(margin);
120 m_parameterBounds = bounds;
126 auto accentColour = getLookAndFeel().findColour(JUCEAppBasics::CustomLookAndFeel::ColourIds::MeteringRmsColourId);
127 auto textColour = getLookAndFeel().findColour(juce::TextButton::ColourIds::textColourOnId);
129 for (
auto const& comboKV : m_parameterValueComboBoxes)
130 comboKV.second->setColour(juce::ComboBox::ColourIds::focusedOutlineColourId, accentColour);
131 for (
auto const& sliderKV : m_parameterValueSliders)
132 sliderKV.second->setColour(juce::Slider::ColourIds::trackColourId, accentColour);
133 for (
auto const& buttonKV : m_parameterValueButtons)
134 buttonKV.second->setColour(juce::TextButton::ColourIds::buttonOnColourId, accentColour);
138 auto drawable = juce::Drawable::createFromSVG(*juce::XmlDocument::parse(BinaryData::power_settings_24dp_svg).get());
139 drawable->replaceColour(juce::Colours::black, textColour);
140 m_enableButton->setImages(drawable.get(),
nullptr,
nullptr,
nullptr, drawable.get());
207 if (index < m_pluginParameterInfos.size())
209 m_pluginParameterInfos.at(index).currentValue = value;
210 m_pluginParameterInfos.at(index).id = id;
212 if (m_parameterValueComboBoxes.count(index) != 0)
213 m_parameterValueComboBoxes.at(index)->setSelectedId(
int(value * (m_pluginParameterInfos.at(index).stepCount - 1) + 1), juce::dontSendNotification);
214 else if (m_parameterValueSliders.count(index) != 0)
215 m_parameterValueSliders.at(index)->setValue(
float(value), juce::dontSendNotification);
216 else if (m_parameterValueButtons.count(index) != 0)
217 m_parameterValueButtons.at(index)->setToggleState(value > 0.5f, juce::dontSendNotification);
223 for (
auto const& parameterInfo : m_pluginParameterInfos)
225 if (!parameterInfo.isRemoteControllable)
228 if (parameterInfo.type != ParameterControlType::Toggle)
230 if (m_parameterNameLabels.count(parameterInfo.index) != 0)
231 m_parameterNameLabels.at(parameterInfo.index)->setText(parameterInfo.name, juce::dontSendNotification);
234 m_parameterNameLabels[parameterInfo.index] = std::make_unique<juce::Label>(parameterInfo.id);
235 m_parameterNameLabels[parameterInfo.index]->setJustificationType(juce::Justification::centredBottom);
236 m_parameterNameLabels[parameterInfo.index]->setText(parameterInfo.name, juce::dontSendNotification);
237 addAndMakeVisible(m_parameterNameLabels[parameterInfo.index].get());
241 if (parameterInfo.type == ParameterControlType::Discrete)
243 if (m_parameterValueComboBoxes.count(parameterInfo.index) != 0)
244 m_parameterValueComboBoxes.at(parameterInfo.index)->setSelectedId(
int(parameterInfo.currentValue * (parameterInfo.stepCount - 1) + 1), juce::dontSendNotification);
247 m_parameterValueComboBoxes[parameterInfo.index] = std::make_unique<juce::ComboBox>(parameterInfo.id);
248 jassert(parameterInfo.stepCount == parameterInfo.stepNames.size());
250 for (
auto const& stepName : parameterInfo.stepNames)
251 m_parameterValueComboBoxes[parameterInfo.index]->addItem(stepName, i++);
252 m_parameterValueComboBoxes[parameterInfo.index]->setSelectedId(
int(parameterInfo.currentValue * (parameterInfo.stepCount - 1) + 1), juce::dontSendNotification);
253 m_parameterValueComboBoxes[parameterInfo.index]->onChange = [=]() {
254 auto pIdx = parameterInfo.index;
255 if (m_parameterValueComboBoxes.count(pIdx) > 0 && m_pluginParameterInfos.size() > pIdx)
257 auto sId = m_parameterValueComboBoxes[pIdx]->getSelectedId();
258 m_pluginParameterInfos[pIdx].currentValue = float((1.0f / (parameterInfo.stepCount - 1)) * (sId - 1));
264 addAndMakeVisible(m_parameterValueComboBoxes[parameterInfo.index].get());
267 else if (parameterInfo.type == ParameterControlType::Continuous)
269 if (m_parameterValueSliders.count(parameterInfo.index) != 0)
270 m_parameterValueSliders.at(parameterInfo.index)->setValue(parameterInfo.currentValue, juce::dontSendNotification);
273 m_parameterValueSliders[parameterInfo.index] = std::make_unique<JUCEAppBasics::ToggleStateSlider>(juce::Slider::Rotary, juce::Slider::NoTextBox);
274 m_parameterValueSliders[parameterInfo.index]->setSliderStyle(juce::Slider::SliderStyle::Rotary);
275 m_parameterValueSliders[parameterInfo.index]->setTogglalbe(
false);
276 m_parameterValueSliders[parameterInfo.index]->setRange(parameterInfo.minValue, parameterInfo.maxValue);
277 m_parameterValueSliders[parameterInfo.index]->setValue(parameterInfo.currentValue, juce::dontSendNotification);
278 m_parameterValueSliders[parameterInfo.index]->onValueChange = [=]() {
279 auto pIdx = parameterInfo.index;
280 if (m_parameterValueSliders.count(pIdx) > 0 && m_pluginParameterInfos.size() > pIdx)
282 auto value = float(m_parameterValueSliders[pIdx]->getValue());
283 m_pluginParameterInfos[pIdx].currentValue = value;
289 addAndMakeVisible(m_parameterValueSliders[parameterInfo.index].get());
292 else if (parameterInfo.type == ParameterControlType::Toggle)
294 if (m_parameterValueButtons.count(parameterInfo.index) != 0)
295 m_parameterValueButtons.at(parameterInfo.index)->setToggleState(parameterInfo.currentValue > 0.5f, juce::dontSendNotification);
298 m_parameterValueButtons[parameterInfo.index] = std::make_unique<juce::TextButton>(parameterInfo.name,
"Toggle to enable or disable parameter.");
299 m_parameterValueButtons[parameterInfo.index]->setClickingTogglesState(
true);
300 m_parameterValueButtons[parameterInfo.index]->setToggleState(parameterInfo.currentValue > 0.5f, juce::dontSendNotification);
301 m_parameterValueButtons[parameterInfo.index]->onStateChange = [=]() {
302 auto pIdx = parameterInfo.index;
303 if (m_parameterValueButtons.count(pIdx) > 0 && m_pluginParameterInfos.size() > pIdx)
305 auto value = float(m_parameterValueButtons[pIdx]->getToggleState() ? 1.0f : 0.0f);
306 m_pluginParameterInfos[pIdx].currentValue = value;
312 addAndMakeVisible(m_parameterValueButtons[parameterInfo.index].get());
322 auto bounds = m_parameterBounds;
323 if (bounds.isEmpty())
326 auto itemCount = int(m_parameterValueComboBoxes.size() + m_parameterValueSliders.size() + m_parameterValueButtons.size());
331 const int labelHeight = 30;
332 const int controlMargin = 5;
333 const int rowPairHeight = labelHeight + gridItemControlSize;
335 const int availableWidth = bounds.getWidth();
336 const int availableHeight = bounds.getHeight();
337 const float availableAspect = float(availableWidth) / float(juce::jmax(1, availableHeight));
340 const int maxItemsPerRow = juce::jmin(itemCount, juce::jmax(1, availableWidth / gridItemControlSize));
342 float bestAspectDiff = std::numeric_limits<float>::max();
343 for (
int n = 1; n <= maxItemsPerRow; ++n)
345 int rows =
static_cast<int>(std::ceil(
float(itemCount) /
float(n)));
346 float layoutAspect = float(n * gridItemControlSize) / float(juce::jmax(1, rows * rowPairHeight));
347 float diff = std::abs(layoutAspect - availableAspect);
348 if (diff < bestAspectDiff)
350 bestAspectDiff = diff;
355 const int numRowPairs =
static_cast<int>(std::ceil(
float(itemCount) /
float(itemsPerRow)));
356 const int totalGridWidth = itemsPerRow * gridItemControlSize;
357 const int totalGridHeight = numRowPairs * rowPairHeight;
360 auto gridBounds = juce::Rectangle<int>(
361 bounds.getX() + juce::jmax(0, (availableWidth - totalGridWidth) / 2),
362 bounds.getY() + juce::jmax(0, (availableHeight - totalGridHeight) / 2),
363 juce::jmin(totalGridWidth, availableWidth),
364 juce::jmin(totalGridHeight, availableHeight));
367 m_parameterControlsGrid->templateRows.clear();
368 m_parameterControlsGrid->templateColumns.clear();
369 m_parameterControlsGrid->items.clear();
371 for (
int i = 0; i < numRowPairs; ++i)
373 m_parameterControlsGrid->templateRows.add(juce::Grid::TrackInfo(juce::Grid::Px(labelHeight)));
374 m_parameterControlsGrid->templateRows.add(juce::Grid::TrackInfo(juce::Grid::Px(gridItemControlSize)));
376 for (
int i = 0; i < itemsPerRow; ++i)
377 m_parameterControlsGrid->templateColumns.add(juce::Grid::TrackInfo(juce::Grid::Px(gridItemControlSize)));
382 for (
auto const& parameterInfo : m_pluginParameterInfos)
384 if (!parameterInfo.isRemoteControllable)
387 int row = (currentItem / itemsPerRow) * 2;
388 int col = currentItem % itemsPerRow;
390 if (parameterInfo.type == ParameterControlType::Toggle)
392 auto buttonIter = m_parameterValueButtons.find(parameterInfo.index);
393 if (buttonIter == m_parameterValueButtons.end() || !buttonIter->second)
395 auto* button = buttonIter->second.get();
396 auto buttonSize = float(gridItemControlSize - (controlMargin * 2));
398 m_parameterControlsGrid->items.add(juce::GridItem(*button)
399 .withArea(row + 2, col + 1)
400 .withMargin(juce::GridItem::Margin(controlMargin))
401 .withWidth(buttonSize)
402 .withHeight(buttonSize)
403 .withJustifySelf(juce::GridItem::JustifySelf::center)
404 .withAlignSelf(juce::GridItem::AlignSelf::center));
406 else if (parameterInfo.type == ParameterControlType::Discrete)
408 auto comboIter = m_parameterValueComboBoxes.find(parameterInfo.index);
409 auto labelIter = m_parameterNameLabels.find(parameterInfo.index);
410 if (comboIter == m_parameterValueComboBoxes.end() || !comboIter->second)
412 if (labelIter == m_parameterNameLabels.end() || !labelIter->second)
415 m_parameterControlsGrid->items.add(juce::GridItem(*labelIter->second)
416 .withArea(row + 1, col + 1)
417 .withMargin(juce::GridItem::Margin(2.0f)));
418 m_parameterControlsGrid->items.add(juce::GridItem(*comboIter->second)
419 .withArea(row + 2, col + 1)
420 .withMargin(juce::GridItem::Margin(controlMargin))
422 .withJustifySelf(juce::GridItem::JustifySelf::center)
423 .withAlignSelf(juce::GridItem::AlignSelf::center));
425 else if (parameterInfo.type == ParameterControlType::Continuous)
427 auto sliderIter = m_parameterValueSliders.find(parameterInfo.index);
428 auto labelIter = m_parameterNameLabels.find(parameterInfo.index);
429 if (sliderIter == m_parameterValueSliders.end() || !sliderIter->second)
431 if (labelIter == m_parameterNameLabels.end() || !labelIter->second)
433 auto sliderSize = float(gridItemControlSize - (controlMargin * 2));
435 m_parameterControlsGrid->items.add(juce::GridItem(*labelIter->second)
436 .withArea(row + 1, col + 1)
437 .withMargin(juce::GridItem::Margin(2.0f)));
438 m_parameterControlsGrid->items.add(juce::GridItem(*sliderIter->second)
439 .withArea(row + 2, col + 1)
440 .withMargin(juce::GridItem::Margin(controlMargin))
441 .withWidth(sliderSize)
442 .withHeight(sliderSize)
443 .withJustifySelf(juce::GridItem::JustifySelf::center)
444 .withAlignSelf(juce::GridItem::AlignSelf::center));
450 m_parameterControlsGrid->performLayout(gridBounds);