mirror of
https://github.com/overte-org/overte.git
synced 2025-04-30 06:02:48 +02:00
514 lines
18 KiB
C++
514 lines
18 KiB
C++
//
|
|
// 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 <QDebug>
|
|
#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
|
|
* <table>
|
|
* <thead>
|
|
* <tr><th>Value</th><th>Description</th></tr>
|
|
* </thead>
|
|
* <tbody>
|
|
* <tr><td><code>"avatar"</code></td><td></td></tr>
|
|
* <tr><td><code>"entity"</code></td><td></td></tr>
|
|
* <tr><td><code>"overlay"</code></td><td></td></tr>
|
|
* </tbody>
|
|
* </table>
|
|
* @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 <class T> 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 <class T> 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<QVariant> avatarIDs;
|
|
QList<QVariant> entityIDs;
|
|
QList<QVariant> 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<SelectionScriptingInterface>()->getList(_listName);
|
|
render::Transaction transaction;
|
|
render::ItemIDs finalList;
|
|
render::ItemID currentID;
|
|
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
|
auto& overlays = qApp->getOverlays();
|
|
|
|
for (QUuid& currentAvatarID : thisList.getAvatarIDs()) {
|
|
auto avatar = std::static_pointer_cast<Avatar>(DependencyManager::get<AvatarManager>()->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 <code>0.0</code> (not visible) to <code>1.0</code>
|
|
* (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 - <code>true</code> 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;
|
|
}
|