/* ============================================================================== This file is part of the JUCE 6 technical preview. Copyright (c) 2020 - Raw Material Software Limited You may use this code under the terms of the GPL v3 (see www.gnu.org/licenses). For this technical preview, this file is not subject to commercial licensing. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ namespace juce { Value::ValueSource::ValueSource() { } Value::ValueSource::~ValueSource() { cancelPendingUpdate(); } void Value::ValueSource::handleAsyncUpdate() { sendChangeMessage (true); } void Value::ValueSource::sendChangeMessage (const bool synchronous) { const int numListeners = valuesWithListeners.size(); if (numListeners > 0) { if (synchronous) { const ReferenceCountedObjectPtr localRef (this); cancelPendingUpdate(); for (int i = numListeners; --i >= 0;) if (Value* const v = valuesWithListeners[i]) v->callListeners(); } else { triggerAsyncUpdate(); } } } //============================================================================== class SimpleValueSource : public Value::ValueSource { public: SimpleValueSource() { } SimpleValueSource (const var& initialValue) : value (initialValue) { } var getValue() const override { return value; } void setValue (const var& newValue) override { if (! newValue.equalsWithSameType (value)) { value = newValue; sendChangeMessage (false); } } private: var value; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimpleValueSource) }; //============================================================================== Value::Value() : value (new SimpleValueSource()) { } Value::Value (ValueSource* const v) : value (v) { jassert (v != nullptr); } Value::Value (const var& initialValue) : value (new SimpleValueSource (initialValue)) { } Value::Value (const Value& other) : value (other.value) { } Value::Value (Value&& other) noexcept { // moving a Value with listeners will lose those listeners, which // probably isn't what you wanted to happen! jassert (other.listeners.size() == 0); other.removeFromListenerList(); value = std::move (other.value); } Value& Value::operator= (Value&& other) noexcept { // moving a Value with listeners will lose those listeners, which // probably isn't what you wanted to happen! jassert (other.listeners.size() == 0); other.removeFromListenerList(); value = std::move (other.value); return *this; } Value::~Value() { removeFromListenerList(); } void Value::removeFromListenerList() { if (listeners.size() > 0 && value != nullptr) // may be nullptr after a move operation value->valuesWithListeners.removeValue (this); } //============================================================================== var Value::getValue() const { return value->getValue(); } Value::operator var() const { return value->getValue(); } void Value::setValue (const var& newValue) { value->setValue (newValue); } String Value::toString() const { return value->getValue().toString(); } Value& Value::operator= (const var& newValue) { value->setValue (newValue); return *this; } void Value::referTo (const Value& valueToReferTo) { if (valueToReferTo.value != value) { if (listeners.size() > 0) { value->valuesWithListeners.removeValue (this); valueToReferTo.value->valuesWithListeners.add (this); } value = valueToReferTo.value; callListeners(); } } bool Value::refersToSameSourceAs (const Value& other) const { return value == other.value; } bool Value::operator== (const Value& other) const { return value == other.value || value->getValue() == other.getValue(); } bool Value::operator!= (const Value& other) const { return value != other.value && value->getValue() != other.getValue(); } //============================================================================== void Value::addListener (Value::Listener* listener) { if (listener != nullptr) { if (listeners.size() == 0) value->valuesWithListeners.add (this); listeners.add (listener); } } void Value::removeListener (Value::Listener* listener) { listeners.remove (listener); if (listeners.size() == 0) value->valuesWithListeners.removeValue (this); } void Value::callListeners() { if (listeners.size() > 0) { Value v (*this); // (create a copy in case this gets deleted by a callback) listeners.call ([&] (Value::Listener& l) { l.valueChanged (v); }); } } OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const Value& value) { return stream << value.toString(); } } // namespace juce