first pass creating Qt <-> QtScript interface

This commit is contained in:
Heather Anderson 2021-12-14 00:30:08 -08:00 committed by ksuprynowicz
parent bd04554150
commit bc6eaf25dc
63 changed files with 1711 additions and 298 deletions

View file

@ -430,9 +430,10 @@ ScriptValue worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDet
return engine->newValue(worldDetailQuality);
}
void worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality) {
bool worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality) {
worldDetailQuality =
static_cast<WorldDetailQuality>(std::min(std::max(object.toInt32(), (int)WORLD_DETAIL_LOW), (int)WORLD_DETAIL_HIGH));
return true;
}
void LODManager::setLODQualityLevel(float quality) {

View file

@ -383,6 +383,6 @@ private:
};
ScriptValue worldDetailQualityToScriptValue(ScriptEngine* engine, const WorldDetailQuality& worldDetailQuality);
void worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality);
bool worldDetailQualityFromScriptValue(const ScriptValue& object, WorldDetailQuality& worldDetailQuality);
#endif // hifi_LODManager_h

View file

@ -5707,16 +5707,18 @@ ScriptValue audioListenModeToScriptValue(ScriptEngine* engine, const AudioListen
return engine->newValue(audioListenerMode);
}
void audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode) {
bool audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode) {
audioListenerMode = static_cast<AudioListenerMode>(object.toUInt16());
return true;
}
ScriptValue driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys) {
return engine->newValue(driveKeys);
}
void driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys) {
bool driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys) {
driveKeys = static_cast<MyAvatar::DriveKeys>(object.toUInt16());
return true;
}

View file

@ -3120,10 +3120,10 @@ private:
};
ScriptValue audioListenModeToScriptValue(ScriptEngine* engine, const AudioListenerMode& audioListenerMode);
void audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode);
bool audioListenModeFromScriptValue(const ScriptValue& object, AudioListenerMode& audioListenerMode);
ScriptValue driveKeysToScriptValue(ScriptEngine* engine, const MyAvatar::DriveKeys& driveKeys);
void driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys);
bool driveKeysFromScriptValue(const ScriptValue& object, MyAvatar::DriveKeys& driveKeys);
bool isWearableEntity(const EntityItemPointer& entity);

View file

@ -451,8 +451,9 @@ ScriptValue pickTypesToScriptValue(ScriptEngine* engine, const PickQuery::PickTy
return engine->newValue(pickType);
}
void pickTypesFromScriptValue(const ScriptValue& object, PickQuery::PickType& pickType) {
bool pickTypesFromScriptValue(const ScriptValue& object, PickQuery::PickType& pickType) {
pickType = static_cast<PickQuery::PickType>(object.toUInt16());
return true;
}
void PickScriptingInterface::registerMetaTypes(ScriptEngine* engine) {

View file

@ -136,7 +136,7 @@ ScriptValue DownloadInfoResultToScriptValue(ScriptEngine* engine, const Download
return object;
}
void DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result) {
bool DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result) {
QList<QVariant> downloading = object.property("downloading").toVariant().toList();
result.downloading.clear();
for (int i = 0; i < downloading.count(); i += 1) {
@ -144,6 +144,7 @@ void DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoRe
}
result.pending = object.property("pending").toVariant().toFloat();
return true;
}
DownloadInfoResult AccountServicesScriptingInterface::getDownloadInfo() {

View file

@ -32,7 +32,7 @@ public:
Q_DECLARE_METATYPE(DownloadInfoResult)
ScriptValue DownloadInfoResultToScriptValue(ScriptEngine* engine, const DownloadInfoResult& result);
void DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result);
bool DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoResult& result);
class AccountServicesScriptingInterface : public QObject {
Q_OBJECT

View file

@ -101,10 +101,11 @@ ScriptValue interactiveWindowPointerToScriptValue(ScriptEngine* engine, const In
return engine->newQObject(in, ScriptEngine::ScriptOwnership);
}
void interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out) {
bool interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out) {
if (const auto interactiveWindow = qobject_cast<InteractiveWindowPointer>(object.toQObject())) {
out = interactiveWindow;
}
return true;
}
void InteractiveWindow::forwardKeyPressEvent(int key, int modifiers) {

View file

@ -411,7 +411,7 @@ private:
typedef InteractiveWindow* InteractiveWindowPointer;
ScriptValue interactiveWindowPointerToScriptValue(ScriptEngine* engine, const InteractiveWindowPointer& in);
void interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out);
bool interactiveWindowPointerFromScriptValue(const ScriptValue& object, InteractiveWindowPointer& out);
void registerInteractiveWindowMetaType(ScriptEngine* engine);

View file

@ -1126,7 +1126,7 @@ ScriptValue RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, co
return obj;
}
void RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value) {
bool RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value) {
value.intersects = object.property("intersects").toVariant().toBool();
ScriptValue overlayIDValue = object.property("overlayID");
quuidFromScriptValue(overlayIDValue, value.overlayID);
@ -1142,6 +1142,7 @@ void RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, Ra
vec3FromScriptValue(surfaceNormal, value.surfaceNormal);
}
value.extraInfo = object.property("extraInfo").toVariant().toMap();
return true;
}
bool Overlays::isLoaded(const QUuid& id) {

View file

@ -54,7 +54,7 @@ public:
};
Q_DECLARE_METATYPE(RayToOverlayIntersectionResult);
ScriptValue RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, const RayToOverlayIntersectionResult& value);
void RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value);
bool RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value);
class ParabolaToOverlayIntersectionResult {
public:

View file

@ -66,10 +66,10 @@ ScriptValue injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInject
* @property {boolean} ignorePenumbra=false - <p class="important">Deprecated: This property is deprecated and will be
* removed.</p>
*/
void injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions) {
bool injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions) {
if (!object.isObject()) {
qWarning() << "Audio injector options is not an object.";
return;
return false;
}
if (injectorOptions.positionSet == false) {
@ -126,4 +126,5 @@ void injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOpti
qCWarning(audio) << "Unknown audio injector option:" << it->name();
}
}
return true;
}

View file

@ -37,6 +37,6 @@ public:
Q_DECLARE_METATYPE(AudioInjectorOptions);
ScriptValue injectorOptionsToScriptValue(ScriptEngine* engine, const AudioInjectorOptions& injectorOptions);
void injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions);
bool injectorOptionsFromScriptValue(const ScriptValue& object, AudioInjectorOptions& injectorOptions);
#endif // hifi_AudioInjectorOptions_h

View file

@ -32,8 +32,9 @@ ScriptValue injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* con
return engine->newQObject(in, ScriptEngine::ScriptOwnership);
}
void injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out) {
bool injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out) {
out = qobject_cast<ScriptAudioInjector*>(object.toQObject());
return true;
}
ScriptAudioInjector::ScriptAudioInjector(const AudioInjectorPointer& injector) :

View file

@ -152,7 +152,7 @@ private:
Q_DECLARE_METATYPE(ScriptAudioInjector*)
ScriptValue injectorToScriptValue(ScriptEngine* engine, ScriptAudioInjector* const& in);
void injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out);
bool injectorFromScriptValue(const ScriptValue& object, ScriptAudioInjector*& out);
#endif // hifi_ScriptAudioInjector_h

View file

@ -428,10 +428,11 @@ ScriptValue soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSo
return engine->newQObject(new SoundScriptingInterface(in), ScriptEngine::ScriptOwnership);
}
void soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out) {
bool soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out) {
if (auto soundInterface = qobject_cast<SoundScriptingInterface*>(object.toQObject())) {
out = soundInterface->getSound();
}
return true;
}
SoundScriptingInterface::SoundScriptingInterface(const SharedSoundPointer& sound) : _sound(sound) {

View file

@ -172,6 +172,6 @@ private:
Q_DECLARE_METATYPE(SharedSoundPointer)
ScriptValue soundSharedPointerToScriptValue(ScriptEngine* engine, const SharedSoundPointer& in);
void soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out);
bool soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPointer& out);
#endif // hifi_Sound_h

View file

@ -3176,7 +3176,7 @@ ScriptValue RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, con
return obj;
}
void RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& value) {
bool RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& value) {
value.intersects = object.property("intersects").toVariant().toBool();
ScriptValue avatarIDValue = object.property("avatarID");
quuidFromScriptValue(avatarIDValue, value.avatarID);
@ -3193,6 +3193,7 @@ void RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, Ray
}
value.jointIndex = object.property("jointIndex").toInt32();
value.extraInfo = object.property("extraInfo").toVariant().toMap();
return true;
}
// these coefficients can be changed via JS for experimental tuning
@ -3226,7 +3227,7 @@ ScriptValue AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntit
return obj;
}
void AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value) {
bool AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value) {
ScriptValueIteratorPointer itr(object.newIterator());
while (itr->hasNext()) {
itr->next();
@ -3240,6 +3241,7 @@ void AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap&
OVERTE_IGNORE_DEPRECATED_END
value[EntityID] = binaryEntityProperties;
}
return true;
}
const float AvatarData::DEFAULT_BUBBLE_SCALE = 2.4f; // magic number determined empirically

View file

@ -1972,7 +1972,7 @@ public:
};
Q_DECLARE_METATYPE(RayToAvatarIntersectionResult)
ScriptValue RayToAvatarIntersectionResultToScriptValue(ScriptEngine* engine, const RayToAvatarIntersectionResult& results);
void RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& results);
bool RayToAvatarIntersectionResultFromScriptValue(const ScriptValue& object, RayToAvatarIntersectionResult& results);
// No JSDoc because it's not provided as a type to the script engine.
class ParabolaToAvatarIntersectionResult {
@ -1990,7 +1990,7 @@ public:
Q_DECLARE_METATYPE(AvatarEntityMap)
ScriptValue AvatarEntityMapToScriptValue(ScriptEngine* engine, const AvatarEntityMap& value);
void AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value);
bool AvatarEntityMapFromScriptValue(const ScriptValue& object, AvatarEntityMap& value);
// faux joint indexes (-1 means invalid)
const int NO_JOINT_INDEX = 65535; // -1

View file

@ -18,10 +18,11 @@ ScriptValue avatarDataToScriptValue(ScriptEngine* engine, ScriptAvatarData* cons
return engine->newQObject(in, ScriptEngine::ScriptOwnership);
}
void avatarDataFromScriptValue(const ScriptValue& object, ScriptAvatarData*& out) {
bool avatarDataFromScriptValue(const ScriptValue& object, ScriptAvatarData*& out) {
// This is not implemented because there are no slots/properties that take an AvatarSharedPointer from a script
assert(false);
out = nullptr;
return false;
}
STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) {

View file

@ -50,7 +50,7 @@ namespace controller {
return obj;
}
void Pose::fromScriptValue(const ScriptValue& object, Pose& pose) {
bool Pose::fromScriptValue(const ScriptValue& object, Pose& pose) {
auto translation = object.property("translation");
auto rotation = object.property("rotation");
auto velocity = object.property("velocity");
@ -67,6 +67,7 @@ namespace controller {
} else {
pose.valid = false;
}
return true;
}
Pose Pose::transform(const glm::mat4& mat) const {

View file

@ -45,7 +45,7 @@ namespace controller {
Pose postTransform(const glm::mat4& mat) const;
static ScriptValue toScriptValue(ScriptEngine* engine, const Pose& event);
static void fromScriptValue(const ScriptValue& object, Pose& event);
static bool fromScriptValue(const ScriptValue& object, Pose& event);
};
}

View file

@ -37,8 +37,9 @@ ScriptValue inputControllerToScriptValue(ScriptEngine* engine, controller::Input
return engine->newQObject(in, ScriptEngine::QtOwnership);
}
void inputControllerFromScriptValue(const ScriptValue& object, controller::InputController*& out) {
bool inputControllerFromScriptValue(const ScriptValue& object, controller::InputController*& out) {
out = qobject_cast<controller::InputController*>(object.toQObject());
return true;
}
STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) {

View file

@ -393,13 +393,13 @@ int poseMetaTypeId = qRegisterMetaType<controller::Pose>("Pose");
int handMetaTypeId = qRegisterMetaType<controller::Hand>();
ScriptValue inputToScriptValue(ScriptEngine* engine, const Input& input);
void inputFromScriptValue(const ScriptValue& object, Input& input);
bool inputFromScriptValue(const ScriptValue& object, Input& input);
ScriptValue actionToScriptValue(ScriptEngine* engine, const Action& action);
void actionFromScriptValue(const ScriptValue& object, Action& action);
bool actionFromScriptValue(const ScriptValue& object, Action& action);
ScriptValue inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair);
void inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair);
bool inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair);
ScriptValue handToScriptValue(ScriptEngine* engine, const controller::Hand& hand);
void handFromScriptValue(const ScriptValue& object, controller::Hand& hand);
bool handFromScriptValue(const ScriptValue& object, controller::Hand& hand);
ScriptValue inputToScriptValue(ScriptEngine* engine, const Input& input) {
ScriptValue obj = engine->newObject();
@ -410,8 +410,9 @@ ScriptValue inputToScriptValue(ScriptEngine* engine, const Input& input) {
return obj;
}
void inputFromScriptValue(const ScriptValue& object, Input& input) {
bool inputFromScriptValue(const ScriptValue& object, Input& input) {
input.id = object.property("id").toInt32();
return true;
}
ScriptValue actionToScriptValue(ScriptEngine* engine, const Action& action) {
@ -422,8 +423,9 @@ ScriptValue actionToScriptValue(ScriptEngine* engine, const Action& action) {
return obj;
}
void actionFromScriptValue(const ScriptValue& object, Action& action) {
bool actionFromScriptValue(const ScriptValue& object, Action& action) {
action = Action(object.property("action").toVariant().toInt());
return true;
}
ScriptValue inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair& inputPair) {
@ -433,17 +435,19 @@ ScriptValue inputPairToScriptValue(ScriptEngine* engine, const Input::NamedPair&
return obj;
}
void inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair) {
bool inputPairFromScriptValue(const ScriptValue& object, Input::NamedPair& inputPair) {
inputFromScriptValue(object.property("input"), inputPair.first);
inputPair.second = QString(object.property("inputName").toVariant().toString());
return true;
}
ScriptValue handToScriptValue(ScriptEngine* engine, const controller::Hand& hand) {
return engine->newValue((int)hand);
}
void handFromScriptValue(const ScriptValue& object, controller::Hand& hand) {
bool handFromScriptValue(const ScriptValue& object, controller::Hand& hand) {
hand = Hand(object.toVariant().toInt());
return true;
}
void UserInputMapper::registerControllerTypes(ScriptEngine* engine) {

View file

@ -2588,20 +2588,22 @@ ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, co
return properties.copyToScriptValue(engine, true);
}
void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue &object, EntityItemProperties& properties) {
bool EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue &object, EntityItemProperties& properties) {
properties.copyFromScriptValue(object, false);
return true;
}
void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue &object, EntityItemProperties& properties) {
bool EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue &object, EntityItemProperties& properties) {
properties.copyFromScriptValue(object, true);
return true;
}
ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) {
return EntityItemProperties::entityPropertyFlagsToScriptValue(engine, flags);
}
void EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) {
EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags);
bool EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) {
return EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags);
}
@ -2610,7 +2612,7 @@ ScriptValue EntityItemProperties::entityPropertyFlagsToScriptValue(ScriptEngine*
return result;
}
void EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) {
bool EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) {
if (object.isString()) {
EntityPropertyInfo propertyInfo;
if (getPropertyInfo(object.toString(), propertyInfo)) {
@ -2627,6 +2629,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValue&
}
}
}
return true;
}
static QHash<QString, EntityPropertyInfo> _propertyInfos;
@ -3027,10 +3030,11 @@ ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPr
return obj;
}
void EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo) {
bool EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo) {
propertyInfo.propertyEnum = (EntityPropertyList)object.property("propertyEnum").toVariant().toUInt();
propertyInfo.minimum = object.property("minimum").toVariant();
propertyInfo.maximum = object.property("maximum").toVariant();
return true;
}
// TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the

