From 9ed6385239cd3418859ef85db81125043a5285e5 Mon Sep 17 00:00:00 2001 From: Daniel Walz Date: Wed, 19 Apr 2023 21:53:05 +0200 Subject: [PATCH] Add a property 'tab-selected' to connect to a property in the state --- Editor/foleys_PropertiesEditor.cpp | 1 + General/foleys_MagicJUCEFactories.cpp | 43 ++++++++++++++++++++------- General/foleys_StringDefinitions.h | 1 + Layout/foleys_Container.cpp | 18 ++++++++++- Layout/foleys_Container.h | 10 +++---- Layout/foleys_GuiItem.h | 2 +- State/foleys_MagicGUIState.cpp | 2 +- VERSION.md | 4 +++ 8 files changed, 63 insertions(+), 18 deletions(-) diff --git a/Editor/foleys_PropertiesEditor.cpp b/Editor/foleys_PropertiesEditor.cpp index a5bfc427..ad68c5a9 100644 --- a/Editor/foleys_PropertiesEditor.cpp +++ b/Editor/foleys_PropertiesEditor.cpp @@ -359,6 +359,7 @@ void PropertiesEditor::addContainerProperties() array.add (new StyleTextPropertyComponent (builder, IDs::repaintHz, styleItem)); array.add (new StyleChoicePropertyComponent (builder, IDs::scrollMode, styleItem, { IDs::noScroll, IDs::scrollHorizontal, IDs::scrollVertical, IDs::scrollBoth })); array.add (new StyleTextPropertyComponent (builder, IDs::tabHeight, styleItem)); + array.add (new StyleChoicePropertyComponent (builder, IDs::selectedTab, styleItem, builder.createPropertiesMenuLambda())); array.add (new StyleChoicePropertyComponent (builder, IDs::flexDirection, styleItem, { IDs::flexDirRow, IDs::flexDirRowReverse, IDs::flexDirColumn, IDs::flexDirColumnReverse })); array.add (new StyleChoicePropertyComponent (builder, IDs::flexWrap, styleItem, { IDs::flexNoWrap, IDs::flexWrapNormal, IDs::flexWrapReverse })); diff --git a/General/foleys_MagicJUCEFactories.cpp b/General/foleys_MagicJUCEFactories.cpp index b838de51..a603a2df 100644 --- a/General/foleys_MagicJUCEFactories.cpp +++ b/General/foleys_MagicJUCEFactories.cpp @@ -264,6 +264,7 @@ class TextButtonItem : public GuiItem FOLEYS_DECLARE_GUI_FACTORY (TextButtonItem) static const juce::Identifier pText; + static const juce::Identifier pProperty; static const juce::Identifier pOnClick; TextButtonItem (MagicGUIBuilder& builder, const juce::ValueTree& node) : GuiItem (builder, node) @@ -284,13 +285,17 @@ class TextButtonItem : public GuiItem attachment.reset(); auto parameterName = configNode.getProperty (IDs::parameter, juce::String()).toString(); - auto radioValue = getProperty (IDs::buttonRadioValue); + auto radioValue = getProperty (IDs::buttonRadioValue); + auto propertyName = getProperty (pProperty).toString(); if (parameterName.isNotEmpty() && radioValue.isVoid()) attachment = getMagicState().createAttachment (parameterName, button); else attachment.reset(); + if (propertyName.isNotEmpty()) + property.referTo (getMagicState().getPropertyAsValue (propertyName)); + auto groupID = static_cast(getProperty (IDs::buttonRadioGroup)); if (groupID > 0) { @@ -301,8 +306,22 @@ class TextButtonItem : public GuiItem button.setButtonText (magicBuilder.getStyleProperty (pText, configNode)); auto triggerID = getProperty (pOnClick).toString(); - if (triggerID.isNotEmpty()) - button.onClick = getMagicState().getTrigger (triggerID); + triggerToCall = triggerID.isNotEmpty() ? getMagicState().getTrigger (triggerID) : nullptr; + + if (propertyName.isNotEmpty()) + { + button.onClick = [this, radioValue] + { + property.setValue (radioValue); + + if (triggerToCall) + triggerToCall(); + }; + } + else + { + button.onClick = triggerToCall; + } handler.setRadioGroupValue(radioValue, getMagicState().getParameter(parameterName)); } @@ -313,6 +332,7 @@ class TextButtonItem : public GuiItem props.push_back ({ configNode, IDs::parameter, SettableProperty::Choice, {}, magicBuilder.createParameterMenuLambda() }); props.push_back ({ configNode, pText, SettableProperty::Text, {}, {} }); + props.push_back ({ configNode, pProperty, SettableProperty::Choice, {}, magicBuilder.createPropertiesMenuLambda() }); props.push_back ({ configNode, pOnClick, SettableProperty::Choice, {}, magicBuilder.createTriggerMenuLambda() }); props.push_back ({ configNode, IDs::buttonRadioGroup, SettableProperty::Number, {}, {} }); props.push_back ({ configNode, IDs::buttonRadioValue, SettableProperty::Number, {}, {} }); @@ -329,11 +349,14 @@ class TextButtonItem : public GuiItem juce::TextButton button; RadioButtonHandler handler {button, magicBuilder.getRadioButtonManager()}; std::unique_ptr attachment; + std::function triggerToCall; + juce::Value property; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextButtonItem) }; -const juce::Identifier TextButtonItem::pText { "text" }; -const juce::Identifier TextButtonItem::pOnClick { "onClick" }; +const juce::Identifier TextButtonItem::pText { "text" }; +const juce::Identifier TextButtonItem::pOnClick { "onClick" }; +const juce::Identifier TextButtonItem::pProperty { "property" }; //============================================================================== @@ -344,7 +367,7 @@ class ToggleButtonItem : public GuiItem FOLEYS_DECLARE_GUI_FACTORY (ToggleButtonItem) static const juce::Identifier pText; - static const juce::Identifier pValue; + static const juce::Identifier pProperty; ToggleButtonItem (MagicGUIBuilder& builder, const juce::ValueTree& node) : GuiItem (builder, node) { @@ -371,7 +394,7 @@ class ToggleButtonItem : public GuiItem button.setButtonText (magicBuilder.getStyleProperty (pText, configNode)); - auto propertyID = getProperty (pValue).toString(); + auto propertyID = getProperty (pProperty).toString(); if (propertyID.isNotEmpty()) button.getToggleStateValue().referTo (getMagicState().getPropertyAsValue (propertyID)); @@ -390,7 +413,7 @@ class ToggleButtonItem : public GuiItem std::vector props; props.push_back ({ configNode, pText, SettableProperty::Text, {}, {} }); props.push_back ({ configNode, IDs::parameter, SettableProperty::Choice, {}, magicBuilder.createParameterMenuLambda() }); - props.push_back ({ configNode, pValue, SettableProperty::Choice, {}, magicBuilder.createPropertiesMenuLambda() }); + props.push_back ({ configNode, pProperty, SettableProperty::Choice, {}, magicBuilder.createPropertiesMenuLambda() }); props.push_back ({ configNode, IDs::buttonRadioGroup, SettableProperty::Number, {}, {} }); props.push_back ({ configNode, IDs::buttonRadioValue, SettableProperty::Number, {}, {} }); return props; @@ -408,8 +431,8 @@ class ToggleButtonItem : public GuiItem JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToggleButtonItem) }; -const juce::Identifier ToggleButtonItem::pText { "text" }; -const juce::Identifier ToggleButtonItem::pValue { "value" }; +const juce::Identifier ToggleButtonItem::pText { "text" }; +const juce::Identifier ToggleButtonItem::pProperty { "property" }; //============================================================================== diff --git a/General/foleys_StringDefinitions.h b/General/foleys_StringDefinitions.h index 7366c71d..d7216212 100644 --- a/General/foleys_StringDefinitions.h +++ b/General/foleys_StringDefinitions.h @@ -105,6 +105,7 @@ namespace IDs static juce::String tabbed { "tabbed" }; static juce::String flexbox { "flexbox" }; static juce::Identifier tabHeight { "tab-height" }; + static juce::Identifier selectedTab { "tab-selected" }; static juce::Identifier focusContainerType { "focus-container" }; static juce::String focusNone { "focus-none" }; diff --git a/Layout/foleys_Container.cpp b/Layout/foleys_Container.cpp index c2e7fc72..e5304645 100644 --- a/Layout/foleys_Container.cpp +++ b/Layout/foleys_Container.cpp @@ -44,6 +44,12 @@ Container::Container (MagicGUIBuilder& builder, juce::ValueTree node) { addAndMakeVisible (viewport); viewport.setViewedComponent (&containerBox, false); + currentTab.addListener (this); +} + +Container::~Container() +{ + currentTab.removeListener (this); } void Container::update() @@ -74,6 +80,10 @@ void Container::update() auto tabHeightProperty = magicBuilder.getStyleProperty (IDs::tabHeight, configNode).toString(); tabbarHeight = tabHeightProperty.isNotEmpty() ? tabHeightProperty.getIntValue() : 30; + const auto tabProperty = magicBuilder.getStyleProperty (IDs::selectedTab, configNode).toString(); + if (tabProperty.isNotEmpty()) + currentTab.referTo(getMagicState().getPropertyAsValue(tabProperty)); + auto repaintHz = magicBuilder.getStyleProperty (IDs::repaintHz, configNode).toString(); if (repaintHz.isNotEmpty()) { @@ -272,7 +282,7 @@ void Container::updateTabbedButtons() } tabbedButtons->addChangeListener (this); - tabbedButtons->setCurrentTabIndex (currentTab, false); + tabbedButtons->setCurrentTabIndex (currentTab.getValue(), false); updateSelectedTab(); } @@ -351,6 +361,12 @@ void Container::changeListenerCallback (juce::ChangeBroadcaster*) updateSelectedTab(); } +void Container::valueChanged (juce::Value& source) +{ + if (source == currentTab) + updateSelectedTab(); +} + void Container::updateSelectedTab() { int index = 0; diff --git a/Layout/foleys_Container.h b/Layout/foleys_Container.h index 7d08f449..18955b95 100644 --- a/Layout/foleys_Container.h +++ b/Layout/foleys_Container.h @@ -75,6 +75,7 @@ class Container : public GuiItem, { public: Container (MagicGUIBuilder& builder, juce::ValueTree node); + ~Container(); /** Updates the layout fo children @@ -154,18 +155,17 @@ class Container : public GuiItem, }; void changeListenerCallback (juce::ChangeBroadcaster*) override; + void valueChanged (juce::Value&) override; void timerCallback() override; void updateTabbedButtons(); void updateSelectedTab(); - int currentTab = 0; - int tabbarHeight = 30; - int refreshRateHz = 30; - + juce::Value currentTab { juce::var {0} }; + int tabbarHeight = 30; + int refreshRateHz = 30; LayoutType layout = LayoutType::FlexBox; juce::FlexBox flexBox; - ScrollMode scrollMode = ScrollMode::NoScroll; juce::Component containerBox; diff --git a/Layout/foleys_GuiItem.h b/Layout/foleys_GuiItem.h index 9e6e9bca..aeb583c8 100644 --- a/Layout/foleys_GuiItem.h +++ b/Layout/foleys_GuiItem.h @@ -55,7 +55,7 @@ enum class LayoutType; to an AudioProcessorValueTreeState. */ class GuiItem : public juce::Component, - private juce::Value::Listener, + public juce::Value::Listener, private juce::ValueTree::Listener, public juce::DragAndDropTarget { diff --git a/State/foleys_MagicGUIState.cpp b/State/foleys_MagicGUIState.cpp index 961ee81b..0b7a2c95 100644 --- a/State/foleys_MagicGUIState.cpp +++ b/State/foleys_MagicGUIState.cpp @@ -211,7 +211,7 @@ void MagicGUIState::addPropertiesToMenu (const juce::ValueTree& tree, juce::Comb for (int i=0; i < tree.getNumProperties(); ++i) { const auto name = tree.getPropertyName (i).toString(); - menu.addItem (name, [&combo, t = path + name] + menu.addItem (name, true, false, [&combo, t = path + name] { combo.setText (t); }); diff --git a/VERSION.md b/VERSION.md index 4d124f11..1792ab9e 100644 --- a/VERSION.md +++ b/VERSION.md @@ -9,6 +9,10 @@ PluginGuiMagic - Versions history - Updated updatePlayheadInformation for JUCE 7 - Added safety to RadioButtonManager - Allow setStateInformation to occur on a background thread +- Add setting a property from a TextButton +- Changed name "value" to "property" on ToggleButton +- Allow setting of Tab-Bar height +- Add a property "tab-selected" to connect to a property in the state 1.3.8 - 31.10.2022 ------------------