1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2017 - ROLI Ltd.
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11    Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12    27th April 2017).
13 
14    End User License Agreement: www.juce.com/juce-5-licence
15    Privacy Policy: www.juce.com/juce-5-privacy-policy
16 
17    Or: You may also use this code under the terms of the GPL v3 (see
18    www.gnu.org/licenses).
19 
20    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22    DISCLAIMED.
23 
24   ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
ValueSource()30 Value::ValueSource::ValueSource()
31 {
32 }
33 
~ValueSource()34 Value::ValueSource::~ValueSource()
35 {
36     cancelPendingUpdate();
37 }
38 
handleAsyncUpdate()39 void Value::ValueSource::handleAsyncUpdate()
40 {
41     sendChangeMessage (true);
42 }
43 
sendChangeMessage(const bool synchronous)44 void Value::ValueSource::sendChangeMessage (const bool synchronous)
45 {
46     const int numListeners = valuesWithListeners.size();
47 
48     if (numListeners > 0)
49     {
50         if (synchronous)
51         {
52             const ReferenceCountedObjectPtr<ValueSource> localRef (this);
53 
54             cancelPendingUpdate();
55 
56             for (int i = numListeners; --i >= 0;)
57                 if (Value* const v = valuesWithListeners[i])
58                     v->callListeners();
59         }
60         else
61         {
62             triggerAsyncUpdate();
63         }
64     }
65 }
66 
67 //==============================================================================
68 class SimpleValueSource  : public Value::ValueSource
69 {
70 public:
SimpleValueSource()71     SimpleValueSource()
72     {
73     }
74 
SimpleValueSource(const var & initialValue)75     SimpleValueSource (const var& initialValue)
76         : value (initialValue)
77     {
78     }
79 
getValue() const80     var getValue() const override
81     {
82         return value;
83     }
84 
setValue(const var & newValue)85     void setValue (const var& newValue) override
86     {
87         if (! newValue.equalsWithSameType (value))
88         {
89             value = newValue;
90             sendChangeMessage (false);
91         }
92     }
93 
94 private:
95     var value;
96 
97     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimpleValueSource)
98 };
99 
100 
101 //==============================================================================
Value()102 Value::Value()  : value (new SimpleValueSource())
103 {
104 }
105 
Value(ValueSource * const v)106 Value::Value (ValueSource* const v)  : value (v)
107 {
108     jassert (v != nullptr);
109 }
110 
Value(const var & initialValue)111 Value::Value (const var& initialValue)  : value (new SimpleValueSource (initialValue))
112 {
113 }
114 
Value(const Value & other)115 Value::Value (const Value& other)  : value (other.value)
116 {
117 }
118 
Value(Value && other)119 Value::Value (Value&& other) noexcept
120 {
121     // moving a Value with listeners will lose those listeners, which
122     // probably isn't what you wanted to happen!
123     jassert (other.listeners.size() == 0);
124 
125     other.removeFromListenerList();
126     value = std::move (other.value);
127 }
128 
operator =(Value && other)129 Value& Value::operator= (Value&& other) noexcept
130 {
131     // moving a Value with listeners will lose those listeners, which
132     // probably isn't what you wanted to happen!
133     jassert (other.listeners.size() == 0);
134 
135     other.removeFromListenerList();
136     value = std::move (other.value);
137     return *this;
138 }
139 
~Value()140 Value::~Value()
141 {
142     removeFromListenerList();
143 }
144 
removeFromListenerList()145 void Value::removeFromListenerList()
146 {
147     if (listeners.size() > 0 && value != nullptr) // may be nullptr after a move operation
148         value->valuesWithListeners.removeValue (this);
149 }
150 
151 //==============================================================================
getValue() const152 var Value::getValue() const
153 {
154     return value->getValue();
155 }
156 
operator var() const157 Value::operator var() const
158 {
159     return value->getValue();
160 }
161 
setValue(const var & newValue)162 void Value::setValue (const var& newValue)
163 {
164     value->setValue (newValue);
165 }
166 
toString() const167 String Value::toString() const
168 {
169     return value->getValue().toString();
170 }
171 
operator =(const var & newValue)172 Value& Value::operator= (const var& newValue)
173 {
174     value->setValue (newValue);
175     return *this;
176 }
177 
referTo(const Value & valueToReferTo)178 void Value::referTo (const Value& valueToReferTo)
179 {
180     if (valueToReferTo.value != value)
181     {
182         if (listeners.size() > 0)
183         {
184             value->valuesWithListeners.removeValue (this);
185             valueToReferTo.value->valuesWithListeners.add (this);
186         }
187 
188         value = valueToReferTo.value;
189         callListeners();
190     }
191 }
192 
refersToSameSourceAs(const Value & other) const193 bool Value::refersToSameSourceAs (const Value& other) const
194 {
195     return value == other.value;
196 }
197 
operator ==(const Value & other) const198 bool Value::operator== (const Value& other) const
199 {
200     return value == other.value || value->getValue() == other.getValue();
201 }
202 
operator !=(const Value & other) const203 bool Value::operator!= (const Value& other) const
204 {
205     return value != other.value && value->getValue() != other.getValue();
206 }
207 
208 //==============================================================================
addListener(Value::Listener * listener)209 void Value::addListener (Value::Listener* listener)
210 {
211     if (listener != nullptr)
212     {
213         if (listeners.size() == 0)
214             value->valuesWithListeners.add (this);
215 
216         listeners.add (listener);
217     }
218 }
219 
removeListener(Value::Listener * listener)220 void Value::removeListener (Value::Listener* listener)
221 {
222     listeners.remove (listener);
223 
224     if (listeners.size() == 0)
225         value->valuesWithListeners.removeValue (this);
226 }
227 
callListeners()228 void Value::callListeners()
229 {
230     if (listeners.size() > 0)
231     {
232         Value v (*this); // (create a copy in case this gets deleted by a callback)
233         listeners.call ([&] (Value::Listener& l) { l.valueChanged (v); });
234     }
235 }
236 
operator <<(OutputStream & stream,const Value & value)237 OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const Value& value)
238 {
239     return stream << value.toString();
240 }
241 
242 } // namespace juce
243