View file

@ -141,7 +141,7 @@ public:
void copyFromJSONString(ScriptEngine& scriptEngine, const QString& jsonString);
static ScriptValue entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags);
static void entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags);
static bool entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags);
static bool getPropertyInfo(const QString& propertyName, EntityPropertyInfo& propertyInfo);
@ -543,16 +543,16 @@ private:
Q_DECLARE_METATYPE(EntityItemProperties);
ScriptValue EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties);
ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue& object, EntityItemProperties& properties);
void EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue& object, EntityItemProperties& properties);
bool EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue& object, EntityItemProperties& properties);
bool EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue& object, EntityItemProperties& properties);
Q_DECLARE_METATYPE(EntityPropertyFlags);
ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags);
void EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags);
bool EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags);
Q_DECLARE_METATYPE(EntityPropertyInfo);
ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo);
void EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo);
bool EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo);
// define these inline here so the macros work
inline void EntityItemProperties::setPosition(const glm::vec3& value)

View file

@ -1690,7 +1690,7 @@ ScriptValue RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, con
return obj;
}
void RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& value) {
bool RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& value) {
value.intersects = object.property("intersects").toVariant().toBool();
value.accurate = object.property("accurate").toVariant().toBool();
ScriptValue entityIDValue = object.property("entityID");
@ -1707,6 +1707,7 @@ void RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, Ray
vec3FromScriptValue(surfaceNormal, value.surfaceNormal);
}
value.extraInfo = object.property("extraInfo").toVariant().toMap();
return true;
}
bool EntityScriptingInterface::polyVoxWorker(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor) {

View file

@ -92,7 +92,7 @@ public:
};
Q_DECLARE_METATYPE(RayToEntityIntersectionResult)
ScriptValue RayToEntityIntersectionResultToScriptValue(ScriptEngine* engine, const RayToEntityIntersectionResult& results);
void RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& results);
bool RayToEntityIntersectionResultFromScriptValue(const ScriptValue& object, RayToEntityIntersectionResult& results);
class ParabolaToEntityIntersectionResult {
public:

View file

@ -325,14 +325,14 @@ namespace scriptable {
}
return engine->newQObject(object, ScriptEngine::QtOwnership, ScriptEngine::AutoCreateDynamicProperties);
},
[](const ScriptValue& value, QPointer<T>& out) {
[](const ScriptValue& value, QPointer<T>& out) -> bool {
auto obj = value.toQObject();
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString();
#endif
if (auto tmp = qobject_cast<T*>(obj)) {
out = QPointer<T>(tmp);
return;
return true;
}
#if 0
if (auto tmp = static_cast<T*>(obj)) {
@ -340,10 +340,11 @@ namespace scriptable {
qCInfo(graphics_scripting) << "qpointer_qobject_cast -- via static_cast" << obj << tmp << value.toString();
#endif
out = QPointer<T>(tmp);
return;
return true;
}
#endif
out = nullptr;
return false;
}
);
}
@ -352,8 +353,9 @@ namespace scriptable {
return scriptValueFromSequence(engine, vector);
}
void qVectorScriptableMaterialLayerFromScriptValue(const ScriptValue& array, QVector<scriptable::ScriptableMaterialLayer>& result) {
bool qVectorScriptableMaterialLayerFromScriptValue(const ScriptValue& array, QVector<scriptable::ScriptableMaterialLayer>& result) {
scriptValueToSequence(array, result);
return true;
}
/*@jsdoc
@ -625,8 +627,9 @@ namespace scriptable {
return obj;
}
void scriptableMaterialFromScriptValue(const ScriptValue &object, scriptable::ScriptableMaterial& material) {
bool scriptableMaterialFromScriptValue(const ScriptValue& object, scriptable::ScriptableMaterial& material) {
// No need to convert from ScriptValue to ScriptableMaterial
return false;
}
ScriptValue scriptableMaterialLayerToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterialLayer &materialLayer) {
@ -636,8 +639,9 @@ namespace scriptable {
return obj;
}
void scriptableMaterialLayerFromScriptValue(const ScriptValue &object, scriptable::ScriptableMaterialLayer& materialLayer) {
bool scriptableMaterialLayerFromScriptValue(const ScriptValue& object, scriptable::ScriptableMaterialLayer& materialLayer) {
// No need to convert from ScriptValue to ScriptableMaterialLayer
return false;
}
ScriptValue multiMaterialMapToScriptValue(ScriptEngine* engine, const scriptable::MultiMaterialMap& map) {
@ -648,8 +652,9 @@ namespace scriptable {
return obj;
}
void multiMaterialMapFromScriptValue(const ScriptValue& map, scriptable::MultiMaterialMap& result) {
bool multiMaterialMapFromScriptValue(const ScriptValue& map, scriptable::MultiMaterialMap& result) {
// No need to convert from ScriptValue to MultiMaterialMap
return false;
}
template <typename T> int registerDebugEnum(ScriptEngine* engine, const DebugEnums<T>& debugEnums) {
@ -659,8 +664,9 @@ namespace scriptable {
[](ScriptEngine* engine, const T& topology) -> ScriptValue {
return engine->newValue(instance.value(topology));
},
[](const ScriptValue& value, T& topology) {
[](const ScriptValue& value, T& topology) -> bool {
topology = instance.key(value.toString());
return true;
}
);
}

View file

@ -187,7 +187,7 @@ ScriptValue KeyEvent::toScriptValue(ScriptEngine* engine, const KeyEvent& event)
return obj;
}
void KeyEvent::fromScriptValue(const ScriptValue& object, KeyEvent& event) {
bool KeyEvent::fromScriptValue(const ScriptValue& object, KeyEvent& event) {
event.isValid = false; // assume the worst
event.isMeta = object.property("isMeta").toVariant().toBool();
@ -281,6 +281,7 @@ void KeyEvent::fromScriptValue(const ScriptValue& object, KeyEvent& event) {
}
event.isValid = true;
}
return true;
}
ScriptValue isShifted = object.property("isShifted");

View file

@ -30,7 +30,7 @@ public:
operator QKeySequence() const;
static ScriptValue toScriptValue(ScriptEngine* engine, const KeyEvent& event);
static void fromScriptValue(const ScriptValue& object, KeyEvent& event);
static bool fromScriptValue(const ScriptValue& object, KeyEvent& event);
int key;
QString text;

View file

@ -35,9 +35,10 @@ ScriptValue midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event)
return obj;
}
void midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event) {
bool midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event) {
event.deltaTime = object.property(MIDI_DELTA_TIME_PROP_NAME).toVariant().toDouble();
event.type = object.property(MIDI_EVENT_TYPE_PROP_NAME).toVariant().toUInt();
event.data1 = object.property(MIDI_DATA_1_PROP_NAME).toVariant().toUInt();
event.data2 = object.property(MIDI_DATA_2_PROP_NAME).toVariant().toUInt();
return true;
}

View file

@ -33,7 +33,7 @@ Q_DECLARE_METATYPE(MIDIEvent)
void registerMIDIMetaTypes(ScriptEngine* engine);
ScriptValue midiEventToScriptValue(ScriptEngine* engine, const MIDIEvent& event);
void midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event);
bool midiEventFromScriptValue(const ScriptValue &object, MIDIEvent& event);
#endif // hifi_MIDIEvent_h

View file

@ -73,7 +73,7 @@ ScriptValue menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItem
* @property {string} [afterItem] - The name of the menu item to place this menu item after.
* @property {string} [grouping] - The name of grouping to add this menu item to.
*/
void menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& properties) {
bool menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& properties) {
properties.menuName = object.property("menuName").toVariant().toString();
properties.menuItemName = object.property("menuItemName").toVariant().toString();
properties.isCheckable = object.property("isCheckable").toVariant().toBool();
@ -99,6 +99,7 @@ void menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProper
properties.beforeItem = object.property("beforeItem").toVariant().toString();
properties.afterItem = object.property("afterItem").toVariant().toString();
properties.grouping = object.property("grouping").toVariant().toString();
return true;
}

View file

@ -55,7 +55,7 @@ private:
};
Q_DECLARE_METATYPE(MenuItemProperties)
ScriptValue menuItemPropertiesToScriptValue(ScriptEngine* engine, const MenuItemProperties& props);
void menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& props);
bool menuItemPropertiesFromScriptValue(const ScriptValue& object, MenuItemProperties& props);
void registerMenuItemProperties(ScriptEngine* engine);

View file

