2018-02-27 08:25:20 +08:00
|
|
|
//
|
|
|
|
// Created by Alex Birch on 01/10/2017.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "Pills.h"
|
|
|
|
#include "MyColours.h"
|
2019-07-15 00:22:36 +08:00
|
|
|
#include <algorithm>
|
2018-02-27 08:25:20 +08:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2019-07-14 21:19:27 +08:00
|
|
|
Pill::Pill(
|
|
|
|
AudioProcessorValueTreeState& valueTreeState,
|
|
|
|
int bank,
|
|
|
|
bool isFirst,
|
|
|
|
bool isLast
|
|
|
|
)
|
|
|
|
// : pills{pills}
|
2019-07-15 00:22:36 +08:00
|
|
|
: valueTreeState{valueTreeState}
|
|
|
|
, bank{bank}
|
2019-07-14 21:19:27 +08:00
|
|
|
, textButton{String(bank)}
|
|
|
|
{
|
2019-07-15 02:31:05 +08:00
|
|
|
setOpaque(true);
|
2019-07-14 21:19:27 +08:00
|
|
|
textButton.setConnectedEdges (
|
|
|
|
(isFirst ? 0 : Button::ConnectedOnLeft)
|
|
|
|
| (isLast ? 0 : Button::ConnectedOnRight)
|
|
|
|
);
|
|
|
|
textButton.setRadioGroupId(34567);
|
2019-07-21 22:04:19 +08:00
|
|
|
// loadToggleState();
|
2019-07-14 21:19:27 +08:00
|
|
|
textButton.setClickingTogglesState(true);
|
2019-07-15 02:31:05 +08:00
|
|
|
|
|
|
|
addAndMakeVisible(textButton);
|
2019-07-14 21:19:27 +08:00
|
|
|
|
2019-07-21 22:04:19 +08:00
|
|
|
// valueTreeState.addParameterListener("bank", this);
|
2019-07-15 00:22:36 +08:00
|
|
|
// valueTreeState.state.addListener(this);
|
2019-07-14 21:19:27 +08:00
|
|
|
textButton.addListener(this);
|
|
|
|
}
|
|
|
|
|
2019-07-21 22:04:19 +08:00
|
|
|
void Pill::paint (Graphics& g) {
|
2019-07-15 02:31:05 +08:00
|
|
|
// (Our component is opaque, so we must completely fill the background with a solid colour)
|
2019-07-21 22:04:19 +08:00
|
|
|
g.fillAll(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));
|
2019-07-15 02:31:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Pill::resized() {
|
|
|
|
textButton.setBounds(getLocalBounds());
|
|
|
|
}
|
|
|
|
|
2019-07-14 21:19:27 +08:00
|
|
|
Pill::~Pill() {
|
2019-07-21 22:04:19 +08:00
|
|
|
// valueTreeState.removeParameterListener("bank", this);
|
2019-07-15 00:22:36 +08:00
|
|
|
// valueTreeState.state.removeListener(this);
|
2019-07-14 21:19:27 +08:00
|
|
|
textButton.removeListener(this);
|
|
|
|
}
|
|
|
|
|
2019-07-21 22:04:19 +08:00
|
|
|
void Pill::bankChanged(int bank) {
|
|
|
|
textButton.setToggleState(this->bank == bank, dontSendNotification);
|
2019-07-14 21:19:27 +08:00
|
|
|
}
|
|
|
|
|
2019-07-21 22:04:19 +08:00
|
|
|
// void Pill::loadToggleState() {
|
|
|
|
// RangedAudioParameter *param {valueTreeState.getParameter("bank")};
|
|
|
|
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
|
|
|
|
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
|
|
|
|
// int value{castParam->get()};
|
|
|
|
// textButton.setToggleState(value == bank, dontSendNotification);
|
|
|
|
// }
|
|
|
|
|
2019-07-21 23:25:22 +08:00
|
|
|
void Pill::buttonClicked(Button* button) {
|
|
|
|
ValueTree banks{valueTreeState.state.getChildWithName("banks")};
|
|
|
|
int banksChildren{banks.getNumChildren()};
|
|
|
|
ValueTree bank;
|
|
|
|
for(int bankIx{0}; bankIx<banksChildren; bankIx++) {
|
|
|
|
ValueTree currentBank{banks.getChild(bankIx)};
|
|
|
|
int bankNum{currentBank.getProperty("num")};
|
|
|
|
if (bankNum == this->bank) {
|
|
|
|
bank = currentBank;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ValueTree preset{bank.getChild(0)};
|
|
|
|
int presetNum{preset.getProperty("num")};
|
|
|
|
|
2019-07-14 21:19:27 +08:00
|
|
|
// selected = button;
|
|
|
|
// onItemSelected(itemToIDMapper(button->getName().toStdString()));
|
2019-07-21 23:25:22 +08:00
|
|
|
{
|
|
|
|
RangedAudioParameter *param{valueTreeState.getParameter("bank")};
|
|
|
|
jassert(dynamic_cast<AudioParameterInt*>(param) != nullptr);
|
|
|
|
AudioParameterInt* castParam{dynamic_cast<AudioParameterInt*>(param)};
|
|
|
|
*castParam = this->bank;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
RangedAudioParameter *param{valueTreeState.getParameter("preset")};
|
|
|
|
jassert(dynamic_cast<AudioParameterInt*>(param) != nullptr);
|
|
|
|
AudioParameterInt* castParam{dynamic_cast<AudioParameterInt*>(param)};
|
|
|
|
*castParam = presetNum;
|
|
|
|
}
|
2019-07-14 21:19:27 +08:00
|
|
|
}
|
|
|
|
|
2019-07-21 22:04:19 +08:00
|
|
|
// void Pill::parameterChanged(const String& parameterID, float newValue) {
|
|
|
|
// if (parameterID == "bank") {
|
|
|
|
// loadToggleState();
|
|
|
|
// }
|
|
|
|
// }
|
2019-07-14 21:19:27 +08:00
|
|
|
|
2019-07-15 00:22:36 +08:00
|
|
|
// void Pill::valueTreePropertyChanged(
|
|
|
|
// ValueTree& treeWhosePropertyHasChanged,
|
|
|
|
// const Identifier& property) {
|
|
|
|
// if (treeWhosePropertyHasChanged.getType() == StringRef("presets")) {
|
|
|
|
// loadModelFrom(treeWhosePropertyHasChanged);
|
|
|
|
// }
|
|
|
|
// }
|
2019-07-14 21:19:27 +08:00
|
|
|
|
2018-02-27 08:25:20 +08:00
|
|
|
Pills::Pills(
|
2019-07-14 21:19:27 +08:00
|
|
|
AudioProcessorValueTreeState& valueTreeState
|
|
|
|
// string label,
|
|
|
|
// const vector<string> &items,
|
|
|
|
// const function<void (int)> &onItemSelected,
|
|
|
|
// const function<int (const string&)> &itemToIDMapper,
|
|
|
|
// int initiallySelectedItem
|
|
|
|
)
|
|
|
|
: valueTreeState{valueTreeState}
|
|
|
|
// , label{label}
|
|
|
|
// items(items),
|
|
|
|
// onItemSelected(onItemSelected),
|
|
|
|
// itemToIDMapper(itemToIDMapper)
|
2018-02-27 08:25:20 +08:00
|
|
|
{
|
|
|
|
// faster (rounded edges introduce transparency)
|
|
|
|
setOpaque (true);
|
|
|
|
|
2019-07-14 21:19:27 +08:00
|
|
|
// populate(initiallySelectedItem);
|
2019-07-15 00:22:36 +08:00
|
|
|
ValueTree banks{valueTreeState.state.getChildWithName("banks")};
|
|
|
|
loadModelFrom(banks);
|
2019-07-14 21:19:27 +08:00
|
|
|
|
|
|
|
valueTreeState.state.addListener(this);
|
2019-07-21 22:04:19 +08:00
|
|
|
valueTreeState.addParameterListener("bank", this);
|
2018-02-27 08:25:20 +08:00
|
|
|
}
|
|
|
|
|
2019-07-14 21:19:27 +08:00
|
|
|
Pills::~Pills() {
|
2019-07-21 22:04:19 +08:00
|
|
|
valueTreeState.removeParameterListener("bank", this);
|
2019-07-14 21:19:27 +08:00
|
|
|
valueTreeState.state.removeListener(this);
|
2018-02-27 08:25:20 +08:00
|
|
|
}
|
|
|
|
|
2019-07-21 22:04:19 +08:00
|
|
|
void Pills::parameterChanged(const String& parameterID, float newValue) {
|
|
|
|
if (parameterID == "bank") {
|
|
|
|
updatePillToggleStates();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Pills::updatePillToggleStates() {
|
|
|
|
RangedAudioParameter *param {valueTreeState.getParameter("bank")};
|
|
|
|
jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
|
|
|
|
AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
|
|
|
|
int bank{castParam->get()};
|
|
|
|
for (auto& pill: pills) {
|
|
|
|
pill->bankChanged(bank);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-14 21:19:27 +08:00
|
|
|
void Pills::valueTreePropertyChanged(
|
|
|
|
ValueTree& treeWhosePropertyHasChanged,
|
|
|
|
const Identifier& property) {
|
|
|
|
if (treeWhosePropertyHasChanged.getType() == StringRef("banks")) {
|
2019-07-15 02:31:05 +08:00
|
|
|
if (property == StringRef("synthetic")) {
|
|
|
|
loadModelFrom(treeWhosePropertyHasChanged);
|
|
|
|
}
|
2018-02-27 08:25:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-14 21:19:27 +08:00
|
|
|
void Pills::loadModelFrom(ValueTree& banks) {
|
|
|
|
pills.clear();
|
|
|
|
int numChildren{banks.getNumChildren()};
|
|
|
|
for(int i{0}; i < numChildren; i++) {
|
|
|
|
ValueTree child{banks.getChild(i)};
|
|
|
|
int num{child.getProperty("num")};
|
|
|
|
// rows.push_back(unique_ptr<Pill>(new Pill(), [](Pill* pill) {
|
|
|
|
// pill->remo
|
|
|
|
// }));
|
2019-07-15 02:31:05 +08:00
|
|
|
unique_ptr<Pill> pill{make_unique<Pill>(
|
2019-07-15 00:22:36 +08:00
|
|
|
valueTreeState,
|
2019-07-14 21:19:27 +08:00
|
|
|
num,
|
|
|
|
i == 0,
|
2019-07-15 02:31:05 +08:00
|
|
|
i == numChildren - 1)};
|
|
|
|
addAndMakeVisible(pill.get());
|
|
|
|
pills.push_back(move(pill));
|
2019-07-14 21:19:27 +08:00
|
|
|
}
|
2019-07-21 22:04:19 +08:00
|
|
|
updatePillToggleStates();
|
2019-07-15 02:31:05 +08:00
|
|
|
resized();
|
2018-02-27 08:25:20 +08:00
|
|
|
}
|
|
|
|
|
2019-07-14 21:19:27 +08:00
|
|
|
// void Pills::populate(int initiallySelectedItem) {
|
|
|
|
// int index = 0;
|
|
|
|
// for (string item : items) {
|
|
|
|
// TextButton* pill = addToList(new TextButton(
|
|
|
|
// item
|
|
|
|
// ));
|
|
|
|
// // pill->setColour (TextButton::buttonOnColourId, Colours::blueviolet.brighter());
|
|
|
|
// // pill->setBounds(20 + index * 55, 260, 55, 24);
|
|
|
|
// pill->setConnectedEdges (
|
|
|
|
// (index == 0 ? 0 : Button::ConnectedOnLeft)
|
|
|
|
// | (index == (items.size()-1) ? 0 : Button::ConnectedOnRight)
|
|
|
|
// );
|
|
|
|
// pill->setRadioGroupId(34567);
|
|
|
|
// if (index == initiallySelectedItem) {
|
|
|
|
// pill->setToggleState(true, dontSendNotification);
|
|
|
|
// selected = pill;
|
|
|
|
// }
|
|
|
|
// pill->setClickingTogglesState(true);
|
|
|
|
// pill->addListener(this);
|
|
|
|
// index++;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// void Pills::setItems(
|
|
|
|
// const vector<string> &items,
|
|
|
|
// int initiallySelectedItem
|
|
|
|
// ) {
|
|
|
|
// this->items = items;
|
|
|
|
// for(TextButton* t : buttons) {
|
|
|
|
// t->removeListener(this);
|
|
|
|
// }
|
|
|
|
// buttons.clear(true);
|
|
|
|
// populate(initiallySelectedItem);
|
|
|
|
// resized();
|
|
|
|
// }
|
|
|
|
|
|
|
|
// TextButton* Pills::addToList (TextButton* newButton) {
|
|
|
|
// buttons.add (newButton);
|
|
|
|
// addAndMakeVisible (newButton);
|
|
|
|
// return newButton;
|
|
|
|
// }
|
2018-02-27 08:25:20 +08:00
|
|
|
|
|
|
|
void Pills::cycle(bool right) {
|
2019-07-15 00:22:36 +08:00
|
|
|
RangedAudioParameter *param {valueTreeState.getParameter("bank")};
|
|
|
|
jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
|
|
|
|
AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
|
2019-07-21 23:25:22 +08:00
|
|
|
int bank{castParam->get()};
|
2019-07-15 00:22:36 +08:00
|
|
|
|
2019-07-21 23:25:22 +08:00
|
|
|
// ValueTree banks{valueTreeState.state.getChildWithName("banks")};
|
2019-07-15 00:22:36 +08:00
|
|
|
// int numChildren{banks.getNumChildren()};
|
|
|
|
|
2019-07-21 23:25:22 +08:00
|
|
|
// vector<int> bankInts;
|
|
|
|
// bankInts.resize(banks.getNumChildren());
|
2019-07-15 00:22:36 +08:00
|
|
|
|
2019-07-21 23:25:22 +08:00
|
|
|
// transform(banks.begin(), banks.end(), bankInts.begin(), [](ValueTree bank) -> int {
|
|
|
|
// return bank.getProperty("num");
|
|
|
|
// });
|
2019-07-15 00:22:36 +08:00
|
|
|
|
2019-07-21 23:25:22 +08:00
|
|
|
// int closestBank{bank};
|
2019-07-15 00:22:36 +08:00
|
|
|
// for(int i{0}; i < numChildren; i++) {
|
|
|
|
// ValueTree child{banks.getChild(i)};
|
|
|
|
// int proposedBank{child.getProperty("num")};
|
2019-07-21 23:25:22 +08:00
|
|
|
// if (right && proposedBank > bank) {
|
2019-07-15 00:22:36 +08:00
|
|
|
// closestBank = jmin(closestBank, proposedBank);
|
|
|
|
// } else if (left )
|
|
|
|
// }
|
|
|
|
|
2019-07-21 23:25:22 +08:00
|
|
|
// int currentIx{static_cast<const int>(distance(bankInts.begin(), find(bankInts.begin(), bankInts.end(), currentlySelectedBank)))};
|
|
|
|
// currentIx += right ? 1 : pills.size()-1;
|
|
|
|
// // pills[currentIx % pills.size()]->textButton.triggerClick();
|
|
|
|
// *castParam = bankInts[currentIx % bankInts.size()];
|
|
|
|
|
|
|
|
int currentIx = static_cast<const int>(
|
|
|
|
distance(
|
|
|
|
pills.begin(),
|
|
|
|
find_if(
|
|
|
|
pills.begin(),
|
|
|
|
pills.end(),
|
|
|
|
[bank](unique_ptr<Pill>& pill){return pill->bank == bank;})));
|
2019-07-14 21:19:27 +08:00
|
|
|
currentIx += right ? 1 : pills.size()-1;
|
2019-07-21 23:25:22 +08:00
|
|
|
pills[currentIx % pills.size()]->textButton.triggerClick();
|
2019-07-15 00:22:36 +08:00
|
|
|
|
|
|
|
|
|
|
|
// TODO: base this on valueTree
|
|
|
|
// int currentIx = static_cast<const int>(distance(pills.begin(), find(pills.begin(), pills.end(), selected)));
|
|
|
|
// currentIx += right ? 1 : pills.size()-1;
|
|
|
|
// pills[currentIx % pills.size()]->textButton.triggerClick();
|
2018-02-27 08:25:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Pills::resized() {
|
|
|
|
int index = 0;
|
|
|
|
Rectangle<int> r (getLocalBounds());
|
2019-07-15 00:22:36 +08:00
|
|
|
const int equalWidth = r.proportionOfWidth(pills.size() <= 0 ? 1.0 : 1.0f/pills.size());
|
|
|
|
for(auto& pill : pills) {
|
2018-02-27 08:25:20 +08:00
|
|
|
Rectangle<int> r2 (getLocalBounds());
|
|
|
|
r2.removeFromLeft(equalWidth * index);
|
2019-07-15 00:22:36 +08:00
|
|
|
r2.removeFromRight(equalWidth * (static_cast<int>(pills.size())-index-1));
|
2019-07-15 02:31:05 +08:00
|
|
|
pill->setBounds(r2);
|
2018-02-27 08:25:20 +08:00
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is required to support setOpaque(true)
|
|
|
|
*/
|
|
|
|
void Pills::paint(Graphics& g)
|
|
|
|
{
|
|
|
|
g.fillAll(MyColours::getUIColourIfAvailable(LookAndFeel_V4::ColourScheme::UIColour::windowBackground, Colours::lightgrey));
|
2019-07-15 00:22:36 +08:00
|
|
|
}
|