From e018192de22be9830ffb73d58e1c28c043f535ab Mon Sep 17 00:00:00 2001 From: jules Date: Sun, 21 Jun 2015 18:54:08 +0100 Subject: [PATCH 01/11] Performance optimisations to the way that Identifier objects are passed into var, ValueTree and NamedValueSet. The Identifer class used to be light enough to pass by value but now contains a String so is better passed by reference. --- .../wrapper/juce_NPAPI_GlueCode.cpp | 30 +++++++----- .../containers/juce_NamedValueSet.cpp | 6 ++- modules/juce_core/containers/juce_Variant.cpp | 18 +++---- modules/juce_core/containers/juce_Variant.h | 19 ++++---- modules/juce_core/text/juce_Identifier.cpp | 12 ++++- modules/juce_core/text/juce_Identifier.h | 14 ++++-- .../values/juce_ValueTree.cpp | 47 +++++++++---------- .../values/juce_ValueTree.h | 26 +++++----- 8 files changed, 97 insertions(+), 75 deletions(-) diff --git a/modules/juce_browser_plugin_client/wrapper/juce_NPAPI_GlueCode.cpp b/modules/juce_browser_plugin_client/wrapper/juce_NPAPI_GlueCode.cpp index e41feda6af..42748b9230 100644 --- a/modules/juce_browser_plugin_client/wrapper/juce_NPAPI_GlueCode.cpp +++ b/modules/juce_browser_plugin_client/wrapper/juce_NPAPI_GlueCode.cpp @@ -584,7 +584,7 @@ public: }; //============================================================================== -static NPIdentifier getIdentifierFromString (const var::identifier& s) noexcept +static NPIdentifier getIdentifierFromString (const Identifier& s) noexcept { return browser.getstringidentifier (s.toString().toUTF8()); } @@ -601,6 +601,7 @@ class DynamicObjectWrappingNPObject : public DynamicObject { NPP npp; NPObject* const source; + mutable var returnValue; public: DynamicObjectWrappingNPObject (NPP npp_, NPObject* const source_) @@ -616,17 +617,20 @@ public: DBG ("num NP wrapper objs: " + String (--numDOWNP)); } - var getProperty (const var::identifier& propertyName) const override + const var& getProperty (const Identifier& propertyName) const override { NPVariant result; VOID_TO_NPVARIANT (result); browser.getproperty (npp, source, getIdentifierFromString (propertyName), &result); - const var v (createValueFromNPVariant (npp, result)); + + // NB: this is just a workaorund for the return type being a reference - not too bothered + // about threading implications of this since this code will all soon be deprecated anyway. + returnValue = createValueFromNPVariant (npp, result); browser.releasevariantvalue (&result); - return v; + return returnValue; } - bool hasProperty (const var::identifier& propertyName) const override + bool hasProperty (const Identifier& propertyName) const override { NPVariant result; VOID_TO_NPVARIANT (result); @@ -635,7 +639,7 @@ public: return hasProp; } - void setProperty (const var::identifier& propertyName, const var& newValue) override + void setProperty (const Identifier& propertyName, const var& newValue) override { NPVariant value; createNPVariantFromValue (npp, value, newValue); @@ -644,12 +648,12 @@ public: browser.releasevariantvalue (&value); } - void removeProperty (const var::identifier& propertyName) override + void removeProperty (const Identifier& propertyName) override { browser.removeproperty (npp, source, getIdentifierFromString (propertyName)); } - bool hasMethod (const var::identifier& methodName) const override + bool hasMethod (const Identifier& methodName) const override { return browser.hasmethod (npp, source, getIdentifierFromString (methodName)); } @@ -721,7 +725,7 @@ private: bool invoke (NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* out) { DynamicObject* const o = object.getDynamicObject(); - const var::identifier methodName (identifierToString (name)); + const Identifier methodName (identifierToString (name)); if (o == nullptr || ! o->hasMethod (methodName)) return false; @@ -761,7 +765,7 @@ private: bool getProperty (NPIdentifier name, NPVariant* out) { DynamicObject* const o = object.getDynamicObject(); - const var::identifier propName (identifierToString (name)); + const Identifier propName (identifierToString (name)); if (o == nullptr || ! o->hasProperty (propName)) return false; @@ -788,7 +792,7 @@ private: bool removeProperty (NPIdentifier name) { DynamicObject* const o = object.getDynamicObject(); - const var::identifier propName (identifierToString (name)); + const Identifier propName (identifierToString (name)); if (o == nullptr || ! o->hasProperty (propName)) return false; @@ -806,10 +810,10 @@ private: NPP npp; var object; - static var::identifier identifierToString (NPIdentifier id) + static Identifier identifierToString (NPIdentifier id) { NPUTF8* const name = browser.utf8fromidentifier (id); - const var::identifier result ((const char*) name); + const Identifier result ((const char*) name); browser.memfree (name); return result; } diff --git a/modules/juce_core/containers/juce_NamedValueSet.cpp b/modules/juce_core/containers/juce_NamedValueSet.cpp index 504ab784f4..2c153e1f19 100644 --- a/modules/juce_core/containers/juce_NamedValueSet.cpp +++ b/modules/juce_core/containers/juce_NamedValueSet.cpp @@ -29,7 +29,7 @@ struct NamedValueSet::NamedValue { NamedValue() noexcept {} - NamedValue (Identifier n, const var& v) : name (n), value (v) {} + NamedValue (const Identifier& n, const var& v) : name (n), value (v) {} NamedValue (const NamedValue& other) : name (other.name), value (other.value) {} #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS @@ -39,7 +39,9 @@ struct NamedValueSet::NamedValue { } - NamedValue (Identifier n, var&& v) : name (n), value (static_cast (v)) + NamedValue (Identifier&& n, var&& v) + : name (static_cast (n)), + value (static_cast (v)) { } diff --git a/modules/juce_core/containers/juce_Variant.cpp b/modules/juce_core/containers/juce_Variant.cpp index 833d7927a8..0cad685920 100644 --- a/modules/juce_core/containers/juce_Variant.cpp +++ b/modules/juce_core/containers/juce_Variant.cpp @@ -576,7 +576,7 @@ var var::clone() const noexcept } //============================================================================== -const var& var::operator[] (Identifier propertyName) const +const var& var::operator[] (const Identifier& propertyName) const { if (DynamicObject* const o = getDynamicObject()) return o->getProperty (propertyName); @@ -589,7 +589,7 @@ const var& var::operator[] (const char* const propertyName) const return operator[] (Identifier (propertyName)); } -var var::getProperty (const Identifier propertyName, const var& defaultReturnValue) const +var var::getProperty (const Identifier& propertyName, const var& defaultReturnValue) const { if (DynamicObject* const o = getDynamicObject()) return o->getProperties().getWithDefault (propertyName, defaultReturnValue); @@ -602,7 +602,7 @@ var::NativeFunction var::getNativeFunction() const return isMethod() ? value.methodValue : nullptr; } -var var::invoke (Identifier method, const var* arguments, int numArguments) const +var var::invoke (const Identifier& method, const var* arguments, int numArguments) const { if (DynamicObject* const o = getDynamicObject()) return o->invokeMethod (method, var::NativeFunctionArgs (*this, arguments, numArguments)); @@ -610,35 +610,35 @@ var var::invoke (Identifier method, const var* arguments, int numArguments) cons return var(); } -var var::call (const Identifier method) const +var var::call (const Identifier& method) const { return invoke (method, nullptr, 0); } -var var::call (const Identifier method, const var& arg1) const +var var::call (const Identifier& method, const var& arg1) const { return invoke (method, &arg1, 1); } -var var::call (const Identifier method, const var& arg1, const var& arg2) const +var var::call (const Identifier& method, const var& arg1, const var& arg2) const { var args[] = { arg1, arg2 }; return invoke (method, args, 2); } -var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3) +var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3) { var args[] = { arg1, arg2, arg3 }; return invoke (method, args, 3); } -var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const +var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const { var args[] = { arg1, arg2, arg3, arg4 }; return invoke (method, args, 4); } -var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const +var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const { var args[] = { arg1, arg2, arg3, arg4, arg5 }; return invoke (method, args, 5); diff --git a/modules/juce_core/containers/juce_Variant.h b/modules/juce_core/containers/juce_Variant.h index 1e0f03cf56..ed624f4d95 100644 --- a/modules/juce_core/containers/juce_Variant.h +++ b/modules/juce_core/containers/juce_Variant.h @@ -62,7 +62,6 @@ public: }; typedef var (*NativeFunction) (const NativeFunctionArgs&); - typedef Identifier identifier; //============================================================================== /** Creates a void variant. */ @@ -242,27 +241,27 @@ public: //============================================================================== /** If this variant is an object, this returns one of its properties. */ - const var& operator[] (Identifier propertyName) const; + const var& operator[] (const Identifier& propertyName) const; /** If this variant is an object, this returns one of its properties. */ const var& operator[] (const char* propertyName) const; /** If this variant is an object, this returns one of its properties, or a default fallback value if the property is not set. */ - var getProperty (Identifier propertyName, const var& defaultReturnValue) const; + var getProperty (const Identifier& propertyName, const var& defaultReturnValue) const; /** Invokes a named method call with no arguments. */ - var call (Identifier method) const; + var call (const Identifier& method) const; /** Invokes a named method call with one argument. */ - var call (Identifier method, const var& arg1) const; + var call (const Identifier& method, const var& arg1) const; /** Invokes a named method call with 2 arguments. */ - var call (Identifier method, const var& arg1, const var& arg2) const; + var call (const Identifier& method, const var& arg1, const var& arg2) const; /** Invokes a named method call with 3 arguments. */ - var call (Identifier method, const var& arg1, const var& arg2, const var& arg3); + var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3); /** Invokes a named method call with 4 arguments. */ - var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; + var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; /** Invokes a named method call with 5 arguments. */ - var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const; + var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const; /** Invokes a named method call with a list of arguments. */ - var invoke (Identifier method, const var* arguments, int numArguments) const; + var invoke (const Identifier& method, const var* arguments, int numArguments) const; /** If this object is a method, this returns the function pointer. */ NativeFunction getNativeFunction() const; diff --git a/modules/juce_core/text/juce_Identifier.cpp b/modules/juce_core/text/juce_Identifier.cpp index 4d9d3ea55f..04cfd13d1c 100644 --- a/modules/juce_core/text/juce_Identifier.cpp +++ b/modules/juce_core/text/juce_Identifier.cpp @@ -31,7 +31,17 @@ Identifier::~Identifier() noexcept {} Identifier::Identifier (const Identifier& other) noexcept : name (other.name) {} -Identifier& Identifier::operator= (const Identifier other) noexcept +#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS +Identifier::Identifier (Identifier&& other) noexcept : name (static_cast (other.name)) {} + +Identifier& Identifier::operator= (Identifier&& other) noexcept +{ + name = static_cast (other.name); + return *this; +} +#endif + +Identifier& Identifier::operator= (const Identifier& other) noexcept { name = other.name; return *this; diff --git a/modules/juce_core/text/juce_Identifier.h b/modules/juce_core/text/juce_Identifier.h index f60eec8d45..0abc1ae4ac 100644 --- a/modules/juce_core/text/juce_Identifier.h +++ b/modules/juce_core/text/juce_Identifier.h @@ -68,16 +68,24 @@ public: Identifier (const Identifier& other) noexcept; /** Creates a copy of another identifier. */ - Identifier& operator= (const Identifier other) noexcept; + Identifier& operator= (const Identifier& other) noexcept; + + #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS + /** Creates a copy of another identifier. */ + Identifier (Identifier&& other) noexcept; + + /** Creates a copy of another identifier. */ + Identifier& operator= (Identifier&& other) noexcept; + #endif /** Destructor */ ~Identifier() noexcept; /** Compares two identifiers. This is a very fast operation. */ - inline bool operator== (Identifier other) const noexcept { return name.getCharPointer() == other.name.getCharPointer(); } + inline bool operator== (const Identifier& other) const noexcept { return name.getCharPointer() == other.name.getCharPointer(); } /** Compares two identifiers. This is a very fast operation. */ - inline bool operator!= (Identifier other) const noexcept { return name.getCharPointer() != other.name.getCharPointer(); } + inline bool operator!= (const Identifier& other) const noexcept { return name.getCharPointer() != other.name.getCharPointer(); } /** Compares the identifier with a string. */ inline bool operator== (StringRef other) const noexcept { return name == other; } diff --git a/modules/juce_data_structures/values/juce_ValueTree.cpp b/modules/juce_data_structures/values/juce_ValueTree.cpp index 43cfc564c7..1efcb0b099 100644 --- a/modules/juce_data_structures/values/juce_ValueTree.cpp +++ b/modules/juce_data_structures/values/juce_ValueTree.cpp @@ -27,7 +27,7 @@ class ValueTree::SharedObject : public ReferenceCountedObject public: typedef ReferenceCountedObjectPtr Ptr; - explicit SharedObject (Identifier t) noexcept + explicit SharedObject (const Identifier& t) noexcept : type (t), parent (nullptr) { } @@ -126,7 +126,7 @@ public: } } - void sendPropertyChangeMessage (const Identifier property) + void sendPropertyChangeMessage (const Identifier& property) { ValueTree tree (this); @@ -169,7 +169,7 @@ 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) { if (undoManager == nullptr) { @@ -190,12 +190,12 @@ public: } } - bool hasProperty (const Identifier name) const noexcept + bool hasProperty (const Identifier& name) const noexcept { return properties.contains (name); } - void removeProperty (const Identifier name, UndoManager* const undoManager) + void removeProperty (const Identifier& name, UndoManager* const undoManager) { if (undoManager == nullptr) { @@ -238,7 +238,7 @@ public: setProperty (source.properties.getName(i), source.properties.getValueAt(i), undoManager); } - ValueTree getChildWithName (const Identifier typeToMatch) const + ValueTree getChildWithName (const Identifier& typeToMatch) const { for (int i = 0; i < children.size(); ++i) { @@ -250,7 +250,7 @@ public: return ValueTree(); } - ValueTree getOrCreateChildWithName (const Identifier typeToMatch, UndoManager* undoManager) + ValueTree getOrCreateChildWithName (const Identifier& typeToMatch, UndoManager* undoManager) { for (int i = 0; i < children.size(); ++i) { @@ -265,7 +265,7 @@ public: } - ValueTree getChildWithProperty (const Identifier propertyName, const var& propertyValue) const + ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const { for (int i = 0; i < children.size(); ++i) { @@ -458,7 +458,7 @@ public: class SetPropertyAction : public UndoableAction { public: - SetPropertyAction (SharedObject* const so, const Identifier propertyName, + SetPropertyAction (SharedObject* const so, const Identifier& propertyName, const var& newVal, const var& oldVal, bool isAdding, bool isDeleting) : target (so), name (propertyName), newValue (newVal), oldValue (oldVal), isAddingNewProperty (isAdding), isDeletingProperty (isDeleting) @@ -629,7 +629,7 @@ ValueTree::ValueTree() noexcept const ValueTree ValueTree::invalid; -ValueTree::ValueTree (Identifier type) : object (new ValueTree::SharedObject (type)) +ValueTree::ValueTree (const Identifier& type) : object (new ValueTree::SharedObject (type)) { jassert (type.toString().isNotEmpty()); // All objects must be given a sensible type name! } @@ -702,7 +702,7 @@ ValueTree ValueTree::createCopy() const return ValueTree (createCopyIfNotNull (object.get())); } -bool ValueTree::hasType (const Identifier typeName) const +bool ValueTree::hasType (const Identifier& typeName) const { return object != nullptr && object->type == typeName; } @@ -727,24 +727,23 @@ ValueTree ValueTree::getSibling (const int delta) const return ValueTree (object->parent->children.getObjectPointer (index)); } -const var& ValueTree::operator[] (const Identifier name) const +const var& ValueTree::operator[] (const Identifier& name) const { return object == nullptr ? var::null : object->properties[name]; } -const var& ValueTree::getProperty (const Identifier name) const +const var& ValueTree::getProperty (const Identifier& name) const { return object == nullptr ? var::null : object->properties[name]; } -var ValueTree::getProperty (const Identifier name, const var& defaultReturnValue) const +var ValueTree::getProperty (const Identifier& name, const var& defaultReturnValue) const { return object == nullptr ? defaultReturnValue : object->properties.getWithDefault (name, defaultReturnValue); } -ValueTree& ValueTree::setProperty (const Identifier name, const var& newValue, - UndoManager* const undoManager) +ValueTree& ValueTree::setProperty (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! @@ -755,12 +754,12 @@ ValueTree& ValueTree::setProperty (const Identifier name, const var& newValue, return *this; } -bool ValueTree::hasProperty (const Identifier name) const +bool ValueTree::hasProperty (const Identifier& name) const { return object != nullptr && object->hasProperty (name); } -void ValueTree::removeProperty (const Identifier name, UndoManager* const undoManager) +void ValueTree::removeProperty (const Identifier& name, UndoManager* const undoManager) { if (object != nullptr) object->removeProperty (name, undoManager); @@ -803,7 +802,7 @@ class ValueTreePropertyValueSource : public Value::ValueSource, private ValueTree::Listener { public: - ValueTreePropertyValueSource (const ValueTree& vt, const Identifier prop, UndoManager* um) + ValueTreePropertyValueSource (const ValueTree& vt, const Identifier& prop, UndoManager* um) : tree (vt), property (prop), undoManager (um) { tree.addListener (this); @@ -836,7 +835,7 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueTreePropertyValueSource) }; -Value ValueTree::getPropertyAsValue (const Identifier name, UndoManager* const undoManager) +Value ValueTree::getPropertyAsValue (const Identifier& name, UndoManager* const undoManager) { return Value (new ValueTreePropertyValueSource (*this, name, undoManager)); } @@ -853,17 +852,17 @@ ValueTree ValueTree::getChild (int index) const : static_cast (nullptr)); } -ValueTree ValueTree::getChildWithName (const Identifier type) const +ValueTree ValueTree::getChildWithName (const Identifier& type) const { return object != nullptr ? object->getChildWithName (type) : ValueTree(); } -ValueTree ValueTree::getOrCreateChildWithName (const Identifier type, UndoManager* undoManager) +ValueTree ValueTree::getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager) { return object != nullptr ? object->getOrCreateChildWithName (type, undoManager) : ValueTree(); } -ValueTree ValueTree::getChildWithProperty (const Identifier propertyName, const var& propertyValue) const +ValueTree ValueTree::getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const { return object != nullptr ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree(); } @@ -945,7 +944,7 @@ void ValueTree::removeListener (Listener* listener) object->valueTreesWithListeners.removeValue (this); } -void ValueTree::sendPropertyChangeMessage (const Identifier property) +void ValueTree::sendPropertyChangeMessage (const Identifier& property) { if (object != nullptr) object->sendPropertyChangeMessage (property); diff --git a/modules/juce_data_structures/values/juce_ValueTree.h b/modules/juce_data_structures/values/juce_ValueTree.h index 9a9ccd16d7..78d870f8ce 100644 --- a/modules/juce_data_structures/values/juce_ValueTree.h +++ b/modules/juce_data_structures/values/juce_ValueTree.h @@ -79,7 +79,7 @@ public: Like an XmlElement, each ValueTree node has a type, which you can access with getType() and hasType(). */ - explicit ValueTree (Identifier type); + explicit ValueTree (const Identifier& type); /** Creates a reference to another ValueTree. */ ValueTree (const ValueTree&); @@ -134,7 +134,7 @@ public: /** Returns true if the node has this type. The comparison is case-sensitive. */ - bool hasType (const Identifier typeName) const; + bool hasType (const Identifier& typeName) const; //============================================================================== /** Returns the value of a named property. @@ -142,21 +142,21 @@ public: You can also use operator[] to get a property. @see var, setProperty, hasProperty */ - const var& getProperty (const Identifier name) const; + const var& getProperty (const Identifier& name) const; /** Returns the value of a named property, or a user-specified default if the property doesn't exist. If no such property has been set, this will return the value of defaultReturnValue. You can also use operator[] and getProperty to get a property. @see var, getProperty, setProperty, hasProperty */ - var getProperty (const Identifier name, const var& defaultReturnValue) const; + var getProperty (const Identifier& name, const var& defaultReturnValue) const; /** Returns the value of a named property. If no such property has been set, this will return a void variant. This is the same as calling getProperty(). @see getProperty */ - const var& operator[] (const Identifier name) const; + const var& operator[] (const Identifier& name) const; /** Changes a named property of the node. The name identifier must not be an empty string. @@ -165,16 +165,16 @@ public: @see var, getProperty, removeProperty @returns a reference to the value tree, so that you can daisy-chain calls to this method. */ - ValueTree& setProperty (const Identifier name, const var& newValue, UndoManager* undoManager); + ValueTree& setProperty (const Identifier& name, const var& newValue, UndoManager* undoManager); /** Returns true if the node contains a named property. */ - bool hasProperty (const Identifier name) const; + bool hasProperty (const Identifier& name) const; /** Removes a property from the node. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ - void removeProperty (const Identifier name, UndoManager* undoManager); + void removeProperty (const Identifier& name, UndoManager* undoManager); /** Removes all properties from the node. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, @@ -198,7 +198,7 @@ public: it needs to change the value. Attaching a Value::Listener to the value object will provide callbacks whenever the property changes. */ - Value getPropertyAsValue (const Identifier name, UndoManager* undoManager); + Value getPropertyAsValue (const Identifier& name, UndoManager* undoManager); /** Overwrites all the properties in this tree with the properties of the source tree. Any properties that already exist will be updated; and new ones will be added, and @@ -223,7 +223,7 @@ public: whether a node is valid). @see getOrCreateChildWithName */ - ValueTree getChildWithName (const Identifier type) const; + ValueTree getChildWithName (const Identifier& type) const; /** Returns the first child node with the speficied type name, creating and adding a child with this name if there wasn't already one there. @@ -232,7 +232,7 @@ public: the method on is itself invalid. @see getChildWithName */ - ValueTree getOrCreateChildWithName (const Identifier type, UndoManager* undoManager); + ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager); /** Looks for the first child node that has the speficied property value. @@ -242,7 +242,7 @@ public: If no such node is found, it'll return an invalid node. (See isValid() to find out whether a node is valid). */ - ValueTree getChildWithProperty (const Identifier propertyName, const var& propertyValue) const; + ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const; /** Adds a child to this node. @@ -453,7 +453,7 @@ public: /** Causes a property-change callback to be triggered for the specified property, calling any listeners that are registered. */ - void sendPropertyChangeMessage (const Identifier property); + void sendPropertyChangeMessage (const Identifier& property); //============================================================================== /** This method uses a comparator object to sort the tree's children into order. From f1c0ceccc3c55b03d628dc0cf895b79a7e3d6700 Mon Sep 17 00:00:00 2001 From: jules Date: Sun, 21 Jun 2015 18:54:20 +0100 Subject: [PATCH 02/11] Removed unused variable --- examples/Demo/Source/Demos/UnitTestsDemo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/Demo/Source/Demos/UnitTestsDemo.cpp b/examples/Demo/Source/Demos/UnitTestsDemo.cpp index fce56fd093..91add7ff52 100644 --- a/examples/Demo/Source/Demos/UnitTestsDemo.cpp +++ b/examples/Demo/Source/Demos/UnitTestsDemo.cpp @@ -183,7 +183,6 @@ struct UnitTestClasses TextButton startTestButton; TextEditor testResultsBox; - Label label; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnitTestsDemo); }; From d8bc6c52c7e25a654ca2c9d60ac1d585d4dcd5cd Mon Sep 17 00:00:00 2001 From: jules Date: Sun, 21 Jun 2015 19:09:05 +0100 Subject: [PATCH 03/11] A couple more optimisations of Identifier object passing. --- .../containers/juce_NamedValueSet.cpp | 4 ++-- .../juce_core/containers/juce_NamedValueSet.h | 4 ++-- .../juce_core/javascript/juce_Javascript.cpp | 18 +++++++++--------- modules/juce_core/javascript/juce_Javascript.h | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/juce_core/containers/juce_NamedValueSet.cpp b/modules/juce_core/containers/juce_NamedValueSet.cpp index 2c153e1f19..8955b126d4 100644 --- a/modules/juce_core/containers/juce_NamedValueSet.cpp +++ b/modules/juce_core/containers/juce_NamedValueSet.cpp @@ -140,7 +140,7 @@ var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept } #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS -bool NamedValueSet::set (Identifier name, var&& newValue) +bool NamedValueSet::set (const Identifier& name, var&& newValue) { if (var* const v = getVarPointer (name)) { @@ -156,7 +156,7 @@ bool NamedValueSet::set (Identifier name, var&& newValue) } #endif -bool NamedValueSet::set (Identifier name, const var& newValue) +bool NamedValueSet::set (const Identifier& name, const var& newValue) { if (var* const v = getVarPointer (name)) { diff --git a/modules/juce_core/containers/juce_NamedValueSet.h b/modules/juce_core/containers/juce_NamedValueSet.h index e4a98edc67..09ad68ee7c 100644 --- a/modules/juce_core/containers/juce_NamedValueSet.h +++ b/modules/juce_core/containers/juce_NamedValueSet.h @@ -78,14 +78,14 @@ public: @returns true if a value was changed or added; false if the value was already set the value passed-in. */ - bool set (Identifier name, const var& newValue); + bool set (const Identifier& name, const var& newValue); #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS /** Changes or adds a named value. @returns true if a value was changed or added; false if the value was already set the value passed-in. */ - bool set (Identifier name, var&& newValue); + bool set (const Identifier& name, var&& newValue); #endif /** Returns true if the set contains an item with the specified name. */ diff --git a/modules/juce_core/javascript/juce_Javascript.cpp b/modules/juce_core/javascript/juce_Javascript.cpp index 1d7fcf45dc..9e5fe3d9d0 100644 --- a/modules/juce_core/javascript/juce_Javascript.cpp +++ b/modules/juce_core/javascript/juce_Javascript.cpp @@ -102,7 +102,7 @@ struct JavascriptEngine::RootObject : public DynamicObject static bool isNumericOrUndefined (const var& v) { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool() || v.isUndefined(); } static int64 getOctalValue (const String& s) { BigInteger b; b.parseString (s, 8); return b.toInt64(); } static Identifier getPrototypeIdentifier() { static const Identifier i ("prototype"); return i; } - static var* getPropertyPointer (DynamicObject* o, Identifier i) { return o->getProperties().getVarPointer (i); } + static var* getPropertyPointer (DynamicObject* o, const Identifier& i) { return o->getProperties().getVarPointer (i); } //============================================================================== struct CodeLocation @@ -136,7 +136,7 @@ struct JavascriptEngine::RootObject : public DynamicObject ReferenceCountedObjectPtr root; DynamicObject::Ptr scope; - var findFunctionCall (const CodeLocation& location, const var& targetObject, Identifier functionName) const + var findFunctionCall (const CodeLocation& location, const var& targetObject, const Identifier& functionName) const { if (DynamicObject* o = targetObject.getDynamicObject()) { @@ -170,7 +170,7 @@ struct JavascriptEngine::RootObject : public DynamicObject return var(); } - var* findRootClassProperty (Identifier className, Identifier propName) const + var* findRootClassProperty (const Identifier& className, const Identifier& propName) const { if (DynamicObject* cls = root->getProperty (className).getDynamicObject()) return getPropertyPointer (cls, propName); @@ -178,7 +178,7 @@ struct JavascriptEngine::RootObject : public DynamicObject return nullptr; } - var findSymbolInParentScopes (Identifier name) const + var findSymbolInParentScopes (const Identifier& name) const { if (const var* v = getPropertyPointer (scope, name)) return *v; @@ -187,7 +187,7 @@ struct JavascriptEngine::RootObject : public DynamicObject : var::undefined(); } - bool findAndInvokeMethod (Identifier function, const var::NativeFunctionArgs& args, var& result) const + bool findAndInvokeMethod (const Identifier& function, const var::NativeFunctionArgs& args, var& result) const { DynamicObject* target = args.thisObject.getDynamicObject(); @@ -352,7 +352,7 @@ struct JavascriptEngine::RootObject : public DynamicObject struct UnqualifiedName : public Expression { - UnqualifiedName (const CodeLocation& l, Identifier n) noexcept : Expression (l), name (n) {} + UnqualifiedName (const CodeLocation& l, const Identifier& n) noexcept : Expression (l), name (n) {} var getResult (const Scope& s) const override { return s.findSymbolInParentScopes (name); } @@ -369,7 +369,7 @@ struct JavascriptEngine::RootObject : public DynamicObject struct DotOperator : public Expression { - DotOperator (const CodeLocation& l, ExpPtr& p, Identifier c) noexcept : Expression (l), parent (p), child (c) {} + DotOperator (const CodeLocation& l, ExpPtr& p, const Identifier& c) noexcept : Expression (l), parent (p), child (c) {} var getResult (const Scope& s) const override { @@ -1670,7 +1670,7 @@ JavascriptEngine::~JavascriptEngine() {} void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; } -void JavascriptEngine::registerNativeObject (Identifier name, DynamicObject* object) +void JavascriptEngine::registerNativeObject (const Identifier& name, DynamicObject* object) { root->setProperty (name, object); } @@ -1706,7 +1706,7 @@ var JavascriptEngine::evaluate (const String& code, Result* result) return var::undefined(); } -var JavascriptEngine::callFunction (Identifier function, const var::NativeFunctionArgs& args, Result* result) +var JavascriptEngine::callFunction (const Identifier& function, const var::NativeFunctionArgs& args, Result* result) { var returnVal (var::undefined()); diff --git a/modules/juce_core/javascript/juce_Javascript.h b/modules/juce_core/javascript/juce_Javascript.h index eafc3cdb60..62eadbb116 100644 --- a/modules/juce_core/javascript/juce_Javascript.h +++ b/modules/juce_core/javascript/juce_Javascript.h @@ -78,7 +78,7 @@ public: The function arguments are passed in the same format as used by native methods in the var class. */ - var callFunction (Identifier function, + var callFunction (const Identifier& function, const var::NativeFunctionArgs& args, Result* errorMessage = nullptr); @@ -87,7 +87,7 @@ public: engine until the engine is deleted. The name must be a simple JS identifier, without any dots. */ - void registerNativeObject (Identifier objectName, DynamicObject* object); + void registerNativeObject (const Identifier& objectName, DynamicObject* object); /** This value indicates how long a call to one of the evaluate methods is permitted to run before timing-out and failing. From b0ca99d26b9210341502e59238ee7dd1f9e4d61b Mon Sep 17 00:00:00 2001 From: jules Date: Sun, 21 Jun 2015 19:26:26 +0100 Subject: [PATCH 04/11] Introjucer: made the modules panel update when the filename is edited --- .../Source/Project/jucer_ConfigTree_Modules.h | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/extras/Introjucer/Source/Project/jucer_ConfigTree_Modules.h b/extras/Introjucer/Source/Project/jucer_ConfigTree_Modules.h index efa27b9dcd..b024590a9d 100644 --- a/extras/Introjucer/Source/Project/jucer_ConfigTree_Modules.h +++ b/extras/Introjucer/Source/Project/jucer_ConfigTree_Modules.h @@ -146,28 +146,37 @@ private: String moduleID; //============================================================================== - class ModuleInfoComponent : public PropertyComponent + class ModuleInfoComponent : public PropertyComponent, + private Value::Listener { public: ModuleInfoComponent (Project& p, const String& modID) : PropertyComponent ("Module", 150), project (p), moduleID (modID) { + for (Project::ExporterIterator exporter (project); exporter.next();) + listeningValues.add (new Value (exporter->getPathForModuleValue (moduleID))) + ->addListener (this); + + refresh(); } - void refresh() {} + private: + void refresh() override + { + info = project.getModules().getModuleInfo (moduleID); + repaint(); + } - void paint (Graphics& g) + void paint (Graphics& g) override { g.setColour (Colours::white.withAlpha (0.4f)); - g.fillRect (0, 0, getWidth(), getHeight() - 1); + g.fillRect (getLocalBounds().withTrimmedBottom (1)); AttributedString s; s.setJustification (Justification::topLeft); Font f (14.0f); - ModuleDescription info (project.getModules().getModuleInfo (moduleID)); - if (info.isValid()) { s.append (info.getName() + "\n\n", f.boldened()); @@ -184,9 +193,15 @@ private: s.draw (g, getLocalBounds().reduced (6, 5).toFloat()); } - private: + void valueChanged (Value&) override + { + refresh(); + } + Project& project; String moduleID; + OwnedArray listeningValues; + ModuleDescription info; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModuleInfoComponent) }; @@ -208,9 +223,9 @@ private: fixButton.addListener (this); } - void refresh() {} + void refresh() override {} - void paint (Graphics& g) + void paint (Graphics& g) override { g.setColour (Colours::white.withAlpha (0.4f)); g.fillRect (0, 0, getWidth(), getHeight() - 1); @@ -225,7 +240,7 @@ private: s.draw (g, getLocalBounds().reduced (4, 16).toFloat()); } - void buttonClicked (Button*) + void buttonClicked (Button*) override { bool anyFailed = false; @@ -250,7 +265,7 @@ private: "folders manually and add them to the list."); } - void resized() + void resized() override { fixButton.setBounds (getWidth() - 168, getHeight() - 26, 160, 22); } @@ -289,7 +304,7 @@ public: bool isMissing() override { return false; } Icon getIcon() const override { return Icon (getIcons().graph, getContrastingColour (Colours::red, 0.5f)); } - void showDocument() + void showDocument() override { if (ProjectContentComponent* pcc = getProjectContentComponent()) pcc->setEditorComponent (new ModulesPanel (project), nullptr); From 26143d5034cf905225733e60779a65a28a39b852 Mon Sep 17 00:00:00 2001 From: jules Date: Sun, 21 Jun 2015 19:47:48 +0100 Subject: [PATCH 05/11] Introjucer: added a better browser for module paths --- .../Source/Project/jucer_ConfigTree_Modules.h | 5 +- .../Source/Utility/jucer_MiscUtilities.h | 116 ++++++++++++++++++ 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/extras/Introjucer/Source/Project/jucer_ConfigTree_Modules.h b/extras/Introjucer/Source/Project/jucer_ConfigTree_Modules.h index b024590a9d..ee1cefe728 100644 --- a/extras/Introjucer/Source/Project/jucer_ConfigTree_Modules.h +++ b/extras/Introjucer/Source/Project/jucer_ConfigTree_Modules.h @@ -88,8 +88,9 @@ private: props.add (new MissingDependenciesComponent (project, moduleID)); for (Project::ExporterIterator exporter (project); exporter.next();) - props.add (new TextPropertyComponent (exporter->getPathForModuleValue (moduleID), - "Path for " + exporter->getName().quoted(), 1024, false), + props.add (new FilePathPropertyComponent (exporter->getPathForModuleValue (moduleID), + "Path for " + exporter->getName().quoted(), + true, "*", project.getProjectFolder()), "A path to the folder that contains the " + moduleID + " module when compiling the " + exporter->getName().quoted() + " target. " "This can be an absolute path, or relative to the jucer project folder, but it " diff --git a/extras/Introjucer/Source/Utility/jucer_MiscUtilities.h b/extras/Introjucer/Source/Utility/jucer_MiscUtilities.h index 1b0a8355fc..e9598ba915 100644 --- a/extras/Introjucer/Source/Utility/jucer_MiscUtilities.h +++ b/extras/Introjucer/Source/Utility/jucer_MiscUtilities.h @@ -380,3 +380,119 @@ public: protected: ColourEditorComponent colourEditor; }; + +//============================================================================== +class FilePathPropertyComponent : public PropertyComponent +{ +public: + /** A Property Component for selecting files or folders. + + The user may drag files over the property box, enter the path + manually and/or click the '...' button to open a file selection + dialog box + */ + FilePathPropertyComponent (Value valueToControl, + const String& propertyDescription, + bool isDirectory, + const String& wildcards = "*", + const File& rootToUseForRelativePaths = File::nonexistent) + : PropertyComponent (propertyDescription), + innerComp (valueToControl, isDirectory, wildcards, rootToUseForRelativePaths) + { + addAndMakeVisible (innerComp); + } + + void refresh() override {} // N/A + +private: + struct InnerComponent : public Component, + public FileDragAndDropTarget, + private Button::Listener + { + InnerComponent (Value v, bool isDir, const String& wc, const File& rt) + : value (v), + isDirectory (isDir), + highlightForDragAndDrop (false), + wildcards (wc), + root (rt), + button ("...") + { + addAndMakeVisible (textbox); + textbox.getTextValue().referTo (value); + + addAndMakeVisible (button); + button.addListener (this); + } + + void paintOverChildren (Graphics& g) override + { + if (highlightForDragAndDrop) + { + g.setColour (Colours::green.withAlpha (0.1f)); + g.fillRect (getLocalBounds()); + } + } + + void resized() override + { + Rectangle r (getLocalBounds()); + + button.setBounds (r.removeFromRight (24)); + textbox.setBounds (r); + } + + bool isInterestedInFileDrag (const StringArray&) override { return true; } + void fileDragEnter (const StringArray&, int, int) override { highlightForDragAndDrop = true; repaint(); } + void fileDragExit (const StringArray&) override { highlightForDragAndDrop = false; repaint(); } + + void filesDropped (const StringArray& files, int, int) override + { + const File firstFile (files[0]); + + if (isDirectory) + setTo (firstFile.isDirectory() ? firstFile + : firstFile.getParentDirectory()); + else + setTo (firstFile); + } + + void buttonClicked (Button*) override + { + const File currentFile (root.getChildFile (value.toString())); + + if (isDirectory) + { + FileChooser chooser ("Select directory", currentFile); + + if (chooser.browseForDirectory()) + setTo (chooser.getResult()); + } + else + { + FileChooser chooser ("Select file", currentFile, wildcards); + + if (chooser.browseForFileToOpen()) + setTo (chooser.getResult()); + } + } + + void setTo (const File& f) + { + value = (root == File::nonexistent) ? f.getFullPathName() + : f.getRelativePathFrom (root); + } + + Value value; + bool isDirectory, highlightForDragAndDrop; + String wildcards; + File root; + TextEditor textbox; + TextButton button; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InnerComponent) + }; + + InnerComponent innerComp; // Used so that the PropertyComponent auto first-child positioning works + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilePathPropertyComponent) +}; From 661533c85d178ae142757341c4a698fbff730ac4 Mon Sep 17 00:00:00 2001 From: hogliux Date: Sun, 21 Jun 2015 18:31:19 +0200 Subject: [PATCH 06/11] Fix clang warnings on linux --- .../format_types/juce_VSTPluginFormat.cpp | 4 +++- .../juce_gui_basics/native/juce_linux_Windowing.cpp | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index 497f54305b..cb1cc2ff08 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -318,6 +318,8 @@ namespace static void translateJuceToXMouseWheelModifiers (const MouseEvent& e, const float increment, XEvent& ev) noexcept { + ignoreUnused (e); + if (increment < 0) { ev.xbutton.button = Button5; @@ -1633,7 +1635,7 @@ public: void* data = nullptr; const size_t bytes = (size_t) dispatch (effGetChunk, isPreset ? 1 : 0, 0, &data, 0.0f); - if (data != nullptr && bytes <= maxSizeMB * 1024 * 1024) + if (data != nullptr && bytes <= (size_t) maxSizeMB * 1024 * 1024) { mb.setSize (bytes); mb.copyFrom (data, 0, bytes); diff --git a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp index 567d094c9c..f597d5c2ab 100644 --- a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp @@ -978,9 +978,9 @@ private: //============================================================================== #if JUCE_USE_XRANDR - friend class ContainerDeletePolicy; - friend class ContainerDeletePolicy; - friend class ContainerDeletePolicy; + friend struct ContainerDeletePolicy; + friend struct ContainerDeletePolicy; + friend struct ContainerDeletePolicy; class XRandrWrapper { @@ -1062,9 +1062,9 @@ private: private: //============================================================================== - friend class ContainerDeletePolicy; - friend class ContainerDeletePolicy; - friend class ContainerDeletePolicy; + friend struct ContainerDeletePolicy; + friend struct ContainerDeletePolicy; + friend struct ContainerDeletePolicy; void freeScreenResources (XRRScreenResources* ptr) { From fd74f1a39d01d1664e3fba8fe199511ee2338501 Mon Sep 17 00:00:00 2001 From: jules Date: Mon, 22 Jun 2015 16:22:50 +0100 Subject: [PATCH 07/11] Changed the way the JUCE_LIVE_CONSTANT singletons are generated, to make it more robust when used in a plugin environment --- .../misc/juce_LiveConstantEditor.cpp | 30 ++++++++----------- .../misc/juce_LiveConstantEditor.h | 4 +-- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/modules/juce_gui_extra/misc/juce_LiveConstantEditor.cpp b/modules/juce_gui_extra/misc/juce_LiveConstantEditor.cpp index a091587625..3c85254bb2 100644 --- a/modules/juce_gui_extra/misc/juce_LiveConstantEditor.cpp +++ b/modules/juce_gui_extra/misc/juce_LiveConstantEditor.cpp @@ -32,13 +32,10 @@ class AllComponentRepainter : private Timer, private DeletedAtShutdown { public: - AllComponentRepainter() {} + AllComponentRepainter() {} + ~AllComponentRepainter() { clearSingletonInstance(); } - static AllComponentRepainter& getInstance() - { - static AllComponentRepainter* instance = new AllComponentRepainter(); - return *instance; - } + juce_DeclareSingleton (AllComponentRepainter, false) void trigger() { @@ -57,8 +54,10 @@ private: if (Component* c = TopLevelWindow::getTopLevelWindow(i)) repaintAndResizeAllComps (c, alreadyDone); - for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;) - if (Component* c = Desktop::getInstance().getComponent(i)) + Desktop& desktop = Desktop::getInstance(); + + for (int i = desktop.getNumComponents(); --i >= 0;) + if (Component* c = desktop.getComponent(i)) repaintAndResizeAllComps (c, alreadyDone); } @@ -85,6 +84,9 @@ private: } }; +juce_ImplementSingleton (AllComponentRepainter) +juce_ImplementSingleton (ValueList) + //============================================================================== int64 parseInt (String s) { @@ -189,7 +191,7 @@ void LivePropertyEditorBase::applyNewValue (const String& s) selectOriginalValue(); valueEditor.setText (s, dontSendNotification); - AllComponentRepainter::getInstance().trigger(); + AllComponentRepainter::getInstance()->trigger(); } void LivePropertyEditorBase::selectOriginalValue() @@ -347,14 +349,8 @@ public: }; //============================================================================== -ValueList::ValueList() {} -ValueList::~ValueList() {} - -ValueList& ValueList::getInstance() -{ - static ValueList* i = new ValueList(); - return *i; -} +ValueList::ValueList() {} +ValueList::~ValueList() { clearSingletonInstance(); } void ValueList::addValue (LiveValueBase* v) { diff --git a/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h b/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h index 44c312cd19..5801ba2fdf 100644 --- a/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h +++ b/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h @@ -194,7 +194,7 @@ namespace LiveConstantEditor ValueList(); ~ValueList(); - static ValueList& getInstance(); + juce_DeclareSingleton (ValueList, false) template LiveValue& getValue (const char* file, int line, const Type& initialValue) @@ -233,7 +233,7 @@ namespace LiveConstantEditor template inline LiveValue& getValue (const char* file, int line, const Type& initialValue) { - return ValueList::getInstance().getValue (file, line, initialValue); + return ValueList::getInstance()->getValue (file, line, initialValue); } inline LiveValue& getValue (const char* file, int line, const char* initialValue) From 9b79610cb0bd1942210fbad76dab7bf8431cd04b Mon Sep 17 00:00:00 2001 From: jules Date: Mon, 22 Jun 2015 20:28:15 +0100 Subject: [PATCH 08/11] Added a flag MouseWheelEvent::isInertial (currently only implemented for OSX 10.7 or later), and used this to replace some clunky behaviour in the Viewport class that was there to avoid inertial wheel movements triggering nested scrollable components. --- .../juce_gui_basics/layout/juce_Viewport.cpp | 32 +------------------ .../juce_gui_basics/layout/juce_Viewport.h | 4 +-- .../juce_gui_basics/mouse/juce_MouseEvent.h | 4 +++ .../mouse/juce_MouseInputSource.cpp | 16 +++++++--- .../native/juce_linux_Windowing.cpp | 1 + .../native/juce_mac_NSViewComponentPeer.mm | 12 ++++--- .../native/juce_win32_Windowing.cpp | 1 + 7 files changed, 28 insertions(+), 42 deletions(-) diff --git a/modules/juce_gui_basics/layout/juce_Viewport.cpp b/modules/juce_gui_basics/layout/juce_Viewport.cpp index 21360a0419..edab5284da 100644 --- a/modules/juce_gui_basics/layout/juce_Viewport.cpp +++ b/modules/juce_gui_basics/layout/juce_Viewport.cpp @@ -24,13 +24,13 @@ Viewport::Viewport (const String& name) : Component (name), - customScrollBarThickness(false), scrollBarThickness (0), singleStepX (16), singleStepY (16), showHScrollbar (true), showVScrollbar (true), deleteContent (true), + customScrollBarThickness (false), allowScrollingWithoutScrollbarV (false), allowScrollingWithoutScrollbarH (false), verticalScrollBar (true), @@ -55,7 +55,6 @@ Viewport::Viewport (const String& name) Viewport::~Viewport() { deleteContentComp(); - mouseWheelTimer = nullptr; } //============================================================================== @@ -382,30 +381,6 @@ static int rescaleMouseWheelDistance (float distance, int singleStepSize) noexce : jmax (distance, 1.0f)); } -// This puts a temporary component overlay over the content component, to prevent -// wheel events from reaching components inside it, so that while spinning a wheel -// with momentum, it won't accidentally scroll any subcomponents of the viewport. -struct Viewport::MouseWheelTimer : public Timer -{ - MouseWheelTimer (Viewport& v) : viewport (v) - { - viewport.contentHolder.addAndMakeVisible (dummyOverlay); - dummyOverlay.setAlwaysOnTop (true); - dummyOverlay.setPaintingIsUnclipped (true); - dummyOverlay.setBounds (viewport.contentHolder.getLocalBounds()); - } - - void timerCallback() override - { - viewport.mouseWheelTimer = nullptr; - } - - Component dummyOverlay; - Viewport& viewport; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MouseWheelTimer) -}; - bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelDetails& wheel) { if (! (e.mods.isAltDown() || e.mods.isCtrlDown() || e.mods.isCommandDown())) @@ -436,11 +411,6 @@ bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelD if (pos != getViewPosition()) { - if (mouseWheelTimer == nullptr) - mouseWheelTimer = new MouseWheelTimer (*this); - - mouseWheelTimer->startTimer (300); - setViewPosition (pos); return true; } diff --git a/modules/juce_gui_basics/layout/juce_Viewport.h b/modules/juce_gui_basics/layout/juce_Viewport.h index 78aa4fa01f..0fa4aaf505 100644 --- a/modules/juce_gui_basics/layout/juce_Viewport.h +++ b/modules/juce_gui_basics/layout/juce_Viewport.h @@ -263,15 +263,13 @@ private: //============================================================================== WeakReference contentComp; Rectangle lastVisibleArea; - bool customScrollBarThickness; int scrollBarThickness; int singleStepX, singleStepY; bool showHScrollbar, showVScrollbar, deleteContent; + bool customScrollBarThickness; bool allowScrollingWithoutScrollbarV, allowScrollingWithoutScrollbarH; Component contentHolder; ScrollBar verticalScrollBar, horizontalScrollBar; - struct MouseWheelTimer; - ScopedPointer mouseWheelTimer; Point viewportPosToCompPos (Point) const; diff --git a/modules/juce_gui_basics/mouse/juce_MouseEvent.h b/modules/juce_gui_basics/mouse/juce_MouseEvent.h index 92ac754ed0..210dd009e0 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseEvent.h +++ b/modules/juce_gui_basics/mouse/juce_MouseEvent.h @@ -354,6 +354,10 @@ struct MouseWheelDetails /** If true, then the wheel has continuous, un-stepped motion. */ bool isSmooth; + + /** If true, then this event is part of the intertial momentum phase that follows + the wheel being released. */ + bool isInertial; }; diff --git a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp index 7df09b4b8f..45c8eba956 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp +++ b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp @@ -331,10 +331,17 @@ public: Time time, const MouseWheelDetails& wheel) { Desktop::getInstance().incrementMouseWheelCounter(); - Point screenPos; - if (Component* current = getTargetForGesture (peer, positionWithinPeer, time, screenPos)) - sendMouseWheel (*current, screenPos, time, wheel); + + // This will make sure that when the wheel spins in its inertial phase, any events + // continue to be sent to the last component that the mouse was over when it was being + // actively controlled by the user. This avoids confusion when scrolling through nested + // scrollable components. + if (lastNonInertialWheelTarget == nullptr || ! wheel.isInertial) + lastNonInertialWheelTarget = getTargetForGesture (peer, positionWithinPeer, time, screenPos); + + if (Component* target = lastNonInertialWheelTarget) + sendMouseWheel (*target, screenPos, time, wheel); } void handleMagnifyGesture (ComponentPeer& peer, Point positionWithinPeer, @@ -467,7 +474,7 @@ public: bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen; private: - WeakReference componentUnderMouse; + WeakReference componentUnderMouse, lastNonInertialWheelTarget; ComponentPeer* lastPeer; void* currentCursorHandle; @@ -512,6 +519,7 @@ private: mouseDowns[0].peerID = 0; mouseMovedSignificantlySincePressed = false; + lastNonInertialWheelTarget = nullptr; } void registerMouseDrag (Point screenPos) noexcept diff --git a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp index f597d5c2ab..03cb822817 100644 --- a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp @@ -2209,6 +2209,7 @@ public: wheel.deltaY = amount; wheel.isReversed = false; wheel.isSmooth = false; + wheel.isInertial = false; handleMouseWheel (0, getMousePos (buttonPressEvent), getEventTime (buttonPressEvent), wheel); } diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index cb0cf5efd7..98c1b74925 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -497,10 +497,7 @@ public: void toBehind (ComponentPeer* other) override { - NSViewComponentPeer* const otherPeer = dynamic_cast (other); - jassert (otherPeer != nullptr); // wrong type of window? - - if (otherPeer != nullptr) + if (NSViewComponentPeer* const otherPeer = dynamic_cast (other)) { if (isSharedWindow) { @@ -514,6 +511,10 @@ public: relativeTo: [otherPeer->window windowNumber]]; } } + else + { + jassertfalse; // wrong type of window? + } } void setIcon (const Image&) override @@ -620,6 +621,7 @@ public: wheel.deltaY = 0; wheel.isReversed = false; wheel.isSmooth = false; + wheel.isInertial = false; #if ! JUCE_PPC @try @@ -628,6 +630,8 @@ public: if ([ev respondsToSelector: @selector (isDirectionInvertedFromDevice)]) wheel.isReversed = [ev isDirectionInvertedFromDevice]; + wheel.isInertial = ([ev momentumPhase] != NSEventPhaseNone); + if ([ev respondsToSelector: @selector (hasPreciseScrollingDeltas)]) { if ([ev hasPreciseScrollingDeltas]) diff --git a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp index 0b55b2ece3..2d8f92d90a 100644 --- a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp @@ -1820,6 +1820,7 @@ private: wheel.deltaY = isVertical ? amount / 256.0f : 0.0f; wheel.isReversed = false; wheel.isSmooth = false; + wheel.isInertial = false; Point localPos; if (ComponentPeer* const peer = findPeerUnderMouse (localPos)) From 0fc929e37d668b77fd168fbede22f96e223078a2 Mon Sep 17 00:00:00 2001 From: jules Date: Mon, 22 Jun 2015 20:28:39 +0100 Subject: [PATCH 09/11] Added comments to clarify that URLs can't be opened on the message thread in Android. --- modules/juce_core/network/juce_URL.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/juce_core/network/juce_URL.h b/modules/juce_core/network/juce_URL.h index d3a87c1344..c02bf96188 100644 --- a/modules/juce_core/network/juce_URL.h +++ b/modules/juce_core/network/juce_URL.h @@ -248,6 +248,9 @@ public: /** Attempts to open a stream that can read from this URL. + Note that on some platforms (Android, for example) it's not permitted to do any network + action from the message thread, so you must only call it from a background thread. + @param usePostCommand if true, it will try to do use a http 'POST' to pass the parameters, otherwise it'll encode them into the URL and do a 'GET'. @@ -287,6 +290,9 @@ public: If it succeeds, this will return true and append the data it read onto the end of the memory block. + Note that on some platforms (Android, for example) it's not permitted to do any network + action from the message thread, so you must only call it from a background thread. + @param destData the memory block to append the new data to @param usePostCommand whether to use a POST command to get the data (uses a GET command if this is false) @@ -302,6 +308,9 @@ public: operation that fails and one that returns an empty string, you'll need to use a different method, such as readEntireBinaryStream(). + Note that on some platforms (Android, for example) it's not permitted to do any network + action from the message thread, so you must only call it from a background thread. + @param usePostCommand whether to use a POST command to get the data (uses a GET command if this is false) @see readEntireBinaryStream, readEntireXmlStream @@ -316,6 +325,9 @@ public: When it returns a valid XmlElement object, the caller is responsibile for deleting this object when no longer needed. + Note that on some platforms (Android, for example) it's not permitted to do any network + action from the message thread, so you must only call it from a background thread. + @param usePostCommand whether to use a POST command to get the data (uses a GET command if this is false) From cd056a89cc0d2c36fca080468e5344809503e11b Mon Sep 17 00:00:00 2001 From: jules Date: Mon, 22 Jun 2015 20:29:07 +0100 Subject: [PATCH 10/11] Whitespace fix. --- .../juce_audio_processors/format_types/juce_VSTPluginFormat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index cb1cc2ff08..1820e46967 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -318,7 +318,7 @@ namespace static void translateJuceToXMouseWheelModifiers (const MouseEvent& e, const float increment, XEvent& ev) noexcept { - ignoreUnused (e); + ignoreUnused (e); if (increment < 0) { From d3f76766db007dbfcaea613c556c2e8e62fc0dc1 Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 23 Jun 2015 12:44:51 +0100 Subject: [PATCH 11/11] Added a flag to FileBrowserComponent to allow it to keep the current name when the folder changes, and used this flag in the introjucer's new project wizard. --- .../Wizards/jucer_NewProjectWizardComponent.h | 19 ++++++++++++-- .../filebrowser/juce_FileBrowserComponent.cpp | 6 +++-- .../filebrowser/juce_FileBrowserComponent.h | 25 ++++++++++--------- 3 files changed, 34 insertions(+), 16 deletions(-) mode change 100644 => 100755 extras/Introjucer/Source/Wizards/jucer_NewProjectWizardComponent.h mode change 100644 => 100755 modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp mode change 100644 => 100755 modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h diff --git a/extras/Introjucer/Source/Wizards/jucer_NewProjectWizardComponent.h b/extras/Introjucer/Source/Wizards/jucer_NewProjectWizardComponent.h old mode 100644 new mode 100755 index cd96575f96..8ba2960bf2 --- a/extras/Introjucer/Source/Wizards/jucer_NewProjectWizardComponent.h +++ b/extras/Introjucer/Source/Wizards/jucer_NewProjectWizardComponent.h @@ -256,7 +256,8 @@ private: class WizardComp : public Component, private ButtonListener, private ComboBoxListener, - private TextEditorListener + private TextEditorListener, + private FileBrowserListener { public: WizardComp() @@ -264,7 +265,9 @@ public: projectName (TRANS("Project name")), nameLabel (String::empty, TRANS("Project Name") + ":"), typeLabel (String::empty, TRANS("Project Type") + ":"), - fileBrowser (FileBrowserComponent::saveMode | FileBrowserComponent::canSelectDirectories, + fileBrowser (FileBrowserComponent::saveMode + | FileBrowserComponent::canSelectDirectories + | FileBrowserComponent::doNotClearFileNameOnRootChange, NewProjectWizardClasses::getLastWizardFolder(), nullptr, nullptr), fileOutline (String::empty, TRANS("Project Folder") + ":"), targetsOutline (String::empty, TRANS("Target Platforms") + ":"), @@ -303,6 +306,8 @@ public: addChildAndSetID (&fileBrowser, "fileBrowser"); fileBrowser.setBounds ("fileOutline.left + 10, fileOutline.top + 20, fileOutline.right - 10, fileOutline.bottom - 32"); fileBrowser.setFilenameBoxLabel ("Folder:"); + fileBrowser.setFileName (File::createLegalFileName (projectName.getText())); + fileBrowser.addListener (this); addChildAndSetID (&createButton, "createButton"); createButton.setBounds ("right - 130, bottom - 34, parent.width - 30, parent.height - 30"); @@ -409,6 +414,16 @@ public: fileBrowser.setFileName (File::createLegalFileName (projectName.getText())); } + void selectionChanged() override {} + + void fileClicked (const File&, const MouseEvent&) override {} + void fileDoubleClicked (const File&) override {} + + void browserRootChanged (const File&) override + { + fileBrowser.setFileName (File::createLegalFileName (projectName.getText())); + } + ComboBox projectType; PlatformTargetsComp platformTargets; diff --git a/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp b/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp old mode 100644 new mode 100755 index 8f41549072..2dc3364fb1 --- a/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp @@ -387,7 +387,7 @@ void FileBrowserComponent::fileDoubleClicked (const File& f) { setRoot (f); - if ((flags & canSelectDirectories) != 0) + if ((flags & canSelectDirectories) != 0 && (flags & doNotClearFileNameOnRootChange) == 0) filenameBox.setText (String::empty); } else @@ -432,7 +432,9 @@ void FileBrowserComponent::textEditorReturnKeyPressed (TextEditor&) { setRoot (f); chosenFiles.clear(); - filenameBox.setText (String::empty); + + if ((flags & doNotClearFileNameOnRootChange) == 0) + filenameBox.setText (String()); } else { diff --git a/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h b/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h old mode 100644 new mode 100755 index a1151ef02f..62d28742da --- a/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h +++ b/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h @@ -51,18 +51,19 @@ public: */ enum FileChooserFlags { - openMode = 1, /**< specifies that the component should allow the user to - choose an existing file with the intention of opening it. */ - saveMode = 2, /**< specifies that the component should allow the user to specify - the name of a file that will be used to save something. */ - canSelectFiles = 4, /**< specifies that the user can select files (can be used in - conjunction with canSelectDirectories). */ - canSelectDirectories = 8, /**< specifies that the user can select directories (can be used in - conjuction with canSelectFiles). */ - canSelectMultipleItems = 16, /**< specifies that the user can select multiple items. */ - useTreeView = 32, /**< specifies that a tree-view should be shown instead of a file list. */ - filenameBoxIsReadOnly = 64, /**< specifies that the user can't type directly into the filename box. */ - warnAboutOverwriting = 128 /**< specifies that the dialog should warn about overwriting existing files (if possible). */ + openMode = 1, /**< specifies that the component should allow the user to + choose an existing file with the intention of opening it. */ + saveMode = 2, /**< specifies that the component should allow the user to specify + the name of a file that will be used to save something. */ + canSelectFiles = 4, /**< specifies that the user can select files (can be used in + conjunction with canSelectDirectories). */ + canSelectDirectories = 8, /**< specifies that the user can select directories (can be used in + conjuction with canSelectFiles). */ + canSelectMultipleItems = 16, /**< specifies that the user can select multiple items. */ + useTreeView = 32, /**< specifies that a tree-view should be shown instead of a file list. */ + filenameBoxIsReadOnly = 64, /**< specifies that the user can't type directly into the filename box. */ + warnAboutOverwriting = 128, /**< specifies that the dialog should warn about overwriting existing files (if possible). */ + doNotClearFileNameOnRootChange = 256 /**< specifies that the file name should not be cleared upon root change. */ }; //==============================================================================