@ -102,6 +102,7 @@ ScriptValue MouseEvent::toScriptValue(ScriptEngine* engine, const MouseEvent& ev
return obj;
}
void MouseEvent::fromScriptValue(const ScriptValue& object, MouseEvent& event) {
bool MouseEvent::fromScriptValue(const ScriptValue& object, MouseEvent& event) {
// nothing for now...
return false;
}

View file

@ -28,7 +28,7 @@ public:
MouseEvent(const QMouseEvent& event);
static ScriptValue toScriptValue(ScriptEngine* engine, const MouseEvent& event);
static void fromScriptValue(const ScriptValue& object, MouseEvent& event);
static bool fromScriptValue(const ScriptValue& object, MouseEvent& event);
ScriptValue toScriptValue(ScriptEngine* engine) const { return MouseEvent::toScriptValue(engine, *this); }

View file

@ -212,7 +212,7 @@ ScriptValue PointerEvent::toScriptValue(ScriptEngine* engine, const PointerEvent
return obj;
}
void PointerEvent::fromScriptValue(const ScriptValue& object, PointerEvent& event) {
bool PointerEvent::fromScriptValue(const ScriptValue& object, PointerEvent& event) {
if (object.isObject()) {
ScriptValue type = object.property("type");
QString typeStr = type.isString() ? type.toString() : "Move";
@ -263,6 +263,7 @@ void PointerEvent::fromScriptValue(const ScriptValue& object, PointerEvent& even
event._keyboardModifiers = (Qt::KeyboardModifiers)(object.property("keyboardModifiers").toUInt32());
}
return true;
}
static const char* typeToStringMap[PointerEvent::NumEventTypes] = { "Press", "DoublePress", "Release", "Move" };

View file

@ -52,7 +52,7 @@ public:
Button button = NoButtons, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::NoModifier);
static ScriptValue toScriptValue(ScriptEngine* engine, const PointerEvent& event);
static void fromScriptValue(const ScriptValue& object, PointerEvent& event);
static bool fromScriptValue(const ScriptValue& object, PointerEvent& event);
ScriptValue toScriptValue(ScriptEngine* engine) const { return PointerEvent::toScriptValue(engine, *this); }

View file

@ -0,0 +1,23 @@
//
// ScriptContext.h
// libraries/script-engine/src
//
// Created by Heather Anderson on 12/5/21.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ScriptContext.h"
#include "Scriptable.h"
ScriptContextGuard::ScriptContextGuard(ScriptContext* context) {
_oldContext = Scriptable::context();
Scriptable::setContext(context);
}
ScriptContextGuard::~ScriptContextGuard() {
Scriptable::setContext(_oldContext);
}

View file

@ -67,6 +67,15 @@ protected:
~ScriptContext() {} // prevent explicit deletion of base class
};
class ScriptContextGuard {
public:
ScriptContextGuard(ScriptContext* context);
~ScriptContextGuard();
private:
ScriptContext* _oldContext;
};
#endif // hifi_ScriptContext_h
/// @}

View file

@ -49,7 +49,7 @@ class ScriptEngine {
public:
typedef ScriptValue (*FunctionSignature)(ScriptContext*, ScriptEngine*);
typedef ScriptValue (*MarshalFunction)(ScriptEngine*, const void*);
typedef void (*DemarshalFunction)(const ScriptValue&, void*);
typedef bool (*DemarshalFunction)(const ScriptValue&, void*);
enum ValueOwnership {
QtOwnership = 0,
@ -136,8 +136,8 @@ public:
public: // not for public use, but I don't like how Qt strings this along with private friend functions
virtual ScriptValue create(int type, const void* ptr) = 0;
virtual bool convert(const ScriptValue& value, int type, void* ptr) = 0;
virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df, const ScriptValue& prototype) = 0;
virtual QVariant convert(const ScriptValue& value, int type) = 0;
virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df) = 0;
protected:
~ScriptEngine() {} // prevent explicit deletion of base class

View file

@ -42,13 +42,16 @@ inline ScriptValue scriptValueFromValue<QVariant>(ScriptEngine* engine, const QV
template <typename T>
inline T scriptvalue_cast(const ScriptValue& value) {
T t;
const int id = qMetaTypeId<T>();
auto engine = value.engine();
if (engine && engine->convert(value, id, &t)) {
return t;
} else if (value.isVariant()) {
if (engine) {
QVariant varValue = engine->convert(value, id);
if (varValue.isValid()) {
return varValue.value<T>();
}
}
if (value.isVariant()) {
return qvariant_cast<T>(value.toVariant());
}
@ -63,13 +66,12 @@ inline QVariant scriptvalue_cast<QVariant>(const ScriptValue& value) {
template <typename T>
int scriptRegisterMetaType(ScriptEngine* eng,
ScriptValue (*toScriptValue)(ScriptEngine*, const T& t),
void (*fromScriptValue)(const ScriptValue&, T& t),
const ScriptValue& prototype = ScriptValue(),
bool (*fromScriptValue)(const ScriptValue&, T& t),
T* = 0)
{
const int id = qRegisterMetaType<T>(); // make sure it's registered
eng->registerCustomType(id, reinterpret_cast<ScriptEngine::MarshalFunction>(toScriptValue),
reinterpret_cast<ScriptEngine::DemarshalFunction>(fromScriptValue), prototype);
reinterpret_cast<ScriptEngine::DemarshalFunction>(fromScriptValue));
return id;
}
@ -87,19 +89,19 @@ ScriptValue scriptValueFromSequence(ScriptEngine* eng, const Container& cont) {
}
template <class Container>
void scriptValueToSequence(const ScriptValue& value, Container& cont) {
bool scriptValueToSequence(const ScriptValue& value, Container& cont) {
quint32 len = value.property(QLatin1String("length")).toUInt32();
for (quint32 i = 0; i < len; ++i) {
ScriptValue item = value.property(i);
cont.push_back(scriptvalue_cast<typename Container::value_type>(item));
}
return true;
}
template <typename T>
int scriptRegisterSequenceMetaType(ScriptEngine* engine,
const ScriptValue& prototype = ScriptValue(),
T* = 0) {
return scriptRegisterMetaType<T>(engine, scriptValueFromSequence, scriptValueToSequence, prototype);
return scriptRegisterMetaType<T>(engine, scriptValueFromSequence, scriptValueToSequence);
}
#endif // hifi_ScriptEngineCast_h

View file

@ -538,8 +538,9 @@ static ScriptValue scriptableResourceToScriptValue(ScriptEngine* engine,
return object;
}
static void scriptableResourceFromScriptValue(const ScriptValue& value, ScriptableResourceRawPtr& resource) {
static bool scriptableResourceFromScriptValue(const ScriptValue& value, ScriptableResourceRawPtr& resource) {
resource = static_cast<ScriptableResourceRawPtr>(value.toQObject());
return true;
}
/*@jsdoc
@ -578,8 +579,9 @@ ScriptValue externalResourceBucketToScriptValue(ScriptEngine* engine, ExternalRe
return engine->newValue((int)in);
}
void externalResourceBucketFromScriptValue(const ScriptValue& object, ExternalResource::Bucket& out) {
bool externalResourceBucketFromScriptValue(const ScriptValue& object, ExternalResource::Bucket& out) {
out = static_cast<ExternalResource::Bucket>(object.toInt32());
return true;
}
void ScriptManager::resetModuleCache(bool deleteScriptCache) {
@ -722,6 +724,11 @@ void ScriptManager::init() {
}));
}
// registers a global object by name
void ScriptManager::registerValue(const QString& valueName, ScriptValue value) {
_engine->globalObject().setProperty(valueName, value);
}
// Unregister the handlers for this eventName and entityID.
void ScriptManager::removeEventHandler(const EntityItemID& entityID, const QString& eventName, const ScriptValue& handler) {
if (QThread::currentThread() != thread()) {

View file

@ -275,6 +275,15 @@ public:
*/
Q_INVOKABLE bool isAgentScript() const { return _context == AGENT_SCRIPT; }
/*@jsdoc
* registers a global object by name.
* @function Script.registerValue
* @param {string} valueName
* @param {value} value
*/
/// registers a global object by name
Q_INVOKABLE void registerValue(const QString& valueName, ScriptValue value);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE - these are intended to be public interfaces available to scripts

View file

@ -99,7 +99,7 @@ ScriptValue vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2) {
return value;
}
void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2) {
bool vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2) {
if (object.isNumber()) {
vec2 = glm::vec2(object.toVariant().toFloat());
} else if (object.isArray()) {
@ -122,6 +122,7 @@ void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2) {
vec2.x = x.toVariant().toFloat();
vec2.y = y.toVariant().toFloat();
}
return true;
}
ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) {
@ -174,7 +175,7 @@ ScriptValue vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3)
return value;
}
void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3) {
bool vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3) {
if (object.isNumber()) {
vec3 = glm::vec3(object.toVariant().toFloat());
} else if (object.isString()) {
@ -220,6 +221,7 @@ void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3) {
vec3.y = y.toVariant().toFloat();
vec3.z = z.toVariant().toFloat();
}
return true;
}
ScriptValue u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3) {
@ -272,7 +274,7 @@ ScriptValue u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& ve
return value;
}
void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3) {
bool u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3) {
if (object.isNumber()) {
vec3 = glm::vec3(object.toVariant().toUInt());
} else if (object.isString()) {
@ -318,6 +320,7 @@ void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3) {
vec3.y = y.toVariant().toUInt();
vec3.z = z.toVariant().toUInt();
}
return true;
}
ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) {
@ -329,11 +332,12 @@ ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4) {
return obj;
}
void vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4) {
bool vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4) {
vec4.x = object.property("x").toVariant().toFloat();
vec4.y = object.property("y").toVariant().toFloat();
vec4.z = object.property("z").toVariant().toFloat();
vec4.w = object.property("w").toVariant().toFloat();
return true;
}
ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) {
@ -357,7 +361,7 @@ ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4) {
return obj;
}
void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4) {
bool mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4) {
mat4[0][0] = object.property("r0c0").toVariant().toFloat();
mat4[0][1] = object.property("r1c0").toVariant().toFloat();
mat4[0][2] = object.property("r2c0").toVariant().toFloat();
@ -374,6 +378,7 @@ void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4) {
mat4[3][1] = object.property("r1c3").toVariant().toFloat();
mat4[3][2] = object.property("r2c3").toVariant().toFloat();
mat4[3][3] = object.property("r3c3").toVariant().toFloat();
return true;
}
ScriptValue qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector<glm::vec3>& vector) {
@ -404,7 +409,7 @@ QVector<glm::vec3> qVectorVec3FromScriptValue(const ScriptValue& array) {
return newVector;
}
void qVectorVec3FromScriptValue(const ScriptValue& array, QVector<glm::vec3>& vector) {
bool qVectorVec3FromScriptValue(const ScriptValue& array, QVector<glm::vec3>& vector) {
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
@ -412,6 +417,7 @@ void qVectorVec3FromScriptValue(const ScriptValue& array, QVector<glm::vec3>& ve
vec3FromScriptValue(array.property(i), newVec3);
vector << newVec3;
}
return true;
}
ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) {
@ -427,7 +433,7 @@ ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) {
return obj;
}
void quatFromScriptValue(const ScriptValue& object, glm::quat& quat) {
bool quatFromScriptValue(const ScriptValue& object, glm::quat& quat) {
quat.x = object.property("x").toVariant().toFloat();
quat.y = object.property("y").toVariant().toFloat();
quat.z = object.property("z").toVariant().toFloat();
@ -440,6 +446,7 @@ void quatFromScriptValue(const ScriptValue& object, glm::quat& quat) {
} else {
quat = glm::quat();
}
return true;
}
ScriptValue qVectorQuatToScriptValue(ScriptEngine* engine, const QVector<glm::quat>& vector) {
@ -482,12 +489,13 @@ ScriptValue qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector<QUuid>
return array;
}
void qVectorQUuidFromScriptValue(const ScriptValue& array, QVector<QUuid>& vector) {
bool qVectorQUuidFromScriptValue(const ScriptValue& array, QVector<QUuid>& vector) {
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
vector << array.property(i).toVariant().toUuid();
}
return true;
}
QVector<QUuid> qVectorQUuidFromScriptValue(const ScriptValue& array) {
@ -523,20 +531,22 @@ ScriptValue qVectorIntToScriptValue(ScriptEngine* engine, const QVector<uint32_t
return array;
}
void qVectorFloatFromScriptValue(const ScriptValue& array, QVector<float>& vector) {
bool qVectorFloatFromScriptValue(const ScriptValue& array, QVector<float>& vector) {
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
vector << array.property(i).toVariant().toFloat();
}
return true;
}
void qVectorIntFromScriptValue(const ScriptValue& array, QVector<uint32_t>& vector) {
bool qVectorIntFromScriptValue(const ScriptValue& array, QVector<uint32_t>& vector) {
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
vector << array.property(i).toVariant().toInt();
}
return true;
}
QVector<glm::quat> qVectorQuatFromScriptValue(const ScriptValue& array) {
@ -551,7 +561,7 @@ QVector<glm::quat> qVectorQuatFromScriptValue(const ScriptValue& array) {
return newVector;
}
void qVectorQuatFromScriptValue(const ScriptValue& array, QVector<glm::quat>& vector) {
bool qVectorQuatFromScriptValue(const ScriptValue& array, QVector<glm::quat>& vector) {
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
@ -559,6 +569,7 @@ void qVectorQuatFromScriptValue(const ScriptValue& array, QVector<glm::quat>& ve
quatFromScriptValue(array.property(i), newQuat);
vector << newQuat;
}
return true;
}
QVector<bool> qVectorBoolFromScriptValue(const ScriptValue& array) {
@ -571,12 +582,13 @@ QVector<bool> qVectorBoolFromScriptValue(const ScriptValue& array) {
return newVector;
}
void qVectorBoolFromScriptValue(const ScriptValue& array, QVector<bool>& vector) {
bool qVectorBoolFromScriptValue(const ScriptValue& array, QVector<bool>& vector) {
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
vector << array.property(i).toBool();
}
return true;
}
ScriptValue qRectToScriptValue(ScriptEngine* engine, const QRect& rect) {
@ -588,11 +600,12 @@ ScriptValue qRectToScriptValue(ScriptEngine* engine, const QRect& rect) {
return obj;
}
void qRectFromScriptValue(const ScriptValue& object, QRect& rect) {
bool qRectFromScriptValue(const ScriptValue& object, QRect& rect) {
rect.setX(object.property("x").toVariant().toInt());
rect.setY(object.property("y").toVariant().toInt());
rect.setWidth(object.property("width").toVariant().toInt());
rect.setHeight(object.property("height").toVariant().toInt());
return true;
}
ScriptValue qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect) {
@ -604,11 +617,12 @@ ScriptValue qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect) {
return obj;
}
void qRectFFromScriptValue(const ScriptValue& object, QRectF& rect) {
bool qRectFFromScriptValue(const ScriptValue& object, QRectF& rect) {
rect.setX(object.property("x").toVariant().toFloat());
rect.setY(object.property("y").toVariant().toFloat());
rect.setWidth(object.property("width").toVariant().toFloat());
rect.setHeight(object.property("height").toVariant().toFloat());
return true;
}
ScriptValue qColorToScriptValue(ScriptEngine* engine, const QColor& color) {
@ -639,7 +653,7 @@ ScriptValue aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube) {
return obj;
}
void aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube) {
bool aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube) {
glm::vec3 corner;
corner.x = object.property("x").toVariant().toFloat();
corner.y = object.property("y").toVariant().toFloat();
@ -647,9 +661,10 @@ void aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube) {
float scale = object.property("scale").toVariant().toFloat();
aaCube.setBox(corner, scale);
return true;
}
void qColorFromScriptValue(const ScriptValue& object, QColor& color) {
bool qColorFromScriptValue(const ScriptValue& object, QColor& color) {
if (object.isNumber()) {
color.setRgb(object.toUInt32());
@ -661,14 +676,16 @@ void qColorFromScriptValue(const ScriptValue& object, QColor& color) {
color.setRgb(object.property("red").toInt32(), object.property("green").toInt32(), object.property("blue").toInt32(),
alphaValue.isNumber() ? alphaValue.toInt32() : 255);
}
return true;
}
ScriptValue qURLToScriptValue(ScriptEngine* engine, const QUrl& url) {
return engine->newValue(url.toString());
}
void qURLFromScriptValue(const ScriptValue& object, QUrl& url) {
bool qURLFromScriptValue(const ScriptValue& object, QUrl& url) {
url = object.toString();
return true;
}
ScriptValue pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay) {
@ -680,7 +697,7 @@ ScriptValue pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay) {
return obj;
}
void pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay) {
bool pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay) {
ScriptValue originValue = object.property("origin");
if (originValue.isValid()) {
auto x = originValue.property("x");
@ -703,6 +720,7 @@ void pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay) {
pickRay.direction.z = z.toVariant().toFloat();
}
}
return true;
}
/**jsdoc
@ -726,8 +744,9 @@ ScriptValue collisionToScriptValue(ScriptEngine* engine, const Collision& collis
return obj;
}
void collisionFromScriptValue(const ScriptValue& object, Collision& collision) {
bool collisionFromScriptValue(const ScriptValue& object, Collision& collision) {
// TODO: implement this when we know what it means to accept collision events from JS
return false;
}
ScriptValue quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid) {
@ -738,14 +757,15 @@ ScriptValue quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid) {
return obj;
}
void quuidFromScriptValue(const ScriptValue& object, QUuid& uuid) {
bool quuidFromScriptValue(const ScriptValue& object, QUuid& uuid) {
if (object.isNull()) {
uuid = QUuid();
return;
return true;
}
QString uuidAsString = object.toVariant().toString();
QUuid fromString(uuidAsString);
uuid = fromString;
return true;
}
/**jsdoc
@ -761,9 +781,10 @@ ScriptValue qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF) {
return obj;
}
void qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF) {
bool qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF) {
qSizeF.setWidth(object.property("width").toVariant().toFloat());
qSizeF.setHeight(object.property("height").toVariant().toFloat());
return true;
}
/**jsdoc
@ -802,16 +823,18 @@ ScriptValue animationDetailsToScriptValue(ScriptEngine* engine, const AnimationD
return obj;
}
void animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& details) {
bool animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& details) {
// nothing for now...
return false;
}
ScriptValue meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in) {
return engine->newQObject(in, ScriptEngine::QtOwnership);
}
void meshFromScriptValue(const ScriptValue& value, MeshProxy*& out) {
bool meshFromScriptValue(const ScriptValue& value, MeshProxy*& out) {
out = qobject_cast<MeshProxy*>(value.toQObject());
return true;
}
ScriptValue meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in) {
@ -822,7 +845,7 @@ ScriptValue meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in) {
return result;
}
void meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out) {
bool meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out) {
ScriptValueIteratorPointer itr(value.newIterator());
qDebug() << "in meshesFromScriptValue, value.length =" << value.property("length").toInt32();
@ -836,6 +859,7 @@ void meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out) {
qDebug() << "null meshProxy";
}
}
return true;
}
/**jsdoc
@ -849,8 +873,8 @@ ScriptValue meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace
return obj;
}
void meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult) {
qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices);
bool meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult) {
return qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices);
}
ScriptValue qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector<MeshFace>& vector) {
@ -861,7 +885,7 @@ ScriptValue qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector<Mes
return array;
}
void qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector<MeshFace>& result) {
bool qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector<MeshFace>& result) {
int length = array.property("length").toInteger();
result.clear();
@ -870,18 +894,21 @@ void qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector<MeshFace>&
meshFaceFromScriptValue(array.property(i), meshFace);
result << meshFace;
}
return true;
}
ScriptValue stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode) {
return engine->newValue((int)stencilMode);
}
void stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode) {
bool stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode) {
stencilMode = StencilMaskMode(object.toVariant().toInt());
return true;
}
void promiseFromScriptValue(const ScriptValue& object, std::shared_ptr<MiniPromise>& promise) {
bool promiseFromScriptValue(const ScriptValue& object, std::shared_ptr<MiniPromise>& promise) {
Q_ASSERT(false);
return false;
}
ScriptValue promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr<MiniPromise>& promise) {
return engine->newQObject(promise.get());
@ -891,8 +918,8 @@ ScriptValue EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID&
return quuidToScriptValue(engine, id);
}
void EntityItemIDfromScriptValue(const ScriptValue &object, EntityItemID& id) {
quuidFromScriptValue(object, id);
bool EntityItemIDfromScriptValue(const ScriptValue& object, EntityItemID& id) {
return quuidFromScriptValue(object, id);
}
QVector<EntityItemID> qVectorEntityItemIDFromScriptValue(const ScriptValue& array) {

View file

@ -52,7 +52,7 @@ void registerMetaTypes(ScriptEngine* engine);
* @property {number} r3c3 - Row 3, column 3 value.
*/
ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4);
void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4);
bool mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4);
/**jsdoc
* A 2-dimensional vector.
@ -69,7 +69,7 @@ void mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4);
* color.v = 0.8; // { x: 0.7, y: 0.8 }
*/
ScriptValue vec2ToScriptValue(ScriptEngine* engine, const glm::vec2& vec2);
void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2);
bool vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2);
/**jsdoc
* A 3-dimensional vector. See also the {@link Vec3(0)|Vec3} object.
@ -93,7 +93,7 @@ void vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2);
*/
ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3);
ScriptValue vec3ColorToScriptValue(ScriptEngine* engine, const glm::vec3& vec3);
void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3);
bool vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3);
/**jsdoc
* A color vector. See also the {@link Vec3(0)|Vec3} object.
@ -135,7 +135,7 @@ void vec3FromScriptValue(const ScriptValue& object, glm::vec3& vec3);
*/
ScriptValue u8vec3ToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3);
ScriptValue u8vec3ColorToScriptValue(ScriptEngine* engine, const glm::u8vec3& vec3);
void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3);
bool u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3);
/**jsdoc
* A 4-dimensional vector.
@ -147,11 +147,11 @@ void u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3);
* @property {number} w - W-coordinate of the vector.
*/
ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4);
void vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4);
bool vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4);
// Quaternions
ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat);
void quatFromScriptValue(const ScriptValue& object, glm::quat& quat);
bool quatFromScriptValue(const ScriptValue& object, glm::quat& quat);
/**jsdoc
* Defines a rectangular portion of an image or screen, or similar.
@ -163,63 +163,63 @@ void quatFromScriptValue(const ScriptValue& object, glm::quat& quat);
*/
class QRect;
ScriptValue qRectToScriptValue(ScriptEngine* engine, const QRect& rect);
void qRectFromScriptValue(const ScriptValue& object, QRect& rect);
bool qRectFromScriptValue(const ScriptValue& object, QRect& rect);
class QRectF;
ScriptValue qRectFToScriptValue(ScriptEngine* engine, const QRectF& rect);
void qRectFFromScriptValue(const ScriptValue& object, QRectF& rect);
bool qRectFFromScriptValue(const ScriptValue& object, QRectF& rect);
// QColor
class QColor;
ScriptValue qColorToScriptValue(ScriptEngine* engine, const QColor& color);
void qColorFromScriptValue(const ScriptValue& object, QColor& color);
bool qColorFromScriptValue(const ScriptValue& object, QColor& color);
class QUrl;
ScriptValue qURLToScriptValue(ScriptEngine* engine, const QUrl& url);
void qURLFromScriptValue(const ScriptValue& object, QUrl& url);
bool qURLFromScriptValue(const ScriptValue& object, QUrl& url);
// vector<vec3>
Q_DECLARE_METATYPE(QVector<glm::vec3>)
ScriptValue qVectorVec3ToScriptValue(ScriptEngine* engine, const QVector<glm::vec3>& vector);
ScriptValue qVectorVec3ColorToScriptValue(ScriptEngine* engine, const QVector<glm::vec3>& vector);
void qVectorVec3FromScriptValue(const ScriptValue& array, QVector<glm::vec3>& vector);
bool qVectorVec3FromScriptValue(const ScriptValue& array, QVector<glm::vec3>& vector);
QVector<glm::vec3> qVectorVec3FromScriptValue(const ScriptValue& array);
// vector<quat>
Q_DECLARE_METATYPE(QVector<glm::quat>)
ScriptValue qVectorQuatToScriptValue(ScriptEngine* engine, const QVector<glm::quat>& vector);
void qVectorQuatFromScriptValue(const ScriptValue& array, QVector<glm::quat>& vector);
bool qVectorQuatFromScriptValue(const ScriptValue& array, QVector<glm::quat>& vector);
QVector<glm::quat> qVectorQuatFromScriptValue(const ScriptValue& array);
// vector<bool>
ScriptValue qVectorBoolToScriptValue(ScriptEngine* engine, const QVector<bool>& vector);
void qVectorBoolFromScriptValue(const ScriptValue& array, QVector<bool>& vector);
bool qVectorBoolFromScriptValue(const ScriptValue& array, QVector<bool>& vector);
QVector<bool> qVectorBoolFromScriptValue(const ScriptValue& array);
// vector<float>
ScriptValue qVectorFloatToScriptValue(ScriptEngine* engine, const QVector<float>& vector);
void qVectorFloatFromScriptValue(const ScriptValue& array, QVector<float>& vector);
bool qVectorFloatFromScriptValue(const ScriptValue& array, QVector<float>& vector);
QVector<float> qVectorFloatFromScriptValue(const ScriptValue& array);
// vector<uint32_t>
ScriptValue qVectorIntToScriptValue(ScriptEngine* engine, const QVector<uint32_t>& vector);
void qVectorIntFromScriptValue(const ScriptValue& array, QVector<uint32_t>& vector);
bool qVectorIntFromScriptValue(const ScriptValue& array, QVector<uint32_t>& vector);
ScriptValue qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector<QUuid>& vector);
void qVectorQUuidFromScriptValue(const ScriptValue& array, QVector<QUuid>& vector);
bool qVectorQUuidFromScriptValue(const ScriptValue& array, QVector<QUuid>& vector);
QVector<QUuid> qVectorQUuidFromScriptValue(const ScriptValue& array);
class AACube;
ScriptValue aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube);
void aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube);
bool aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube);
class PickRay;
ScriptValue pickRayToScriptValue(ScriptEngine* engine, const PickRay& pickRay);
void pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay);
bool pickRayFromScriptValue(const ScriptValue& object, PickRay& pickRay);
class Collision;
ScriptValue collisionToScriptValue(ScriptEngine* engine, const Collision& collision);
void collisionFromScriptValue(const ScriptValue& object, Collision& collision);
bool collisionFromScriptValue(const ScriptValue& object, Collision& collision);
/**jsdoc
* UUIDs (Universally Unique IDentifiers) are used to uniquely identify entities, avatars, and the like. They are represented
@ -229,42 +229,42 @@ void collisionFromScriptValue(const ScriptValue& object, Collision& collision);
*/
//Q_DECLARE_METATYPE(QUuid) // don't need to do this for QUuid since it's already a meta type
ScriptValue quuidToScriptValue(ScriptEngine* engine, const QUuid& uuid);
void quuidFromScriptValue(const ScriptValue& object, QUuid& uuid);
bool quuidFromScriptValue(const ScriptValue& object, QUuid& uuid);
//Q_DECLARE_METATYPE(QSizeF) // Don't need to to this becase it's arleady a meta type
class QSizeF;
ScriptValue qSizeFToScriptValue(ScriptEngine* engine, const QSizeF& qSizeF);
void qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF);
bool qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF);
class AnimationDetails;
ScriptValue animationDetailsToScriptValue(ScriptEngine* engine, const AnimationDetails& event);
void animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& event);
bool animationDetailsFromScriptValue(const ScriptValue& object, AnimationDetails& event);
class MeshProxy;
ScriptValue meshToScriptValue(ScriptEngine* engine, MeshProxy* const& in);
void meshFromScriptValue(const ScriptValue& value, MeshProxy*& out);
bool meshFromScriptValue(const ScriptValue& value, MeshProxy*& out);
class MeshProxyList;
ScriptValue meshesToScriptValue(ScriptEngine* engine, const MeshProxyList& in);
void meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out);
bool meshesFromScriptValue(const ScriptValue& value, MeshProxyList& out);
class MeshFace;
ScriptValue meshFaceToScriptValue(ScriptEngine* engine, const MeshFace& meshFace);
void meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult);
bool meshFaceFromScriptValue(const ScriptValue& object, MeshFace& meshFaceResult);
ScriptValue qVectorMeshFaceToScriptValue(ScriptEngine* engine, const QVector<MeshFace>& vector);
void qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector<MeshFace>& result);
bool qVectorMeshFaceFromScriptValue(const ScriptValue& array, QVector<MeshFace>& result);
enum class StencilMaskMode;
ScriptValue stencilMaskModeToScriptValue(ScriptEngine* engine, const StencilMaskMode& stencilMode);
void stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode);
bool stencilMaskModeFromScriptValue(const ScriptValue& object, StencilMaskMode& stencilMode);
class MiniPromise;
void promiseFromScriptValue(const ScriptValue& object, std::shared_ptr<MiniPromise>& promise);
bool promiseFromScriptValue(const ScriptValue& object, std::shared_ptr<MiniPromise>& promise);
ScriptValue promiseToScriptValue(ScriptEngine* engine, const std::shared_ptr<MiniPromise>& promise);
class EntityItemID;
ScriptValue EntityItemIDtoScriptValue(ScriptEngine* engine, const EntityItemID& properties);
void EntityItemIDfromScriptValue(const ScriptValue& object, EntityItemID& properties);
bool EntityItemIDfromScriptValue(const ScriptValue& object, EntityItemID& properties);
QVector<EntityItemID> qVectorEntityItemIDFromScriptValue(const ScriptValue& array);
#endif // #define hifi_ScriptValueUtils_h

