Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 4 files). Show all
Unified · Split
| @@ -389,82 +389,84 @@ 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. | 392 | // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args |
| 393 | QScriptValue ScriptEngine::getEntityEventHandler(const EntityItemID& entityID, const QString& eventName) { | 393 | void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) { |
| 394 | if (!_registeredHandlers.contains(entityID)) return _illegal; | 394 | if (!_registeredHandlers.contains(entityID)) return; |
| 395 | const RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID]; | 395 | const RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID]; |
| 396 | if (!handlersOnEntity.contains(eventName)) return _illegal; | 396 | if (!handlersOnEntity.contains(eventName)) return; |
| 397 | // FIXME: Need one more level of indirection. We need to allow multiple handlers per event, registered by different scripts. | 397 | // FIXME: Need one more level of indirection. We need to allow multiple handlers per event, registered by different scripts. |
| 398 | return handlersOnEntity[eventName]; | 398 | QScriptValue handlerForEvent = handlersOnEntity[eventName]; |
| 399 | if (handlerForEvent.isValid()) { | ||
| 400 | QScriptValueList args = argGenerator(); | ||
| 401 | handlerForEvent.call(QScriptValue(), args); | ||
| 402 | } | ||
| 399 | } | 403 | } |
| 404 | // Unregister the handler for this eventName and entityID. | ||
| 400 | void ScriptEngine::removeEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { | 405 | void ScriptEngine::removeEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { |
| 401 | // FIXME | 406 | if (!_registeredHandlers.contains(entityID)) return; |
| 407 | RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID]; | ||
| 408 | if (!handlersOnEntity.contains(eventName)) return; | ||
| 409 | handlersOnEntity.remove(eventName); | ||
| 402 | } | 410 | } |
| 403 | // FIXME: deletingEntity, changingEntityID | 411 | // FIXME: deletingEntity, changingEntityID |
| 412 | // Register the handler. | ||
| 404 | void ScriptEngine::addEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { | 413 | void ScriptEngine::addEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { |
| 405 | if (!_registeredHandlers.contains(entityID)) { | 414 | if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script... |
| 406 | _registeredHandlers[entityID] = RegisteredEventHandlers(); | 415 | // Connect up ALL the handlers to the global entities object's signals. |
| 407 | } | 416 | // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) |
| 408 | _registeredHandlers[entityID][eventName] = handler; | 417 | auto entities = DependencyManager::get<EntityScriptingInterface>(); |
| 409 | 418 | connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, | |
| 410 | // The rest connects the Entities signal to the handler here. | 419 | [=](const EntityItemID& entityID) { |
| 411 | auto entities = DependencyManager::get<EntityScriptingInterface>(); | 420 | _registeredHandlers.remove(entityID); |
| 412 | 421 | }); | |
| 413 | // Given thunk that generates the arglist, evaluate that thunk only if needed, and call the handler. | 422 | connect(entities.data(), &EntityScriptingInterface::changingEntityID, this, |
| 414 | auto generalHandler = [=](std::function<QScriptValueList()> argGenerator) { | 423 | [=](const EntityItemID& oldEntityID, const EntityItemID& newEntityID) { |
| 415 | QScriptValue handlerForEvent = getEntityEventHandler(entityID, eventName); | 424 | if (!_registeredHandlers.contains(oldEntityID)) return; |
| 416 | if (handlerForEvent.isValid()) { | 425 | _registeredHandlers[newEntityID] = _registeredHandlers[oldEntityID]; |
| 417 | QScriptValueList args = argGenerator(); | 426 | _registeredHandlers.remove(oldEntityID); |
| 418 | handlerForEvent.call(QScriptValue(), args); | 427 | }); |
| 419 | } | 428 | |
| 420 | }; | 429 | // Two common cases of event handler, differing only in argument signature. |
| 421 | // Two common cases of event handler, differing only in argument signature. | 430 | auto makeSingleEntityHandler = [=](const QString& eventName) { |
| 422 | auto singleEntityHandler = [=](const EntityItemID& entityItemID) { | 431 | return [=](const EntityItemID& entityItemID) { |
| 423 | generalHandler([=]() { | 432 | generalHandler(entityItemID, eventName, [=]() { |
| 424 | return QScriptValueList() << entityItemID.toScriptValue(this); | 433 | return QScriptValueList() << entityItemID.toScriptValue(this); |
| 425 | }); | 434 | }); |
| 426 | }; | 435 | }; |
| 427 | auto mouseHandler = [=](const EntityItemID& entityItemID, const MouseEvent& event) { | 436 | }; |
| 428 | generalHandler([=]() { | 437 | auto makeMouseHandler = [=](const QString& eventName) { |
| 429 | return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this); | 438 | return [=](const EntityItemID& entityItemID, const MouseEvent& event) { |
| 430 | }); | 439 | generalHandler(entityItemID, eventName, [=]() { |
| 431 | }; | 440 | return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this); |
| 432 | // This string comparison maze only happens when adding a handler, which isn't often, rather than during events. | 441 | }); |
| 433 | // Nonetheless, I wish it were more DRY. Variadic signals from strings? "I know reflection. I've worked with reflection. QT is no reflection." | 442 | }; |
| 434 | if (eventName == "enterEntity") { | 443 | }; |
| 435 | connect(entities.data(), &EntityScriptingInterface::enterEntity, this, singleEntityHandler); | 444 | connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); |
| 436 | } else if (eventName == "leaveEntity") { | 445 | connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); |
| 437 | connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, singleEntityHandler); | 446 | |
| 438 | 447 | connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makeMouseHandler("mousePressOnEntity")); | |
| 439 | } else if (eventName == "mousePressOnEntity") { | 448 | connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makeMouseHandler("mouseMoveOnEntity")); |
| 440 | connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, mouseHandler); | 449 | connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makeMouseHandler("mouseReleaseOnEntity")); |
| 441 | } else if (eventName == "mouseMoveOnEntity") { | 450 | |
| 442 | connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, mouseHandler); | 451 | connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makeMouseHandler("clickDownOnEntity")); |
| 443 | } else if (eventName == "mouseReleaseOnEntity") { | 452 | connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makeMouseHandler("holdingClickOnEntity")); |
| 444 | connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, mouseHandler); | 453 | connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makeMouseHandler("clickReleaseOnEntity")); |
| 445 | 454 | ||
| 446 | } else if (eventName == "clickDownOnEntity") { | 455 | connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makeMouseHandler("hoverEnterEntity")); |
| 447 | connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, mouseHandler); | 456 | connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity")); |
| 448 | } else if (eventName == "holdingClickOnEntity") { | 457 | connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity")); |
| 449 | connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, mouseHandler); | 458 | |
| 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, | 459 | connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, |
| 462 | [=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { | 460 | [=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { |
| 463 | generalHandler([=]() { | 461 | generalHandler(idA, "collisionWithEntity", [=]() { |
| 464 | return QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision); | 462 | return QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision); |
| 465 | }); | 463 | }); |
| 466 | }); | 464 | }); |
| 467 | } | 465 | } |
| 466 | if (!_registeredHandlers.contains(entityID)) { | ||
| 467 | _registeredHandlers[entityID] = RegisteredEventHandlers(); | ||
| 468 | } | ||
| 469 | _registeredHandlers[entityID][eventName] = handler; | ||
| 468 | } | 470 | } |
| 469 | 471 | ||
| 470 | 472 | ||