7 const String PerformanceArea::TemplateFileExtension =
"kst";
12 const std::string PerformanceArea::analyticsEventTemplateSelected{
"analyticsEventTemplateSelected:"};
14 PerformanceArea::PerformanceArea(ValueTree& customDataTree, KwidgetAudioProcessor& processor,
int id,
15 const StringArray& kTypes)
16 : m_customDataTree(customDataTree), m_processor(processor), m_layoutSelector(
"layout selector"),
17 m_editorSelector(
"editor selector"), m_layoutBuilderTree(XmlType::Tag::kwidgets), m_id(id),
18 m_optionKTypes(kTypes)
20 initialiseListeners();
22 addAndMakeVisible(m_layoutEditor);
23 addAndMakeVisible(m_layoutSelector);
24 addChildComponent(m_editorSelector);
26 initialiseEditorControls();
27 m_layoutEditor.setComponentID(ComponentIds::PerformanceAreaLayoutComponentId);
30 m_layoutEditor.
treeRedirected = [
this]() { m_layoutSelector.setSelectedId(0); };
32 m_layoutSelector.setComponentID(ComponentIds::ComboboxTemplateId);
34 m_layoutSelector.getProperties().set(LAFProperty::ComboBox::DisableHover,
true);
35 m_layoutSelector.getProperties().set(LAFProperty::ComboBox::RoundedCornerID,
36 LAFProperty::ComboBox::RoundedCorner::Top);
37 m_layoutSelector.getProperties().set(LAFProperty::ComboBox::IconPositionID,
38 LAFProperty::ComboBox::IconPosition::Left);
39 m_layoutSelector.getProperties().set(LAFProperty::ComboBox::UseCustomIcon,
true);
40 m_layoutSelector.getProperties().set(LAFProperty::ComboBox::FontSize, 18.0f);
42 m_layoutSelector.setColour(ComboBox::backgroundColourId, findColour(TabbedComponent::backgroundColourId));
43 m_layoutSelector.setColour(ComboBox::textColourId, Colours::white);
44 m_layoutSelector.setTextWhenNothingSelected(
"Select a Performing Template");
47 m_dropdownIcon = Drawable::createFromImageData(KrotosBinaryData::SampleBrowser_Dropdown_Icon_svg,
48 KrotosBinaryData::SampleBrowser_Dropdown_Icon_svgSize);
49 addAndMakeVisible(*m_dropdownIcon);
51 m_editorSelector.getProperties().set(LAFProperty::ComboBox::DisableHover,
true);
52 m_editorSelector.setColour(ComboBox::backgroundColourId, findColour(TabbedComponent::backgroundColourId));
54 m_lastSelectedTemplate = m_layoutSelector.getSelectedId();
55 m_layoutSelector.onChange = [
this] {
57 auto selectedId = m_layoutSelector.getSelectedId();
58 if (selectedId == m_lastSelectedTemplate || selectedId == 0)
60 m_lastSelectedTemplate = selectedId;
64 std::function<void(
int)> changeCallback = [
this, selectedId,
65 target = WeakReference<Component>{
this}](
int option) {
74 if (selectedId > 0 && selectedId <= m_templateFiles.size())
76 File file = m_templateFiles[selectedId - 1];
77 if (file.hasFileExtension(PerformanceArea::TemplateFileExtension))
79 XmlDocument doc(file);
80 loadTemplateXml(*doc.getDocumentElement());
81 m_lastSelectedTemplate = selectedId;
84 sendActionMessage(analyticsEventTemplateSelected +
85 m_layoutSelector.getItemText(selectedId).toStdString());
91 m_layoutSelector.setSelectedId(m_lastSelectedTemplate);
96 AlertWindow::showAsync(
98 .withIconType(MessageBoxIconType::WarningIcon)
99 .withTitle(
"Template Switch")
100 .withMessage(
"Please note that switching to another\ntemplate will lead to a "
101 "destructive change,\nresulting in the loss of all prior "
102 "components,\nparameter settings, and modulation\nassignments")
103 .withButton(
"Cancel")
104 .withButton(
"Switch")
105 .withAssociatedComponent(
this),
113 if (getAutoLayoutBoundsFromType)
115 return getAutoLayoutBoundsFromType(type, currentBounds);
120 return Rectangle<int>();
125 m_backgroundImage = Drawable::createFromImageData(KrotosBinaryData::Perform_Area_Background_png,
126 KrotosBinaryData::Perform_Area_Background_pngSize);
128 m_dropdownIcon->toFront(
false);
133 void PerformanceArea::initialiseListeners()
137 jassert(m_customDataTree.isValid());
138 jassert(m_customDataTree.hasType(XmlType::Tag::customData));
145 auto layoutTree = m_customDataTree.getChildWithName(CustomLayout::Tag::layout);
150 if (layoutTree.isValid())
153 jassert(layoutTree.hasType(CustomLayout::Tag::layout));
156 resetLayoutTree(layoutTree);
161 m_customDataTree.appendChild(getLayoutTree(),
nullptr);
163 layoutTree = m_customDataTree.getChildWithName(CustomLayout::Tag::layout);
165 jassert(layoutTree.isValid());
166 jassert(layoutTree.hasType(CustomLayout::Tag::layout));
168 setLayoutTree(layoutTree);
173 m_customTreeAttachment->onChildAdded = [
this](ValueTree& , ValueTree& child) {
176 if (child.getType() == CustomLayout::Tag::layout)
178 resetLayoutTree(child);
182 m_customTreeAttachment->onChildRemoved = [
this](ValueTree& , ValueTree& child) {
184 if (child.getType() == CustomLayout::Tag::layout)
185 m_layoutBuilderTree.removeAllChildren(
nullptr);
189 void PerformanceArea::resized()
191 const auto barHeight = 30;
193 auto bounds = getLocalBounds();
195 auto selectorBar = m_layoutSelector.isVisible() || m_showEditorControls ? bounds.removeFromTop(barHeight)
198 if (m_showEditorControls)
200 setTemplateSelectorVisible(
true);
201 m_editorSelector.setBounds(selectorBar.removeFromLeft((
int)((
float)selectorBar.getWidth() * 0.5f)));
203 auto layoutBounds = bounds;
204 layoutBounds.setHeight(bounds.getHeight());
205 m_layoutEditor.setBounds(layoutBounds);
207 selectorBar.removeFromRight(Layout::selectorBar);
208 m_layoutSelector.setBounds(selectorBar);
210 auto layoutBoxBounds = m_layoutSelector.getBounds();
212 auto iconBounds = layoutBoxBounds.removeFromLeft(28).withSizeKeepingCentre(12, 12);
213 m_dropdownIcon->setBounds(iconBounds);
216 void PerformanceArea::paint(Graphics& g)
218 if (m_drawBackground)
220 m_backgroundImage->drawWithin(g, getLocalBounds().toFloat(), RectanglePlacement::stretchToFit, 1.0f);
224 void PerformanceArea::addToLayoutBuilder(
const ValueTree& tree)
226 m_layoutBuilderTree.appendChild(tree.createCopy(),
nullptr);
230 void PerformanceArea::addKwidgetGUI(
KwidgetGUI* gui, Rectangle<int> bounds)
232 jassert(gui !=
nullptr);
236 auto slotTree = getLayoutTree().getChildWithProperty(CustomLayout::Property::name,
id);
239 if (slotTree.isValid())
240 addComponent(*gui, slotTree);
243 addComponent(*gui, bounds);
248 std::unique_ptr<XmlElement> PerformanceArea::saveTemplateXml()
250 ValueTree outputTree(Tag::Template);
251 outputTree.appendChild(m_layoutBuilderTree.createCopy(),
nullptr);
252 outputTree.appendChild(getLayoutTree().createCopy(),
nullptr);
255 return outputTree.createXml();
258 void PerformanceArea::loadTemplateXml(
const XmlElement& templateXml)
260 auto newTree = ValueTree::fromXml(templateXml);
261 if (newTree.hasType(Tag::Template))
263 auto kwidgetsTree = newTree.getChildWithName(XmlType::Tag::kwidgets);
264 auto layoutTree = newTree.getChildWithName(CustomLayout::Tag::layout);
267 jassert(kwidgetsTree.isValid());
268 jassert(layoutTree.isValid());
270 auto numberOfLayoutSlots = newTree.getChildWithName(CustomLayout::Tag::layout).getNumChildren();
271 auto numberOfKwidgets = kwidgetsTree.getNumChildren();
275 if (numberOfKwidgets != numberOfLayoutSlots)
277 AlertWindow::showMessageBoxAsync(MessageBoxIconType::WarningIcon,
"Could not load template",
278 "Error: Invalid template.");
284 StringArray slotNames, kwidgetNames;
286 for (
auto s : layoutTree)
287 slotNames.add(s[CustomLayout::Property::name]);
289 for (
auto k : kwidgetsTree)
290 kwidgetNames.add(k[XmlType::Property::id]);
294 slotNames.mergeArray(kwidgetNames);
297 if (slotNames.size() != numberOfKwidgets)
299 AlertWindow::showMessageBoxAsync(MessageBoxIconType::WarningIcon,
"Could not load template",
300 "Error: Invalid template.");
309 if (layoutTree.isValid())
313 getLayoutTree().copyPropertiesAndChildrenFrom(layoutTree,
nullptr);
317 if (kwidgetsTree.isValid())
319 for (
auto kwidget : kwidgetsTree)
324 String kType = kwidget[XmlType::Property::type];
325 String ID = kwidget[XmlType::Property::id];
326 auto k = KwidgetFactory::createKwidget(kType, ID);
327 if (k->getCustomParameter(Kwidget::Constants::Parent) !=
nullptr)
328 k->getCustomParameter(Kwidget::Constants::Parent)->setValue(1);
329 auto vt = k->getState().createCopy();
336 void PerformanceArea::clearLayout()
338 m_layoutBuilderTree.removeAllChildren(
nullptr);
341 for (
auto slot : getLayoutTree())
343 auto kwidgetToRemove = slot[CustomLayout::Property::name];
346 getLayoutTree().removeAllChildren(
nullptr);
349 void PerformanceArea::refreshTemplates()
351 m_layoutSelector.clear();
353 File templateDir = PresetManager::getFactoryTemplateDirectory().getFullPathName();
355 m_templateFiles = templateDir.findChildFiles(File::TypesOfFileToFind::findFiles,
true,
356 "*." + PerformanceArea::TemplateFileExtension);
358 std::sort(m_templateFiles.begin(), m_templateFiles.end());
362 !templateDir.findChildFiles(File::TypesOfFileToFind::findFiles,
true,
"*." + edit_mode_file_ext)
366 for (
auto file : m_templateFiles)
368 m_layoutSelector.addItem(file.getFileNameWithoutExtension(), i++);
372 void PerformanceArea::initialiseEditorControls()
377 m_saveWindow.reset(
new juce::FileChooser(
"Save template",
378 PresetManager::getFactoryTemplateDirectory().getFullPathName(),
379 "*." + PerformanceArea::TemplateFileExtension));
382 const StringArray optionSettings{
"edit",
"save",
"clear"};
384 const String pAdd =
"add ";
385 const String pSmall = pAdd +
"small ";
388 StringArray itemList;
392 itemList.add(pAdd + m_optionKTypes[i]);
395 if (m_optionKTypes[i] != KType::TriggerButton)
396 itemList.add(pSmall + m_optionKTypes[i]);
398 itemList.addArray(optionSettings);
405 auto option = itemList[id];
408 if (addKwidget &&
id >= 0 &&
id < (itemList.size() - optionSettings.size()))
412 if (option.contains(pSmall))
414 kwidget = option.substring(pSmall.length());
417 else if (option.contains(pAdd))
419 kwidget = option.substring(pAdd.length());
425 if (option ==
"edit")
427 setEditModeActive(!isEditModeActive());
429 else if (option ==
"save")
431 auto flags = juce::FileBrowserComponent::saveMode;
432 m_saveWindow->launchAsync(flags, [
this](
const juce::FileChooser& fc) {
433 auto file = fc.getResult();
434 if (file != juce::File())
436 saveTemplateXml()->writeTo(file);
442 else if (option ==
"clear")
453 void PerformanceArea::showEditorControls(
bool isEnabled)
std::function< Rectangle< int >(String componentType, Rectangle< int > currentBounds)> getAutoLayoutBoundsFromType
Used to look up what bounds should be used for a given component type when using auto layout....
Definition CustomLayout.h:134
std::function< void()> treeRedirected
Definition CustomLayout.h:138
Definition ValueTreeAttachment.h:4
Definition AirAbsorptionFilter.cpp:2
static const Identifier AlertHeightID
Definition Krotos_LookAndFeel.h:24
static const Identifier AlertWidthID
Definition Krotos_LookAndFeel.h:23
Definition Krotos_LookAndFeel.h:20