21namespace tracktion {
inline namespace engine
28template<
typename VarType>
31 if (
const auto* prop = v.getPropertyPointer (
id))
33 (*
const_cast<juce::var*
> (prop)) =
static_cast<VarType
> (*prop);
38static bool setIfDifferent (T& val, T newVal)
noexcept
48template<
typename Type>
51 for (
auto&& h : haystack)
59template<
typename Type,
typename UnaryFunction>
67template <
typename... Others>
70 static_assert ((
sizeof...(others) & 1) == 0,
"The property list must be a sequence of name, value pairs");
72 v.setProperty (name, value,
nullptr);
74 if constexpr (
sizeof...(others) != 0)
78template <
typename... Properties>
81 static_assert ((
sizeof...(properties) & 1) == 0,
"The property list must be a sequence of name, value pairs");
90template<
typename ObjectType,
typename CriticalSectionType = juce::DummyCriticalSection>
104 inline int size()
const {
return objects.
size(); }
105 inline bool isEmpty()
const noexcept {
return size() == 0; }
106 ObjectType* operator[] (
int idx)
const {
return objects[idx]; }
107 ObjectType* at (
int idx) {
return objects[idx]; }
108 ObjectType** begin() {
return objects.
begin(); }
109 ObjectType*
const* begin()
const {
return objects.
begin(); }
110 ObjectType** end() {
return objects.
end(); }
111 ObjectType*
const* end()
const {
return objects.
end(); }
114 void rebuildObjects()
118 for (
const auto& v : parent)
119 if (isSuitableType (v))
120 if (
auto newObject = createNewObject (v))
121 objects.
add (newObject);
134 virtual void deleteObject (ObjectType*) = 0;
136 virtual void newObjectAdded (ObjectType*) = 0;
137 virtual void objectRemoved (ObjectType*) = 0;
138 virtual void objectOrderChanged() = 0;
143 if (isChildTree (tree))
145 auto index = parent.
indexOf (tree);
149 if (
auto* newObject = createNewObject (tree))
152 const ScopedLockType sl (arrayLock);
155 objects.
add (newObject);
160 newObjectAdded (newObject);
169 if (parent == exParent && isSuitableType (tree))
171 auto oldIndex = indexOf (tree);
178 const ScopedLockType sl (arrayLock);
188 void valueTreeChildOrderChanged (
juce::ValueTree& tree,
int,
int)
override
193 const ScopedLockType sl (arrayLock);
197 objectOrderChanged();
207 CriticalSectionType arrayLock;
208 using ScopedLockType =
typename CriticalSectionType::ScopedLockType;
213 void deleteAllObjects()
215 const ScopedLockType sl (arrayLock);
217 while (objects.
size() > 0)
223 return isSuitableType (v) && v.getParent() == parent;
228 for (
int i = 0; i < objects.
size(); ++i)
237 objects.
sort (*
this);
241 int compareElements (ObjectType* first, ObjectType* second)
const
243 int index1 = parent.
indexOf (first->state);
244 int index2 = parent.
indexOf (second->state);
245 jassert (index1 >= 0 && index2 >= 0);
246 return index1 - index2;
253template<
typename ObjectType>
279 TRACKTION_ASSERT_MESSAGE_THREAD
280 jassert (! insidePropertyChangedMethod);
282 if (setIfDifferent (needsSorting,
false))
288 return sortedObjects;
293 void newObjectAdded (ObjectType* o)
override { triggerSortIfNeeded (o, -1); }
294 void objectOrderChanged()
override { triggerSort(); }
303 const int objectIndex = getSortedIndex (v);
304 triggerSortIfNeeded (sortedObjects.
getUnchecked (objectIndex), objectIndex);
308 mutable bool needsSorting =
true;
310 bool insidePropertyChangedMethod =
false;
314 for (
int i = sortedObjects.
size(); --i >= 0;)
321 void triggerSort()
const
323 TRACKTION_ASSERT_MESSAGE_THREAD
327 void triggerSortIfNeeded (ObjectType* o,
int objectIndex)
333 return triggerSort();
339 return triggerSort();
341 if (objectIndex < (sortedObjects.
size() - 1)
343 return triggerSort();
351template<
typename ObjectType>
354 for (
auto* o : objectList.objects)
365 virtual void valueTreeChanged() = 0;
371 void valueTreeChildOrderChanged (
juce::ValueTree&,
int,
int)
override { valueTreeChanged(); }
372 void valueTreeParentChanged (
juce::ValueTree&)
override { valueTreeChanged(); }
373 void valueTreeRedirected (
juce::ValueTree&)
override { valueTreeChanged(); }
376template<
typename Type>
381 : attributeToSort (attributeToSort_), direction (forwards ? 1 : -1)
386 const int result = (Type (first[attributeToSort]) > Type (second[attributeToSort])) ? 1 : -1;
388 return direction * result;
401 const int result = first[attributeToSort].toString().compareNatural (second[attributeToSort].toString());
403 return direction * result;
418 : tree (treeToReference)
438 return refTree->getValueTree();
455 return juce::ValueTree::fromXml (*xml);
462 return juce::ValueTree::readFromStream (is);
476 if (! os.getStatus().wasOk())
481 if (
auto xml = v.createXml())
486 v.writeToStream (os);
490 if (temp.getFile().existsAsFile())
491 return temp.overwriteTargetFileWithTemporary();
499 if (! v.hasProperty (
id))
500 v.setProperty (
id, value, um);
508 dest = src.createCopy();
515 for (
int i = 0; i < src.getNumChildren(); ++i)
516 dest.
addChild (src.getChild (i).createCopy(), i, um);
522template <
typename Predicate>
526 for (
int i = 0; i < src.getNumProperties(); ++i)
528 auto name = src.getPropertyName (i);
530 if (shouldCopyProperty (name))
531 dest.
setProperty (name, src.getProperty (name), um);
539 const int numChildren = p.getNumChildren();
541 for (
int i = 0; i < numChildren; ++i)
543 auto c = p.getChild (i);
545 if (c.getProperty (propertyName) == propertyValue)
548 c = getChildWithPropertyRecursively (c, propertyName, propertyValue);
557template<
typename ValueType,
typename... CachedValues>
560 if (
auto p = v.getPropertyPointer (cachedValue.
getPropertyID()))
561 cachedValue = ValueType (*p);
565 if constexpr (
sizeof...(cachedValues) != 0)
572 for (
int i = trees.
size(); --i >= 0;)
585 for (
const auto& v : trees)
586 if (v.hasType (type))
595 for (
auto child : tree)
598 getChildTreesRecursive (result, child);
613 for (
auto child : tree)
614 renamePropertyRecursive (child, oldName, newName, um);
ElementType getUnchecked(int index) const
bool isEmpty() const noexcept
int size() const noexcept
void remove(int indexToRemove)
ElementType * begin() noexcept
ElementType * end() noexcept
void add(const ElementType &newElement)
ElementType removeAndReturn(int indexToRemove)
int addSorted(ElementComparator &comparator, ParameterType newElement)
ElementType & getReference(int index) noexcept
const Identifier & getPropertyID() const noexcept
static Colour fromString(StringRef encodedColourString)
bool isValid() const noexcept
const String & toString() const noexcept
int getNumChildren() const noexcept
void copyPropertiesFrom(const ValueTree &source, UndoManager *undoManager)
bool isValid() const noexcept
const var * getPropertyPointer(const Identifier &name) const noexcept
ValueTree & setProperty(const Identifier &name, const var &newValue, UndoManager *undoManager)
void removeAllChildren(UndoManager *undoManager)
void addListener(Listener *listener)
int indexOf(const ValueTree &child) const noexcept
void addChild(const ValueTree &child, int index, UndoManager *undoManager)
ValueTree getParent() const noexcept
void removeListener(Listener *listener)
void removeProperty(const Identifier &name, UndoManager *undoManager)
Holds a ValueTree as a ReferenceCountedObject.
juce::ValueTree getValueTree() noexcept
Returns the ValueTree being held.
static juce::ValueTree getTreeFromObject(const juce::var &treeObject) noexcept
Provides a simple way of getting the tree from a var object which is a ReferencedCountedValueTree.
ReferenceCountedValueTree(const juce::ValueTree &treeToReference) noexcept
Creates a ReferenceCountedValueTree for a given ValueTree.
~ReferenceCountedValueTree()
Destructor.
void setValueTree(juce::ValueTree newTree)
Sets the ValueTree being held.
std::unique_ptr< XmlElement > parseXML(const String &textToParse)
void ignoreUnused(Types &&...) noexcept
void forEachItem(const juce::Array< Type * > &items, const UnaryFunction &fn)
Calls a function object on each item in an array.
juce::Array< juce::ValueTree > getTreesOfType(const juce::Array< juce::ValueTree > &trees, const juce::Identifier &type)
Returns a new array with any trees without the given type removed.
void convertPropertyToType(juce::ValueTree &v, const juce::Identifier &id)
Ensures a property is a given type which can avoid having to parse a string every time it is read aft...
bool matchesAnyOf(const Type &needle, const std::initializer_list< Type > &haystack)
Returns true if the needle is found in the haystack.
juce::Array< juce::ValueTree > & removeInvalidValueTrees(juce::Array< juce::ValueTree > &trees)
Strips out any invalid trees from the array.
const juce::Array< ObjectType * > & getSortedObjects() const
Returns the object for a given state.
virtual bool isSortableProperty(juce::ValueTree &, const juce::Identifier &)=0
Should return true if the given Identifier is used to sort the tree.
virtual void sortObjects(juce::Array< ObjectType * > &objectsToBeSorted) const =0
Must sort the given array.
virtual bool objectsAreSorted(const ObjectType &first, const ObjectType &second)=0
Should return true if the objects are in a sorted order.