mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Fixed issues with AudioProcessorValueTreeState parameter synchronization
This commit is contained in:
parent
5a2ebefa00
commit
d438fa59e8
6 changed files with 483 additions and 31 deletions
|
|
@ -112,7 +112,7 @@ struct AudioProcessorValueTreeState::Parameter : public AudioProcessorParamete
|
|||
void copyValueToValueTree()
|
||||
{
|
||||
if (state.isValid())
|
||||
state.setProperty (owner.valuePropertyID, value, owner.undoManager);
|
||||
state.setPropertyExcludingListener (this, owner.valuePropertyID, value, owner.undoManager);
|
||||
}
|
||||
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier& property) override
|
||||
|
|
@ -397,7 +397,7 @@ struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private Attached
|
|||
private Slider::Listener
|
||||
{
|
||||
Pimpl (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
|
||||
: AttachedControlBase (s, p), slider (sl)
|
||||
: AttachedControlBase (s, p), slider (sl), ignoreCallbacks (false)
|
||||
{
|
||||
NormalisableRange<float> range (s.getParameterRange (paramID));
|
||||
slider.setRange (range.start, range.end, range.interval);
|
||||
|
|
@ -418,19 +418,28 @@ struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private Attached
|
|||
|
||||
void setValue (float newValue) override
|
||||
{
|
||||
const ScopedLock selfCallbackLock (selfCallbackMutex);
|
||||
|
||||
ignoreCallbacks = true;
|
||||
slider.setValue (newValue, sendNotificationSync);
|
||||
}
|
||||
|
||||
void sliderValueChanged (Slider* s) override
|
||||
{
|
||||
if (! ModifierKeys::getCurrentModifiers().isRightButtonDown())
|
||||
const ScopedLock selfCallbackLock (selfCallbackMutex);
|
||||
|
||||
if ((! ignoreCallbacks) && (! ModifierKeys::getCurrentModifiers().isRightButtonDown()))
|
||||
setNewUnnormalisedValue ((float) s->getValue());
|
||||
|
||||
ignoreCallbacks = false;
|
||||
}
|
||||
|
||||
void sliderDragStarted (Slider*) override { beginParameterChange(); }
|
||||
void sliderDragEnded (Slider*) override { endParameterChange(); }
|
||||
|
||||
Slider& slider;
|
||||
bool ignoreCallbacks;
|
||||
CriticalSection selfCallbackMutex;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
|
@ -447,7 +456,7 @@ struct AudioProcessorValueTreeState::ComboBoxAttachment::Pimpl : private Attach
|
|||
private ComboBox::Listener
|
||||
{
|
||||
Pimpl (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
|
||||
: AttachedControlBase (s, p), combo (c)
|
||||
: AttachedControlBase (s, p), combo (c), ignoreCallbacks (false)
|
||||
{
|
||||
sendInitialUpdate();
|
||||
combo.addListener (this);
|
||||
|
|
@ -461,17 +470,28 @@ struct AudioProcessorValueTreeState::ComboBoxAttachment::Pimpl : private Attach
|
|||
|
||||
void setValue (float newValue) override
|
||||
{
|
||||
const ScopedLock selfCallbackLock (selfCallbackMutex);
|
||||
|
||||
ignoreCallbacks = true;
|
||||
combo.setSelectedItemIndex (roundToInt (newValue), sendNotificationSync);
|
||||
}
|
||||
|
||||
void comboBoxChanged (ComboBox* comboBox) override
|
||||
{
|
||||
beginParameterChange();
|
||||
setNewUnnormalisedValue ((float) comboBox->getSelectedId() - 1.0f);
|
||||
endParameterChange();
|
||||
const ScopedLock selfCallbackLock (selfCallbackMutex);
|
||||
|
||||
if (! ignoreCallbacks)
|
||||
{
|
||||
beginParameterChange();
|
||||
setNewUnnormalisedValue ((float) comboBox->getSelectedId() - 1.0f);
|
||||
endParameterChange();
|
||||
}
|
||||
ignoreCallbacks = false;
|
||||
}
|
||||
|
||||
ComboBox& combo;
|
||||
bool ignoreCallbacks;
|
||||
CriticalSection selfCallbackMutex;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
|
@ -488,7 +508,7 @@ struct AudioProcessorValueTreeState::ButtonAttachment::Pimpl : private Attached
|
|||
private Button::Listener
|
||||
{
|
||||
Pimpl (AudioProcessorValueTreeState& s, const String& p, Button& b)
|
||||
: AttachedControlBase (s, p), button (b)
|
||||
: AttachedControlBase (s, p), button (b), ignoreCallbacks (false)
|
||||
{
|
||||
sendInitialUpdate();
|
||||
button.addListener (this);
|
||||
|
|
@ -502,17 +522,28 @@ struct AudioProcessorValueTreeState::ButtonAttachment::Pimpl : private Attached
|
|||
|
||||
void setValue (float newValue) override
|
||||
{
|
||||
const ScopedLock selfCallbackLock (selfCallbackMutex);
|
||||
|
||||
ignoreCallbacks = true;
|
||||
button.setToggleState (newValue >= 0.5f, sendNotificationSync);
|
||||
}
|
||||
|
||||
void buttonClicked (Button* b) override
|
||||
{
|
||||
beginParameterChange();
|
||||
setNewUnnormalisedValue (b->getToggleState() ? 1.0f : 0.0f);
|
||||
endParameterChange();
|
||||
const ScopedLock selfCallbackLock (selfCallbackMutex);
|
||||
|
||||
if (! ignoreCallbacks)
|
||||
{
|
||||
beginParameterChange();
|
||||
setNewUnnormalisedValue (b->getToggleState() ? 1.0f : 0.0f);
|
||||
endParameterChange();
|
||||
}
|
||||
ignoreCallbacks = false;
|
||||
}
|
||||
|
||||
Button& button;
|
||||
bool ignoreCallbacks;
|
||||
CriticalSection selfCallbackMutex;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
|
|
|||
183
modules/juce_core/containers/juce_ListenerList.cpp
Normal file
183
modules/juce_core/containers/juce_ListenerList.cpp
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the juce_core module of the JUCE library.
|
||||
Copyright (c) 2016 - ROLI Ltd.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||
or without fee is hereby granted, provided that the above copyright notice and this
|
||||
permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||
using any other modules, be sure to check that you also comply with their license.
|
||||
|
||||
For more details, visit www.juce.com
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
struct ListenerBase
|
||||
{
|
||||
ListenerBase (int& counter) : c (counter) {}
|
||||
virtual ~ListenerBase () {}
|
||||
|
||||
virtual void f () = 0;
|
||||
virtual void f (void*) = 0;
|
||||
virtual void f (void*, void*) = 0;
|
||||
virtual void f (void*, void*, void*) = 0;
|
||||
virtual void f (void*, void*, void*, void*) = 0;
|
||||
virtual void f (void*, void*, void*, void*, void*) = 0;
|
||||
virtual void f (void*, void*, void*, void*, void*, void*) = 0;
|
||||
|
||||
int& c;
|
||||
};
|
||||
|
||||
struct Listener1 : public ListenerBase
|
||||
{
|
||||
Listener1 (int& counter) : ListenerBase (counter) {}
|
||||
|
||||
void f () override { c += 1; }
|
||||
void f (void*) override { c += 2; }
|
||||
void f (void*, void*) override { c += 3; }
|
||||
void f (void*, void*, void*) override { c += 4; }
|
||||
void f (void*, void*, void*, void*) override { c += 5; }
|
||||
void f (void*, void*, void*, void*, void*) override { c += 6; }
|
||||
void f (void*, void*, void*, void*, void*, void*) override { c += 7; }
|
||||
};
|
||||
|
||||
struct Listener2 : public ListenerBase
|
||||
{
|
||||
Listener2 (int& counter) : ListenerBase (counter) {}
|
||||
|
||||
void f () override { c -= 2; }
|
||||
void f (void*) override { c -= 4; }
|
||||
void f (void*, void*) override { c -= 6; }
|
||||
void f (void*, void*, void*) override { c -= 8; }
|
||||
void f (void*, void*, void*, void*) override { c -= 10; }
|
||||
void f (void*, void*, void*, void*, void*) override { c -= 12; }
|
||||
void f (void*, void*, void*, void*, void*, void*) override { c -= 14; }
|
||||
};
|
||||
|
||||
class ListenerListTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
ListenerListTests() : UnitTest ("ListenerList") {}
|
||||
|
||||
template <typename T>
|
||||
void callHelper (std::vector<int>& expectedCounterValues, T v)
|
||||
{
|
||||
counter = 0;
|
||||
listeners.call (&ListenerBase::f, v);
|
||||
expect (counter == expectedCounterValues[1]);
|
||||
|
||||
counter = 0;
|
||||
listeners.call (&ListenerBase::f);
|
||||
expect (counter == expectedCounterValues[0]);
|
||||
|
||||
ListenerList<ListenerBase>::DummyBailOutChecker boc;
|
||||
|
||||
counter = 0;
|
||||
listeners.callChecked (boc, &ListenerBase::f, v);
|
||||
expect (counter == expectedCounterValues[1]);
|
||||
|
||||
counter = 0;
|
||||
listeners.callChecked (boc, &ListenerBase::f);
|
||||
expect (counter == expectedCounterValues[0]);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void callHelper (std::vector<int>& expectedCounterValues, T first, Args... args)
|
||||
{
|
||||
const int expected = expectedCounterValues[sizeof... (args) + 1];
|
||||
|
||||
counter = 0;
|
||||
listeners.call (&ListenerBase::f, first, args...);
|
||||
expect (counter == expected);
|
||||
|
||||
ListenerList<ListenerBase>::DummyBailOutChecker boc;
|
||||
counter = 0;
|
||||
listeners.callChecked (boc, &ListenerBase::f, first, args...);
|
||||
expect (counter == expected);
|
||||
|
||||
callHelper (expectedCounterValues, args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void callExcludingHelper (ListenerBase& listenerToExclude,
|
||||
std::vector<int>& expectedCounterValues, T v)
|
||||
{
|
||||
counter = 0;
|
||||
listeners.callExcluding (listenerToExclude, &ListenerBase::f, v);
|
||||
expect (counter == expectedCounterValues[1]);
|
||||
|
||||
counter = 0;
|
||||
listeners.callExcluding (listenerToExclude, &ListenerBase::f);
|
||||
expect (counter == expectedCounterValues[0]);
|
||||
|
||||
ListenerList<ListenerBase>::DummyBailOutChecker boc;
|
||||
|
||||
counter = 0;
|
||||
listeners.callCheckedExcluding (listenerToExclude, boc, &ListenerBase::f, v);
|
||||
expect (counter == expectedCounterValues[1]);
|
||||
|
||||
counter = 0;
|
||||
listeners.callCheckedExcluding (listenerToExclude, boc, &ListenerBase::f);
|
||||
expect (counter == expectedCounterValues[0]);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void callExcludingHelper (ListenerBase& listenerToExclude,
|
||||
std::vector<int>& expectedCounterValues, T first, Args... args)
|
||||
{
|
||||
const int expected = expectedCounterValues[sizeof... (args) + 1];
|
||||
|
||||
counter = 0;
|
||||
listeners.callExcluding (listenerToExclude, &ListenerBase::f, first, args...);
|
||||
expect (counter == expected);
|
||||
|
||||
ListenerList<ListenerBase>::DummyBailOutChecker boc;
|
||||
counter = 0;
|
||||
listeners.callCheckedExcluding (listenerToExclude, boc, &ListenerBase::f, first, args...);
|
||||
expect (counter == expected);
|
||||
|
||||
callExcludingHelper (listenerToExclude, expectedCounterValues, args...);
|
||||
}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("Call single listener");
|
||||
listeners.add (&listener1);
|
||||
std::vector<int> expectedCounterValues = { 1, 2, 3, 4, 5, 6, 7 };
|
||||
callHelper (expectedCounterValues, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
beginTest ("Call multiple listeners");
|
||||
listeners.add (&listener2);
|
||||
expectedCounterValues = { -1, -2, -3, -4, -5, -6, -7 };
|
||||
callHelper (expectedCounterValues, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
beginTest ("Call listeners excluding");
|
||||
expectedCounterValues = { 1, 2, 3, 4, 5, 6, 7 };
|
||||
callExcludingHelper (listener2, expectedCounterValues, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
ListenerList<ListenerBase> listeners;
|
||||
Listener1 listener1 {counter};
|
||||
Listener2 listener2 {counter};
|
||||
};
|
||||
|
||||
static ListenerListTests listenerListTests;
|
||||
|
||||
#endif
|
||||
|
|
@ -152,8 +152,18 @@ public:
|
|||
callChecked (static_cast<const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction);
|
||||
}
|
||||
|
||||
/** Calls a member function, with no parameters, on all but the specified listener in the list.
|
||||
This can be useful if the caller is also a listener and needs to exclude itself.
|
||||
*/
|
||||
void callExcluding (ListenerClass& listenerToExclude, void (ListenerClass::*callbackFunction) ())
|
||||
{
|
||||
callCheckedExcluding (listenerToExclude,
|
||||
static_cast<const DummyBailOutChecker&> (DummyBailOutChecker()), callbackFunction);
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with no parameters and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker. */
|
||||
See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) ())
|
||||
|
|
@ -162,6 +172,20 @@ public:
|
|||
(iter.getListener()->*callbackFunction) ();
|
||||
}
|
||||
|
||||
/** Calls a member function on all but the specified listener in the list with a bail-out-checker.
|
||||
This can be useful if the caller is also a listener and needs to exclude itself. See the class
|
||||
description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType>
|
||||
void callCheckedExcluding (ListenerClass& listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) ())
|
||||
{
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) ();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Calls a member function on each listener in the list, with 1 parameter. */
|
||||
template <LL_TEMPLATE(1)>
|
||||
|
|
@ -171,8 +195,21 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1);
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with one parameter and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker. */
|
||||
/** Calls a member function, with 1 parameter, on all but the specified listener in the list.
|
||||
This can be useful if the caller is also a listener and needs to exclude itself.
|
||||
*/
|
||||
template <LL_TEMPLATE(1)>
|
||||
void callExcluding (ListenerClass& listenerToExclude,
|
||||
void (ListenerClass::*callbackFunction) (P1), LL_PARAM(1))
|
||||
{
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1);
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with 1 parameter and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1)>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1),
|
||||
|
|
@ -182,6 +219,21 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 1 parameter, on all but the specified listener in the list
|
||||
with a bail-out-checker. This can be useful if the caller is also a listener and needs to
|
||||
exclude itself. See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1)>
|
||||
void callCheckedExcluding (ListenerClass& listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1),
|
||||
LL_PARAM(1))
|
||||
{
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Calls a member function on each listener in the list, with 2 parameters. */
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2)>
|
||||
|
|
@ -192,8 +244,22 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 2 parameters, on all but the specified listener in the list.
|
||||
This can be useful if the caller is also a listener and needs to exclude itself.
|
||||
*/
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2)>
|
||||
void callExcluding (ListenerClass& listenerToExclude,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2),
|
||||
LL_PARAM(1), LL_PARAM(2))
|
||||
{
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2);
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with 2 parameters and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker. */
|
||||
See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2)>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2),
|
||||
|
|
@ -203,6 +269,21 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 2 parameters, on all but the specified listener in the list
|
||||
with a bail-out-checker. This can be useful if the caller is also a listener and needs to
|
||||
exclude itself. See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2)>
|
||||
void callCheckedExcluding (ListenerClass& listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2),
|
||||
LL_PARAM(1), LL_PARAM(2))
|
||||
{
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Calls a member function on each listener in the list, with 3 parameters. */
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
|
||||
|
|
@ -213,8 +294,22 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2, param3);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 3 parameters, on all but the specified listener in the list.
|
||||
This can be useful if the caller is also a listener and needs to exclude itself.
|
||||
*/
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
|
||||
void callExcluding (ListenerClass& listenerToExclude,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3),
|
||||
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3))
|
||||
{
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2, param3);
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with 3 parameters and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker. */
|
||||
See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3),
|
||||
|
|
@ -224,6 +319,21 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2, param3);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 3 parameters, on all but the specified listener in the list
|
||||
with a bail-out-checker. This can be useful if the caller is also a listener and needs to
|
||||
exclude itself. See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
|
||||
void callCheckedExcluding (ListenerClass& listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3),
|
||||
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3))
|
||||
{
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2, param3);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Calls a member function on each listener in the list, with 4 parameters. */
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
|
||||
|
|
@ -234,8 +344,22 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 4 parameters, on all but the specified listener in the list.
|
||||
This can be useful if the caller is also a listener and needs to exclude itself.
|
||||
*/
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
|
||||
void callExcluding (ListenerClass& listenerToExclude,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
|
||||
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4))
|
||||
{
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with 4 parameters and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker. */
|
||||
See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
|
||||
|
|
@ -245,6 +369,21 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 4 parameters, on all but the specified listener in the list
|
||||
with a bail-out-checker. This can be useful if the caller is also a listener and needs to
|
||||
exclude itself. See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
|
||||
void callCheckedExcluding (ListenerClass& listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
|
||||
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4))
|
||||
{
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Calls a member function on each listener in the list, with 5 parameters. */
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
|
||||
|
|
@ -255,8 +394,22 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 5 parameters, on all but the specified listener in the list.
|
||||
This can be useful if the caller is also a listener and needs to exclude itself.
|
||||
*/
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
|
||||
void callExcluding (ListenerClass& listenerToExclude,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
|
||||
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5))
|
||||
{
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with 5 parameters and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker. */
|
||||
See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
|
||||
|
|
@ -266,8 +419,23 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 5 parameters, on all but the specified listener in the list
|
||||
with a bail-out-checker. This can be useful if the caller is also a listener and needs to
|
||||
exclude itself. See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
|
||||
void callCheckedExcluding (ListenerClass& listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
|
||||
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5))
|
||||
{
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Calls a member function on each listener in the list, with 5 parameters. */
|
||||
/** Calls a member function on each listener in the list, with 6 parameters. */
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5), LL_TEMPLATE(6)>
|
||||
void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5, P6),
|
||||
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5), LL_PARAM(6))
|
||||
|
|
@ -276,8 +444,22 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5, param6);
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with 5 parameters and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker. */
|
||||
/** Calls a member function, with 6 parameters, on all but the specified listener in the list.
|
||||
This can be useful if the caller is also a listener and needs to exclude itself.
|
||||
*/
|
||||
template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5), LL_TEMPLATE(6)>
|
||||
void callExcluding (ListenerClass& listenerToExclude,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5, P6),
|
||||
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5), LL_PARAM(6))
|
||||
{
|
||||
for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5, param6);
|
||||
}
|
||||
|
||||
/** Calls a member function on each listener in the list, with 6 parameters and a bail-out-checker.
|
||||
See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5), LL_TEMPLATE(6)>
|
||||
void callChecked (const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5, P6),
|
||||
|
|
@ -287,6 +469,20 @@ public:
|
|||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5, param6);
|
||||
}
|
||||
|
||||
/** Calls a member function, with 5 parameters, on all but the specified listener in the list
|
||||
with a bail-out-checker. This can be useful if the caller is also a listener and needs to
|
||||
exclude itself. See the class description for info about writing a bail-out checker.
|
||||
*/
|
||||
template <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5), LL_TEMPLATE(6)>
|
||||
void callCheckedExcluding (ListenerClass& listenerToExclude,
|
||||
const BailOutCheckerType& bailOutChecker,
|
||||
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5, P6),
|
||||
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5), LL_PARAM(6))
|
||||
{
|
||||
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
||||
if (iter.getListener() != &listenerToExclude)
|
||||
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5, param6);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** A dummy bail-out checker that always returns false.
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ namespace juce
|
|||
|
||||
#include "containers/juce_AbstractFifo.cpp"
|
||||
#include "containers/juce_NamedValueSet.cpp"
|
||||
#include "containers/juce_ListenerList.cpp"
|
||||
#include "containers/juce_PropertySet.cpp"
|
||||
#include "containers/juce_Variant.cpp"
|
||||
#include "files/juce_DirectoryIterator.cpp"
|
||||
|
|
|
|||
|
|
@ -103,6 +103,30 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template <typename Method, typename ParamType>
|
||||
void callListenersExcluding (ValueTree::Listener* listenerToExclude,
|
||||
Method method, ValueTree& tree, ParamType& param2) const
|
||||
{
|
||||
const int numListeners = valueTreesWithListeners.size();
|
||||
|
||||
if (numListeners == 1)
|
||||
{
|
||||
valueTreesWithListeners.getUnchecked(0)->listeners.callExcluding (*listenerToExclude, method, tree, param2);
|
||||
}
|
||||
else if (numListeners > 0)
|
||||
{
|
||||
const SortedSet<ValueTree*> listenersCopy (valueTreesWithListeners);
|
||||
|
||||
for (int i = 0; i < numListeners; ++i)
|
||||
{
|
||||
ValueTree* const v = listenersCopy.getUnchecked(i);
|
||||
|
||||
if (i == 0 || valueTreesWithListeners.contains (v))
|
||||
v->listeners.callExcluding (*listenerToExclude, method, tree, param2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Method, typename ParamType1, typename ParamType2>
|
||||
void callListeners (Method method, ValueTree& tree, ParamType1& param2, ParamType2& param3) const
|
||||
{
|
||||
|
|
@ -126,12 +150,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void sendPropertyChangeMessage (const Identifier& property)
|
||||
void sendPropertyChangeMessage (const Identifier& property, ValueTree::Listener* listenerToExclude = nullptr)
|
||||
{
|
||||
ValueTree tree (this);
|
||||
|
||||
for (ValueTree::SharedObject* t = this; t != nullptr; t = t->parent)
|
||||
t->callListeners (&ValueTree::Listener::valueTreePropertyChanged, tree, property);
|
||||
if (listenerToExclude == nullptr)
|
||||
t->callListeners (&ValueTree::Listener::valueTreePropertyChanged, tree, property);
|
||||
else
|
||||
t->callListenersExcluding (listenerToExclude, &ValueTree::Listener::valueTreePropertyChanged, tree, property);
|
||||
}
|
||||
|
||||
void sendChildAddedMessage (ValueTree child)
|
||||
|
|
@ -169,23 +196,24 @@ public:
|
|||
callListeners (&ValueTree::Listener::valueTreeParentChanged, tree);
|
||||
}
|
||||
|
||||
void setProperty (const Identifier& name, const var& newValue, UndoManager* const undoManager)
|
||||
void setProperty (const Identifier& name, const var& newValue, UndoManager* const undoManager,
|
||||
ValueTree::Listener* listenerToExclude = nullptr)
|
||||
{
|
||||
if (undoManager == nullptr)
|
||||
{
|
||||
if (properties.set (name, newValue))
|
||||
sendPropertyChangeMessage (name);
|
||||
sendPropertyChangeMessage (name, listenerToExclude);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (const var* const existingValue = properties.getVarPointer (name))
|
||||
{
|
||||
if (*existingValue != newValue)
|
||||
undoManager->perform (new SetPropertyAction (this, name, newValue, *existingValue, false, false));
|
||||
undoManager->perform (new SetPropertyAction (this, name, newValue, *existingValue, false, false, listenerToExclude));
|
||||
}
|
||||
else
|
||||
{
|
||||
undoManager->perform (new SetPropertyAction (this, name, newValue, var(), true, false));
|
||||
undoManager->perform (new SetPropertyAction (this, name, newValue, var(), true, false, listenerToExclude));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -459,9 +487,11 @@ public:
|
|||
{
|
||||
public:
|
||||
SetPropertyAction (SharedObject* const so, const Identifier& propertyName,
|
||||
const var& newVal, const var& oldVal, bool isAdding, bool isDeleting)
|
||||
const var& newVal, const var& oldVal, bool isAdding, bool isDeleting,
|
||||
ValueTree::Listener* listenerToExclude = nullptr)
|
||||
: target (so), name (propertyName), newValue (newVal), oldValue (oldVal),
|
||||
isAddingNewProperty (isAdding), isDeletingProperty (isDeleting)
|
||||
isAddingNewProperty (isAdding), isDeletingProperty (isDeleting),
|
||||
excludeListener (listenerToExclude)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -472,7 +502,7 @@ public:
|
|||
if (isDeletingProperty)
|
||||
target->removeProperty (name, nullptr);
|
||||
else
|
||||
target->setProperty (name, newValue, nullptr);
|
||||
target->setProperty (name, newValue, nullptr, excludeListener);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -511,6 +541,7 @@ public:
|
|||
const var newValue;
|
||||
var oldValue;
|
||||
const bool isAddingNewProperty : 1, isDeletingProperty : 1;
|
||||
ValueTree::Listener* excludeListener;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (SetPropertyAction)
|
||||
};
|
||||
|
|
@ -762,12 +793,17 @@ const var* ValueTree::getPropertyPointer (const Identifier& name) const noexcept
|
|||
}
|
||||
|
||||
ValueTree& ValueTree::setProperty (const Identifier& name, const var& newValue, UndoManager* undoManager)
|
||||
{
|
||||
return setPropertyExcludingListener (nullptr, name, newValue, undoManager);
|
||||
}
|
||||
|
||||
ValueTree& ValueTree::setPropertyExcludingListener (Listener* listenerToExclude, const Identifier& name, const var& newValue, UndoManager* undoManager)
|
||||
{
|
||||
jassert (name.toString().isNotEmpty()); // Must have a valid property name!
|
||||
jassert (object != nullptr); // Trying to add a property to a null ValueTree will fail!
|
||||
|
||||
if (object != nullptr)
|
||||
object->setProperty (name, newValue, undoManager);
|
||||
object->setProperty (name, newValue, undoManager, listenerToExclude);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -483,6 +483,11 @@ public:
|
|||
/** Removes a listener that was previously added with addListener(). */
|
||||
void removeListener (Listener* listener);
|
||||
|
||||
/** Changes a named property of the node, but will not notify a specified listener of the change.
|
||||
@see setProperty
|
||||
*/
|
||||
ValueTree& setPropertyExcludingListener (Listener* listenerToExclude, const Identifier& name, const var& newValue, UndoManager* undoManager);
|
||||
|
||||
/** Causes a property-change callback to be triggered for the specified property,
|
||||
calling any listeners that are registered.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue