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. | |
| 393 | −QScriptValue ScriptEngine::getEntityEventHandler(const EntityItemID& entityID, const QString& eventName) { | |
| 394 | − if (!_registeredHandlers.contains(entityID)) return _illegal; | |
| 392 | +// Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args | |
| 393 | +void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function<QScriptValueList()> argGenerator) { | |
| 394 | + if (!_registeredHandlers.contains(entityID)) return; | |
| 395 | 395 | const RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID]; |
| 396 | − if (!handlersOnEntity.contains(eventName)) return _illegal; | |
| 396 | + if (!handlersOnEntity.contains(eventName)) return; | |
| 397 | 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 | 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 | 411 | // FIXME: deletingEntity, changingEntityID |
| 412 | +// Register the handler. | |
| 404 | 413 | void ScriptEngine::addEntityEventHandler(const EntityItemID& entityID, const QString& eventName, QScriptValue handler) { |
| 405 | − if (!_registeredHandlers.contains(entityID)) { | |
| 406 | − _registeredHandlers[entityID] = RegisteredEventHandlers(); | |
| 407 | − } | |
| 408 | − _registeredHandlers[entityID][eventName] = handler; | |
| 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") { | |
| 414 | + if (_registeredHandlers.count() == 0) { // First time any per-entity handler has been added in this script... | |
| 415 | + // Connect up ALL the handlers to the global entities object's signals. | |
| 416 | + // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) | |
| 417 | + auto entities = DependencyManager::get<EntityScriptingInterface>(); | |
| 418 | + connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, | |
| 419 | + [=](const EntityItemID& entityID) { | |
| 420 | + _registeredHandlers.remove(entityID); | |
| 421 | + }); | |
| 422 | + connect(entities.data(), &EntityScriptingInterface::changingEntityID, this, | |
| 423 | + [=](const EntityItemID& oldEntityID, const EntityItemID& newEntityID) { | |
| 424 | + if (!_registeredHandlers.contains(oldEntityID)) return; | |
| 425 | + _registeredHandlers[newEntityID] = _registeredHandlers[oldEntityID]; | |
| 426 | + _registeredHandlers.remove(oldEntityID); | |
| 427 | + }); | |
| 428 | + | |
| 429 | + // Two common cases of event handler, differing only in argument signature. | |
| 430 | + auto makeSingleEntityHandler = [=](const QString& eventName) { | |
| 431 | + return [=](const EntityItemID& entityItemID) { | |
| 432 | + generalHandler(entityItemID, eventName, [=]() { | |
| 433 | + return QScriptValueList() << entityItemID.toScriptValue(this); | |
| 434 | + }); | |
| 435 | + }; | |
| 436 | + }; | |
| 437 | + auto makeMouseHandler = [=](const QString& eventName) { | |
| 438 | + return [=](const EntityItemID& entityItemID, const MouseEvent& event) { | |
| 439 | + generalHandler(entityItemID, eventName, [=]() { | |
| 440 | + return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this); | |
| 441 | + }); | |
| 442 | + }; | |
| 443 | + }; | |
| 444 | + connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); | |
| 445 | + connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); | |
| 446 | + | |
| 447 | + connect(entities.data(), &EntityScriptingInterface::mousePressOnEntity, this, makeMouseHandler("mousePressOnEntity")); | |
| 448 | + connect(entities.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, makeMouseHandler("mouseMoveOnEntity")); | |
| 449 | + connect(entities.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, makeMouseHandler("mouseReleaseOnEntity")); | |
| 450 | + | |
| 451 | + connect(entities.data(), &EntityScriptingInterface::clickDownOnEntity, this, makeMouseHandler("clickDownOnEntity")); | |
| 452 | + connect(entities.data(), &EntityScriptingInterface::holdingClickOnEntity, this, makeMouseHandler("holdingClickOnEntity")); | |
| 453 | + connect(entities.data(), &EntityScriptingInterface::clickReleaseOnEntity, this, makeMouseHandler("clickReleaseOnEntity")); | |
| 454 | + | |
| 455 | + connect(entities.data(), &EntityScriptingInterface::hoverEnterEntity, this, makeMouseHandler("hoverEnterEntity")); | |
| 456 | + connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity")); | |
| 457 | + connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity")); | |
| 458 | + | |
| 461 | 459 | connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, |
| 462 | 460 | [=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { |
| 463 | − generalHandler([=]() { | |
| 461 | + generalHandler(idA, "collisionWithEntity", [=]() { | |
| 464 | 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 | |