View file

@ -44,6 +44,7 @@ ScriptValue SpatialEvent::toScriptValue(ScriptEngine* engine, const SpatialEvent
return obj;
}
void SpatialEvent::fromScriptValue(const ScriptValue& object,SpatialEvent& event) {
bool SpatialEvent::fromScriptValue(const ScriptValue& object, SpatialEvent& event) {
// nothing for now...
return false;
}

View file

@ -29,7 +29,7 @@ public:
SpatialEvent(const SpatialEvent& other);
static ScriptValue toScriptValue(ScriptEngine* engine, const SpatialEvent& event);
static void fromScriptValue(const ScriptValue& object, SpatialEvent& event);
static bool fromScriptValue(const ScriptValue& object, SpatialEvent& event);
glm::vec3 locTranslation;
glm::quat locRotation;

View file

@ -245,6 +245,7 @@ ScriptValue TouchEvent::toScriptValue(ScriptEngine* engine, const TouchEvent& ev
return obj;
}
void TouchEvent::fromScriptValue(const ScriptValue& object, TouchEvent& event) {
bool TouchEvent::fromScriptValue(const ScriptValue& object, TouchEvent& event) {
// nothing for now...
return false;
}

View file

@ -32,7 +32,7 @@ public:
TouchEvent(const QTouchEvent& event, const TouchEvent& other);
static ScriptValue toScriptValue(ScriptEngine* engine, const TouchEvent& event);
static void fromScriptValue(const ScriptValue& object, TouchEvent& event);
static bool fromScriptValue(const ScriptValue& object, TouchEvent& event);
float x;
float y;

View file

@ -208,22 +208,25 @@ ScriptValue qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProt
return engine->newValue(closeCode);
}
void qWSCloseCodeFromScriptValue(const ScriptValue &object, QWebSocketProtocol::CloseCode &closeCode) {
bool qWSCloseCodeFromScriptValue(const ScriptValue &object, QWebSocketProtocol::CloseCode &closeCode) {
closeCode = (QWebSocketProtocol::CloseCode)object.toUInt16();
return true;
}
ScriptValue webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in) {
return engine->newQObject(in, ScriptEngine::ScriptOwnership);
}
void webSocketFromScriptValue(const ScriptValue &object, WebSocketClass* &out) {
bool webSocketFromScriptValue(const ScriptValue &object, WebSocketClass* &out) {
out = qobject_cast<WebSocketClass*>(object.toQObject());
return true;
}
ScriptValue wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState) {
return engine->newValue(readyState);
}
void wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState) {
bool wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState) {
readyState = (WebSocketClass::ReadyState)object.toUInt16();
return true;
}

View file

@ -253,13 +253,13 @@ Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode);
Q_DECLARE_METATYPE(WebSocketClass::ReadyState);
ScriptValue qWSCloseCodeToScriptValue(ScriptEngine* engine, const QWebSocketProtocol::CloseCode& closeCode);
void qWSCloseCodeFromScriptValue(const ScriptValue& object, QWebSocketProtocol::CloseCode& closeCode);
bool qWSCloseCodeFromScriptValue(const ScriptValue& object, QWebSocketProtocol::CloseCode& closeCode);
ScriptValue webSocketToScriptValue(ScriptEngine* engine, WebSocketClass* const &in);
void webSocketFromScriptValue(const ScriptValue &object, WebSocketClass* &out);
bool webSocketFromScriptValue(const ScriptValue& object, WebSocketClass*& out);
ScriptValue wscReadyStateToScriptValue(ScriptEngine* engine, const WebSocketClass::ReadyState& readyState);
void wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState);
bool wscReadyStateFromScriptValue(const ScriptValue& object, WebSocketClass::ReadyState& readyState);
#endif // hifi_WebSocketClass_h

View file

@ -96,6 +96,7 @@ ScriptValue WheelEvent::toScriptValue(ScriptEngine* engine, const WheelEvent& ev
return obj;
}
void WheelEvent::fromScriptValue(const ScriptValue& object, WheelEvent& event) {
bool WheelEvent::fromScriptValue(const ScriptValue& object, WheelEvent& event) {
// nothing for now...
return false;
}

View file

@ -29,7 +29,7 @@ public:
WheelEvent(const QWheelEvent& event);
static ScriptValue toScriptValue(ScriptEngine* engine, const WheelEvent& event);
static void fromScriptValue(const ScriptValue& object, WheelEvent& event);
static bool fromScriptValue(const ScriptValue& object, WheelEvent& event);
int x;
int y;

View file

@ -87,7 +87,8 @@ QScriptValue ArrayBufferClass::newInstance(qint32 size) {
}
QScriptValue ArrayBufferClass::newInstance(const QByteArray& ba) {
QScriptValue data = engine()->newVariant(QVariant::fromValue(ba));
QScriptEngine* eng = engine();
QScriptValue data = eng->newVariant(QVariant::fromValue(ba));
return engine()->newObject(this, data);
}

View file

@ -49,17 +49,13 @@
#include "../ScriptValue.h"
#include "ScriptContextQtWrapper.h"
#include "ScriptObjectQtProxy.h"
#include "ScriptProgramQtWrapper.h"
#include "ScriptValueQtWrapper.h"
#include "ScriptContextQtAgent.h"
static const int MAX_DEBUG_VALUE_LENGTH { 80 };
static const QScriptEngine::QObjectWrapOptions DEFAULT_QOBJECT_WRAP_OPTIONS =
QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects;
Q_DECLARE_METATYPE(ScriptValue);
Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature)
int qfunctionSignatureMetaID = qRegisterMetaType<QScriptEngine::FunctionSignature>();
@ -311,21 +307,12 @@ void ScriptEngineQtScript::_debugDump(const QString& header, const QScriptValue&
}
#endif
static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValue& src) {
return ScriptValueQtWrapper::fullUnwrap(static_cast<ScriptEngineQtScript*>(engine), src);
}
static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValue& dest) {
ScriptEngineQtScript* engine = static_cast<ScriptEngineQtScript*>(src.engine());
dest = ScriptValue(new ScriptValueQtWrapper(engine, src));
}
ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) :
QScriptEngine(),
_scriptManager(scriptManager),
_arrayBufferClass(new ArrayBufferClass(this))
{
qScriptRegisterMetaType(this, ScriptValueToQScriptValue, ScriptValueFromQScriptValue);
registerSystemTypes();
if (_scriptManager) {
connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {
@ -343,10 +330,10 @@ ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) :
}
QScriptValue null = QScriptEngine::nullValue();
_nullValue = ScriptValue(new ScriptValueQtWrapper(const_cast<ScriptEngineQtScript*>(this), std::move(null)));
_nullValue = ScriptValue(new ScriptValueQtWrapper(this, std::move(null)));
QScriptValue undefined = QScriptEngine::undefinedValue();
_undefinedValue = ScriptValue(new ScriptValueQtWrapper(const_cast<ScriptEngineQtScript*>(this), std::move(undefined)));
_undefinedValue = ScriptValue(new ScriptValueQtWrapper(this, std::move(undefined)));
QScriptEngine::setProcessEventsInterval(MSECS_PER_SECOND);
@ -417,7 +404,7 @@ void ScriptEngineQtScript::registerGlobalObject(const QString& name, QObject* ob
if (!QScriptEngine::globalObject().property(name).isValid()) {
if (object) {
QScriptValue value = QScriptEngine::newQObject(object, QScriptEngine::QtOwnership, DEFAULT_QOBJECT_WRAP_OPTIONS);
QScriptValue value = ScriptObjectQtProxy::newQObject(this, object, ScriptEngine::QtOwnership);
QScriptEngine::globalObject().setProperty(name, value);
} else {
QScriptEngine::globalObject().setProperty(name, QScriptValue());
@ -747,7 +734,7 @@ void ScriptEngineQtScript::updateMemoryCost(const qint64& deltaSize) {
ScriptValue ScriptEngineQtScript::globalObject() const {
QScriptValue global = QScriptEngine::globalObject(); // can't cache the value as it may change
return ScriptValue(new ScriptValueQtWrapper(const_cast < ScriptEngineQtScript*>(this), std::move(global)));
return ScriptValue(new ScriptValueQtWrapper(const_cast<ScriptEngineQtScript*>(this), std::move(global)));
}
ScriptManager* ScriptEngineQtScript::manager() const {
@ -783,8 +770,7 @@ ScriptProgramPointer ScriptEngineQtScript::newProgram(const QString& sourceCode,
ScriptValue ScriptEngineQtScript::newQObject(QObject* object,
ScriptEngine::ValueOwnership ownership,
const ScriptEngine::QObjectWrapOptions& options) {
QScriptValue result = QScriptEngine::newQObject(object, static_cast<QScriptEngine::ValueOwnership>(ownership),
(QScriptEngine::QObjectWrapOptions)((int)options | DEFAULT_QOBJECT_WRAP_OPTIONS));
QScriptValue result = ScriptObjectQtProxy::newQObject(this, object, ownership, options);
return ScriptValue(new ScriptValueQtWrapper(this, std::move(result)));
}
@ -824,7 +810,7 @@ ScriptValue ScriptEngineQtScript::newValue(const char* value) {
}
ScriptValue ScriptEngineQtScript::newVariant(const QVariant& value) {
QScriptValue result = QScriptEngine::newVariant(value);
QScriptValue result = castVariantToValue(value);
return ScriptValue(new ScriptValueQtWrapper(this, std::move(result)));
}
@ -832,13 +818,6 @@ ScriptValue ScriptEngineQtScript::nullValue() {
return _nullValue;
}
void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValue& prototype){
ScriptValueQtWrapper* unwrappedPrototype = ScriptValueQtWrapper::unwrap(prototype);
if (unwrappedPrototype) {
QScriptEngine::setDefaultPrototype(metaTypeId, unwrappedPrototype->toQtValue());
}
}
ScriptValue ScriptEngineQtScript::undefinedValue() {
return _undefinedValue;
}
@ -928,112 +907,26 @@ bool ScriptEngineQtScript::raiseException(const ScriptValue& exception) {
}
ScriptValue ScriptEngineQtScript::create(int type, const void* ptr) {
QScriptValue result = qScriptValueFromValue_helper(this, type, ptr);
return ScriptValue(new ScriptValueQtWrapper(const_cast<ScriptEngineQtScript*>(this), std::move(result)));
QVariant variant(type, ptr);
QScriptValue scriptValue = castVariantToValue(variant);
return ScriptValue(new ScriptValueQtWrapper(this, std::move(scriptValue)));
}
bool ScriptEngineQtScript::convert(const ScriptValue& value, int type, void* ptr) {
QVariant ScriptEngineQtScript::convert(const ScriptValue& value, int type) {
ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value);
if (unwrapped == nullptr) {
return false;
return QVariant();
}
return qscriptvalue_cast_helper(unwrapped->toQtValue(), type, ptr);
}
template <int i>
class CustomTypeInstance {
public:
static ScriptEngine::MarshalFunction marshalFunc;
static ScriptEngine::DemarshalFunction demarshalFunc;
static QScriptValue internalMarshalFunc(QScriptEngine* engine, const void* src) {
ScriptEngineQtScript* unwrappedEngine = static_cast<ScriptEngineQtScript*>(engine);
ScriptValue dest = marshalFunc(unwrappedEngine, src);
return ScriptValueQtWrapper::fullUnwrap(unwrappedEngine, dest);
}
static void internalDemarshalFunc(const QScriptValue& src, void* dest) {
ScriptEngineQtScript* unwrappedEngine = static_cast<ScriptEngineQtScript*>(src.engine());
ScriptValue wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src));
demarshalFunc(wrappedSrc, dest);
}
};
template <int i>
ScriptEngine::MarshalFunction CustomTypeInstance<i>::marshalFunc;
template <int i>
ScriptEngine::DemarshalFunction CustomTypeInstance<i>::demarshalFunc;
// I would *LOVE* it if there was a different way to do this, jeez!
// Qt requires two functions that have no parameters that give any context,
// one of the must return a QScriptValue (so we can't void* them into generics and stick them in the templates).
// This *has* to be done via templates but the whole point of this is to avoid leaking types into the rest of
// the system that would require anyone other than us to have a dependency on QtScript
#define CUSTOM_TYPE_ENTRY(idx) \
case idx: \
CustomTypeInstance<idx>::marshalFunc = marshalFunc; \
CustomTypeInstance<idx>::demarshalFunc = demarshalFunc; \
internalMarshalFunc = CustomTypeInstance<idx>::internalMarshalFunc; \
internalDemarshalFunc = CustomTypeInstance<idx>::internalDemarshalFunc; \
break;
#define CUSTOM_TYPE_ENTRY_10(idx) \
CUSTOM_TYPE_ENTRY((idx * 10)); \
CUSTOM_TYPE_ENTRY((idx * 10) + 1); \
CUSTOM_TYPE_ENTRY((idx * 10) + 2); \
CUSTOM_TYPE_ENTRY((idx * 10) + 3); \
CUSTOM_TYPE_ENTRY((idx * 10) + 4); \
CUSTOM_TYPE_ENTRY((idx * 10) + 5); \
CUSTOM_TYPE_ENTRY((idx * 10) + 6); \
CUSTOM_TYPE_ENTRY((idx * 10) + 7); \
CUSTOM_TYPE_ENTRY((idx * 10) + 8); \
CUSTOM_TYPE_ENTRY((idx * 10) + 9);
void ScriptEngineQtScript::registerCustomType(int type,
ScriptEngine::MarshalFunction marshalFunc,
ScriptEngine::DemarshalFunction demarshalFunc,
const ScriptValue& prototype)
{
QScriptValue unwrapped = ScriptValueQtWrapper::fullUnwrap(this, prototype);
QScriptEngine::MarshalFunction internalMarshalFunc;
QScriptEngine::DemarshalFunction internalDemarshalFunc;
if (_nextCustomType >= 300) { // have we ran out of translators?
Q_ASSERT(false);
return;
}
switch (_nextCustomType++) {
CUSTOM_TYPE_ENTRY_10(0);
CUSTOM_TYPE_ENTRY_10(1);
CUSTOM_TYPE_ENTRY_10(2);
CUSTOM_TYPE_ENTRY_10(3);
CUSTOM_TYPE_ENTRY_10(4);
CUSTOM_TYPE_ENTRY_10(5);
CUSTOM_TYPE_ENTRY_10(6);
CUSTOM_TYPE_ENTRY_10(7);
CUSTOM_TYPE_ENTRY_10(8);
CUSTOM_TYPE_ENTRY_10(9);
CUSTOM_TYPE_ENTRY_10(10);
CUSTOM_TYPE_ENTRY_10(11);
CUSTOM_TYPE_ENTRY_10(12);
CUSTOM_TYPE_ENTRY_10(13);
CUSTOM_TYPE_ENTRY_10(14);
CUSTOM_TYPE_ENTRY_10(15);
CUSTOM_TYPE_ENTRY_10(16);
CUSTOM_TYPE_ENTRY_10(17);
CUSTOM_TYPE_ENTRY_10(18);
CUSTOM_TYPE_ENTRY_10(19);
CUSTOM_TYPE_ENTRY_10(20);
CUSTOM_TYPE_ENTRY_10(21);
CUSTOM_TYPE_ENTRY_10(22);
CUSTOM_TYPE_ENTRY_10(23);
CUSTOM_TYPE_ENTRY_10(24);
CUSTOM_TYPE_ENTRY_10(25);
CUSTOM_TYPE_ENTRY_10(26);
CUSTOM_TYPE_ENTRY_10(27);
CUSTOM_TYPE_ENTRY_10(28);
CUSTOM_TYPE_ENTRY_10(29);
CUSTOM_TYPE_ENTRY_10(30);
}
qScriptRegisterMetaType_helper(this, type, internalMarshalFunc, internalDemarshalFunc, unwrapped);
QVariant var;
if (!castValueToVariant(unwrapped->toQtValue(), var, type)) {
return QVariant();
}
int destType = var.userType();
if (destType != type) {
var.convert(type); // if conversion fails then var is set to QVariant()
}
return var;
}

View file

@ -19,7 +19,9 @@
#include <memory>
#include <QtCore/QByteArray>
#include <QtCore/QHash>
#include <QtCore/QMetaEnum>
#include <QtCore/QMutex>
#include <QtCore/QObject>
#include <QtCore/QPointer>
#include <QtCore/QString>
@ -148,10 +150,11 @@ public: // public non-interface methods for other QtScript-specific classes to u
public: // not for public use, but I don't like how Qt strings this along with private friend functions
virtual ScriptValue create(int type, const void* ptr) override;
virtual bool convert(const ScriptValue& value, int type, void* ptr) override;
virtual QVariant convert(const ScriptValue& value, int type) override;
virtual void registerCustomType(int type, ScriptEngine::MarshalFunction marshalFunc,
ScriptEngine::DemarshalFunction demarshalFunc,
const ScriptValue& prototype) override;
ScriptEngine::DemarshalFunction demarshalFunc) override;
bool castValueToVariant(const QScriptValue& val, QVariant& dest, int destType);
QScriptValue castVariantToValue(const QVariant& val);
protected:
// like `newFunction`, but allows mapping inline C++ lambdas with captures as callable QScriptValues
@ -162,9 +165,21 @@ protected:
const QScriptValue& data = QScriptValue(),
const QScriptEngine::ValueOwnership& ownership = QScriptEngine::AutoOwnership);
void registerSystemTypes();
protected:
struct CustomMarshal {
ScriptEngine::MarshalFunction marshalFunc;
ScriptEngine::DemarshalFunction demarshalFunc;
};
using CustomMarshalMap = QHash<int, CustomMarshal>;
using CustomPrototypeMap = QHash<int, QScriptValue>;
QPointer<ScriptManager> _scriptManager;
mutable QMutex _customTypeProtect;
CustomMarshalMap _customTypes;
CustomPrototypeMap _customPrototypes;
int _nextCustomType = 0;
ScriptValue _nullValue;
ScriptValue _undefinedValue;

View file

@ -0,0 +1,538 @@
//
// ScriptEngineQtScript_cast.cpp
// libraries/script-engine/src/qtscript
//
// Created by Heather Anderson 12/9/2021
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ScriptEngineQtScript.h"
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonValue>
#include <QtScript/QScriptEngine>
#include "../ScriptValueIterator.h"
#include "ScriptObjectQtProxy.h"
#include "ScriptValueQtWrapper.h"
template <int i>
class CustomTypeInstance {
public:
static ScriptEngine::MarshalFunction marshalFunc;
static ScriptEngine::DemarshalFunction demarshalFunc;
static QScriptValue internalMarshalFunc(QScriptEngine* engine, const void* src) {
ScriptEngineQtScript* unwrappedEngine = static_cast<ScriptEngineQtScript*>(engine);
ScriptValue dest = marshalFunc(unwrappedEngine, src);
return ScriptValueQtWrapper::fullUnwrap(unwrappedEngine, dest);
}
static void internalDemarshalFunc(const QScriptValue& src, void* dest) {
ScriptEngineQtScript* unwrappedEngine = static_cast<ScriptEngineQtScript*>(src.engine());
ScriptValue wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src));
demarshalFunc(wrappedSrc, dest);
}
};
template <int i>
ScriptEngine::MarshalFunction CustomTypeInstance<i>::marshalFunc;
template <int i>
ScriptEngine::DemarshalFunction CustomTypeInstance<i>::demarshalFunc;
// I would *LOVE* it if there was a different way to do this, jeez!
// Qt requires two functions that have no parameters that give any context,
// one of the must return a QScriptValue (so we can't void* them into generics and stick them in the templates).
// This *has* to be done via templates but the whole point of this is to avoid leaking types into the rest of
// the system that would require anyone other than us to have a dependency on QtScript
#define CUSTOM_TYPE_ENTRY(idx) \
case idx: \
CustomTypeInstance<idx>::marshalFunc = marshalFunc; \
CustomTypeInstance<idx>::demarshalFunc = demarshalFunc; \
internalMarshalFunc = CustomTypeInstance<idx>::internalMarshalFunc; \
internalDemarshalFunc = CustomTypeInstance<idx>::internalDemarshalFunc; \
break;
#define CUSTOM_TYPE_ENTRY_10(idx) \
CUSTOM_TYPE_ENTRY((idx * 10)); \
CUSTOM_TYPE_ENTRY((idx * 10) + 1); \
CUSTOM_TYPE_ENTRY((idx * 10) + 2); \
CUSTOM_TYPE_ENTRY((idx * 10) + 3); \
CUSTOM_TYPE_ENTRY((idx * 10) + 4); \
CUSTOM_TYPE_ENTRY((idx * 10) + 5); \
CUSTOM_TYPE_ENTRY((idx * 10) + 6); \
CUSTOM_TYPE_ENTRY((idx * 10) + 7); \
CUSTOM_TYPE_ENTRY((idx * 10) + 8); \
CUSTOM_TYPE_ENTRY((idx * 10) + 9);
void ScriptEngineQtScript::setDefaultPrototype(int metaTypeId, const ScriptValue& prototype) {
ScriptValueQtWrapper* unwrappedPrototype = ScriptValueQtWrapper::unwrap(prototype);
if (unwrappedPrototype) {
const QScriptValue& scriptPrototype = unwrappedPrototype->toQtValue();
QScriptEngine::setDefaultPrototype(metaTypeId, scriptPrototype);
QMutexLocker guard(&_customTypeProtect);
_customPrototypes.insert(metaTypeId, scriptPrototype);
}
}
void ScriptEngineQtScript::registerCustomType(int type,
ScriptEngine::MarshalFunction marshalFunc,
ScriptEngine::DemarshalFunction demarshalFunc)
{
QScriptEngine::MarshalFunction internalMarshalFunc;
QScriptEngine::DemarshalFunction internalDemarshalFunc;
{
QMutexLocker guard(&_customTypeProtect);
// storing it in a map for our own benefit
CustomMarshal& customType = _customTypes.insert(type, CustomMarshal()).value();
customType.demarshalFunc = demarshalFunc;
customType.marshalFunc = marshalFunc;
// creating a conversion for QtScript's benefit
if (_nextCustomType >= 300) { // have we ran out of translators?
Q_ASSERT(false);
return;
}
switch (_nextCustomType++) {
CUSTOM_TYPE_ENTRY_10(0);
CUSTOM_TYPE_ENTRY_10(1);
CUSTOM_TYPE_ENTRY_10(2);
CUSTOM_TYPE_ENTRY_10(3);
CUSTOM_TYPE_ENTRY_10(4);
CUSTOM_TYPE_ENTRY_10(5);
CUSTOM_TYPE_ENTRY_10(6);
CUSTOM_TYPE_ENTRY_10(7);
CUSTOM_TYPE_ENTRY_10(8);
CUSTOM_TYPE_ENTRY_10(9);
CUSTOM_TYPE_ENTRY_10(10);
CUSTOM_TYPE_ENTRY_10(11);
CUSTOM_TYPE_ENTRY_10(12);
CUSTOM_TYPE_ENTRY_10(13);
CUSTOM_TYPE_ENTRY_10(14);
CUSTOM_TYPE_ENTRY_10(15);
CUSTOM_TYPE_ENTRY_10(16);
CUSTOM_TYPE_ENTRY_10(17);
CUSTOM_TYPE_ENTRY_10(18);
CUSTOM_TYPE_ENTRY_10(19);
CUSTOM_TYPE_ENTRY_10(20);
CUSTOM_TYPE_ENTRY_10(21);
CUSTOM_TYPE_ENTRY_10(22);
CUSTOM_TYPE_ENTRY_10(23);
CUSTOM_TYPE_ENTRY_10(24);
CUSTOM_TYPE_ENTRY_10(25);
CUSTOM_TYPE_ENTRY_10(26);
CUSTOM_TYPE_ENTRY_10(27);
CUSTOM_TYPE_ENTRY_10(28);
CUSTOM_TYPE_ENTRY_10(29);
CUSTOM_TYPE_ENTRY_10(30);
}
}
qScriptRegisterMetaType_helper(this, type, internalMarshalFunc, internalDemarshalFunc, QScriptValue());
}
Q_DECLARE_METATYPE(ScriptValue);
static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValue& src) {
return ScriptValueQtWrapper::fullUnwrap(static_cast<ScriptEngineQtScript*>(engine), src);
}
static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValue& dest) {
ScriptEngineQtScript* engine = static_cast<ScriptEngineQtScript*>(src.engine());
dest = ScriptValue(new ScriptValueQtWrapper(engine, src));
}
static ScriptValue StringListToScriptValue(ScriptEngine* engine, const void* pSrc) {
const QStringList& src = *reinterpret_cast<const QStringList*>(pSrc);
int len = src.length();
ScriptValue dest = engine->newArray(len);
for (int idx = 0; idx < len; ++idx) {
dest.setProperty(idx, engine->newValue(src.at(idx)));
}
return dest;
}
static bool StringListFromScriptValue(const ScriptValue& src, void* pDest) {
if(!src.isArray()) return false;
QStringList& dest = *reinterpret_cast<QStringList*>(pDest);
int len = src.property("length").toInteger();
dest.clear();
for (int idx = 0; idx < len; ++idx) {
dest.append(src.property(idx).toString());
}
return true;
}
static ScriptValue VariantListToScriptValue(ScriptEngine* engine, const void* pSrc) {
const QVariantList& src = *reinterpret_cast<const QVariantList*>(pSrc);
int len = src.length();
ScriptValue dest = engine->newArray(len);
for (int idx = 0; idx < len; ++idx) {
dest.setProperty(idx, engine->newVariant(src.at(idx)));
}
return dest;
}
static bool VariantListFromScriptValue(const ScriptValue& src, void* pDest) {
if(!src.isArray()) return false;
QVariantList& dest = *reinterpret_cast<QVariantList*>(pDest);
int len = src.property("length").toInteger();
dest.clear();
for (int idx = 0; idx < len; ++idx) {
dest.append(src.property(idx).toVariant());
}
return true;
}
static ScriptValue VariantMapToScriptValue(ScriptEngine* engine, const void* pSrc) {
const QVariantMap& src = *reinterpret_cast<const QVariantMap*>(pSrc);
ScriptValue dest = engine->newObject();
for (QVariantMap::const_iterator iter = src.cbegin(); iter != src.cend(); ++iter) {
dest.setProperty(iter.key(), engine->newVariant(iter.value()));
}
return dest;
}
static bool VariantMapFromScriptValue(const ScriptValue& src, void* pDest) {
QVariantMap& dest = *reinterpret_cast<QVariantMap*>(pDest);
dest.clear();
ScriptValueIteratorPointer iter = src.newIterator();
while (iter->hasNext()) {
iter->next();
dest.insert(iter->name(), iter->value().toVariant());
}
return true;
}
static ScriptValue VariantHashToScriptValue(ScriptEngine* engine, const void* pSrc) {
const QVariantHash& src = *reinterpret_cast<const QVariantHash*>(pSrc);
ScriptValue dest = engine->newObject();
for (QVariantHash::const_iterator iter = src.cbegin(); iter != src.cend(); ++iter) {
dest.setProperty(iter.key(), engine->newVariant(iter.value()));
}
return dest;
}
static bool VariantHashFromScriptValue(const ScriptValue& src, void* pDest) {
QVariantHash& dest = *reinterpret_cast<QVariantHash*>(pDest);
dest.clear();
ScriptValueIteratorPointer iter = src.newIterator();
while (iter->hasNext()) {
iter->next();
dest.insert(iter->name(), iter->value().toVariant());
}
return true;
}
static ScriptValue JsonValueToScriptValue(ScriptEngine* engine, const void* pSrc) {
const QJsonValue& src = *reinterpret_cast<const QJsonValue*>(pSrc);
return engine->newVariant(src.toVariant());
}
static bool JsonValueFromScriptValue(const ScriptValue& src, void* pDest) {
QJsonValue& dest = *reinterpret_cast<QJsonValue*>(pDest);
dest = QJsonValue::fromVariant(src.toVariant());
return true;
}
static ScriptValue JsonObjectToScriptValue(ScriptEngine* engine, const void* pSrc) {
const QJsonObject& src = *reinterpret_cast<const QJsonObject*>(pSrc);
QVariantMap map = src.toVariantMap();
ScriptValue dest = engine->newObject();
for (QVariantMap::const_iterator iter = map.cbegin(); iter != map.cend(); ++iter) {
dest.setProperty(iter.key(), engine->newVariant(iter.value()));
}
return dest;
}
static bool JsonObjectFromScriptValue(const ScriptValue& src, void* pDest) {
QJsonObject& dest = *reinterpret_cast<QJsonObject*>(pDest);
QVariantMap map;
ScriptValueIteratorPointer iter = src.newIterator();
while (iter->hasNext()) {
iter->next();
map.insert(iter->name(), iter->value().toVariant());
}
dest = QJsonObject::fromVariantMap(map);
return true;
}
static ScriptValue JsonArrayToScriptValue(ScriptEngine* engine, const void* pSrc) {
const QJsonArray& src = *reinterpret_cast<const QJsonArray*>(pSrc);
QVariantList list = src.toVariantList();
int len = list.length();
ScriptValue dest = engine->newArray(len);
for (int idx = 0; idx < len; ++idx) {
dest.setProperty(idx, engine->newVariant(list.at(idx)));
}
return dest;
}
static bool JsonArrayFromScriptValue(const ScriptValue& src, void* pDest) {
if(!src.isArray()) return false;
QJsonArray& dest = *reinterpret_cast<QJsonArray*>(pDest);
QVariantList list;
int len = src.property("length").toInteger();
for (int idx = 0; idx < len; ++idx) {
list.append(src.property(idx).toVariant());
}
dest = QJsonArray::fromVariantList(list);
return true;
}
// QMetaType::QJsonArray
void ScriptEngineQtScript::registerSystemTypes() {
qScriptRegisterMetaType(this, ScriptValueToQScriptValue, ScriptValueFromQScriptValue);
QMutexLocker guard(&_customTypeProtect);
{
CustomMarshal& customType = _customTypes.insert(QMetaType::QStringList, CustomMarshal()).value();
customType.demarshalFunc = StringListFromScriptValue;
customType.marshalFunc = StringListToScriptValue;
}
{
CustomMarshal& customType = _customTypes.insert(QMetaType::QVariantList, CustomMarshal()).value();
customType.demarshalFunc = VariantListFromScriptValue;
customType.marshalFunc = VariantListToScriptValue;
}
{
CustomMarshal& customType = _customTypes.insert(QMetaType::QVariantMap, CustomMarshal()).value();
customType.demarshalFunc = VariantMapFromScriptValue;
customType.marshalFunc = VariantMapToScriptValue;
}
{
CustomMarshal& customType = _customTypes.insert(QMetaType::QVariantHash, CustomMarshal()).value();
customType.demarshalFunc = VariantHashFromScriptValue;
customType.marshalFunc = VariantHashToScriptValue;
}
{
CustomMarshal& customType = _customTypes.insert(QMetaType::QJsonValue, CustomMarshal()).value();
customType.demarshalFunc = JsonValueFromScriptValue;
customType.marshalFunc = JsonValueToScriptValue;
}
{
CustomMarshal& customType = _customTypes.insert(QMetaType::QJsonObject, CustomMarshal()).value();
customType.demarshalFunc = JsonObjectFromScriptValue;
customType.marshalFunc = JsonObjectToScriptValue;
}
{
CustomMarshal& customType = _customTypes.insert(QMetaType::QJsonArray, CustomMarshal()).value();
customType.demarshalFunc = JsonArrayFromScriptValue;
customType.marshalFunc = JsonArrayToScriptValue;
}
}
bool ScriptEngineQtScript::castValueToVariant(const QScriptValue& val, QVariant& dest, int destType) {
// if we're not particularly interested in a specific type, try to detect if we're dealing with a registered type
if (destType == QMetaType::UnknownType) {
QObject* obj = ScriptObjectQtProxy::unwrap(val);
if (obj) {
for (const QMetaObject* metaObject = obj->metaObject(); metaObject; metaObject = metaObject->superClass()) {
QByteArray typeName = QByteArray(metaObject->className()) + "*";
int typeId = QMetaType::type(typeName.constData());
if (typeId != QMetaType::UnknownType) {
destType = typeId;
break;
}
}
}
}
if (destType == qMetaTypeId<ScriptValue>()) {
dest = QVariant::fromValue(ScriptValue(new ScriptValueQtWrapper(this, val)));
return true;
}
// do we have a registered handler for this type?
ScriptEngine::DemarshalFunction demarshalFunc = nullptr;
{
QMutexLocker guard(&_customTypeProtect);
CustomMarshalMap::const_iterator lookup = _customTypes.find(destType);
if (lookup != _customTypes.cend()) {
demarshalFunc = lookup.value().demarshalFunc;
}
}
if (demarshalFunc) {
void* destStorage = QMetaType::create(destType);
ScriptValue wrappedVal(new ScriptValueQtWrapper(this, val));
bool success = demarshalFunc(wrappedVal, destStorage);
dest = success ? QVariant(destType, destStorage) : QVariant();
QMetaType::destroy(destType, destStorage);
return success;
} else {
switch (destType) {
case QMetaType::UnknownType:
if (val.isUndefined()) {
dest = QVariant();
break;
}
if (val.isNull()) {
dest = QVariant::fromValue(nullptr);
break;
}
if (val.isBool()) {
dest = QVariant::fromValue(val.toBool());
break;
}
if (val.isString()) {
dest = QVariant::fromValue(val.toString());
break;
}
if (val.isNumber()) {
dest = QVariant::fromValue(val.toNumber());
break;
}
{
QObject* obj = ScriptObjectQtProxy::unwrap(val);
if (obj) {
dest = QVariant::fromValue(obj);
break;
}
}
{
QVariant var = ScriptVariantQtProxy::unwrap(val);
if (var.isValid()) {
dest = var;
break;
}
}
dest = val.toVariant();
break;
case QMetaType::Bool:
dest = QVariant::fromValue(val.toBool());
break;
case QMetaType::QDateTime:
case QMetaType::QDate:
Q_ASSERT(val.isDate());
dest = QVariant::fromValue(val.toDateTime());
break;
case QMetaType::UInt:
case QMetaType::ULong:
dest = QVariant::fromValue(val.toUInt32());
break;
case QMetaType::Int:
case QMetaType::Long:
case QMetaType::Short:
dest = QVariant::fromValue(val.toInt32());
break;
case QMetaType::Double:
case QMetaType::Float:
case QMetaType::ULongLong:
case QMetaType::LongLong:
dest = QVariant::fromValue(val.toNumber());
break;
case QMetaType::QString:
case QMetaType::QByteArray:
dest = QVariant::fromValue(val.toString());
break;
case QMetaType::UShort:
dest = QVariant::fromValue(val.toUInt16());
break;
case QMetaType::QObjectStar:
dest = QVariant::fromValue(ScriptObjectQtProxy::unwrap(val));
break;
default:
// check to see if this is a pointer to a QObject-derived object
if (QMetaType::typeFlags(destType) & QMetaType::PointerToQObject) {
dest = QVariant::fromValue(ScriptObjectQtProxy::unwrap(val));
break;
}
// check to see if we have a registered prototype
{
QVariant var = ScriptVariantQtProxy::unwrap(val);
if (var.isValid()) {
dest = var;
break;
}
}
// last chance, just convert it to a variant
dest = val.toVariant();
break;
}
}
return destType == QMetaType::UnknownType || dest.userType() == destType || dest.convert(destType);
}
QScriptValue ScriptEngineQtScript::castVariantToValue(const QVariant& val) {
int valTypeId = val.userType();
if (valTypeId == qMetaTypeId<ScriptValue>()) {
// this is a wrapped ScriptValue, so just unwrap it and call it good
ScriptValue innerVal = val.value<ScriptValue>();
return ScriptValueQtWrapper::fullUnwrap(this, innerVal);
}
// do we have a registered handler for this type?
ScriptEngine::MarshalFunction marshalFunc = nullptr;
{
QMutexLocker guard(&_customTypeProtect);
CustomMarshalMap::const_iterator lookup = _customTypes.find(valTypeId);
if (lookup != _customTypes.cend()) {
marshalFunc = lookup.value().marshalFunc;
}
}
if (marshalFunc) {
ScriptValue wrappedVal = marshalFunc(this, val.constData());
return ScriptValueQtWrapper::fullUnwrap(this, wrappedVal);
}
switch (valTypeId) {
case QMetaType::UnknownType:
case QMetaType::Void:
return QScriptValue(this, QScriptValue::UndefinedValue);
case QMetaType::Nullptr:
return QScriptValue(this, QScriptValue::NullValue);
case QMetaType::Bool:
return QScriptValue(this, val.toBool());
case QMetaType::Int:
case QMetaType::Long:
case QMetaType::Short:
return QScriptValue(this, val.toInt());
case QMetaType::UInt:
case QMetaType::ULong:
case QMetaType::UShort:
return QScriptValue(this, val.toUInt());
case QMetaType::Float:
case QMetaType::LongLong:
case QMetaType::ULongLong:
case QMetaType::Double:
return QScriptValue(this, val.toFloat());
case QMetaType::QString:
case QMetaType::QByteArray:
return QScriptValue(this, val.toString());
case QMetaType::QVariant:
return castVariantToValue(val.value<QVariant>());
case QMetaType::QObjectStar:
return ScriptObjectQtProxy::newQObject(this, val.value<QObject*>(), ScriptEngine::QtOwnership);
case QMetaType::QDateTime:
return static_cast<QScriptEngine*>(this)->newDate(val.value<QDateTime>());
case QMetaType::QDate:
return static_cast<QScriptEngine*>(this)->newDate(val.value<QDate>().startOfDay());
default:
// check to see if this is a pointer to a QObject-derived object
if (QMetaType::typeFlags(valTypeId) & QMetaType::PointerToQObject) {
return ScriptObjectQtProxy::newQObject(this, val.value<QObject*>(), ScriptEngine::QtOwnership);
}
// have we set a prototype'd variant?
{
QMutexLocker guard(&_customTypeProtect);
CustomPrototypeMap::const_iterator lookup = _customPrototypes.find(valTypeId);
if (lookup != _customPrototypes.cend()) {
return ScriptVariantQtProxy::newVariant(this, val, lookup.value());
}
}
// just do a generic variant
return QScriptEngine::newVariant(val);
}
}

View file

@ -0,0 +1,622 @@
//
// ScriptObjectQtProxy.cpp
// libraries/script-engine/src/qtscript
//
// Created by Heather Anderson on 12/5/21.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ScriptObjectQtProxy.h"
#include <QtCore/QList>
#include <QtCore/QSharedPointer>
#include <QtScript/QScriptContext>
#include "ScriptContextQtWrapper.h"
#include "ScriptValueQtWrapper.h"
Q_DECLARE_METATYPE(QScriptContext*)
Q_DECLARE_METATYPE(ScriptValue)
Q_DECLARE_METATYPE(QScriptValue)
Q_DECLARE_METATYPE(QSharedPointer<ScriptObjectQtProxy>)
Q_DECLARE_METATYPE(QSharedPointer<ScriptVariantQtProxy>)
// Used strictly to replace the "this" object value for property access. May expand to a full context element
// if we find it necessary to, but hopefully not needed
class ScriptPropertyContextQtWrapper final : public ScriptContext {
public: // construction
inline ScriptPropertyContextQtWrapper(const ScriptValue& object, ScriptContext* parentContext) :
_parent(parentContext), _object(object) {}
public: // ScriptContext implementation
virtual int argumentCount() const override { return _parent->argumentCount(); }
virtual ScriptValue argument(int index) const override { return _parent->argument(index); }
virtual QStringList backtrace() const override { return _parent->backtrace(); }
virtual ScriptValue callee() const override { return _parent->callee(); }
virtual ScriptEnginePointer engine() const override { return _parent->engine(); }
virtual ScriptFunctionContextPointer functionContext() const override { return _parent->functionContext(); }
virtual ScriptContextPointer parentContext() const override { return _parent->parentContext(); }
virtual ScriptValue thisObject() const override { return _object; }
virtual ScriptValue throwError(const QString& text) override { return _parent->throwError(text); }
virtual ScriptValue throwValue(const ScriptValue& value) override { return _parent->throwValue(value); }
private: // storage
ScriptContext* _parent;
const ScriptValue& _object;
};
QScriptValue ScriptObjectQtProxy::newQObject(ScriptEngineQtScript* engine, QObject* object,
ScriptEngine::ValueOwnership ownership,
const ScriptEngine::QObjectWrapOptions& options) {
bool ownsObject;
switch (ownership) {
case ScriptEngine::QtOwnership:
ownsObject = false;
break;
case ScriptEngine::ScriptOwnership:
ownsObject = true;
break;
case ScriptEngine::AutoOwnership:
ownsObject = !object->parent();
break;
}
QScriptEngine* qengine = static_cast<QScriptEngine*>(engine);
auto proxy = QSharedPointer<ScriptObjectQtProxy>::create(engine, object, ownsObject, options);
return static_cast<QScriptEngine*>(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));
}
ScriptObjectQtProxy* ScriptObjectQtProxy::unwrapProxy(const QScriptValue& val) {
QScriptClass* scriptClass = val.scriptClass();
return scriptClass ? dynamic_cast<ScriptObjectQtProxy*>(scriptClass) : nullptr;
}
QObject* ScriptObjectQtProxy::unwrap(const QScriptValue& val) {
if (val.isQObject()) {
return val.toQObject();
}
ScriptObjectQtProxy* proxy = unwrapProxy(val);
return proxy ? proxy->toQtValue() : nullptr;
}
ScriptObjectQtProxy::~ScriptObjectQtProxy() {
if (_ownsObject) {
QObject* qobject = _object;
if(qobject) qobject->deleteLater();
}
}
void ScriptObjectQtProxy::investigate() {
QObject* qobject = _object;
Q_ASSERT(qobject);
if (!qobject) return;
const QMetaObject* metaObject = qobject->metaObject();
_name = QString::fromLatin1(metaObject->className());
// discover properties
int startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassProperties ? metaObject->propertyOffset() : 0;
int num = metaObject->propertyCount();
for (int idx = startIdx; idx < num; ++idx) {
QMetaProperty prop = metaObject->property(idx);
if (!prop.isScriptable()) continue;
// always exclude child objects (at least until we decide otherwise)
int metaTypeId = prop.userType();
if (metaTypeId != QMetaType::UnknownType) {
QMetaType metaType(metaTypeId);
if (metaType.flags() & QMetaType::PointerToQObject) {
continue;
}
}
PropertyDef& propDef = _props.insert(idx, PropertyDef()).value();
propDef.name = _engine->toStringHandle(QString::fromLatin1(prop.name()));
propDef.flags = QScriptValue::Undeletable | QScriptValue::PropertyGetter | QScriptValue::PropertySetter |
QScriptValue::QObjectMember;
if (prop.isConstant()) propDef.flags |= QScriptValue::ReadOnly;
}
// discover methods
startIdx = _wrapOptions & ScriptEngine::ExcludeSuperClassMethods ? metaObject->methodCount() : 0;
num = metaObject->methodCount();
QHash<QScriptString, int> methodNames;
for (int idx = startIdx; idx < num; ++idx) {
QMetaMethod method = metaObject->method(idx);
// perhaps keep this comment? Calls (like AudioScriptingInterface::playSound) seem to expect non-public methods to be script-accessible
/* if (method.access() != QMetaMethod::Public) continue;*/
bool isSignal = false;
QByteArray szName = method.name();
switch (method.methodType()) {
case QMetaMethod::Constructor:
continue;
case QMetaMethod::Signal:
isSignal = true;
break;
case QMetaMethod::Slot:
if (_wrapOptions & ScriptEngine::ExcludeSlots) {
continue;
}
if (szName == "deleteLater") {
continue;
}
break;
}
QScriptString name = _engine->toStringHandle(QString::fromLatin1(szName));
auto nameLookup = methodNames.find(name);
if (isSignal) {
if (nameLookup == methodNames.end()) {
SignalDef& signalDef = _signals.insert(idx, SignalDef()).value();
signalDef.name = name;
signalDef.signal = method;
methodNames.insert(name, idx);
} else {
int originalMethodId = nameLookup.value();
SignalDefMap::iterator signalLookup = _signals.find(originalMethodId);
Q_ASSERT(signalLookup != _signals.end());
SignalDef& signalDef = signalLookup.value();
Q_ASSERT(signalDef.signal.parameterCount() != method.parameterCount());
if (signalDef.signal.parameterCount() < method.parameterCount()) {
signalDef.signal = method;
}
}
} else {
if (nameLookup == methodNames.end()) {
MethodDef& methodDef = _methods.insert(idx, MethodDef()).value();
methodDef.name = name;
methodDef.methods.append(method);
methodNames.insert(name, idx);
} else {
int originalMethodId = nameLookup.value();
MethodDefMap::iterator methodLookup = _methods.find(originalMethodId);
Q_ASSERT(methodLookup != _methods.end());
MethodDef& methodDef = methodLookup.value();
methodDef.methods.append(method);
}
}
}
}
QScriptClass::QueryFlags ScriptObjectQtProxy::queryProperty(const QScriptValue& object, const QScriptString& name, QueryFlags flags, uint* id) {
// check for properties
for (PropertyDefMap::const_iterator trans = _props.cbegin(); trans != _props.cend(); ++trans) {
const PropertyDef& propDef = trans.value();
if (propDef.name != name) continue;
*id = trans.key() | PROPERTY_TYPE;
return flags & (HandlesReadAccess | HandlesWriteAccess);
}
// check for methods
for (MethodDefMap::const_iterator trans = _methods.cbegin(); trans != _methods.cend(); ++trans) {
if (trans.value().name != name) continue;
*id = trans.key() | METHOD_TYPE;
return flags & (HandlesReadAccess | HandlesWriteAccess);
}
// check for signals
for (SignalDefMap::const_iterator trans = _signals.cbegin(); trans != _signals.cend(); ++trans) {
if (trans.value().name != name) continue;
*id = trans.key() | SIGNAL_TYPE;
return flags & (HandlesReadAccess | HandlesWriteAccess);
}
return QueryFlags();
}
QScriptValue::PropertyFlags ScriptObjectQtProxy::propertyFlags(const QScriptValue& object, const QScriptString& name, uint id) {
QObject* qobject = _object;
if (!qobject) {
return QScriptValue::PropertyFlags();
}
switch (id & TYPE_MASK) {
case PROPERTY_TYPE: {
PropertyDefMap::const_iterator lookup = _props.find(id & ~TYPE_MASK);
if (lookup == _props.cend()) return QScriptValue::PropertyFlags();
const PropertyDef& propDef = lookup.value();
return propDef.flags;
}
case METHOD_TYPE: {
MethodDefMap::const_iterator lookup = _methods.find(id & ~TYPE_MASK);
if (lookup == _methods.cend()) return QScriptValue::PropertyFlags();
return QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::QObjectMember;
}
case SIGNAL_TYPE: {
SignalDefMap::const_iterator lookup = _signals.find(id & ~TYPE_MASK);
if (lookup == _signals.cend()) return QScriptValue::PropertyFlags();
return QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::QObjectMember;
}
}
return QScriptValue::PropertyFlags();
}
QScriptValue ScriptObjectQtProxy::property(const QScriptValue& object, const QScriptString& name, uint id) {
QObject* qobject = _object;
if (!qobject) {
QScriptContext* currentContext = static_cast<QScriptEngine*>(_engine)->currentContext();
currentContext->throwError(QScriptContext::ReferenceError, "Referencing deleted native object");
return QScriptValue();
}
const QMetaObject* metaObject = qobject->metaObject();
switch (id & TYPE_MASK) {
case PROPERTY_TYPE: {
int propId = id & ~TYPE_MASK;
PropertyDefMap::const_iterator lookup = _props.find(propId);
if (lookup == _props.cend()) return QScriptValue();
const PropertyDef& propDef = lookup.value();
QMetaProperty prop = metaObject->property(propId);
ScriptValue scriptThis = ScriptValue(new ScriptValueQtWrapper(_engine, object));
ScriptPropertyContextQtWrapper ourContext(scriptThis, _engine->currentContext());
ScriptContextGuard guard(&ourContext);
QVariant varValue = prop.read(qobject);
return _engine->castVariantToValue(varValue);
}
case METHOD_TYPE: {
int methodId = id & ~TYPE_MASK;
MethodDefMap::const_iterator lookup = _methods.find(methodId);
if (lookup == _methods.cend()) return QScriptValue();
return static_cast<QScriptEngine*>(_engine)->newObject(
new ScriptMethodQtProxy(_engine, qobject, object, name, lookup.value().methods));
}
case SIGNAL_TYPE: {
int signalId = id & ~TYPE_MASK;
SignalDefMap::const_iterator defLookup = _signals.find(signalId);
if (defLookup == _signals.cend()) return QScriptValue();
InstanceMap::const_iterator instLookup = _signalInstances.find(signalId);
if (instLookup == _signalInstances.cend() || instLookup.value().isNull()) {
instLookup = _signalInstances.insert(signalId,
new ScriptSignalQtProxy(_engine, qobject, object, name, defLookup.value().signal));
Q_ASSERT(instLookup != _signalInstances.cend());
}
ScriptSignalQtProxy* proxy = instLookup.value();
QScriptEngine::QObjectWrapOptions options = QScriptEngine::ExcludeSuperClassContents |
QScriptEngine::ExcludeDeleteLater |
QScriptEngine::PreferExistingWrapperObject;
return static_cast<QScriptEngine*>(_engine)->newQObject(proxy, QScriptEngine::ScriptOwnership, options);
}
}
return QScriptValue();
}
void ScriptObjectQtProxy::setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) {
if (!(id & PROPERTY_TYPE)) return;
QObject* qobject = _object;
if (!qobject) {
QScriptContext* currentContext = static_cast<QScriptEngine*>(_engine)->currentContext();
currentContext->throwError(QScriptContext::ReferenceError, "Referencing deleted native object");
return;
}
int propId = id & ~TYPE_MASK;
PropertyDefMap::const_iterator lookup = _props.find(propId);
if (lookup == _props.cend()) return;
const PropertyDef& propDef = lookup.value();
if (propDef.flags & QScriptValue::ReadOnly) return;
const QMetaObject* metaObject = qobject->metaObject();
QMetaProperty prop = metaObject->property(propId);
ScriptValue scriptThis = ScriptValue(new ScriptValueQtWrapper(_engine, object));
ScriptPropertyContextQtWrapper ourContext(scriptThis, _engine->currentContext());
ScriptContextGuard guard(&ourContext);
int propTypeId = prop.userType();
QVariant varValue;
if(!_engine->castValueToVariant(value, varValue, propTypeId)) {
QByteArray propTypeName = QMetaType(propTypeId).name();
QByteArray valTypeName = value.toVariant().typeName();
QScriptContext* currentContext = static_cast<QScriptEngine*>(_engine)->currentContext();
currentContext->throwError(QScriptContext::TypeError, QString("Cannot convert %1 to %2").arg(valTypeName, propTypeName));
return;
}
prop.write(qobject, varValue);
}
ScriptVariantQtProxy::ScriptVariantQtProxy(ScriptEngineQtScript* engine, const QVariant& variant, QScriptValue scriptProto, ScriptObjectQtProxy* proto) :
QScriptClass(engine), _engine(engine), _variant(variant), _scriptProto(scriptProto), _proto(proto) {
_name = QString::fromLatin1(variant.typeName());
}
QScriptValue ScriptVariantQtProxy::newVariant(ScriptEngineQtScript* engine, const QVariant& variant, QScriptValue proto) {
QScriptEngine* qengine = static_cast<QScriptEngine*>(engine);
ScriptObjectQtProxy* protoProxy = ScriptObjectQtProxy::unwrapProxy(proto);
if (!protoProxy) {
Q_ASSERT(protoProxy);
return qengine->newVariant(variant);
}
auto proxy = QSharedPointer<ScriptVariantQtProxy>::create(engine, variant, proto, protoProxy);
return static_cast<QScriptEngine*>(engine)->newObject(proxy.get(), qengine->newVariant(QVariant::fromValue(proxy)));
}
ScriptVariantQtProxy* ScriptVariantQtProxy::unwrapProxy(const QScriptValue& val) {
QScriptClass* scriptClass = val.scriptClass();
return scriptClass ? dynamic_cast<ScriptVariantQtProxy*>(scriptClass) : nullptr;
}
QVariant ScriptVariantQtProxy::unwrap(const QScriptValue& val) {
ScriptVariantQtProxy* proxy = unwrapProxy(val);
return proxy ? proxy->toQtValue() : QVariant();
}
bool ScriptMethodQtProxy::supportsExtension(Extension extension) const {
switch (extension) {
case Callable:
return true;
default:
return false;
}
}
QVariant ScriptMethodQtProxy::extension(Extension extension, const QVariant& argument) {
if (extension != Callable) return QVariant();
QScriptContext* context = qvariant_cast<QScriptContext*>(argument);
QObject* qobject = _object;
if (!qobject) {
context->throwError(QScriptContext::ReferenceError, "Referencing deleted native object");
return QVariant();
}
int scriptNumArgs = context->argumentCount();
Q_ASSERT(scriptNumArgs < 10);
int numArgs = std::min(scriptNumArgs, 10);
const int scriptValueTypeId = qMetaTypeId<ScriptValue>();
for (auto iter = _metas.cbegin(); iter != _metas.end(); ++iter) {
const QMetaMethod& meta = *iter;
int methodNumArgs = meta.parameterCount();
if (methodNumArgs != numArgs) {
continue;
}
QList<ScriptValue> qScriptArgList;
QList<QVariant> qVarArgList;
QGenericArgument qGenArgs[10];
int arg;
bool conversionFailed = false;
for (arg = 0; arg < numArgs && !conversionFailed; ++arg) {
int methodArgTypeId = meta.parameterType(arg);
QScriptValue argVal = context->argument(arg);
if (methodArgTypeId == scriptValueTypeId) {
qScriptArgList.append(ScriptValue(new ScriptValueQtWrapper(_engine, argVal)));
qGenArgs[arg] = Q_ARG(ScriptValue, qScriptArgList.back());
} else if (methodArgTypeId == QMetaType::QVariant) {
qVarArgList.append(argVal.toVariant());
qGenArgs[arg] = Q_ARG(QVariant, qVarArgList.back());
} else {
QVariant varArgVal;
if (!_engine->castValueToVariant(argVal, varArgVal, methodArgTypeId)) {
conversionFailed = true;
break;
/*QByteArray methodTypeName = QMetaType(methodArgTypeId).name();
QByteArray argTypeName = argVal.toVariant().typeName();
context->throwError(QScriptContext::TypeError,
QString("Cannot convert %1 to %2").arg(argTypeName, methodTypeName));
return QVariant();*/
}
qVarArgList.append(varArgVal);
const QVariant& converted = qVarArgList.back();
// a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant
// A const_cast is needed because calling data() would detach the QVariant.
qGenArgs[arg] =
QGenericArgument(QMetaType::typeName(converted.userType()), const_cast<void*>(converted.constData()));
}
}
if (conversionFailed) {
continue;
}
ScriptContextQtWrapper ourContext(_engine, context);
ScriptContextGuard guard(&ourContext);
int returnTypeId = meta.returnType();
if (returnTypeId == QMetaType::Void) {
bool success = meta.invoke(qobject, Qt::DirectConnection, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3],
qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]);
if (!success) {
context->throwError("Native call failed");
}
return QVariant();
} else if (returnTypeId == scriptValueTypeId) {
ScriptValue result;
bool success = meta.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(ScriptValue, result), qGenArgs[0],
qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6],
qGenArgs[7], qGenArgs[8], qGenArgs[9]);
if (!success) {
context->throwError("Native call failed");
return QVariant();
}
QScriptValue qResult = ScriptValueQtWrapper::fullUnwrap(_engine, result);
return QVariant::fromValue(qResult);
} else {
// a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant
const char* typeName = meta.typeName();
QVariant qRetVal(returnTypeId, static_cast<void*>(NULL));
QGenericReturnArgument sRetVal(typeName, const_cast<void*>(qRetVal.constData()));
bool success =
meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3],
qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]);
if (!success) {
context->throwError("Native call failed");
return QVariant();
}
QScriptValue qResult = _engine->castVariantToValue(qRetVal);
return QVariant::fromValue(qResult);
}
}
context->throwError("Native call failed: could not locate an overload with the requested arguments");
return QVariant();
}
// Adapted from https://doc.qt.io/archives/qq/qq16-dynamicqobject.html, for connecting to a signal without a compile-time definition for it
int ScriptSignalQtProxy::qt_metacall(QMetaObject::Call call, int id, void** arguments) {
id = ScriptSignalQtProxyBase::qt_metacall(call, id, arguments);
if (id != 0 || call != QMetaObject::InvokeMetaMethod) {
return id;
}
QScriptValueList args;
int numArgs = _meta.parameterCount();
for (int arg = 0; arg < numArgs; ++arg) {
int methodArgTypeId = _meta.parameterType(arg);
QVariant argValue(methodArgTypeId, arguments[arg+1]);
args.append(_engine->castVariantToValue(argValue));
}
for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) {
Connection& conn = *iter;
conn.callback.call(conn.thisValue, args);
}
return -1;
}
int ScriptSignalQtProxy::discoverMetaCallIdx() {
const QMetaObject* ourMeta = metaObject();
return ourMeta->methodCount();
}
ScriptSignalQtProxy::ConnectionList::iterator ScriptSignalQtProxy::findConnection(QScriptValue thisObject,
QScriptValue callback) {
for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) {
Connection& conn = *iter;
if (conn.callback.strictlyEquals(callback) && conn.thisValue.strictlyEquals(thisObject)) {
return iter;
}
}
return _connections.end();
}
void ScriptSignalQtProxy::connect(QScriptValue arg0, QScriptValue arg1) {
QObject* qobject = _object;
if (!qobject) {
QScriptContext* currentContext = static_cast<QScriptEngine*>(_engine)->currentContext();
currentContext->throwError(QScriptContext::ReferenceError, "Referencing deleted native object");
return;
}
// untangle the arguments
QScriptValue callback;
QScriptValue callbackThis;
if (arg1.isFunction()) {
callbackThis = arg0;
callback = arg1;
} else {
callback = arg0;
}
if (!callback.isFunction()) {
QScriptContext* currentContext = static_cast<QScriptEngine*>(_engine)->currentContext();
currentContext->throwError(QScriptContext::TypeError, "Function expected as argument to 'connect'");
return;
}
// are we already connected?
ConnectionList::iterator lookup = findConnection(callbackThis, callback);
if (lookup != _connections.end()) {
return; // already exists
}
// add a reference to ourselves to the destination callback
QScriptValue destData = callback.data();
Q_ASSERT(!destData.isValid() || destData.isArray());
if (!destData.isArray()) {
destData = static_cast<QScriptEngine*>(_engine)->newArray();
}
{
QScriptValueList args;
args << thisObject();
destData.property("push").call(destData, args);
}
callback.setData(destData);
// add this to our internal list of connections
Connection newConn;
newConn.callback = callback;
newConn.thisValue = callbackThis;
_connections.append(newConn);
// inform Qt that we're connecting to this signal
if (!_isConnected) {
auto result = QMetaObject::connect(qobject, _meta.methodIndex(), this, _metaCallId);
Q_ASSERT(result);
_isConnected = true;
}
}
void ScriptSignalQtProxy::disconnect(QScriptValue arg0, QScriptValue arg1) {
QObject* qobject = _object;
if (!qobject) {
QScriptContext* currentContext = static_cast<QScriptEngine*>(_engine)->currentContext();
currentContext->throwError(QScriptContext::ReferenceError, "Referencing deleted native object");
return;
}
// untangle the arguments
QScriptValue callback;
QScriptValue callbackThis;
if (arg1.isFunction()) {
callbackThis = arg0;
callback = arg1;
} else {
callback = arg0;
}
if (!callback.isFunction()) {
QScriptContext* currentContext = static_cast<QScriptEngine*>(_engine)->currentContext();
currentContext->throwError(QScriptContext::TypeError, "Function expected as argument to 'disconnect'");
return;
}
// locate this connection in our list of connections
ConnectionList::iterator lookup = findConnection(callbackThis, callback);
if (lookup == _connections.end()) {
return; // not here
}
// remove it from our internal list of connections
_connections.erase(lookup);
// remove a reference to ourselves from the destination callback
QScriptValue destData = callback.data();
Q_ASSERT(destData.isArray());
if (destData.isArray()) {
QScriptValue qThis = thisObject();
int len = destData.property("length").toInteger();
bool foundIt = false;
for (int idx = 0; idx < len && !foundIt; ++idx) {
QScriptValue entry = destData.property(idx);
if (entry.strictlyEquals(qThis)) {
foundIt = true;
QScriptValueList args;
args << idx << 1;
destData.property("splice").call(destData, args);
}
}
Q_ASSERT(foundIt);
}
// inform Qt that we're no longer connected to this signal
if (_connections.empty()) {
Q_ASSERT(_isConnected);
bool result = QMetaObject::disconnect(qobject, _meta.methodIndex(), this, _metaCallId);
Q_ASSERT(result);
_isConnected = false;
}
}

View file

@ -0,0 +1,205 @@
//
// ScriptObjectQtProxy.h
// libraries/script-engine/src/qtscript
//
// Created by Heather Anderson on 12/5/21.
// Copyright 2021 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/// @addtogroup ScriptEngine
/// @{
#ifndef hifi_ScriptObjectQtProxy_h
#define hifi_ScriptObjectQtProxy_h
#include <QtCore/QHash>
#include <QtCore/QList>
#include <QtCore/QPointer>
#include <QtCore/QString>
#include <QtScript/QScriptable>
#include <QtScript/QScriptClass>
#include <QtScript/QScriptString>
#include <QtScript/QScriptValue>
#include "../ScriptEngine.h"
#include "ScriptEngineQtScript.h"
class ScriptEngineQtScript;
class ScriptSignalQtProxy;
/// [QtScript] (re-)implements the translation layer between ScriptValue and QObject. This object
/// will focus exclusively on property get/set until function calls appear to be a problem
class ScriptObjectQtProxy final : public QScriptClass {
private: // implementation
struct PropertyDef {
QScriptString name;
QScriptValue::PropertyFlags flags;
};
struct MethodDef {
QScriptString name;
QList<QMetaMethod> methods;
};
struct SignalDef {
QScriptString name;
QMetaMethod signal;
};
using PropertyDefMap = QHash<uint, PropertyDef>;
using MethodDefMap = QHash<uint, MethodDef>;
using SignalDefMap = QHash<uint, SignalDef>;
using InstanceMap = QHash<uint, QPointer<ScriptSignalQtProxy> >;
static constexpr uint PROPERTY_TYPE = 0x1000;
static constexpr uint METHOD_TYPE = 0x2000;
static constexpr uint SIGNAL_TYPE = 0x3000;
static constexpr uint TYPE_MASK = 0xF000;
public: // construction
inline ScriptObjectQtProxy(ScriptEngineQtScript* engine, QObject* object, bool ownsObject, const ScriptEngine::QObjectWrapOptions& options) :
QScriptClass(engine), _engine(engine), _object(object), _wrapOptions(options), _ownsObject(ownsObject) {
investigate();
}
virtual ~ScriptObjectQtProxy();
static QScriptValue newQObject(ScriptEngineQtScript* engine,
QObject* object,
ScriptEngine::ValueOwnership ownership = ScriptEngine::QtOwnership,
const ScriptEngine::QObjectWrapOptions& options = ScriptEngine::QObjectWrapOptions());
static ScriptObjectQtProxy* unwrapProxy(const QScriptValue& val);
static QObject* unwrap(const QScriptValue& val);
inline QObject* toQtValue() const { return _object; }
public: // QScriptClass implementation
virtual QString name() const override { return _name; }
virtual QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override;
virtual QScriptValue::PropertyFlags propertyFlags(const QScriptValue& object, const QScriptString& name, uint id) override;
virtual QueryFlags queryProperty(const QScriptValue& object, const QScriptString& name, QueryFlags flags, uint* id) override;
virtual void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override;
private: // implementation
void investigate();
private: // storage
ScriptEngineQtScript* _engine;
const ScriptEngine::QObjectWrapOptions _wrapOptions;
PropertyDefMap _props;
MethodDefMap _methods;
SignalDefMap _signals;
InstanceMap _signalInstances;
const bool _ownsObject;
QPointer<QObject> _object;
QString _name;
Q_DISABLE_COPY(ScriptObjectQtProxy)
};
/// [QtScript] (re-)implements the translation layer between ScriptValue and QVariant where a prototype is set.
/// This object depends on a ScriptObjectQtProxy to provide the prototype's behavior
class ScriptVariantQtProxy final : public QScriptClass {
public: // construction
ScriptVariantQtProxy(ScriptEngineQtScript* engine, const QVariant& variant, QScriptValue scriptProto, ScriptObjectQtProxy* proto);
static QScriptValue newVariant(ScriptEngineQtScript* engine, const QVariant& variant, QScriptValue proto);
static ScriptVariantQtProxy* unwrapProxy(const QScriptValue& val);
static QVariant unwrap(const QScriptValue& val);
inline QVariant toQtValue() const { return _variant; }
public: // QScriptClass implementation
virtual QString name() const override { return _name; }
virtual QScriptValue prototype() const override { return _scriptProto; }
virtual QScriptValue property(const QScriptValue& object, const QScriptString& name, uint id) override {
return _proto->property(object, name, id);
}
virtual QScriptValue::PropertyFlags propertyFlags(const QScriptValue& object, const QScriptString& name, uint id) override {
return _proto->propertyFlags(object, name, id);
}
virtual QueryFlags queryProperty(const QScriptValue& object, const QScriptString& name, QueryFlags flags, uint* id) override {
return _proto->queryProperty(object, name, flags, id);
}
virtual void setProperty(QScriptValue& object, const QScriptString& name, uint id, const QScriptValue& value) override {
return _proto->setProperty(object, name, id, value);
}
private: // storage
ScriptEngineQtScript* _engine;
QVariant _variant;
QScriptValue _scriptProto;
ScriptObjectQtProxy* _proto;
QString _name;
Q_DISABLE_COPY(ScriptVariantQtProxy)
};
class ScriptMethodQtProxy final : public QScriptClass {
public: // construction
inline ScriptMethodQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, QString name, const QList<QMetaMethod>& metas) :
QScriptClass(engine), _engine(engine), _object(object), _objectLifetime(lifetime), _name(name), _metas(metas) {}
public: // QScriptClass implementation
virtual QString name() const override { return _name; }
virtual bool supportsExtension(Extension extension) const override;
virtual QVariant extension(Extension extension, const QVariant& argument = QVariant()) override;
private: // storage
ScriptEngineQtScript* _engine;
QPointer<QObject> _object;
QScriptValue _objectLifetime;
const QString _name;
const QList<QMetaMethod> _metas;
Q_DISABLE_COPY(ScriptMethodQtProxy)
};
// This abstract base class serves solely to declare the Q_INVOKABLE methods for ScriptSignalQtProxy
// as we're overriding qt_metacall later for the signal callback yet still want to support
// metacalls for the connect/disconnect API
class ScriptSignalQtProxyBase : public QObject, protected QScriptable {
Q_OBJECT
public: // API
Q_INVOKABLE virtual void connect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) = 0;
Q_INVOKABLE virtual void disconnect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) = 0;
};
class ScriptSignalQtProxy final : public ScriptSignalQtProxyBase {
private: // storage
struct Connection {
QScriptValue thisValue;
QScriptValue callback;
};
using ConnectionList = QList<Connection>;
public: // construction
inline ScriptSignalQtProxy(ScriptEngineQtScript* engine, QObject* object, QScriptValue lifetime, QString name, const QMetaMethod& meta) :
_engine(engine), _object(object), _objectLifetime(lifetime), _name(name), _meta(meta), _metaCallId(discoverMetaCallIdx()) {}
private: // implementation
virtual int qt_metacall(QMetaObject::Call call, int id, void** arguments);
int discoverMetaCallIdx();
ConnectionList::iterator findConnection(QScriptValue thisObject, QScriptValue callback);
public: // API
virtual void connect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) override;
virtual void disconnect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) override;
private: // storage
ScriptEngineQtScript* _engine;
QPointer<QObject> _object;
QScriptValue _objectLifetime;
QString _name;
const QMetaMethod _meta;
const int _metaCallId;
ConnectionList _connections;
bool _isConnected{ false };
Q_DISABLE_COPY(ScriptSignalQtProxy)
};
#endif // hifi_ScriptObjectQtProxy_h
/// @}

