further progress making TableComponent use valueTree for its model. begin doing the same for Pills.

This commit is contained in:
Alex Birch 2019-07-14 14:19:27 +01:00
parent 4140b3b85b
commit 58574425f3
No known key found for this signature in database
GPG Key ID: 305EB1F98D44ACBA
6 changed files with 316 additions and 166 deletions

View File

@ -7,74 +7,163 @@
using namespace std;
Pill::Pill(
AudioProcessorValueTreeState& valueTreeState,
int bank,
bool isFirst,
bool isLast
)
// : pills{pills}
: bank{bank}
, textButton{String(bank)}
{
textButton.setConnectedEdges (
(isFirst ? 0 : Button::ConnectedOnLeft)
| (isLast ? 0 : Button::ConnectedOnRight)
);
textButton.setRadioGroupId(34567);
loadToggleState();
textButton.setClickingTogglesState(true);
valueTreeState.state.addListener(this);
textButton.addListener(this);
}
Pill::~Pill() {
valueTreeState.state.removeListener(this);
textButton.removeListener(this);
}
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);
}
void Pill::buttonClicked (Button* button) {
// selected = button;
// onItemSelected(itemToIDMapper(button->getName().toStdString()));
RangedAudioParameter *param {valueTreeState.getParameter("bank")};
jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
*castParam = bank;
}
void Pill::parameterChanged(const String& parameterID, float newValue) {
if (parameterID == "bank") {
loadToggleState();
}
}
void Pill::valueTreePropertyChanged(
ValueTree& treeWhosePropertyHasChanged,
const Identifier& property) {
if (treeWhosePropertyHasChanged.getType() == StringRef("presets")) {
loadModelFrom(treeWhosePropertyHasChanged);
}
}
Pills::Pills(
string label,
const vector<string> &items,
const function<void (int)> &onItemSelected,
const function<int (const string&)> &itemToIDMapper,
int initiallySelectedItem
) : label(label),
items(items),
onItemSelected(onItemSelected),
itemToIDMapper(itemToIDMapper)
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)
{
// faster (rounded edges introduce transparency)
setOpaque (true);
populate(initiallySelectedItem);
// populate(initiallySelectedItem);
loadModelFrom(valueTreeState.state.getChildWithName("banks"));
valueTreeState.state.addListener(this);
}
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++;
Pills::~Pills() {
valueTreeState.state.removeListener(this);
}
void Pills::valueTreePropertyChanged(
ValueTree& treeWhosePropertyHasChanged,
const Identifier& property) {
if (treeWhosePropertyHasChanged.getType() == StringRef("banks")) {
loadModelFrom(treeWhosePropertyHasChanged);
}
}
void Pills::setItems(
const vector<string> &items,
int initiallySelectedItem
) {
this->items = items;
for(TextButton* t : buttons) {
t->removeListener(this);
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
// }));
pills.emplace_back(
this.valueTreeState,
num,
i == 0,
i == numChildren - 1);
}
buttons.clear(true);
populate(initiallySelectedItem);
resized();
}
void Pills::buttonClicked (Button* button) {
selected = button;
onItemSelected(itemToIDMapper(button->getName().toStdString()));
}
// 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++;
// }
// }
TextButton* Pills::addToList (TextButton* newButton) {
buttons.add (newButton);
addAndMakeVisible (newButton);
return newButton;
}
// 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;
// }
void Pills::cycle(bool right) {
int currentIx = static_cast<const int>(distance(buttons.begin(), find(buttons.begin(), buttons.end(), selected)));
currentIx += right ? 1 : buttons.size()-1;
buttons[currentIx % buttons.size()]->triggerClick();
// 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();
}
void Pills::resized() {

View File

@ -8,35 +8,81 @@
using namespace std;
class Pills : public Component,
public Button::Listener {
class Pill
: public Button::Listener
, public AudioProcessorValueTreeState::Listener
{
public:
Pills(
string label,
const vector<string> &items,
const function<void (int)> &onItemSelected,
const function<int (const string&)> &itemToIDMapper,
int initiallySelectedItem
);
void setItems(
const vector<string> &items,
int initiallySelectedItem
Pill(
AudioProcessorValueTreeState& valueTreeState,
int bank,
bool isFirst,
bool isLast
);
~Pill();
void buttonClicked (Button* button) override;
virtual void parameterChanged (const String& parameterID, float newValue) override;
private:
void loadToggleState();
AudioProcessorValueTreeState& valueTreeState;
int bank;
TextButton textButton;
friend class Pills;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pill)
}
class Pills
: public Component
, public ValueTree::Listener
{
public:
Pills(
AudioProcessorValueTreeState& valueTreeState
// string label
// const vector<string> &items,
// const function<void (int)> &onItemSelected,
// const function<int (const string&)> &itemToIDMapper,
// int initiallySelectedItem
);
~Pills();
// void setItems(
// const vector<string> &items,
// int initiallySelectedItem
// );
// void buttonClicked (Button* button) override;
void cycle(bool right);
virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged,
const Identifier& property) override;
inline virtual void valueTreeChildAdded (ValueTree& parentTree,
ValueTree& childWhichHasBeenAdded) override {};
inline virtual void valueTreeChildRemoved (ValueTree& parentTree,
ValueTree& childWhichHasBeenRemoved,
int indexFromWhichChildWasRemoved) override {};
inline virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved,
int oldIndex, int newIndex) override {};
inline virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) override {};
inline virtual void valueTreeRedirected (ValueTree& treeWhichHasBeenChanged) override {};
private:
string label;
vector<string> items;
function<void (int)> onItemSelected;
function<int (const string&)> itemToIDMapper;
void loadModelFrom(ValueTree& banks);
OwnedArray<TextButton> buttons;
AudioProcessorValueTreeState& valueTreeState;
// string label;
// vector<string> items;
// function<void (int)> onItemSelected;
// function<int (const string&)> itemToIDMapper;
// OwnedArray<Pill> buttons;
vector<unique_ptr<Pill>> pills;
Button *selected;
TextButton* addToList (TextButton* newButton);
// Pill* addToList (Pill* newButton);
void populate(int initiallySelectedItem);
void resized() override;

