Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 5 files). Show all
Unified · Split
| @@ -389,30 +389,85 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func · 388 unmodified lines | ||
| 389 | 389 | } |
| 390 | 390 | } |
| 391 | 391 | |
| 392 | +// Answer the previously registered handler for the given entityID/eventName, else an invalid QScriptValue. | |
| 393 | +QScriptValue ScriptEngine::getEntityEventHandler(const EntityItemID& entityID, const QString& eventName) { | |
| 394 | + if (!_registeredHandlers.contains(entityID)) return _illegal; | |
| 395 | + const RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID]; | |
| 396 | + if (!handlersOnEntity.contains(eventName)) return _illegal; | |
| 397 | + // FIXME: Need one more level of indirection. We need to allow multiple handlers per event, registered by different scripts. | |
| 398 | + return handlersOnEntity[eventName]; | |
| 399 | +} | |
| 400 | +void ScriptEngine::removeEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { | |
| 401 | + // FIXME | |
| 402 | +} | |
| 403 | +// FIXME: deletingEntity, changingEntityID | |
| 392 | 404 | void ScriptEngine::addEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { |
| 393 | − auto entities = DependencyManager::get<EntityScriptingInterface>(); | |
| 394 | 405 | if (!_registeredHandlers.contains(entityID)) { |
| 395 | 406 | _registeredHandlers[entityID] = RegisteredEventHandlers(); |
| 396 | 407 | } |
| 397 | 408 | _registeredHandlers[entityID][eventName] = handler; |
| 398 | − if (eventName == "collisionWithEntity") { | |
| 399 | − connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, &ScriptEngine::collisionWithEntity); | |
| 409 | + | |
| 410 | + // The rest connects the Entities signal to the handler here. | |
| 411 | + auto entities = DependencyManager::get<EntityScriptingInterface>(); | |
| 412 | + | |
| 413 | + // Given thunk that generates the arglist, evaluate that thunk only if needed, and call the handler. | |
| 414 | + auto generalHandler = [=](std::function<QScriptValueList()> argGenerator) { | |
| 415 | + QScriptValue handlerForEvent = getEntityEventHandler(entityID, eventName); | |
| 416 | + if (handlerForEvent.isValid()) { | |
| 417 | + QScriptValueList args = argGenerator(); | |
| 418 | + handlerForEvent.call(QScriptValue(), args); | |
| 419 | + } | |
| 420 | + }; | |
| 421 | + // Two common cases of event handler, differing only in argument signature. | |
| 422 | + auto singleEntityHandler = [=](const EntityItemID& entityItemID) { | |
| 423 | + generalHandler([=]() { | |
| 424 | + return QScriptValueList() << entityItemID.toScriptValue(this); | |
| 425 | + }); | |
| 426 | + }; | |
| 427 | + auto mouseHandler = [=](const EntityItemID& entityItemID, const MouseEvent& event) { | |
| 428 | + generalHandler([=]() { | |
| 429 | + return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this); | |
| 430 | + }); | |
| 431 | + }; | |
| 432 | + // This string comparison maze only happens when adding a handler, which isn't often, rather than during events. | |
| 433 | + // Nonetheless, I wish it were more DRY. Variadic signals from strings? "I know reflection. I've worked with reflection. QT is no reflection." | |
| 434 | + if (eventName == "enterEntity") { | |
| 435 | + connect(entities.data(), &EntityScriptingInterface::enterEntity, this, singleEntityHandler); | |
| 436 | + } else if (eventName == "leaveEntity") { | |
| 437 | + connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, singleEntityHandler); | |
| 438 | + | |
| 439 | + } else if (eventName == "mousePressOnEntity") { | |
| 440 | + connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, mouseHandler); | |
| 441 | + } else if (eventName == "mouseMoveOnEntity") { | |
| 442 | + connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, mouseHandler); | |
| 443 | + } else if (eventName == "mouseReleaseOnEntity") { | |
| 444 | + connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, mouseHandler); | |
| 445 | + | |
| 446 | + } else if (eventName == "clickDownOnEntity") { | |
| 447 | + connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, mouseHandler); | |
| 448 | + } else if (eventName == "holdingClickOnEntity") { | |
| 449 | + connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, mouseHandler); | |
| 450 | + } else if (eventName == "clickReleaseOnEntity") { | |
| 451 | + connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, mouseHandler); | |
| 452 | + | |
| 453 | + } else if (eventName == "hoverEnterEntity") { | |
| 454 | + connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, mouseHandler); | |
| 455 | + } else if (eventName == "hoverOverEntity") { | |
| 456 | + connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, mouseHandler); | |
| 457 | + } else if (eventName == "hoverLeaveEntity") { | |
| 458 | + connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, mouseHandler); | |
| 459 | + | |
| 460 | + } else if (eventName == "collisionWithEntity") { | |
| 461 | + connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, | |
| 462 | + [=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { | |
| 463 | + generalHandler([=]() { | |
| 464 | + return QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision); | |
| 465 | + }); | |
| 466 | + }); | |
| 400 | 467 | } |
| 401 | − // FIXME: deletingEntity, changingEntityID | |
| 402 | −} | |
| 403 | −void ScriptEngine::removeEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { | |
| 404 | − // FIXME | |
| 405 | −} | |
| 406 | −void ScriptEngine::collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { | |
| 407 | − if (!_registeredHandlers.contains(idA)) return; | |
| 408 | − const RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[idA]; | |
| 409 | − if (!handlersOnEntity.contains("collisionWithEntity")) return; | |
| 410 | − // FIXME: Need one more level of indirection. We need to allow multiple handlers per event, registered by different scripts. | |
| 411 | − QScriptValue handlerForEvent = handlersOnEntity["collisionWithEntity"]; | |
| 412 | − QScriptValueList args = QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision); | |
| 413 | − handlerForEvent.call(QScriptValue(), args); | |
| 414 | 468 | } |
| 415 | 469 | |
| 470 | + | |
| 416 | 471 | void ScriptEngine::evaluate() { |
| 417 | 472 | if (_stoppingAllScripts) { |
| 418 | 473 | return; // bail early |