commit 6015028cc667da1a1e8f81616eeab864daa2e0fb
parent 4b1da5c976c9c2c97af72f9b69e58e3b1c03344c
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Thu, 30 May 2024 16:51:29 +0200
add copy/paste support for parameter regions
Diffstat:
6 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/source/jucePluginEditorLib/pluginEditor.cpp b/source/jucePluginEditorLib/pluginEditor.cpp
@@ -257,8 +257,129 @@ namespace jucePluginEditorLib
if(!_event || !_event->originalComponent)
return false;
- // TODO
- return false;
+ const auto* param = m_binding.getBoundParameter(_event->originalComponent);
+ if(!param)
+ return false;
+
+ const auto& controller = m_processor.getController();
+
+ const auto& regions = controller.getParameterDescriptions().getRegions();
+ const auto paramRegionIds = controller.getRegionIdsForParameter(param);
+
+ if(paramRegionIds.empty())
+ return false;
+
+ juce::PopupMenu menu;
+
+ for (const auto& regionId : paramRegionIds)
+ {
+ const auto& regionName = regions.find(regionId)->second.getName();
+
+ menu.addItem(std::string("Copy region '") + regionName + "'", [this, regionId]
+ {
+ copyRegionToClipboard(regionId);
+ });
+ }
+
+ const auto data = pluginLib::Clipboard::getDataFromString(m_processor, juce::SystemClipboard::getTextFromClipboard().toStdString());
+
+ if(!data.parameterValuesByRegion.empty())
+ {
+ bool haveSeparator = false;
+
+ for (const auto& paramRegionId : paramRegionIds)
+ {
+ const auto it = data.parameterValuesByRegion.find(paramRegionId);
+
+ if(it == data.parameterValuesByRegion.end())
+ continue;
+
+ // if region is not fully covered, skip it
+ const auto& region = regions.find(it->first)->second;
+ if(it->second.size() < region.getParams().size())
+ continue;
+
+ const auto& parameterValues = it->second;
+
+ if(!haveSeparator)
+ {
+ menu.addSeparator();
+ haveSeparator = true;
+ }
+
+ const auto& regionName = regions.find(paramRegionId)->second.getName();
+
+ menu.addItem("Paste region '" + regionName + "'", [this, parameterValues]
+ {
+ setParameters(parameterValues);
+ });
+ }
+
+ menu.addSeparator();
+
+ const auto& desc = param->getDescription();
+ const auto& paramName = desc.name;
+
+ const auto itParam = data.parameterValues.find(paramName);
+
+ if(itParam != data.parameterValues.end())
+ {
+ const auto& paramValue = itParam->second;
+
+ const auto& valueText = desc.valueList.valueToText(paramValue);
+
+ menu.addItem("Paste value '" + valueText + "' for parameter '" + desc.displayName + "'", [this, paramName, paramValue]
+ {
+ pluginLib::Clipboard::Data::ParameterValues params;
+ params.insert({paramName, paramValue});
+ setParameters(params);
+ });
+ }
+ }
+
+ menu.showMenuAsync({});
+
+ return true;
+ }
+
+ bool Editor::copyRegionToClipboard(const std::string& _regionId) const
+ {
+ const auto& regions = m_processor.getController().getParameterDescriptions().getRegions();
+ const auto it = regions.find(_regionId);
+ if(it == regions.end())
+ return false;
+
+ const auto& region = it->second;
+
+ const auto& params = region.getParams();
+
+ std::vector<std::string> paramsList;
+ paramsList.reserve(params.size());
+
+ for (const auto& p : params)
+ paramsList.push_back(p.first);
+
+ return copyParametersToClipboard(paramsList, _regionId);
+ }
+
+ bool Editor::copyParametersToClipboard(const std::vector<std::string>& _params, const std::string& _regionId) const
+ {
+ const auto result = pluginLib::Clipboard::parametersToString(m_processor, _params, _regionId);
+
+ if(result.empty())
+ return false;
+
+ juce::SystemClipboard::copyTextToClipboard(result);
+
+ return true;
+ }
+
+ bool Editor::setParameters(const std::map<std::string, uint8_t>& _paramValues) const
+ {
+ if(_paramValues.empty())
+ return false;
+
+ return getProcessor().getController().setParameters(_paramValues, m_processor.getController().getCurrentPart(), pluginLib::Parameter::ChangedBy::Ui);
}
bool Editor::keyPressed(const juce::KeyPress& _key)
diff --git a/source/jucePluginEditorLib/pluginEditor.h b/source/jucePluginEditorLib/pluginEditor.h
@@ -72,6 +72,10 @@ namespace jucePluginEditorLib
virtual void openMenu(juce::MouseEvent* _event);
virtual bool openContextMenuForParameter(const juce::MouseEvent* _event);
+ bool copyRegionToClipboard(const std::string& _regionId) const;
+ bool copyParametersToClipboard(const std::vector<std::string>& _params, const std::string& _regionId = {}) const;
+ bool setParameters(const std::map<std::string, uint8_t>& _paramValues) const;
+
private:
bool keyPressed(const juce::KeyPress& _key) override;
diff --git a/source/jucePluginLib/controller.cpp b/source/jucePluginLib/controller.cpp
@@ -301,6 +301,28 @@ namespace pluginLib
return m_descriptions.getIndexByName(index, _name) ? index : InvalidParameterIndex;
}
+ bool Controller::setParameters(const std::map<std::string, uint8_t>& _values, const uint8_t _part, const Parameter::ChangedBy _changedBy) const
+ {
+ bool res = false;
+
+ for (const auto& it : _values)
+ {
+ const auto& name = it.first;
+ const auto& value = it.second;
+
+ const auto index = getParameterIndexByName(name);
+ auto* param = getParameter(index, _part);
+
+ if(param)
+ {
+ res = true;
+ param->setUnnormalizedValue(value, _changedBy);
+ }
+ }
+
+ return res;
+ }
+
const MidiPacket* Controller::getMidiPacket(const std::string& _name) const
{
return m_descriptions.getMidiPacket(_name);
diff --git a/source/jucePluginLib/controller.h b/source/jucePluginLib/controller.h
@@ -36,6 +36,8 @@ namespace pluginLib
uint32_t getParameterIndexByName(const std::string& _name) const;
+ bool setParameters(const std::map<std::string, uint8_t>& _values, uint8_t _part, Parameter::ChangedBy _changedBy) const;
+
const MidiPacket* getMidiPacket(const std::string& _name) const;
bool createNamedParamValues(MidiPacket::NamedParamValues& _params, const std::string& _packetName, uint8_t _part) const;
diff --git a/source/jucePluginLib/parameter.cpp b/source/jucePluginLib/parameter.cpp
@@ -155,6 +155,12 @@ namespace pluginLib
m_changingDerivedValues = false;
}
+ void Parameter::setUnnormalizedValue(const int _newValue, const ChangedBy _origin)
+ {
+ const auto v = convertTo0to1(static_cast<float>(_newValue));
+ setValue(v, _origin);
+ }
+
void Parameter::setValueFromSynth(int newValue, const bool notifyHost, ChangedBy _origin)
{
const auto clampedValue = juce::roundToInt(m_range.getRange().clipValue(static_cast<float>(newValue)));
diff --git a/source/jucePluginLib/parameter.h b/source/jucePluginLib/parameter.h
@@ -42,6 +42,7 @@ namespace pluginLib
int getUnnormalizedValue() const { return juce::roundToInt(m_value.getValue()); }
void setValue(float _newValue) override;
void setValue(float _newValue, ChangedBy _origin);
+ void setUnnormalizedValue(int _newValue, ChangedBy _origin);
void setValueFromSynth(int newValue, bool notifyHost, ChangedBy _origin);
bool isDiscrete() const override { return m_desc.isDiscrete; }