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 | void ScriptEngine::addEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { | 404 | void ScriptEngine::addEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { |
| 393 | auto entities = DependencyManager::get<EntityScriptingInterface>(); | ||
| 394 | if (!_registeredHandlers.contains(entityID)) { | 405 | if (!_registeredHandlers.contains(entityID)) { |
| 395 | _registeredHandlers[entityID] = RegisteredEventHandlers(); | 406 | _registeredHandlers[entityID] = RegisteredEventHandlers(); |
| 396 | } | 407 | } |
| 397 | _registeredHandlers[entityID][eventName] = handler; | 408 | _registeredHandlers[entityID][eventName] = handler; |
| 398 | if (eventName == "collisionWithEntity") { | 409 | |
| 399 | connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, &ScriptEngine::collisionWithEntity); | 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 | void ScriptEngine::evaluate() { | 471 | void ScriptEngine::evaluate() { |
| 417 | if (_stoppingAllScripts) { | 472 | if (_stoppingAllScripts) { |
| 418 | return; // bail early | 473 | return; // bail early |