View File

@ -20,16 +20,16 @@ TableComponent::TableComponent(
AudioProcessorValueTreeState& valueTreeState,
// const vector<string> &columns,
// const vector<TableRow> &rows,
const function<void (int)> &onRowSelected,
// const function<void (int)> &onRowSelected,
// const function<int (const vector<string>&)> &rowToIDMapper,
int initiallySelectedRow
// int initiallySelectedRow
)
: valueTreeState{valueTreeState}
, font{14.0f}
//, columns{columns}
//, rows{rows}
, onRowSelected{onRowSelected}/*,
rowToIDMapper(rowToIDMapper)*/
// , onRowSelected{onRowSelected}
// rowToIDMapper(rowToIDMapper)
{
// Create our table component and add it to this component..
addAndMakeVisible (table);
@ -73,7 +73,9 @@ rowToIDMapper(rowToIDMapper)*/
table.setWantsKeyboardFocus(false);
table.selectRow(initiallySelectedRow);
// table.selectRow();
loadModelFrom(valueTreeState.state.getChildWithName("presets"));
// selectCurrentPreset();
// we could now change some initial settings..
table.getHeader().setSortColumnId(1, false); // sort ascending by ID column
@ -90,40 +92,38 @@ TableComponent::~TableComponent() {
valueTreeState.state.removeListener(this);
}
// void TableComponent::parameterChanged(const String& parameterID, float newValue) {
// // valueTreeState.getParameter
// RangedAudioParameter *param {valueTreeState.getParameter("bank")};
// if (parameterID == "bank") {
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// int value{castParam->get()};
// } else if (parameterID == "preset") {
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// int value{castParam->get()};
// }
// }
void TableComponent::loadModelFrom(ValueTree& presets) {
rows.clear();
int numChildren{presets.getNumChildren()};
for(int i{0}; i<numChildren; i++) {
ValueTree child{presets.getChild(i)};
int num{child.getProperty("num")};
String name{child.getProperty("name")};
rows.emplace_back(num, name);
}
table.deselectAllRows();
table.updateContent();
table.getHeader().setSortColumnId(0, true);
selectCurrentPreset();
table.repaint();
}
void TableComponent::parameterChanged(const String& parameterID, float newValue) {
// valueTreeState.getParameter
if (parameterID == "preset") {
selectCurrentPreset();
// RangedAudioParameter *param {valueTreeState.getParameter("preset")};
// jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
// AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
// int value{castParam->get()};
}
}
void TableComponent::valueTreePropertyChanged(
ValueTree& treeWhosePropertyHasChanged,
const Identifier& property) {
if (treeWhosePropertyHasChanged.getType() == StringRef("presets")) {
rows.clear();
int numChildren{treeWhosePropertyHasChanged.getNumChildren()};
for(int i{0}; i<numChildren; i++) {
ValueTree child{treeWhosePropertyHasChanged.getChild(i)};
int num{child.getProperty("num")};
String name{child.getProperty("name")};
rows.emplace_back(num, name);
}
// if (&treeWhosePropertyHasChanged == &valueTree) {
// if (property == StringRef("path")) {
// String soundFontPath{treeWhosePropertyHasChanged.getProperty("path", "")};
// DEBUG_PRINT(soundFontPath);
// if (soundFontPath.isNotEmpty()) {
// loadFont(soundFontPath);
// }
// }
loadModelFrom(treeWhosePropertyHasChanged);
}
}
@ -158,6 +158,13 @@ void TableComponent::paintRowBackground (
g.fillAll (alternateColour);
}
String TableRow::getStringContents(int columnId) {
if (columnId <= 1) {
return String(row.preset);
}
return row.name;
}
// This is overloaded from TableListBoxModel, and must paint any cells that aren't using custom
// components.
void TableComponent::paintCell (
@ -172,12 +179,7 @@ void TableComponent::paintCell (
g.setFont (font);
TableRow& row{rows[rowNumber]};
String text;
if (columnId <= 1) {
text = String(row.preset);
} else {
text = row.name;
}
String text{row.getStringContents(columnId)};
g.drawText (text, 2, 0, width - 4, height, Justification::centredLeft, true);
g.setColour (getLookAndFeel().findColour (ListBox::backgroundColourId));
@ -191,7 +193,7 @@ void TableComponent::sortOrderChanged (
bool isForwards
) {
if (newSortColumnId != 0) {
int selectedRowIx = table.getSelectedRow();
// int selectedRowIx = table.getSelectedRow();
// TableRow* selectedRow;
// if (selectedRowIx >= 0) {
// selectedRow = &rows[selectedRowIx];
@ -201,20 +203,32 @@ void TableComponent::sortOrderChanged (
sort(rows.begin(), rows.end(), sorter);
table.updateContent();
selectCurrentPreset();
RangedAudioParameter *param {valueTreeState.getParameter("preset")};
jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
int value{castParam->get()};
// if (selectedRowIx >= 0) {
// for (auto it = rows.begin(); it != rows.end(); ++it) {
// if(it->preset == value) {
// int index {static_cast<int>(std::distance(rows.begin(), it))};
// table.selectRow(index);
// break;
// }
// }
// }
}
}
if (selectedRowIx >= 0) {
for (auto it = rows.begin(); it != rows.end(); ++it) {
if(it->preset == value) {
int index {static_cast<int>(std::distance(rows.begin(), it))};
table.selectRow(index);
break;
}
}
void TableComponent::selectCurrentPreset() {
table.deselectAllRows();
RangedAudioParameter *param {valueTreeState.getParameter("preset")};
jassert(dynamic_cast<AudioParameterInt*> (param) != nullptr);
AudioParameterInt* castParam {dynamic_cast<AudioParameterInt*> (param)};
int value{castParam->get()};
for (auto it = rows.begin(); it != rows.end(); ++it) {
if(it->preset == value) {
int index {static_cast<int>(std::distance(rows.begin(), it))};
table.selectRow(index);
break;
}
}
}
@ -231,12 +245,7 @@ int TableComponent::getColumnAutoSizeWidth (int columnId) {
// find the widest bit of text in this column..
for (int i{getNumRows()}; --i >= 0;) {
TableRow& row{rows[i]};
String text;
if (columnId <= 1) {
text = String(row.preset);
} else {
text = row.name;
}
String text{row.getStringContents(columnId)};
widest = jmax (widest, font.getStringWidth (text));
}
@ -302,5 +311,5 @@ TableRow::TableRow(
String name
)
: preset{preset}
: name{name}
, name{name}
{}

View File

@ -22,6 +22,9 @@ public:
String name
);
private:
/** 1-indexed */
String getStringContents(int columnId);
int preset;
String name;
@ -32,16 +35,16 @@ private:
class TableComponent : public Component,
public TableListBoxModel,
public ValueTree::Listener/*,
public AudioProcessorValueTreeState::Listener */ {
public ValueTree::Listener,
public AudioProcessorValueTreeState::Listener {
public:
TableComponent(
AudioProcessorValueTreeState& valueTreeState,
AudioProcessorValueTreeState& valueTreeState
// const vector<string> &columns,
// const vector<TableRow> &rows,
const function<void (int)> &onRowSelected,
// const function<void (int)> &onRowSelected,
// const function<int (const vector<string>&)> &rowToIDMapper,
int initiallySelectedRow
// int initiallySelectedRow
);
~TableComponent();
@ -75,7 +78,7 @@ public:
bool keyPressed(const KeyPress &key) override;
// virtual void parameterChanged (const String& parameterID, float newValue) override;
virtual void parameterChanged (const String& parameterID, float newValue) override;
virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged,
const Identifier& property) override;
@ -89,6 +92,9 @@ public:
inline virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) override {};
inline virtual void valueTreeRedirected (ValueTree& treeWhichHasBeenChanged) override {};
private:
void loadModelFrom(ValueTree& presets);
void selectCurrentPreset();
AudioProcessorValueTreeState& valueTreeState;
TableListBox table; // the table component itself
@ -97,7 +103,7 @@ private:
// vector<string> columns;
vector<TableRow> rows;
function<void (int)> onRowSelected;
// function<void (int)> onRowSelected;
// function<int (const vector<string>&)> rowToIDMapper;
// A comparator used to sort our data when the user clicks a column header

View File

@ -41,11 +41,11 @@ TablesComponent::TablesComponent(
// banksToPresets,
// selectedBank
// ),
[this](int preset){
this->onPresetSelected(preset);
},
// [this](int preset){
// this->onPresetSelected(preset);
// },
// rowToPresetMapper,
presetToIndexMapper(selectedPreset)
// presetToIndexMapper(selectedPreset)
);
banks = new Pills(
"Banks",
@ -108,19 +108,19 @@ int TablesComponent::presetToIndexMapper(int preset) {
return 0;
}
void TablesComponent::onPresetSelected(int preset) {
if (!initialised || preset == -1) {
return;
}
cout << "Preset " << preset << endl;
// selectedPreset = preset;
fluidSynthModel.changePreset(selectedBank, preset);
}
// void TablesComponent::onPresetSelected(int preset) {
// if (!initialised || preset == -1) {
// return;
// }
// cout << "Preset " << preset << endl;
// // selectedPreset = preset;
// fluidSynthModel.changePreset(selectedBank, preset);
// }
TablesComponent::~TablesComponent() {
delete presetTable;
delete banks;
fluidSynthModel.removeListener(this);
// fluidSynthModel.removeListener(this);
}
vector<string> TablesComponent::mapBanks(const BanksToPresets &banksToPresets) {
@ -138,21 +138,21 @@ vector<string> TablesComponent::mapBanks(const BanksToPresets &banksToPresets) {
}
vector<vector<string>> TablesComponent::mapPresets(const BanksToPresets &banksToPresets, int bank) {
vector<vector<string>> rows;
// vector<vector<string>> TablesComponent::mapPresets(const BanksToPresets &banksToPresets, int bank) {
// vector<vector<string>> rows;
pair<BanksToPresets::const_iterator, BanksToPresets::const_iterator> iterators = banksToPresets.equal_range(bank);
for (auto it = iterators.first; it != iterators.second; ++it) {
Preset b = it->second;
vector<string> row;
row.push_back(to_string(b.getPreset()));
row.push_back(b.getName());
// pair<BanksToPresets::const_iterator, BanksToPresets::const_iterator> iterators = banksToPresets.equal_range(bank);
// for (auto it = iterators.first; it != iterators.second; ++it) {
// Preset b = it->second;
// vector<string> row;
// row.push_back(to_string(b.getPreset()));
// row.push_back(b.getName());
rows.push_back(row);
}
// rows.push_back(row);
// }
return rows;
}
// return rows;
// }
void TablesComponent::resized() {
Rectangle<int> r (getLocalBounds());

View File

@ -35,12 +35,12 @@ private:
FluidSynthModel& fluidSynthModel;
int selectedBank;
Pills* banks;
TableComponent* presetTable;
Pills banks;
TableComponent presetTable;
BanksToPresets banksToPresets;
static vector<vector<string>> mapPresets(const BanksToPresets &banksToPresets, int bank);
// static vector<vector<string>> mapPresets(const BanksToPresets &banksToPresets, int bank);
static vector<string> mapBanks(const BanksToPresets &banksToPresets);
void onBankSelected(int bank);