View file

@ -28,19 +28,27 @@ ScriptValueQtWrapper* ScriptValueQtWrapper::unwrap(const ScriptValue& val) {
QScriptValue ScriptValueQtWrapper::fullUnwrap(const ScriptValue& value) const {
ScriptValueQtWrapper* unwrapped = unwrap(value);
if (unwrapped) {
return unwrapped->toQtValue();
if (unwrapped->engine().get() != _engine) {
return static_cast<QScriptEngine*>(_engine)->toScriptValue(unwrapped->toVariant());
} else {
return unwrapped->toQtValue();
}
}
QVariant varValue = value.toVariant();
return static_cast<QScriptEngine*>(_engine)->newVariant(varValue);
return _engine->castVariantToValue(varValue);
}
QScriptValue ScriptValueQtWrapper::fullUnwrap(ScriptEngineQtScript* engine, const ScriptValue& value) {
ScriptValueQtWrapper* unwrapped = unwrap(value);
if (unwrapped) {
return unwrapped->toQtValue();
if (unwrapped->engine().get() != engine) {
return static_cast<QScriptEngine*>(engine)->toScriptValue(unwrapped->toVariant());
} else {
return unwrapped->toQtValue();
}
}
QVariant varValue = value.toVariant();
return static_cast<QScriptEngine*>(engine)->newVariant(varValue);
return engine->castVariantToValue(varValue);
}
ScriptValue ScriptValueQtWrapper::call(const ScriptValue& thisObject, const ScriptValueList& args) {
@ -157,11 +165,23 @@ quint32 ScriptValueQtWrapper::toUInt32() const {
}
QVariant ScriptValueQtWrapper::toVariant() const {
return _value.toVariant();
QVariant dest;
if (_engine->castValueToVariant(_value, dest, QMetaType::UnknownType)) {
return dest;
} else {
Q_ASSERT(false);
return QVariant();
}
}
QObject* ScriptValueQtWrapper::toQObject() const {
return _value.toQObject();
QVariant dest;
if (_engine->castValueToVariant(_value, dest, QMetaType::QObjectStar)) {
return dest.value<QObject*>();
} else {
Q_ASSERT(false);
return nullptr;
}
}
bool ScriptValueQtWrapper::equals(const ScriptValue& other) const {

View file

@ -40,8 +40,9 @@ ScriptValue wrapperToScriptValue(ScriptEngine* engine, T* const &in) {
}
template <typename T>
void wrapperFromScriptValue(const ScriptValue& value, T* &out) {
bool wrapperFromScriptValue(const ScriptValue& value, T* &out) {
out = qobject_cast<T*>(value.toQObject());
return !!out;
}
#endif