// // SelectionScriptingInterface.cpp // interface/src/scripting // // Created by Zach Fox on 2017-08-22. // Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "SelectionScriptingInterface.h" #include #include "Application.h" GameplayObjects::GameplayObjects() { } bool GameplayObjects::addToGameplayObjects(const QUuid& avatarID) { containsData = true; if (std::find(_avatarIDs.begin(), _avatarIDs.end(), avatarID) == _avatarIDs.end()) { _avatarIDs.push_back(avatarID); } return true; } bool GameplayObjects::removeFromGameplayObjects(const QUuid& avatarID) { _avatarIDs.erase(std::remove(_avatarIDs.begin(), _avatarIDs.end(), avatarID), _avatarIDs.end()); return true; } bool GameplayObjects::addToGameplayObjects(const EntityItemID& entityID) { containsData = true; if (std::find(_entityIDs.begin(), _entityIDs.end(), entityID) == _entityIDs.end()) { _entityIDs.push_back(entityID); } return true; } bool GameplayObjects::removeFromGameplayObjects(const EntityItemID& entityID) { _entityIDs.erase(std::remove(_entityIDs.begin(), _entityIDs.end(), entityID), _entityIDs.end()); return true; } bool GameplayObjects::addToGameplayObjects(const OverlayID& overlayID) { containsData = true; if (std::find(_overlayIDs.begin(), _overlayIDs.end(), overlayID) == _overlayIDs.end()) { _overlayIDs.push_back(overlayID); } return true; } bool GameplayObjects::removeFromGameplayObjects(const OverlayID& overlayID) { _overlayIDs.erase(std::remove(_overlayIDs.begin(), _overlayIDs.end(), overlayID), _overlayIDs.end()); return true; } SelectionScriptingInterface::SelectionScriptingInterface() { } /**jsdoc * * * * * * * * * *
ValueDescription
"avatar"
"entity"
"overlay"
* @typedef {string} Selection.ItemType */ bool SelectionScriptingInterface::addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) { if (itemType == "avatar") { return addToGameplayObjects(listName, (QUuid)id); } else if (itemType == "entity") { return addToGameplayObjects(listName, (EntityItemID)id); } else if (itemType == "overlay") { return addToGameplayObjects(listName, (OverlayID)id); } return false; } bool SelectionScriptingInterface::removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) { if (itemType == "avatar") { return removeFromGameplayObjects(listName, (QUuid)id); } else if (itemType == "entity") { return removeFromGameplayObjects(listName, (EntityItemID)id); } else if (itemType == "overlay") { return removeFromGameplayObjects(listName, (OverlayID)id); } return false; } bool SelectionScriptingInterface::clearSelectedItemsList(const QString& listName) { { QWriteLocker lock(&_selectionListsLock); _selectedItemsListMap.insert(listName, GameplayObjects()); } onSelectedItemsListChanged(listName); return true; } QStringList SelectionScriptingInterface::getListNames() const { QStringList list; QReadLocker lock(&_selectionListsLock); list = _selectedItemsListMap.keys(); return list; } QStringList SelectionScriptingInterface::getHighlightedListNames() const { QStringList list; QReadLocker lock(&_highlightStylesLock); list = _highlightStyleMap.keys(); return list; } bool SelectionScriptingInterface::enableListHighlight(const QString& listName, const QVariantMap& highlightStyleValues) { QWriteLocker lock(&_highlightStylesLock); auto highlightStyle = _highlightStyleMap.find(listName); if (highlightStyle == _highlightStyleMap.end()) { highlightStyle = _highlightStyleMap.insert(listName, SelectionHighlightStyle()); } if (!(*highlightStyle).isBoundToList()) { enableListToScene(listName); (*highlightStyle).setBoundToList(true); } (*highlightStyle).fromVariantMap(highlightStyleValues); auto mainScene = qApp->getMain3DScene(); if (mainScene) { render::Transaction transaction; transaction.resetSelectionHighlight(listName.toStdString(), (*highlightStyle).getStyle()); mainScene->enqueueTransaction(transaction); } else { qWarning() << "SelectionToSceneHandler::highlightStyleChanged(), Unexpected null scene, possibly during application shutdown"; } return true; } bool SelectionScriptingInterface::disableListHighlight(const QString& listName) { QWriteLocker lock(&_highlightStylesLock); auto highlightStyle = _highlightStyleMap.find(listName); if (highlightStyle != _highlightStyleMap.end()) { if ((*highlightStyle).isBoundToList()) { disableListToScene(listName); } _highlightStyleMap.erase(highlightStyle); auto mainScene = qApp->getMain3DScene(); if (mainScene) { render::Transaction transaction; transaction.removeHighlightFromSelection(listName.toStdString()); mainScene->enqueueTransaction(transaction); } else { qWarning() << "SelectionToSceneHandler::highlightStyleChanged(), Unexpected null scene, possibly during application shutdown"; } } return true; } QVariantMap SelectionScriptingInterface::getListHighlightStyle(const QString& listName) const { QReadLocker lock(&_highlightStylesLock); auto highlightStyle = _highlightStyleMap.find(listName); if (highlightStyle == _highlightStyleMap.end()) { return QVariantMap(); } else { return (*highlightStyle).toVariantMap(); } } render::HighlightStyle SelectionScriptingInterface::getHighlightStyle(const QString& listName) const { QReadLocker lock(&_highlightStylesLock); auto highlightStyle = _highlightStyleMap.find(listName); if (highlightStyle == _highlightStyleMap.end()) { return render::HighlightStyle(); } else { return (*highlightStyle).getStyle(); } } bool SelectionScriptingInterface::enableListToScene(const QString& listName) { setupHandler(listName); return true; } bool SelectionScriptingInterface::disableListToScene(const QString& listName) { removeHandler(listName); return true; } template bool SelectionScriptingInterface::addToGameplayObjects(const QString& listName, T idToAdd) { { QWriteLocker lock(&_selectionListsLock); GameplayObjects currentList = _selectedItemsListMap.value(listName); currentList.addToGameplayObjects(idToAdd); _selectedItemsListMap.insert(listName, currentList); } onSelectedItemsListChanged(listName); return true; } template bool SelectionScriptingInterface::removeFromGameplayObjects(const QString& listName, T idToRemove) { bool listExist = false; { QWriteLocker lock(&_selectionListsLock); auto currentList = _selectedItemsListMap.find(listName); if (currentList != _selectedItemsListMap.end()) { listExist = true; (*currentList).removeFromGameplayObjects(idToRemove); } } if (listExist) { onSelectedItemsListChanged(listName); return true; } else { return false; } } // // END HANDLING GENERIC ITEMS // GameplayObjects SelectionScriptingInterface::getList(const QString& listName) { QReadLocker lock(&_selectionListsLock); return _selectedItemsListMap.value(listName); } void SelectionScriptingInterface::printList(const QString& listName) { QReadLocker lock(&_selectionListsLock); auto currentList = _selectedItemsListMap.find(listName); if (currentList != _selectedItemsListMap.end()) { if ((*currentList).getContainsData()) { qDebug() << "List named " << listName << ":"; qDebug() << "Avatar IDs:"; for (auto i : (*currentList).getAvatarIDs()) { qDebug() << i << ';'; } qDebug() << ""; qDebug() << "Entity IDs:"; for (auto j : (*currentList).getEntityIDs()) { qDebug() << j << ';'; } qDebug() << ""; qDebug() << "Overlay IDs:"; for (auto k : (*currentList).getOverlayIDs()) { qDebug() << k << ';'; } qDebug() << ""; } else { qDebug() << "List named " << listName << " empty"; } } else { qDebug() << "List named " << listName << " doesn't exist."; } } /**jsdoc * @typedef {object} Selection.SelectedItemsList * @property {Uuid[]} avatars - The IDs of the avatars in the selection. * @property {Uuid[]} entities - The IDs of the entities in the selection. * @property {Uuid[]} overlays - The IDs of the overlays in the selection. */ QVariantMap SelectionScriptingInterface::getSelectedItemsList(const QString& listName) const { QReadLocker lock(&_selectionListsLock); QVariantMap list; auto currentList = _selectedItemsListMap.find(listName); if (currentList != _selectedItemsListMap.end()) { QList avatarIDs; QList entityIDs; QList overlayIDs; if ((*currentList).getContainsData()) { if (!(*currentList).getAvatarIDs().empty()) { for (auto j : (*currentList).getAvatarIDs()) { avatarIDs.push_back((QUuid)j); } } if (!(*currentList).getEntityIDs().empty()) { for (auto j : (*currentList).getEntityIDs()) { entityIDs.push_back((QUuid)j ); } } if (!(*currentList).getOverlayIDs().empty()) { for (auto j : (*currentList).getOverlayIDs()) { overlayIDs.push_back((QUuid)j); } } } list["avatars"] = (avatarIDs); list["entities"] = (entityIDs); list["overlays"] = (overlayIDs); return list; } else { return list; } } bool SelectionScriptingInterface::removeListFromMap(const QString& listName) { bool removed = false; { QWriteLocker lock(&_selectionListsLock); removed = _selectedItemsListMap.remove(listName); } if (removed) { onSelectedItemsListChanged(listName); return true; } else { return false; } } void SelectionScriptingInterface::setupHandler(const QString& selectionName) { QWriteLocker lock(&_selectionHandlersLock); auto handler = _handlerMap.find(selectionName); if (handler == _handlerMap.end()) { handler = _handlerMap.insert(selectionName, new SelectionToSceneHandler()); } (*handler)->initialize(selectionName); } void SelectionScriptingInterface::removeHandler(const QString& selectionName) { QWriteLocker lock(&_selectionHandlersLock); auto handler = _handlerMap.find(selectionName); if (handler != _handlerMap.end()) { delete handler.value(); _handlerMap.erase(handler); } } void SelectionScriptingInterface::onSelectedItemsListChanged(const QString& listName) { { QWriteLocker lock(&_selectionHandlersLock); auto handler = _handlerMap.find(listName); if (handler != _handlerMap.end()) { (*handler)->updateSceneFromSelectedList(); } } emit selectedItemsListChanged(listName); } SelectionToSceneHandler::SelectionToSceneHandler() { } void SelectionToSceneHandler::initialize(const QString& listName) { _listName = listName; updateSceneFromSelectedList(); } void SelectionToSceneHandler::selectedItemsListChanged(const QString& listName) { if (listName == _listName) { updateSceneFromSelectedList(); } } void SelectionToSceneHandler::updateSceneFromSelectedList() { auto mainScene = qApp->getMain3DScene(); if (mainScene) { GameplayObjects thisList = DependencyManager::get()->getList(_listName); render::Transaction transaction; render::ItemIDs finalList; render::ItemID currentID; auto entityTreeRenderer = DependencyManager::get(); auto& overlays = qApp->getOverlays(); for (QUuid& currentAvatarID : thisList.getAvatarIDs()) { auto avatar = std::static_pointer_cast(DependencyManager::get()->getAvatarBySessionID(currentAvatarID)); if (avatar) { currentID = avatar->getRenderItemID(); if (currentID != render::Item::INVALID_ITEM_ID) { finalList.push_back(currentID); } } } for (EntityItemID& currentEntityID : thisList.getEntityIDs()) { currentID = entityTreeRenderer->renderableIdForEntityId(currentEntityID); if (currentID != render::Item::INVALID_ITEM_ID) { finalList.push_back(currentID); } } for (OverlayID& currentOverlayID : thisList.getOverlayIDs()) { auto overlay = overlays.getOverlay(currentOverlayID); if (overlay != NULL) { currentID = overlay->getRenderItemID(); if (currentID != render::Item::INVALID_ITEM_ID) { finalList.push_back(currentID); } } } render::Selection selection(_listName.toStdString(), finalList); transaction.resetSelection(selection); mainScene->enqueueTransaction(transaction); } else { qWarning() << "SelectionToSceneHandler::updateRendererSelectedList(), Unexpected null scene, possibly during application shutdown"; } } bool SelectionHighlightStyle::fromVariantMap(const QVariantMap& properties) { auto colorVariant = properties["outlineUnoccludedColor"]; if (colorVariant.isValid()) { bool isValid; auto color = xColorFromVariant(colorVariant, isValid); if (isValid) { _style._outlineUnoccluded.color = toGlm(color); } } colorVariant = properties["outlineOccludedColor"]; if (colorVariant.isValid()) { bool isValid; auto color = xColorFromVariant(colorVariant, isValid); if (isValid) { _style._outlineOccluded.color = toGlm(color); } } colorVariant = properties["fillUnoccludedColor"]; if (colorVariant.isValid()) { bool isValid; auto color = xColorFromVariant(colorVariant, isValid); if (isValid) { _style._fillUnoccluded.color = toGlm(color); } } colorVariant = properties["fillOccludedColor"]; if (colorVariant.isValid()) { bool isValid; auto color = xColorFromVariant(colorVariant, isValid); if (isValid) { _style._fillOccluded.color = toGlm(color); } } auto intensityVariant = properties["outlineUnoccludedAlpha"]; if (intensityVariant.isValid()) { _style._outlineUnoccluded.alpha = intensityVariant.toFloat(); } intensityVariant = properties["outlineOccludedAlpha"]; if (intensityVariant.isValid()) { _style._outlineOccluded.alpha = intensityVariant.toFloat(); } intensityVariant = properties["fillUnoccludedAlpha"]; if (intensityVariant.isValid()) { _style._fillUnoccluded.alpha = intensityVariant.toFloat(); } intensityVariant = properties["fillOccludedAlpha"]; if (intensityVariant.isValid()) { _style._fillOccluded.alpha = intensityVariant.toFloat(); } auto outlineWidth = properties["outlineWidth"]; if (outlineWidth.isValid()) { _style._outlineWidth = outlineWidth.toFloat(); } auto isOutlineSmooth = properties["isOutlineSmooth"]; if (isOutlineSmooth.isValid()) { _style._isOutlineSmooth = isOutlineSmooth.toBool(); } return true; } /**jsdoc * @typedef {object} Selection.HighlightStyle * @property {Color} outlineUnoccludedColor - Color of the specified highlight region. * @property {Color} outlineOccludedColor - "" * @property {Color} fillUnoccludedColor- "" * @property {Color} fillOccludedColor- "" * @property {number} outlineUnoccludedAlpha - Alpha value ranging from 0.0 (not visible) to 1.0 * (fully opaque) for the specified highlight region. * @property {number} outlineOccludedAlpha - "" * @property {number} fillUnoccludedAlpha - "" * @property {number} fillOccludedAlpha - "" * @property {number} outlineWidth - Width of the outline, in pixels. * @property {boolean} isOutlineSmooth - true to enable outline smooth fall-off. */ QVariantMap SelectionHighlightStyle::toVariantMap() const { QVariantMap properties; properties["outlineUnoccludedColor"] = xColorToVariant(xColorFromGlm(_style._outlineUnoccluded.color)); properties["outlineOccludedColor"] = xColorToVariant(xColorFromGlm(_style._outlineOccluded.color)); properties["fillUnoccludedColor"] = xColorToVariant(xColorFromGlm(_style._fillUnoccluded.color)); properties["fillOccludedColor"] = xColorToVariant(xColorFromGlm(_style._fillOccluded.color)); properties["outlineUnoccludedAlpha"] = _style._outlineUnoccluded.alpha; properties["outlineOccludedAlpha"] = _style._outlineOccluded.alpha; properties["fillUnoccludedAlpha"] = _style._fillUnoccluded.alpha; properties["fillOccludedAlpha"] = _style._fillOccluded.alpha; properties["outlineWidth"] = _style._outlineWidth; properties["isOutlineSmooth"] = _style._isOutlineSmooth; return properties; }