From 58574425f350d6f1465dc26dfd0515ec261c479f Mon Sep 17 00:00:00 2001 From: Alex Birch Date: Sun, 14 Jul 2019 14:19:27 +0100 Subject: [PATCH] further progress making TableComponent use valueTree for its model. begin doing the same for Pills. --- Source/Pills.cpp | 193 +++++++++++++++++++++++++++---------- Source/Pills.h | 84 ++++++++++++---- Source/TableComponent.cpp | 129 +++++++++++++------------ Source/TableComponent.h | 20 ++-- Source/TablesComponent.cpp | 50 +++++----- Source/TablesComponent.h | 6 +- 6 files changed, 316 insertions(+), 166 deletions(-) diff --git a/Source/Pills.cpp b/Source/Pills.cpp index 6e5afc5..438f7a6 100644 --- a/Source/Pills.cpp +++ b/Source/Pills.cpp @@ -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 (param) != nullptr); + AudioParameterInt* castParam {dynamic_cast (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 (param) != nullptr); + AudioParameterInt* castParam {dynamic_cast (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 &items, - const function &onItemSelected, - const function &itemToIDMapper, - int initiallySelectedItem -) : label(label), - items(items), - onItemSelected(onItemSelected), - itemToIDMapper(itemToIDMapper) + AudioProcessorValueTreeState& valueTreeState + // string label, + // const vector &items, + // const function &onItemSelected, + // const function &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 &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(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 &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(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(distance(pills.begin(), find(pills.begin(), pills.end(), selected))); + currentIx += right ? 1 : pills.size()-1; + pills[currentIx % pills.size()]->textButton.triggerClick(); } void Pills::resized() { diff --git a/Source/Pills.h b/Source/Pills.h index 530a0eb..1440ae1 100644 --- a/Source/Pills.h +++ b/Source/Pills.h @@ -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 &items, - const function &onItemSelected, - const function &itemToIDMapper, - int initiallySelectedItem - ); - - void setItems( - const vector &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 &items, + // const function &onItemSelected, + // const function &itemToIDMapper, + // int initiallySelectedItem + ); + ~Pills(); + + // void setItems( + // const vector &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 items; - function onItemSelected; - function itemToIDMapper; + void loadModelFrom(ValueTree& banks); - OwnedArray buttons; + AudioProcessorValueTreeState& valueTreeState; + // string label; + // vector items; + // function onItemSelected; + // function itemToIDMapper; + + // OwnedArray buttons; + vector> pills; Button *selected; - TextButton* addToList (TextButton* newButton); + // Pill* addToList (Pill* newButton); void populate(int initiallySelectedItem); void resized() override; diff --git a/Source/TableComponent.cpp b/Source/TableComponent.cpp index 8888c18..0023c4b 100644 --- a/Source/TableComponent.cpp +++ b/Source/TableComponent.cpp @@ -20,16 +20,16 @@ TableComponent::TableComponent( AudioProcessorValueTreeState& valueTreeState, // const vector &columns, // const vector &rows, - const function &onRowSelected, + // const function &onRowSelected, // const function&)> &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 (param) != nullptr); -// AudioParameterInt* castParam {dynamic_cast (param)}; -// int value{castParam->get()}; -// } else if (parameterID == "preset") { -// jassert(dynamic_cast (param) != nullptr); -// AudioParameterInt* castParam {dynamic_cast (param)}; -// int value{castParam->get()}; -// } -// } +void TableComponent::loadModelFrom(ValueTree& presets) { + rows.clear(); + int numChildren{presets.getNumChildren()}; + for(int i{0}; i (param) != nullptr); + // AudioParameterInt* castParam {dynamic_cast (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= 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 (param) != nullptr); - AudioParameterInt* castParam {dynamic_cast (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(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(std::distance(rows.begin(), it))}; - table.selectRow(index); - break; - } - } +void TableComponent::selectCurrentPreset() { + table.deselectAllRows(); + RangedAudioParameter *param {valueTreeState.getParameter("preset")}; + jassert(dynamic_cast (param) != nullptr); + AudioParameterInt* castParam {dynamic_cast (param)}; + int value{castParam->get()}; + + for (auto it = rows.begin(); it != rows.end(); ++it) { + if(it->preset == value) { + int index {static_cast(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} {} diff --git a/Source/TableComponent.h b/Source/TableComponent.h index 7153923..8292249 100644 --- a/Source/TableComponent.h +++ b/Source/TableComponent.h @@ -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 &columns, // const vector &rows, - const function &onRowSelected, + // const function &onRowSelected, // const function&)> &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 columns; vector rows; - function onRowSelected; + // function onRowSelected; // function&)> rowToIDMapper; // A comparator used to sort our data when the user clicks a column header diff --git a/Source/TablesComponent.cpp b/Source/TablesComponent.cpp index 1f89040..6549909 100644 --- a/Source/TablesComponent.cpp +++ b/Source/TablesComponent.cpp @@ -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 TablesComponent::mapBanks(const BanksToPresets &banksToPresets) { @@ -138,21 +138,21 @@ vector TablesComponent::mapBanks(const BanksToPresets &banksToPresets) { } -vector> TablesComponent::mapPresets(const BanksToPresets &banksToPresets, int bank) { - vector> rows; +// vector> TablesComponent::mapPresets(const BanksToPresets &banksToPresets, int bank) { +// vector> rows; - pair iterators = banksToPresets.equal_range(bank); - for (auto it = iterators.first; it != iterators.second; ++it) { - Preset b = it->second; - vector row; - row.push_back(to_string(b.getPreset())); - row.push_back(b.getName()); +// pair iterators = banksToPresets.equal_range(bank); +// for (auto it = iterators.first; it != iterators.second; ++it) { +// Preset b = it->second; +// vector 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 r (getLocalBounds()); diff --git a/Source/TablesComponent.h b/Source/TablesComponent.h index 9156db6..69191c9 100644 --- a/Source/TablesComponent.h +++ b/Source/TablesComponent.h @@ -35,12 +35,12 @@ private: FluidSynthModel& fluidSynthModel; int selectedBank; - Pills* banks; - TableComponent* presetTable; + Pills banks; + TableComponent presetTable; BanksToPresets banksToPresets; - static vector> mapPresets(const BanksToPresets &banksToPresets, int bank); + // static vector> mapPresets(const BanksToPresets &banksToPresets, int bank); static vector mapBanks(const BanksToPresets &banksToPresets); void onBankSelected(int bank);