Krotos Modules 3
Loading...
Searching...
No Matches
ModulationAssignerTable.cpp
Go to the documentation of this file.
2
3namespace krotos
4{
5 const String ModulationAssignerTable::ComponentIds::TextButtonBackId("ModulationBackLevelButton");
6 const String ModulationAssignerTable::ComponentIds::TextButtonDeleteId("ParamDeleteButton");
7 const String ModulationAssignerTable::ComponentIds::SliderDepthId("ParamDepthSlider");
8
10 : Component(name), m_id(id), m_assigner(owner), m_backButton("Back"), m_titleLabel(name, name), m_numRows(0)
11 {
12 addAndMakeVisible(m_backButton);
14 m_backButton.onClick = [this]() {
15 auto tabs = dynamic_cast<TabbedComponent*>(this->getParentComponent());
16 tabs->setCurrentTabIndex(k_dropTabIndex);
17 };
18
19 // Title Label
20 addAndMakeVisible(m_titleLabel);
21 m_titleLabel.setJustificationType(juce::Justification::centredRight);
22 m_titleLabel.setFont(Font(18.0f));
23
24 // Begin setting up the TableListBox
25 m_table.setModel(this);
26 m_table.setHeaderHeight(19);
27 m_table.setRowHeight(30);
28 m_table.getViewport()->setScrollBarThickness(6);
29 m_table.getHeader().addColumn("Source", col_Source, /*width*/ 50);
30 m_table.getHeader().addColumn("Destination", col_Destination, /*width*/ 228, /*minWidth*/ 110);
31 m_table.getHeader().addColumn("Depth", col_Depth, /*width*/ 110, /*minWidth*/ 60);
32 m_table.getHeader().addColumn("", col_Delete, /*width*/ 25, /*minWidth*/ 25, /*maxWidth*/ 25);
33
34 // sort forwards by the ID column
35 m_table.getHeader().setSortColumnId(col_Destination, true);
36 m_table.getHeader().setColumnVisible(col_Source, false);
37
38 // Stretch-to-fit mode
39 m_table.getHeader().setStretchToFitActive(true);
40
41 addAndMakeVisible(m_table);
42 }
43
45
46 void ModulationAssignerTable::paintRowBackground(Graphics& g, int rowNumber, int /*width*/, int /*height*/,
47 bool /*rowIsSelected*/)
48 {
49 g.fillAll(getLookAndFeel().findColour(ListBox::backgroundColourId));
50 if (rowNumber % 2)
51 {
52 g.fillAll(Colours::white.withAlpha(0.04f));
53 }
54 }
55
56 void ModulationAssignerTable::paintCell(Graphics& g, int rowNumber, int columnId, int width, int height,
57 bool /*rowIsSelected*/)
58 {
59 g.setColour(getLookAndFeel().findColour(juce::ListBox::textColourId));
60 g.setFont(m_font.withExtraKerningFactor(0.1f));
61
62 String text;
63
64 switch (columnId)
65 {
66 case col_Source:
67 text = m_sources[rowNumber];
68 break;
69 case col_Destination:
70 text = m_destinations[rowNumber];
71 break;
72 }
73
74 g.drawText(text, /*x*/ 8, /*y*/ 0, width - 4, height, juce::Justification::centredLeft, /*useEllipses*/ true);
75 }
76
77 Component* ModulationAssignerTable::refreshComponentForCell(int rowNumber, int columnId, bool /*isRowSelected*/,
78 Component* existingComponentToUpdate)
79 {
80 switch (columnId)
81 {
82 case col_Depth: {
83 auto* depthSlider = static_cast<ModDepthSlider*>(existingComponentToUpdate);
84
85 if (depthSlider == nullptr)
86 {
87 depthSlider = new ModDepthSlider(*this);
88 }
89
90 depthSlider->setAttachment(rowNumber, columnId, m_modulationTrees[rowNumber],
91 m_depthIdentifier); // more thought needed here to handle removal of rows
92 depthSlider->setValue(m_modulationTrees[rowNumber].getProperty(XmlType::Property::depth));
93
94 return depthSlider;
95 }
96 case col_Delete: {
97 auto* deleteButton = static_cast<DrawableButton*>(existingComponentToUpdate);
98
99 if (deleteButton == nullptr)
100 {
101 deleteButton = new DrawableButton("", DrawableButton::ButtonStyle::ImageFitted);
102 std::unique_ptr<Drawable> defaultCross(
103 Drawable::createFromImageData(KrotosBinaryData::table_close_button_faded_svg,
104 KrotosBinaryData::table_close_button_faded_svgSize));
105 std::unique_ptr<Drawable> crossHover(
106 Drawable::createFromImageData(KrotosBinaryData::table_close_button_very_faded_svg,
107 KrotosBinaryData::table_close_button_very_faded_svgSize));
108 std::unique_ptr<Drawable> crossClicked(
109 Drawable::createFromImageData(KrotosBinaryData::table_close_button_solid_svg,
110 KrotosBinaryData::table_close_button_solid_svgSize));
111 deleteButton->setImages(defaultCross.get(), crossHover.get(), crossClicked.get());
112 deleteButton->onClick = [this, rowNumber]() { deleteRow(rowNumber, true); };
113
114 deleteButton->setComponentID(ComponentIds::TextButtonDeleteId);
115 }
116
117 return deleteButton;
118 }
119 }
120
121 jassert(existingComponentToUpdate == nullptr);
122 return nullptr;
123 }
124
126 {
127 g.setColour(getLookAndFeel().findColour(ListBox::outlineColourId));
128 g.fillRoundedRectangle(getLocalBounds().toFloat(), /*cornerSize*/ 4.0f);
129 // draw line above header row
130 const Colour horizontalLineColour(0x33FFFFFF); // white, 0.2 opacity
131 g.setColour(horizontalLineColour);
132 g.fillRect(/*x*/ 0, /*y*/ 20, /*w*/ getWidth(), /*h*/ 1);
133 }
134
136 {
137 auto bounds = getLocalBounds();
138 auto topBar = bounds.removeFromTop(21);
139 topBar.removeFromLeft(8);
140 m_backButton.setBounds(topBar.removeFromLeft(60));
141 m_titleLabel.setBounds(topBar);
142 m_table.setBounds(bounds.withX(0).withWidth(getWidth()));
143 }
144
145 void ModulationAssignerTable::addRow(const ValueTree& modulationInstanceTree)
146 {
147 String source = modulationInstanceTree.getProperty(XmlType::Property::source);
148 String index = modulationInstanceTree.getProperty(XmlType::Property::modulatorIndex);
149 String destination = modulationInstanceTree.getProperty(XmlType::Property::destination);
150 String param = modulationInstanceTree.getProperty(XmlType::Property::param);
151
152 // Construct strings for row labels.
153 source.append(index, k_maxAppendLength);
154 destination.append(param, k_maxAppendLength);
155
156 if (m_sources.contains(source) && m_destinations.contains(destination))
157 {
158 // Mod routing already exists in the table.
159 // This may be because there's multiple instances of
160 // the same modulation in the ValueTree, or because
161 // the user is trying to route modulation that already exists.
162 jassertfalse;
163 }
164 else
165 {
166 m_sources.add(source);
167 m_destinations.add(destination);
168
169 m_modulationTrees.push_back(modulationInstanceTree);
170
171 m_numRows++;
172 m_table.updateContent();
173 }
174 }
175
176 void ModulationAssignerTable::deleteRow(const ValueTree& modulationInstanceTree, int row, bool notifyAssigner)
177 {
178 String source = modulationInstanceTree.getProperty(XmlType::Property::source).toString();
179 String index = modulationInstanceTree.getProperty(XmlType::Property::modulatorIndex).toString();
180 String destination = modulationInstanceTree.getProperty(XmlType::Property::destination).toString();
181 String param = modulationInstanceTree.getProperty(XmlType::Property::param).toString();
182
183 // Construct strings for row labels.
184 source.append(index, k_maxAppendLength);
185 destination.append(param, k_maxAppendLength);
186
187 if (m_sources[row] == source && m_destinations[row] == destination)
188 {
189 m_sources.remove(row);
190 m_destinations.remove(row);
191
192 // If we are deleting because of a ValueTree state change, we don't need to notify the assigner
193 // to delete it again.
194 if (notifyAssigner)
195 m_assigner.modulationDeleted(modulationInstanceTree);
196
197 m_modulationTrees.erase(m_modulationTrees.begin() + row);
198
199 m_numRows--;
200 m_table.updateContent();
201 }
202 }
203
204 void ModulationAssignerTable::deleteRow(int row, bool notifyAssigner)
205 {
206 deleteRow(m_modulationTrees[row], row, notifyAssigner);
207 }
208
209 void ModulationAssignerTable::deleteRow(const ValueTree& modInstanceTree, bool notifyAssigner)
210 {
211 int tableIndex = -1;
212 for (int i = 0; i < m_modulationTrees.size(); i++)
213 {
214 if (m_modulationTrees[i].isEquivalentTo(modInstanceTree))
215 tableIndex = i;
216 }
217 if (tableIndex >= 0)
218 deleteRow(tableIndex, notifyAssigner);
219 }
220
221 // ========================== Mod Depth Slider ==========================
222
224 : m_owner(modList), Slider(Slider::SliderStyle::LinearHorizontal, Slider::TextEntryBoxPosition::NoTextBox)
225 {
227 setLookAndFeel(&m_laf);
228 setRange(-1.0, 1.0, 0.01);
229 setValue(0.0, dontSendNotification);
230 setDoubleClickReturnValue(true, 0.0);
231 setComponentID(ComponentIds::SliderDepthId);
232 }
233
235
236 void ModulationAssignerTable::ModDepthSlider::setAttachment(int row, int column, const ValueTree& tree,
237 const Identifier& property)
238 {
239 m_row = row;
240 m_column = column;
241 m_tree = tree;
242 m_property = property;
243
244 m_tree.addListener(this);
245 }
246
248 {
249 m_tree.setPropertyExcludingListener(this, m_property, getValue(), nullptr);
250 }
251
252 void ModulationAssignerTable::ModDepthSlider::valueTreePropertyChanged(ValueTree& tree, const Identifier& property)
253 {
254 if (property == m_property)
255 setValue(tree[property]);
256 }
257
259 {
260 setPopupDisplayEnabled(true, true, findParentComponentOfClass<AudioProcessorEditor>());
261 }
262
263} // namespace krotos
void setDrawMirrored(bool shouldDrawMirrored)
Definition BipolarSliderLAF.h:11
Definition ModulationAssigner.h:12
std::function< void(ValueTree modulationChildTree)> modulationDeleted
Definition ModulationAssigner.h:97
Definition ModulationAssignerTable.h:113
void lookAndFeelChanged() override
Definition ModulationAssignerTable.cpp:258
ModDepthSlider(ModulationAssignerTable &modList)
Definition ModulationAssignerTable.cpp:223
~ModDepthSlider()
Definition ModulationAssignerTable.cpp:234
BipolarSliderLAF m_laf
Definition ModulationAssignerTable.h:130
void valueTreePropertyChanged(ValueTree &treeWhosePropertyHasChanged, const Identifier &property) override
Definition ModulationAssignerTable.cpp:252
void valueChanged() override
Definition ModulationAssignerTable.cpp:247
void setAttachment(int row, int column, const ValueTree &tree, const Identifier &property)
Definition ModulationAssignerTable.cpp:236
Definition ModulationAssignerTable.h:9
int getNumRows() override
Definition ModulationAssignerTable.cpp:44
ModulationAssigner & m_assigner
Definition ModulationAssignerTable.h:85
void paint(Graphics &g)
Definition ModulationAssignerTable.cpp:125
const int k_maxAppendLength
Definition ModulationAssignerTable.h:105
void resized() override
Definition ModulationAssignerTable.cpp:135
void deleteRow(const ValueTree &modulationInstanceTree, int row, bool notifyAssigner)
Definition ModulationAssignerTable.cpp:176
std::vector< ValueTree > m_modulationTrees
Definition ModulationAssignerTable.h:88
Label m_titleLabel
Definition ModulationAssignerTable.h:91
@ col_Source
Definition ModulationAssignerTable.h:69
@ col_Delete
Definition ModulationAssignerTable.h:72
@ col_Depth
Definition ModulationAssignerTable.h:71
@ col_Destination
Definition ModulationAssignerTable.h:70
int m_numRows
Definition ModulationAssignerTable.h:102
StringArray m_destinations
Definition ModulationAssignerTable.h:96
Component * refreshComponentForCell(int rowNumber, int columnId, bool isRowSelected, Component *existingComponentToUpdate) override
Definition ModulationAssignerTable.cpp:77
TableListBox m_table
Definition ModulationAssignerTable.h:98
Font m_font
Definition ModulationAssignerTable.h:99
void addRow(const ValueTree &modulationInstanceTree)
Definition ModulationAssignerTable.cpp:145
void paintCell(Graphics &g, int rowNumber, int columnId, int width, int height, bool rowIsSelected) override
Definition ModulationAssignerTable.cpp:56
void paintRowBackground(Graphics &g, int rowNumber, int width, int height, bool rowIsSelected) override
Definition ModulationAssignerTable.cpp:46
const Identifier m_depthIdentifier
Definition ModulationAssignerTable.h:87
StringArray m_sources
Definition ModulationAssignerTable.h:95
TextButton m_backButton
Definition ModulationAssignerTable.h:90
const int k_dropTabIndex
Definition ModulationAssignerTable.h:104
ModulationAssignerTable(ModulationAssigner &owner, String name, String id)
Definition ModulationAssignerTable.cpp:9
Definition AirAbsorptionFilter.cpp:2
static const String TextButtonBackId
Definition ModulationAssignerTable.h:79
static const String TextButtonDeleteId
Definition ModulationAssignerTable.h:80
static const String SliderDepthId
Definition ModulationAssignerTable.h:81
static const Identifier modulatorIndex
Definition XmlType.h:48
static const Identifier destination
Definition XmlType.h:46
static const Identifier source
Definition XmlType.h:45
static const Identifier depth
Definition XmlType.h:49
static const Identifier param
Definition XmlType.h:47