3
0
Fork 0
mirror of https://github.com/JulianGro/overte.git synced 2025-04-29 18:22:55 +02:00

Merge branch 'master' of https://github.com/highfidelity/hifi into hackathonLightening

This commit is contained in:
Brad Hefta-Gaub 2016-03-04 15:31:32 -08:00
commit 3f85daf276
205 changed files with 5029 additions and 2081 deletions
assignment-client/src/octree
cmake
domain-server
examples
ice-server
interface

View file

@ -236,10 +236,6 @@ OctreeServer::OctreeServer(ReceivedMessage& message) :
{
_averageLoopTime.updateAverage(0);
qDebug() << "Octree server starting... [" << this << "]";
// make sure the AccountManager has an Auth URL for payment redemptions
AccountManager::getInstance().setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
}
OctreeServer::~OctreeServer() {

View file

@ -64,11 +64,10 @@ macro(install_beside_console)
)
endif()
# set variables used by manual ssleay library copy
set(TARGET_INSTALL_DIR ${COMPONENT_INSTALL_DIR})
set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT})
manually_install_openssl_for_qt()
endif ()
# set variables used by manual ssleay library copy
set(TARGET_INSTALL_DIR ${COMPONENT_INSTALL_DIR})
set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT})
manually_install_ssl_eay()
endmacro()

View file

@ -0,0 +1,34 @@
#
# ManuallyInstallOpenSSLforQt.cmake
#
# Created by Stephen Birarda on 1/15/16.
# Copyright 2014 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
#
macro(manually_install_openssl_for_qt)
# Qt dynamically links OpenSSL if it can find it on the user's machine
# We want to avoid it being found somewhere random and have it not being a compatible version
# So even though we don't need the dynamic version of OpenSSL for our direct-use purposes
# we use this macro to include the two SSL DLLs with the targets using QtNetwork
if (WIN32)
# we have to call find_package(OpenSSL) here even though this target may not directly need it
find_package(OpenSSL REQUIRED)
install(
FILES "${OPENSSL_DLL_PATH}/ssleay32.dll"
DESTINATION ${TARGET_INSTALL_DIR}
COMPONENT ${TARGET_INSTALL_COMPONENT}
)
install(
FILES "${OPENSSL_DLL_PATH}/libeay32.dll"
DESTINATION ${TARGET_INSTALL_DIR}
COMPONENT ${TARGET_INSTALL_COMPONENT}
)
endif()
endmacro()

View file

@ -1,28 +0,0 @@
#
# ManuallyInstallSSLEay.cmake
#
# Created by Stephen Birarda on 1/15/16.
# Copyright 2014 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
#
macro(manually_install_ssl_eay)
# on windows we have had issues with targets missing ssleay library
# not convinced we actually need it (I assume it would show up in the dependency tree)
# but to be safe we install it manually beside the current target
if (WIN32)
# we need to find SSL_EAY_LIBRARY_* so we can install it beside this target
# so we have to call find_package(OpenSSL) here even though this target may not specifically need it
find_package(OpenSSL REQUIRED)
install(
FILES "${OPENSSL_DLL_PATH}/ssleay32.dll"
DESTINATION ${TARGET_INSTALL_DIR}
COMPONENT ${TARGET_INSTALL_COMPONENT}
)
endif()
endmacro()

View file

@ -67,10 +67,7 @@ find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AN
if (WIN32 AND NOT CYGWIN)
if (MSVC)
# /MD and /MDd are the standard values - if someone wants to use
# others, the libnames have to change here too
# use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b
# TODO: handle /MT and static lib
# In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix:
# * MD for dynamic-release
# * MDd for dynamic-debug
@ -81,20 +78,23 @@ if (WIN32 AND NOT CYGWIN)
# We are using the libraries located in the VC subdir instead of the parent directory eventhough :
# libeay32MD.lib is identical to ../libeay32.lib, and
# ssleay32MD.lib is identical to ../ssleay32.lib
find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32d
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
# The Kitware FindOpenSSL module has been modified here by High Fidelity to look specifically for static libraries
find_library(LIB_EAY_DEBUG NAMES libeay32MTd
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static"
)
find_library(LIB_EAY_RELEASE NAMES libeay32MD libeay32
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
find_library(LIB_EAY_RELEASE NAMES libeay32MT
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static"
)
find_library(SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32d
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
find_library(SSL_EAY_DEBUG NAMES ssleay32MTd
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static"
)
find_library(SSL_EAY_RELEASE NAMES ssleay32MD ssleay32 ssl
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC"
find_library(SSL_EAY_RELEASE NAMES ssleay32MT
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static"
)
set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}")
@ -109,37 +109,6 @@ if (WIN32 AND NOT CYGWIN)
set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY})
find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS})
elseif (MINGW)
# same player, for MinGW
set(LIB_EAY_NAMES libeay32)
set(SSL_EAY_NAMES ssleay32)
if (CMAKE_CROSSCOMPILING)
list(APPEND LIB_EAY_NAMES crypto)
list(APPEND SSL_EAY_NAMES ssl)
endif ()
find_library(LIB_EAY NAMES ${LIB_EAY_NAMES}
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW"
)
find_library(SSL_EAY NAMES ${SSL_EAY_NAMES}
${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW"
)
mark_as_advanced(SSL_EAY LIB_EAY)
set(OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY})
unset(LIB_EAY_NAMES)
unset(SSL_EAY_NAMES)
else ()
# Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues:
find_library(LIB_EAY NAMES libeay32 HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR} PATH_SUFFIXES lib)
find_library(SSL_EAY NAMES ssleay32 HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR} PATH_SUFFIXES lib)
mark_as_advanced(SSL_EAY LIB_EAY)
set(OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY})
endif()
else()
@ -250,8 +219,4 @@ else ()
)
endif ()
if (WIN32)
add_paths_to_fixup_libs(${OPENSSL_DLL_PATH})
endif ()
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_SEARCH_DIRS)

View file

@ -778,7 +778,7 @@ function chooseFromHighFidelityDomains(clickedButton) {
function createTemporaryDomain() {
swal({
title: 'Create temporary place name',
text: "This will create a temporary place name and domain ID (valid for 30 days)"
text: "This will create a temporary place name and domain ID"
+ " so other users can easily connect to your domain.</br></br>"
+ "In order to make your domain reachable, this will also enable full automatic networking.",
showCancelButton: true,

View file

@ -258,9 +258,26 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
if (onlyEditorsAreRezzers) {
canRez = isAllowedEditor;
}
QUuid hintNodeID;
// in case this is a node that's failing to connect
// double check we don't have a node whose sockets match exactly already in the list
limitedNodeList->eachNodeBreakable([&nodeConnection, &hintNodeID](const SharedNodePointer& node){
if (node->getPublicSocket() == nodeConnection.publicSockAddr
&& node->getLocalSocket() == nodeConnection.localSockAddr) {
// we have a node that already has these exact sockets - this occurs if a node
// is unable to connect to the domain
hintNodeID = node->getUUID();
return false;
}
return true;
});
// add the new node
SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection);
// add the connecting node (or re-use the matched one from eachNodeBreakable above)
SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection, hintNodeID);
// set the edit rights for this user
newNode->setIsAllowedEditor(isAllowedEditor);
@ -279,28 +296,29 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
return newNode;
}
SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection) {
SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection,
QUuid nodeID) {
HifiSockAddr discoveredSocket = nodeConnection.senderSockAddr;
SharedNetworkPeer connectedPeer = _icePeers.value(nodeConnection.connectUUID);
QUuid nodeUUID;
if (connectedPeer) {
// this user negotiated a connection with us via ICE, so re-use their ICE client ID
nodeUUID = nodeConnection.connectUUID;
nodeID = nodeConnection.connectUUID;
if (connectedPeer->getActiveSocket()) {
// set their discovered socket to whatever the activated socket on the network peer object was
discoveredSocket = *connectedPeer->getActiveSocket();
}
} else {
// we got a connectUUID we didn't recognize, just add the node with a new UUID
nodeUUID = QUuid::createUuid();
// we got a connectUUID we didn't recognize, either use the hinted node ID or randomly generate a new one
if (nodeID.isNull()) {
nodeID = QUuid::createUuid();
}
}
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
SharedNodePointer newNode = limitedNodeList->addOrUpdateNode(nodeUUID, nodeConnection.nodeType,
SharedNodePointer newNode = limitedNodeList->addOrUpdateNode(nodeID, nodeConnection.nodeType,
nodeConnection.publicSockAddr, nodeConnection.localSockAddr);
// So that we can send messages to this node at will - we need to activate the correct socket on this node now
@ -331,7 +349,6 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username,
QCryptographicHash::Sha256);
if (rsaPublicKey) {
QByteArray decryptedArray(RSA_size(rsaPublicKey), 0);
int decryptResult = RSA_verify(NID_sha256,
reinterpret_cast<const unsigned char*>(usernameWithToken.constData()),
usernameWithToken.size(),

View file

@ -59,7 +59,8 @@ private:
SharedNodePointer processAgentConnectRequest(const NodeConnectionData& nodeConnection,
const QString& username,
const QByteArray& usernameSignature);
SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection);
SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection,
QUuid nodeID = QUuid());
bool verifyUserSignature(const QString& username, const QByteArray& usernameSignature,
const HifiSockAddr& senderSockAddr);

View file

@ -96,7 +96,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
// make sure we hear about newly connected nodes from our gatekeeper
connect(&_gatekeeper, &DomainGatekeeper::connectedNode, this, &DomainServer::handleConnectedNode);
if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth() && optionallySetupAssignmentPayment()) {
if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth()) {
// we either read a certificate and private key or were not passed one
// and completed login or did not need to
@ -198,7 +198,6 @@ bool DomainServer::optionallySetupOAuth() {
}
AccountManager& accountManager = AccountManager::getInstance();
accountManager.disableSettingsFilePersistence();
accountManager.setAuthURL(_oauthProviderURL);
_oauthClientID = settingsMap.value(OAUTH_CLIENT_ID_OPTION).toString();
@ -372,20 +371,12 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
packetReceiver.registerListener(PacketType::ICEPing, &_gatekeeper, "processICEPingPacket");
packetReceiver.registerListener(PacketType::ICEPingReply, &_gatekeeper, "processICEPingReplyPacket");
packetReceiver.registerListener(PacketType::ICEServerPeerInformation, &_gatekeeper, "processICEPeerInformationPacket");
packetReceiver.registerListener(PacketType::ICEServerHeartbeatDenied, this, "processICEServerHeartbeatDenialPacket");
// add whatever static assignments that have been parsed to the queue
addStaticAssignmentsToQueue();
}
bool DomainServer::didSetupAccountManagerWithAccessToken() {
if (AccountManager::getInstance().hasValidAccessToken()) {
// we already gave the account manager a valid access token
return true;
}
return resetAccountManagerAccessToken();
}
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
bool DomainServer::resetAccountManagerAccessToken() {
@ -401,9 +392,13 @@ bool DomainServer::resetAccountManagerAccessToken() {
if (accessTokenVariant && accessTokenVariant->canConvert(QMetaType::QString)) {
accessToken = accessTokenVariant->toString();
} else {
qDebug() << "A domain-server feature that requires authentication is enabled but no access token is present."
<< "Set an access token via the web interface, in your user or master config"
qDebug() << "A domain-server feature that requires authentication is enabled but no access token is present.";
qDebug() << "Set an access token via the web interface, in your user or master config"
<< "at keypath metaverse.access_token or in your ENV at key DOMAIN_SERVER_ACCESS_TOKEN";
// clear any existing access token from AccountManager
AccountManager::getInstance().setAccessTokenForCurrentAuthURL(QString());
return false;
}
} else {
@ -429,34 +424,6 @@ bool DomainServer::resetAccountManagerAccessToken() {
}
}
bool DomainServer::optionallySetupAssignmentPayment() {
const QString PAY_FOR_ASSIGNMENTS_OPTION = "pay-for-assignments";
const QVariantMap& settingsMap = _settingsManager.getSettingsMap();
if (settingsMap.contains(PAY_FOR_ASSIGNMENTS_OPTION) &&
settingsMap.value(PAY_FOR_ASSIGNMENTS_OPTION).toBool() &&
didSetupAccountManagerWithAccessToken()) {
qDebug() << "Assignments will be paid for via" << qPrintable(_oauthProviderURL.toString());
// assume that the fact we are authing against HF data server means we will pay for assignments
// setup a timer to send transactions to pay assigned nodes every 30 seconds
QTimer* creditSetupTimer = new QTimer(this);
connect(creditSetupTimer, &QTimer::timeout, this, &DomainServer::setupPendingAssignmentCredits);
const qint64 CREDIT_CHECK_INTERVAL_MSECS = 5 * 1000;
creditSetupTimer->start(CREDIT_CHECK_INTERVAL_MSECS);
QTimer* nodePaymentTimer = new QTimer(this);
connect(nodePaymentTimer, &QTimer::timeout, this, &DomainServer::sendPendingTransactionsToServer);
const qint64 TRANSACTION_SEND_INTERVAL_MSECS = 30 * 1000;
nodePaymentTimer->start(TRANSACTION_SEND_INTERVAL_MSECS);
}
return true;
}
void DomainServer::setupAutomaticNetworking() {
auto nodeList = DependencyManager::get<LimitedNodeList>();
@ -467,9 +434,9 @@ void DomainServer::setupAutomaticNetworking() {
setupICEHeartbeatForFullNetworking();
}
if (!didSetupAccountManagerWithAccessToken()) {
qDebug() << "Cannot send heartbeat to data server without an access token.";
qDebug() << "Add an access token to your config file or via the web interface.";
if (!resetAccountManagerAccessToken()) {
qDebug() << "Will not send heartbeat to Metaverse API without an access token.";
qDebug() << "If this is not a temporary domain add an access token to your config file or via the web interface.";
return;
}
@ -526,6 +493,19 @@ void DomainServer::setupICEHeartbeatForFullNetworking() {
// we need this DS to know what our public IP is - start trying to figure that out now
limitedNodeList->startSTUNPublicSocketUpdate();
// to send ICE heartbeats we'd better have a private key locally with an uploaded public key
auto& accountManager = AccountManager::getInstance();
auto domainID = accountManager.getAccountInfo().getDomainID();
// if we have an access token and we don't have a private key or the current domain ID has changed
// we should generate a new keypair
if (!accountManager.getAccountInfo().hasPrivateKey() || domainID != limitedNodeList->getSessionUUID()) {
accountManager.generateNewDomainKeypair(limitedNodeList->getSessionUUID());
}
// hookup to the signal from account manager that tells us when keypair is available
connect(&accountManager, &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange);
if (!_iceHeartbeatTimer) {
// setup a timer to heartbeat with the ice-server every so often
_iceHeartbeatTimer = new QTimer { this };
@ -1082,11 +1062,76 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
domainUpdateJSON.toUtf8());
}
// TODO: have data-web respond with ice-server hostname to use
void DomainServer::sendHeartbeatToIceServer() {
if (!_iceServerSocket.getAddress().isNull()) {
DependencyManager::get<LimitedNodeList>()->sendHeartbeatToIceServer(_iceServerSocket);
auto& accountManager = AccountManager::getInstance();
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
if (!accountManager.getAccountInfo().hasPrivateKey()) {
qWarning() << "Cannot send an ice-server heartbeat without a private key for signature.";
qWarning() << "Waiting for keypair generation to complete before sending ICE heartbeat.";
if (!limitedNodeList->getSessionUUID().isNull()) {
accountManager.generateNewDomainKeypair(limitedNodeList->getSessionUUID());
} else {
qWarning() << "Attempting to send ICE server heartbeat with no domain ID. This is not supported";
}
return;
}
// NOTE: I'd love to specify the correct size for the packet here, but it's a little trickey with
// QDataStream and the possibility of IPv6 address for the sockets.
if (!_iceServerHeartbeatPacket) {
_iceServerHeartbeatPacket = NLPacket::create(PacketType::ICEServerHeartbeat);
}
bool shouldRecreatePacket = false;
if (_iceServerHeartbeatPacket->getPayloadSize() > 0) {
// if either of our sockets have changed we need to re-sign the heartbeat
// first read the sockets out from the current packet
_iceServerHeartbeatPacket->seek(0);
QDataStream heartbeatStream(_iceServerHeartbeatPacket.get());
QUuid senderUUID;
HifiSockAddr publicSocket, localSocket;
heartbeatStream >> senderUUID >> publicSocket >> localSocket;
if (senderUUID != limitedNodeList->getSessionUUID()
|| publicSocket != limitedNodeList->getPublicSockAddr()
|| localSocket != limitedNodeList->getLocalSockAddr()) {
shouldRecreatePacket = true;
}
} else {
shouldRecreatePacket = true;
}
if (shouldRecreatePacket) {
// either we don't have a heartbeat packet yet or some combination of sockets, ID and keypair have changed
// and we need to make a new one
// reset the position in the packet before writing
_iceServerHeartbeatPacket->reset();
// write our plaintext data to the packet
QDataStream heartbeatDataStream(_iceServerHeartbeatPacket.get());
heartbeatDataStream << limitedNodeList->getSessionUUID()
<< limitedNodeList->getPublicSockAddr() << limitedNodeList->getLocalSockAddr();
// setup a QByteArray that points to the plaintext data
auto plaintext = QByteArray::fromRawData(_iceServerHeartbeatPacket->getPayload(), _iceServerHeartbeatPacket->getPayloadSize());
// generate a signature for the plaintext data in the packet
auto signature = accountManager.getAccountInfo().signPlaintext(plaintext);
// pack the signature with the data
heartbeatDataStream << signature;
}
// send the heartbeat packet to the ice server now
limitedNodeList->sendUnreliablePacket(*_iceServerHeartbeatPacket, _iceServerSocket);
}
}
@ -1970,3 +2015,31 @@ void DomainServer::processNodeDisconnectRequestPacket(QSharedPointer<ReceivedMes
});
}
}
void DomainServer::processICEServerHeartbeatDenialPacket(QSharedPointer<ReceivedMessage> message) {
static const int NUM_HEARTBEAT_DENIALS_FOR_KEYPAIR_REGEN = 3;
static int numHeartbeatDenials = 0;
if (++numHeartbeatDenials > NUM_HEARTBEAT_DENIALS_FOR_KEYPAIR_REGEN) {
qDebug() << "Received" << NUM_HEARTBEAT_DENIALS_FOR_KEYPAIR_REGEN << "heartbeat denials from ice-server"
<< "- re-generating keypair now";
// we've hit our threshold of heartbeat denials, trigger a keypair re-generation
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
AccountManager::getInstance().generateNewDomainKeypair(limitedNodeList->getSessionUUID());
// reset our number of heartbeat denials
numHeartbeatDenials = 0;
}
}
void DomainServer::handleKeypairChange() {
if (_iceServerHeartbeatPacket) {
// reset the payload size of the ice-server heartbeat packet - this causes the packet to be re-generated
// the next time we go to send an ice-server heartbeat
_iceServerHeartbeatPacket->setPayloadSize(0);
// send a heartbeat to the ice server immediately
sendHeartbeatToIceServer();
}
}

View file

@ -61,6 +61,7 @@ public slots:
void processNodeJSONStatsPacket(QSharedPointer<ReceivedMessage> packetList, SharedNodePointer sendingNode);
void processPathQueryPacket(QSharedPointer<ReceivedMessage> packet);
void processNodeDisconnectRequestPacket(QSharedPointer<ReceivedMessage> message);
void processICEServerHeartbeatDenialPacket(QSharedPointer<ReceivedMessage> message);
private slots:
void aboutToQuit();
@ -78,16 +79,16 @@ private slots:
void handleTempDomainError(QNetworkReply& requestReply);
void queuedQuit(QString quitMessage, int exitCode);
void handleKeypairChange();
private:
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
bool optionallySetupOAuth();
bool optionallyReadX509KeyAndCertificate();
bool optionallySetupAssignmentPayment();
void optionallyGetTemporaryName(const QStringList& arguments);
bool didSetupAccountManagerWithAccessToken();
bool resetAccountManagerAccessToken();
void setupAutomaticNetworking();
@ -153,6 +154,7 @@ private:
DomainServerSettingsManager _settingsManager;
HifiSockAddr _iceServerSocket;
std::unique_ptr<NLPacket> _iceServerHeartbeatPacket;
QTimer* _iceHeartbeatTimer { nullptr }; // this looks like it dangles when created but it's parented to the DomainServer

View file

@ -206,8 +206,9 @@ function maybeGoActive(event) {
goActive();
}
}
var wasHmdActive = false;
var wasMouseCaptured = false;
var wasHmdActive = HMD.active;
var wasMouseCaptured = Reticle.mouseCaptured;
function maybeGoAway() {
if (HMD.active !== wasHmdActive) {
wasHmdActive = !wasHmdActive;

View file

@ -46,7 +46,7 @@ function emitter(jointName) {
x:0,
y: 0,
z: 0,
w: Math.PI
w: 1
},
emitRadiusStart: 0,
polarStart: 0,
@ -84,7 +84,7 @@ function emitter(jointName) {
alpha: 1,
alphaSpread: 0,
alphaStart: 1,
alphaFinish: 1
alphaFinish: 1
});
return newEmitter;
}

View file

@ -0,0 +1,689 @@
//
// flappyAvatars.js
// examples/toybox
//
// Created by Clement 3/2/16
// Copyright 2015 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
//
(function() {
// Constants
var TRIGGER_CONTROLS = [
Controller.Standard.LT,
Controller.Standard.RT,
];
var G = 4.0;
Number.prototype.clamp = function(min, max) {
return Math.min(Math.max(this, min), max);
};
var entityManager = new EntityManager();
// Class definitions
function Avatar(DEFAULT_X, DEFAULT_Y, rotation, to3DPosition) {
var DIMENSION = 0.15;
var JUMP_VELOCITY = 1.0;
var xPosition = DEFAULT_X;
var color = { red: 0, green: 0, blue: 255 };
var dimensionsSet = false;
var dimensions = { x: DIMENSION, y: DIMENSION, z: DIMENSION };
var yPosition = DEFAULT_Y;
var yVelocity = 0.0;
var yAcceleration = -G;
var airSwipeSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Air Swipe 05.wav");
var injector = null;
this.position = function() {
return { x: xPosition, y: yPosition };
}
this.dimensions = function() {
return dimensions;
}
var id = entityManager.add({
type: "Model",
modelURL: MyAvatar.skeletonModelURL,
animation: {
url: "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/fly.fbx",
running: true,
fps: 30,
firstFrame: 1.0,
lastFrame: 80.0,
currentFrame: 1.0,
loop: true,
hold: false
},
position: to3DPosition(this.position()),
rotation: rotation,
dimensions: dimensions
});
this.changeModel = function(modelURL) {
dimensionsSet = false;
dimensions = { x: 0.10, y: 0.10, z: 0.01 };
Entities.editEntity(id, {
modelURL: modelURL,
rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, -90, 0)),
dimensions: dimensions,
animation: {running: false}
});
airSwipeSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/8bit Jump 03.wav");
injector = null;
}
this.jump = function() {
yVelocity = JUMP_VELOCITY;
if (airSwipeSound.downloaded && !injector) {
injector = Audio.playSound(airSwipeSound, { position: to3DPosition(this.position()), volume: 0.05 });
} else if (injector) {
injector.restart();
}
}
this.update = function(deltaTime) {
if (!dimensionsSet) {
var properties = Entities.getEntityProperties(id, ["naturalDimensions"]);
var naturalDimensions = properties.naturalDimensions;
if (naturalDimensions.x != 1 || naturalDimensions.y != 1 || naturalDimensions.z != 1) {
var max = Math.max(naturalDimensions.x, Math.max(naturalDimensions.y, naturalDimensions.z));
dimensions.x = naturalDimensions.x / max * dimensions.x;
dimensions.y = naturalDimensions.y / max * dimensions.y;
dimensions.z = naturalDimensions.z / max * dimensions.z;
dimensionsSet = true;
Entities.editEntity(id, {
dimensions: dimensions
});
}
} else {
dimensions = Entities.getEntityProperties(id, ["dimensions"]).dimensions;
}
yPosition += deltaTime * (yVelocity + deltaTime * yAcceleration / 2.0);
yVelocity += deltaTime * yAcceleration;
}
this.draw = function() {
Entities.editEntity(id, {
position: to3DPosition(this.position())
});
}
this.reset = function() {
yPosition = DEFAULT_Y;
yVelocity = 0.0;
}
}
function Coin(xPosition, yPosition, to3DPosition) {
var velocity = 0.4;
var dimensions = { x: 0.0625, y: 0.0625, z: 0.0088 };
this.position = function() {
return { x: xPosition, y: yPosition };
}
var id = entityManager.add({
type: "Model",
modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/coin.fbx",
angularVelocity: { x: 0, y: 20, z: 0 },
position: to3DPosition(this.position()),
dimensions:dimensions
});
this.update = function(deltaTime) {
xPosition -= deltaTime * velocity;
}
this.isColliding = function(avatar) {
var deltaX = Math.abs(this.position().x - avatar.position().x);
var deltaY = Math.abs(this.position().Y - avatar.position().Y);
if (deltaX < (avatar.dimensions().x + dimensions.x) / 2.0 &&
deltaX < (avatar.dimensions().y + dimensions.y) / 2.0) {
return true;
}
return false;
}
this.draw = function() {
Entities.editEntity(id, { position: to3DPosition({ x: xPosition, y: yPosition }) });
}
this.clear = function() {
entityManager.remove(id);
}
}
function Pipe(xPosition, yPosition, height, gap, to3DPosition) {
var velocity = 0.4;
var width = 0.1;
this.position = function() {
return xPosition;
}
var upHeight = yPosition - (height + gap);
var upYPosition = height + gap + upHeight / 2.0;
var idUp = entityManager.add({
type: "Model",
modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx",
rotation: Quat.fromPitchYawRollDegrees(180, 0, 0),
position: to3DPosition({ x: xPosition, y: upYPosition }),
dimensions: { x: width, y: upHeight, z: width }
});
var idDown = entityManager.add({
type: "Model",
modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx",
position: to3DPosition({ x: xPosition, y: height / 2.0 }),
dimensions: { x: width, y: height, z: width }
});
this.update = function(deltaTime) {
xPosition -= deltaTime * velocity;
}
this.isColliding = function(avatar) {
var deltaX = Math.abs(this.position() - avatar.position().x);
if (deltaX < (avatar.dimensions().z + width) / 2.0) {
var factor = 0.8;
var upDistance = (yPosition - upHeight) - (avatar.position().y + avatar.dimensions().y * factor);
var downDistance = (avatar.position().y - avatar.dimensions().y * factor) - height;
if (upDistance <= 0 || downDistance <= 0) {
return true;
}
}
return false;
}
this.draw = function() {
Entities.editEntity(idUp, { position: to3DPosition({ x: xPosition, y: upYPosition }) });
Entities.editEntity(idDown, { position: to3DPosition({ x: xPosition, y: height / 2.0 }) });
}
this.clear = function() {
entityManager.remove(idUp);
entityManager.remove(idDown);
}
}
function Pipes(newPipesPosition, newPipesHeight, to3DPosition, moveScore) {
var lastPipe = 0;
var pipesInterval = 2.0;
var pipes = new Array();
var coins = new Array();
var coinsSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Coin.wav");
var injector = null;
this.update = function(deltaTime, gameTime, startedPlaying) {
// Move pipes forward
pipes.forEach(function(element) {
element.update(deltaTime);
});
// Move coins forward
coins.forEach(function(element) {
element.update(deltaTime);
});
// Delete pipes over the end
var count = 0;
while(count < pipes.length && pipes[count].position() <= 0.0) {
pipes[count].clear();
count++;
}
if (count > 0) {
pipes = pipes.splice(count);
}
// Delete coins over the end
count = 0;
while(count < coins.length && coins[count].position() <= 0.0) {
coins[count].clear();
count++;
}
if (count > 0) {
coins = coins.splice(count);
}
// Make new pipes and coins
if (startedPlaying && gameTime - lastPipe > pipesInterval) {
var min = 0.4;
var max = 0.7;
var height = Math.random() * (max - min) + min;
pipes.push(new Pipe(newPipesPosition, newPipesHeight, height, 0.5, to3DPosition));
coins.push(new Coin(newPipesPosition, height + 0.5 / 2.0, to3DPosition));
lastPipe = gameTime;
}
}
this.isColliding = function(avatar) {
// Check coin collection
var collected = -1;
coins.forEach(function(element, index) {
if (element.isColliding(avatar)) {
element.clear();
collected = index;
moveScore(1);
if (coinsSound.downloaded && !injector) {
injector = Audio.playSound(coinsSound, { position: to3DPosition({ x: newPipesPosition, y: newPipesHeight }), volume: 0.1 });
} else if (injector) {
injector.restart();
}
}
});
if (collected > -1) {
coins.splice(collected, 1);
}
// Check collisions
var isColliding = false;
pipes.forEach(function(element) {
isColliding |= element.isColliding(avatar);
});
return isColliding;
}
this.draw = function() {
// Drawing pipes
pipes.forEach(function(element) {
element.draw();
});
// Drawing coins
coins.forEach(function(element) {
element.draw();
});
}
this.clear = function() {
// Clearing pipes
pipes.forEach(function(element) {
element.clear();
});
pipes = new Array();
// Clearing coins
coins.forEach(function(element) {
element.clear();
});
coins = new Array();
}
}
function Score(space, bestScore) {
var score = 0;
var highScore = bestScore;
var topOffset = Vec3.multiplyQbyV(space.orientation, { x: -0.1, y: 0.2, z: -0.2 });
var topLeft = Vec3.sum(space.position, topOffset);
var bottomOffset = Vec3.multiplyQbyV(space.orientation, { x: -0.1, y: 0.0, z: -0.2 });
var bottomLeft = Vec3.sum(space.position, bottomOffset);
var numberDimensions = { x: 0.0660, y: 0.1050, z: 0.0048 };
function numberUrl(number) {
return "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/" + number + ".fbx"
}
function digitPosition(digit) {
return Vec3.multiplyQbyV(space.orientation, { x: 0.3778 + digit * (numberDimensions.x + 0.01), y: 0.0, z: 0.0 });
}
this.score = function() {
return score;
}
this.highScore = function() {
return highScore;
}
var numDigits = 3;
var bestId = entityManager.add({
type: "Model",
modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/best.fbx",
position: topLeft,
rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)),
dimensions: { x: 0.2781, y: 0.0063, z: 0.1037 }
});
var bestDigitsId = []
for (var i = 0; i < numDigits; i++) {
bestDigitsId[i] = entityManager.add({
type: "Model",
modelURL: numberUrl(0),
position: Vec3.sum(topLeft, digitPosition(i)),
rotation: space.orientation,
dimensions: numberDimensions
});
}
var scoreId = entityManager.add({
type: "Model",
modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/score.fbx",
position: bottomLeft,
rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)),
dimensions: { x: 0.3678, y: 0.0063, z: 0.1037 }
});
var scoreDigitsId = []
for (var i = 0; i < numDigits; i++) {
scoreDigitsId[i] = entityManager.add({
type: "Model",
modelURL: numberUrl(0),
position: Vec3.sum(bottomLeft, digitPosition(i)),
rotation: space.orientation,
dimensions: numberDimensions
});
}
this.moveScore = function(delta) {
score += delta;
if (score > highScore) {
highScore = score;
}
}
this.resetScore = function() {
score = 0;
}
this.draw = function() {
for (var i = 0; i < numDigits; i++) {
Entities.editEntity(bestDigitsId[i], { modelURL: numberUrl(Math.floor((highScore / Math.pow(10, numDigits- i - 1)) % 10)) });
}
for (var i = 0; i < numDigits; i++) {
Entities.editEntity(scoreDigitsId[i], { modelURL: numberUrl(Math.floor(score / Math.pow(10, numDigits - i - 1)) % 10) });
}
}
}
function Game(bestScore) {
// public methods
this.start = function() {
if (!isRunning) {
isRunning = true;
setup();
}
}
this.stop = function() {
if (isRunning) {
cleanup();
isRunning = false;
}
}
// Game loop setup
var timestamp = 0;
this.idle = function(triggerValue) {
var now = Date.now();
var deltaTime = (now - timestamp) / 1000.0;
if (timestamp === 0) {
deltaTime = 0;
}
gameTime += deltaTime;
inputs(triggerValue);
update(deltaTime);
draw();
timestamp = now;
}
// Constants
var spaceDimensions = { x: 2.0, y: 1.5, z: 0.01 };
var spaceDistance = 1.5;
var spaceYOffset = 0.6;
// Private game state
var that = this;
var isRunning = false;
var startedPlaying = false;
var coolDown = 1.5;
var lastLost = -coolDown;
var gameTime = 0;
var isJumping = false;
var lastJumpValue = 0.0;
var lastTriggerValue = 0.0;
var TRIGGER_THRESHOLD = 0.9;
var space = null;
var avatar = null;
var pipes = null;
var score = null;
var gameOverSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Game Over.wav");
var injector = null;
var directions = ["UP", "DOWN", "LEFT", "RIGHT"];
var sequence = [directions[0], directions[0], directions[1], directions[1], directions[2], directions[3], directions[2], directions[3], "b", "a"];
var current = 0;
function keyPress(event) {
if (event.text === sequence[current]) {
++current;
} else {
current = 0;
}
if (current === sequence.length) {
avatar.changeModel("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/mario.fbx");
current = 0;
}
}
var isBoardReset = true;
function moveScore(delta) {
score.moveScore(delta);
}
this.score = function() {
return score.score();
}
this.highScore = function() {
return score.highScore();
}
function setup() {
space = {
position: getSpacePosition(),
orientation: getSpaceOrientation(),
dimensions: getSpaceDimensions()
}
var rotation = Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(0, 90, 0));
avatar = new Avatar(space.dimensions.x / 2.0, space.dimensions.y / 2.0, rotation, to3DPosition);
pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition, moveScore);
score = new Score(space, bestScore);
Controller.keyPressEvent.connect(keyPress);
}
function inputs(triggerValue) {
if (!startedPlaying && !isBoardReset && (gameTime - lastLost) > coolDown) {
score.resetScore();
avatar.reset();
pipes.clear();
isBoardReset = true;
}
if (triggerValue > TRIGGER_THRESHOLD &&
lastTriggerValue < TRIGGER_THRESHOLD &&
(gameTime - lastLost) > coolDown) {
isJumping = true;
startedPlaying = true;
}
lastTriggerValue = triggerValue;
}
function update(deltaTime) {
// Keep entities alive
entityManager.update(deltaTime);
if (!startedPlaying && (gameTime - lastLost) < coolDown && !isBoardReset) {
return;
}
// Update Avatar
if (!startedPlaying && avatar.position().y < spaceDimensions.y / 2.0) {
isJumping = true;
}
// Apply jumps
if (isJumping) {
avatar.jump();
isJumping = false;
}
avatar.update(deltaTime);
pipes.update(deltaTime, gameTime, startedPlaying);
// Check lost
var hasLost = avatar.position().y < 0.0 ||
avatar.position().y > space.dimensions.y ||
pipes.isColliding(avatar);
// Cleanup
if (hasLost) {
if (gameOverSound.downloaded && !injector) {
injector = Audio.playSound(gameOverSound, { position: space.position, volume: 0.4 });
} else if (injector) {
injector.restart();
}
isBoardReset = false;
startedPlaying = false;
lastLost = gameTime;
}
}
function draw() {
avatar.draw();
pipes.draw();
score.draw();
}
function cleanup() {
entityManager.removeAll();
Controller.keyPressEvent.disconnect(keyPress);
}
// Private methods
function getSpacePosition() {
var forward = Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.FRONT);
var spacePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(spaceDistance, forward));
return Vec3.sum(spacePosition, Vec3.multiply(spaceYOffset, Vec3.UP));
}
function getSpaceOrientation() {
return MyAvatar.orientation;
}
function getSpaceDimensions() {
return spaceDimensions;
}
function to3DPosition(position) {
var position2D = {
x: position.x - space.dimensions.x / 2.0,
y: position.y - space.dimensions.y / 2.0,
z: 0.0
}
return Vec3.sum(space.position, Vec3.multiplyQbyV(space.orientation, position2D));
}
}
function EntityManager() {
var OBJECTS_LIFETIME = 1;
var entities = new Array();
var lifetime = OBJECTS_LIFETIME;
this.setLifetime = function(newLifetime) {
lifetime = newLifetime;
this.update();
}
this.add = function(properties) {
// Add to scene
properties.lifetime = lifetime;
var entityID = Entities.addEntity(properties);
// Add to array
entities.push({ id: entityID, properties: properties });
return entityID;
}
this.update = function(deltaTime) {
entities.forEach(function(element) {
// Get entity's age
var properties = Entities.getEntityProperties(element.id, ["age"]);
// Update entity's lifetime
Entities.editEntity(element.id, { lifetime: properties.age + lifetime });
});
}
this.remove = function(entityID) {
// Remove from scene
Entities.deleteEntity(entityID);
// Remove from array
entities = entities.filter(function(element) {
return element.id !== entityID;
});
}
this.removeAll = function() {
// Remove all from scene
entities.forEach(function(element) {
Entities.deleteEntity(element.id);
});
// Remove all from array
entities = new Array();
}
}
PartableGame = function() {
this.entityID = null;
this.equipped = false;
this.triggerValue = 0.0;
this.hand = 0;
this.game = null;
};
PartableGame.prototype = {
preload: function(entityID) {
this.entityID = entityID;
},
unload: function() {
},
startEquip: function(id, params) {
this.equipped = true;
this.hand = params[0] == "left" ? 0 : 1;
var bestScore = 0;
var properties = Entities.getEntityProperties(this.entityID, ["userData"]);
var userData = JSON.parse(properties.userData);
if (userData.highScore) {
bestScore = userData.highScore;
}
this.game = new Game(bestScore);
this.game.start();
},
releaseEquip: function(id, params) {
this.equipped = false;
var properties = Entities.getEntityProperties(this.entityID, ["userData"]);
var userData = JSON.parse(properties.userData);
userData.highScore = this.game.highScore();
properties.userData = JSON.stringify(userData);
Entities.editEntity(this.entityID, properties);
this.game.stop();
delete this.game;
},
continueEquip: function(id, params) {
if (!this.equipped) {
return;
}
this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]);
this.game.idle(this.triggerValue);
},
};
// entity scripts always need to return a newly constructed object of our type
return new PartableGame();
});

View file

@ -0,0 +1,34 @@
{
"Entities": [
{
"collisionsWillMove": 1,
"created": "2016-03-03T19:00:10Z",
"dimensions": {
"x": 0.11497055739164352,
"y": 0.11497056484222412,
"z": 0.11497056484222412
},
"dynamic": 1,
"id": "{ee5b25e6-aca2-4dc7-9462-51537d89c126}",
"modelURL": "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/cube.fbx",
"queryAACube": {
"scale": 0.5974045991897583,
"x": -5.1575918197631836,
"y": 23.078603744506836,
"z": 16.521066665649414
},
"rotation": {
"w": 0.92288088798522949,
"x": -0.10148775577545166,
"y": -0.13279926776885986,
"z": 0.34688329696655273
},
"script": "https://raw.githubusercontent.com/Atlante45/hifi/feat/hackaton/examples/toybox/flappyAvatars/flappyAvatars.js",
"scriptTimestamp": 1457031937425,
"shapeType": "box",
"type": "Model",
"userData": "{\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.07079616189002991,\"y\":0.20177987217903137,\"z\":0.06374628841876984},{\"x\":-0.5863648653030396,\"y\":-0.46007341146469116,\"z\":0.46949487924575806,\"w\":-0.4733745753765106}],\"LeftHand\":[{\"x\":-0.018704339861869812,\"y\":0.20499876141548157,\"z\":0.08445858210325241},{\"x\":0.2061777561903,\"y\":-0.6629757881164551,\"z\":0.5865269303321838,\"w\":0.41706138849258423}]}},\"grabbableKey\":{\"invertSolidWhileHeld\":true},\"resetMe\":{\"resetMe\":true},\"highScore\":0}"
}
],
"Version": 57
}

View file

@ -0,0 +1,51 @@
//
// ddebugFramBuffer.js
// examples/utilities/tools/render
//
// Sam Gateau created on 2/18/2016.
// Copyright 2016 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
//
var DDB = Render.RenderDeferredTask.DebugDeferredBuffer;
oldConfig = DDB.toJSON();
DDB.enabled = true;
// Set up the qml ui
var qml = Script.resolvePath('framebuffer.qml');
var window = new OverlayWindow({
title: 'Framebuffer Debug',
source: qml,
width: 400, height: 400,
});
window.setPosition(25, 50);
window.closed.connect(function() { Script.stop(); });
// Debug buffer sizing
var resizing = false;
Controller.mousePressEvent.connect(function (e) {
if (shouldStartResizing(e.x)) {
resizing = true;
}
});
Controller.mouseReleaseEvent.connect(function() { resizing = false; });
Controller.mouseMoveEvent.connect(function (e) { resizing && setDebugBufferSize(e.x); });
function shouldStartResizing(eventX) {
var x = Math.abs(eventX - Window.innerWidth * (1.0 + DDB.size.x) / 2.0);
var mode = DDB.mode;
return mode !== -1 && x < 20;
}
function setDebugBufferSize(x) {
x = (2.0 * (x / Window.innerWidth) - 1.0); // scale
x = Math.min(Math.max(-1, x), 1); // clamp
DDB.size = { x: x, y: -1, z: 1, w: 1 };
}
Script.scriptEnding.connect(function () { DDB.fromJSON(oldConfig); });

View file

@ -0,0 +1,52 @@
//
// main.qml
// examples/utilities/tools/render
//
// Created by Zach Pomerantz on 2/8/2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
Column {
spacing: 8
Column {
id: debug
property var config: Render.getConfig("DebugDeferredBuffer")
function setDebugMode(mode) {
debug.config.enabled = (mode != -1);
debug.config.mode = mode;
}
Label { text: qsTr("Debug Buffer") }
ExclusiveGroup { id: bufferGroup }
Repeater {
model: [
"Off",
"Depth",
"Albedo",
"Normal",
"Roughness",
"Metallic",
"Emissive",
"Occlusion",
"Lightmap",
"Lighting",
"Shadow",
"Pyramid Depth",
"Ambient Occlusion",
"Custom Shader"
]
RadioButton {
text: qsTr(modelData)
exclusiveGroup: bufferGroup
checked: index == 0
onCheckedChanged: if (checked) debug.setDebugMode(index - 1);
}
}
}
}

View file

@ -6,3 +6,17 @@ setup_hifi_project(Network)
# link the shared hifi libraries
link_hifi_libraries(embedded-webserver networking shared)
package_libraries_for_deployment()
# find OpenSSL
find_package(OpenSSL REQUIRED)
if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include")
# this is a user on OS X using system OpenSSL, which is going to throw warnings since they're deprecating for their common crypto
message(WARNING "The found version of OpenSSL is the OS X system version. This will produce deprecation warnings."
"\nWe recommend you install a newer version (at least 1.0.1h) in a different directory and set OPENSSL_ROOT_DIR in your env so Cmake can find it.")
endif ()
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
# append OpenSSL to our list of libraries to link
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})

View file

@ -9,14 +9,21 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QTimer>
#include "IceServer.h"
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <QtCore/QJsonDocument>
#include <QtCore/QTimer>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <LimitedNodeList.h>
#include <NetworkingConstants.h>
#include <udt/PacketHeaders.h>
#include <SharedUtil.h>
#include "IceServer.h"
const int CLEAR_INACTIVE_PEERS_INTERVAL_MSECS = 1 * 1000;
const int PEER_SILENCE_THRESHOLD_MSECS = 5 * 1000;
@ -45,7 +52,6 @@ IceServer::IceServer(int argc, char* argv[]) :
QTimer* inactivePeerTimer = new QTimer(this);
connect(inactivePeerTimer, &QTimer::timeout, this, &IceServer::clearInactivePeers);
inactivePeerTimer->start(CLEAR_INACTIVE_PEERS_INTERVAL_MSECS);
}
bool IceServer::packetVersionMatch(const udt::Packet& packet) {
@ -70,9 +76,14 @@ void IceServer::processPacket(std::unique_ptr<udt::Packet> packet) {
if (nlPacket->getType() == PacketType::ICEServerHeartbeat) {
SharedNetworkPeer peer = addOrUpdateHeartbeatingPeer(*nlPacket);
// so that we can send packets to the heartbeating peer when we need, we need to activate a socket now
peer->activateMatchingOrNewSymmetricSocket(nlPacket->getSenderSockAddr());
if (peer) {
// so that we can send packets to the heartbeating peer when we need, we need to activate a socket now
peer->activateMatchingOrNewSymmetricSocket(nlPacket->getSenderSockAddr());
} else {
// we couldn't verify this peer - respond back to them so they know they may need to perform keypair re-generation
static auto deniedPacket = NLPacket::create(PacketType::ICEServerHeartbeatDenied);
_serverSocket.writePacket(*deniedPacket, nlPacket->getSenderSockAddr());
}
} else if (nlPacket->getType() == PacketType::ICEServerQuery) {
QDataStream heartbeatStream(nlPacket.get());
@ -114,31 +125,135 @@ SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(NLPacket& packet) {
// pull the UUID, public and private sock addrs for this peer
QUuid senderUUID;
HifiSockAddr publicSocket, localSocket;
QByteArray signature;
QDataStream heartbeatStream(&packet);
heartbeatStream >> senderUUID;
heartbeatStream >> publicSocket >> localSocket;
heartbeatStream >> senderUUID >> publicSocket >> localSocket;
// make sure we have this sender in our peer hash
SharedNetworkPeer matchingPeer = _activePeers.value(senderUUID);
auto signedPlaintext = QByteArray::fromRawData(packet.getPayload(), heartbeatStream.device()->pos());
heartbeatStream >> signature;
if (!matchingPeer) {
// if we don't have this sender we need to create them now
matchingPeer = QSharedPointer<NetworkPeer>::create(senderUUID, publicSocket, localSocket);
_activePeers.insert(senderUUID, matchingPeer);
// make sure this is a verified heartbeat before performing any more processing
if (isVerifiedHeartbeat(senderUUID, signedPlaintext, signature)) {
// make sure we have this sender in our peer hash
SharedNetworkPeer matchingPeer = _activePeers.value(senderUUID);
qDebug() << "Added a new network peer" << *matchingPeer;
if (!matchingPeer) {
// if we don't have this sender we need to create them now
matchingPeer = QSharedPointer<NetworkPeer>::create(senderUUID, publicSocket, localSocket);
_activePeers.insert(senderUUID, matchingPeer);
qDebug() << "Added a new network peer" << *matchingPeer;
} else {
// we already had the peer so just potentially update their sockets
matchingPeer->setPublicSocket(publicSocket);
matchingPeer->setLocalSocket(localSocket);
}
// update our last heard microstamp for this network peer to now
matchingPeer->setLastHeardMicrostamp(usecTimestampNow());
return matchingPeer;
} else {
// we already had the peer so just potentially update their sockets
matchingPeer->setPublicSocket(publicSocket);
matchingPeer->setLocalSocket(localSocket);
// not verified, return the empty peer object
return SharedNetworkPeer();
}
}
bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& plaintext, const QByteArray& signature) {
// check if we have a private key for this domain ID - if we do not then fire off the request for it
auto it = _domainPublicKeys.find(domainID);
if (it != _domainPublicKeys.end()) {
// attempt to verify the signature for this heartbeat
const unsigned char* publicKeyData = reinterpret_cast<const unsigned char*>(it->second.constData());
// first load up the public key into an RSA struct
RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, it->second.size());
if (rsaPublicKey) {
auto hashedPlaintext = QCryptographicHash::hash(plaintext, QCryptographicHash::Sha256);
int verificationResult = RSA_verify(NID_sha256,
reinterpret_cast<const unsigned char*>(hashedPlaintext.constData()),
hashedPlaintext.size(),
reinterpret_cast<const unsigned char*>(signature.constData()),
signature.size(),
rsaPublicKey);
// free up the public key and remove connection token before we return
RSA_free(rsaPublicKey);
if (verificationResult == 1) {
// this is the only success case - we return true here to indicate that the heartbeat is verified
return true;
} else {
qDebug() << "Failed to verify heartbeat for" << domainID << "- re-requesting public key from API.";
}
} else {
// we can't let this user in since we couldn't convert their public key to an RSA key we could use
qWarning() << "Could not convert in-memory public key for" << domainID << "to usable RSA public key.";
qWarning() << "Re-requesting public key from API";
}
}
// update our last heard microstamp for this network peer to now
matchingPeer->setLastHeardMicrostamp(usecTimestampNow());
// we could not verify this heartbeat (missing public key, could not load public key, bad actor)
// ask the metaverse API for the right public key and return false to indicate that this is not verified
requestDomainPublicKey(domainID);
return matchingPeer;
return false;
}
void IceServer::requestDomainPublicKey(const QUuid& domainID) {
// send a request to the metaverse API for the public key for this domain
QNetworkAccessManager* manager = new QNetworkAccessManager { this };
connect(manager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished);
QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL };
QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID));
publicKeyURL.setPath(publicKeyPath);
QNetworkRequest publicKeyRequest { publicKeyURL };
publicKeyRequest.setAttribute(QNetworkRequest::User, domainID);
qDebug() << "Requesting public key for domain with ID" << domainID;
manager->get(publicKeyRequest);
}
void IceServer::publicKeyReplyFinished(QNetworkReply* reply) {
// get the domain ID from the QNetworkReply attribute
QUuid domainID = reply->request().attribute(QNetworkRequest::User).toUuid();
if (reply->error() == QNetworkReply::NoError) {
// pull out the public key and store it for this domain
// the response should be JSON
QJsonDocument responseDocument = QJsonDocument::fromJson(reply->readAll());
static const QString DATA_KEY = "data";
static const QString PUBLIC_KEY_KEY = "public_key";
static const QString STATUS_KEY = "status";
static const QString SUCCESS_VALUE = "success";
auto responseObject = responseDocument.object();
if (responseObject[STATUS_KEY].toString() == SUCCESS_VALUE) {
auto dataObject = responseObject[DATA_KEY].toObject();
if (dataObject.contains(PUBLIC_KEY_KEY)) {
_domainPublicKeys[domainID] = QByteArray::fromBase64(dataObject[PUBLIC_KEY_KEY].toString().toUtf8());
} else {
qWarning() << "There was no public key present in response for domain with ID" << domainID;
}
} else {
qWarning() << "The metaverse API did not return success for public key request for domain with ID" << domainID;
}
} else {
// there was a problem getting the public key for the domain
// log it since it will be re-requested on the next heartbeat
qWarning() << "Error retreiving public key for domain with ID" << domainID << "-" << reply->errorString();
}
}
void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr) {

View file

@ -16,13 +16,15 @@
#include <QtCore/QSharedPointer>
#include <QUdpSocket>
#include <UUIDHasher.h>
#include <NetworkPeer.h>
#include <HTTPConnection.h>
#include <HTTPManager.h>
#include <NLPacket.h>
#include <udt/Socket.h>
typedef QHash<QUuid, SharedNetworkPeer> NetworkPeerHash;
class QNetworkReply;
class IceServer : public QCoreApplication, public HTTPRequestHandler {
Q_OBJECT
@ -31,6 +33,7 @@ public:
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false);
private slots:
void clearInactivePeers();
void publicKeyReplyFinished(QNetworkReply* reply);
private:
bool packetVersionMatch(const udt::Packet& packet);
void processPacket(std::unique_ptr<udt::Packet> packet);
@ -38,10 +41,19 @@ private:
SharedNetworkPeer addOrUpdateHeartbeatingPeer(NLPacket& incomingPacket);
void sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr);
bool isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& plaintext, const QByteArray& signature);
void requestDomainPublicKey(const QUuid& domainID);
QUuid _id;
udt::Socket _serverSocket;
using NetworkPeerHash = QHash<QUuid, SharedNetworkPeer>;
NetworkPeerHash _activePeers;
HTTPManager _httpManager;
using DomainPublicKeyHash = std::unordered_map<QUuid, QByteArray>;
DomainPublicKeyHash _domainPublicKeys;
};
#endif // hifi_IceServer_h

View file

@ -268,7 +268,7 @@ if (WIN32)
set(TARGET_INSTALL_DIR ${INTERFACE_INSTALL_DIR})
set(TARGET_INSTALL_COMPONENT ${CLIENT_COMPONENT})
manually_install_ssl_eay()
manually_install_openssl_for_qt()
package_libraries_for_deployment()
endif()

View file

@ -18,7 +18,7 @@ Original.Button {
id: button
property int color: 0
width: 120
height: 30
height: 28
style: ButtonStyle {

View file

@ -0,0 +1,70 @@
//
// CheckBox.qml
//
// Created by David Rowe on 26 Feb 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4 as Original
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
Original.CheckBox {
id: checkBox
HifiConstants { id: hifi }
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
readonly property int boxSize: 14
readonly property int boxRadius: 3
readonly property int checkSize: 10
readonly property int checkRadius: 2
style: CheckBoxStyle {
indicator: Rectangle {
id: box
width: boxSize
height: boxSize
radius: boxRadius
gradient: Gradient {
GradientStop {
position: 0.2
color: pressed || hovered
? (checkBox.isLightColorScheme ? hifi.colors.checkboxDarkStart : hifi.colors.checkboxLightStart)
: (checkBox.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart)
}
GradientStop {
position: 1.0
color: pressed || hovered
? (checkBox.isLightColorScheme ? hifi.colors.checkboxDarkFinish : hifi.colors.checkboxLightFinish)
: (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish)
}
}
Rectangle {
id: check
width: checkSize
height: checkSize
radius: checkRadius
anchors.centerIn: parent
color: hifi.colors.checkboxChecked
border.width: 1
border.color: hifi.colors.checkboxCheckedBorder
visible: checked && !pressed || !checked && pressed
}
}
label: Label {
text: control.text
colorScheme: checkBox.colorScheme
x: checkBox.boxSize / 2
wrapMode: Text.Wrap
}
}
}

View file

@ -0,0 +1,202 @@
//
// ComboBox.qml
//
// Created by Bradley Austin David on 27 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
import "." as VrControls
FocusScope {
id: root
property alias model: comboBox.model;
property alias comboBox: comboBox
readonly property alias currentText: comboBox.currentText;
property alias currentIndex: comboBox.currentIndex;
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property string label: ""
property real controlHeight: height + (comboBoxLabel.visible ? comboBoxLabel.height + comboBoxLabel.anchors.bottomMargin : 0)
readonly property ComboBox control: comboBox
implicitHeight: comboBox.height;
focus: true
Rectangle {
id: background
gradient: Gradient {
GradientStop {
position: 0.2
color: popup.visible
? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark)
: (isLightColorScheme ? hifi.colors.dropDownLightStart : hifi.colors.dropDownDarkStart)
}
GradientStop {
position: 1.0
color: popup.visible
? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark)
: (isLightColorScheme ? hifi.colors.dropDownLightFinish : hifi.colors.dropDownDarkFinish)
}
}
anchors.fill: parent
}
SystemPalette { id: palette }
ComboBox {
id: comboBox
anchors.fill: parent
visible: false
height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control.
}
FiraSansSemiBold {
id: textField
anchors {
left: parent.left
leftMargin: hifi.dimensions.textPadding
right: dropIcon.left
verticalCenter: parent.verticalCenter
}
size: hifi.fontSizes.textFieldInput
text: comboBox.currentText
elide: Text.ElideRight
color: controlHover.containsMouse || popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText )
}
Item {
id: dropIcon
anchors { right: parent.right; verticalCenter: parent.verticalCenter }
height: background.height
width: height
Rectangle {
width: 1
height: parent.height
anchors.top: parent.top
anchors.left: parent.left
color: isLightColorScheme ? hifi.colors.faintGray : hifi.colors.baseGray
}
HiFiGlyphs {
anchors {
top: parent.top
topMargin: -8
horizontalCenter: parent.horizontalCenter
}
size: hifi.dimensions.spinnerSize
text: hifi.glyphs.caratDn
color: controlHover.containsMouse || popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText)
}
}
MouseArea {
id: controlHover
hoverEnabled: true
anchors.fill: parent
onClicked: toggleList();
}
function toggleList() {
if (popup.visible) {
hideList();
} else {
showList();
}
}
function showList() {
var r = desktop.mapFromItem(root, 0, 0, root.width, root.height);
listView.currentIndex = root.currentIndex
scrollView.x = r.x;
scrollView.y = r.y + r.height;
var bottom = scrollView.y + scrollView.height;
if (bottom > desktop.height) {
scrollView.y -= bottom - desktop.height + 8;
}
popup.visible = true;
popup.forceActiveFocus();
}
function hideList() {
popup.visible = false;
}
FocusScope {
id: popup
parent: desktop
anchors.fill: parent
z: desktop.zLevels.menu
visible: false
focus: true
MouseArea {
anchors.fill: parent
onClicked: hideList();
}
function previousItem() { listView.currentIndex = (listView.currentIndex + listView.count - 1) % listView.count; }
function nextItem() { listView.currentIndex = (listView.currentIndex + listView.count + 1) % listView.count; }
function selectCurrentItem() { root.currentIndex = listView.currentIndex; hideList(); }
function selectSpecificItem(index) { root.currentIndex = index; hideList(); }
Keys.onUpPressed: previousItem();
Keys.onDownPressed: nextItem();
Keys.onSpacePressed: selectCurrentItem();
Keys.onRightPressed: selectCurrentItem();
Keys.onReturnPressed: selectCurrentItem();
Keys.onEscapePressed: hideList();
ScrollView {
id: scrollView
height: 480
ListView {
id: listView
height: textField.height * count * 1.4
model: root.model
delegate: Rectangle {
width: root.width + 4
height: popupText.implicitHeight * 1.4
color: popupHover.containsMouse ? hifi.colors.primaryHighlight : (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark)
FiraSansSemiBold {
anchors.left: parent.left
anchors.leftMargin: hifi.dimensions.textPadding
anchors.verticalCenter: parent.verticalCenter
id: popupText
text: listView.model[index]
size: hifi.fontSizes.textFieldInput
color: hifi.colors.baseGray
}
MouseArea {
id: popupHover
anchors.fill: parent;
hoverEnabled: true
onEntered: listView.currentIndex = index;
onClicked: popup.selectSpecificItem(index)
}
}
}
}
}
HifiControls.Label {
id: comboBoxLabel
text: root.label
colorScheme: root.colorScheme
anchors.left: parent.left
anchors.bottom: parent.top
anchors.bottomMargin: 4
visible: label != ""
}
}

View file

@ -0,0 +1,133 @@
//
// ContentSection.qml
//
// Created by David Rowe on 16 Feb 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtGraphicalEffects 1.0
import "../styles-uit"
Column {
property string name: "Static Section"
property bool isFirst: false
property bool isCollapsible: false // Set at creation.
property bool isCollapsed: false
spacing: 0 // Defer spacing decisions to individual controls.
anchors {
left: parent.left
leftMargin: hifi.dimensions.contentMargin.x
right: parent.right
rightMargin: hifi.dimensions.contentMargin.x
}
function toggleCollapsed() {
if (isCollapsible) {
isCollapsed = !isCollapsed;
for (var i = 1; i < children.length; i++) {
children[i].visible = !isCollapsed;
}
}
}
Item {
id: sectionName
anchors.left: parent.left
anchors.right: parent.right
height: leadingSpace.height + topBar.height + heading.height + bottomBar.height
Item {
id: leadingSpace
width: 1
height: isFirst ? hifi.dimensions.contentSpacing.y : hifi.dimensions.controlInterlineHeight
anchors.top: parent.top
}
Item {
id: topBar
visible: !isFirst
height: visible ? 2 : 0
anchors.top: leadingSpace.bottom
Rectangle {
id: shadow
width: frame.width
height: 1
color: hifi.colors.baseGrayShadow
x: -hifi.dimensions.contentMargin.x
}
Rectangle {
width: frame.width
height: 1
color: hifi.colors.baseGrayHighlight
x: -hifi.dimensions.contentMargin.x
anchors.top: shadow.bottom
}
}
Item {
id: heading
anchors {
left: parent.left
right: parent.right
top: topBar.bottom
}
height: (isCollapsible ? 3 : 2) * hifi.dimensions.contentSpacing.y
RalewayRegular {
id: title
anchors {
left: parent.left
top: parent.top
topMargin: hifi.dimensions.contentSpacing.y
}
size: hifi.fontSizes.sectionName
font.capitalization: Font.AllUppercase
text: name
color: hifi.colors.lightGrayText
}
HiFiGlyphs {
anchors {
verticalCenter: title.verticalCenter
right: parent.right
rightMargin: -4
}
y: -2
size: hifi.fontSizes.disclosureButton
text: isCollapsed ? hifi.glyphs.disclosureButtonExpand : hifi.glyphs.disclosureButtonCollapse
color: hifi.colors.lightGrayText
visible: isCollapsible
}
MouseArea {
anchors.fill: parent
onClicked: toggleCollapsed()
}
}
LinearGradient {
id: bottomBar
visible: isCollapsible
width: frame.width
height: visible ? 4 : 0
x: -hifi.dimensions.contentMargin.x
anchors.top: heading.bottom
start: Qt.point(0, 0)
end: Qt.point(0, 4)
gradient: Gradient {
GradientStop { position: 0.0; color: hifi.colors.darkGray }
GradientStop { position: 1.0; color: hifi.colors.baseGray } // Equivalent of darkGray0 over baseGray background.
}
cached: true
}
}
}

View file

@ -0,0 +1,20 @@
//
// Label.qml
//
// Created by David Rowe on 26 Feb 2016
// Copyright 2016 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
//
import QtQuick 2.5
import "../styles-uit"
RalewaySemibold {
property int colorScheme: hifi.colorSchemes.light
size: hifi.fontSizes.inputLabel
color: colorScheme == hifi.colorSchemes.light ? hifi.colors.lightGray : hifi.colors.lightGrayText
}

View file

@ -0,0 +1,98 @@
//
// Slider.qml
//
// Created by David Rowe on 27 Feb 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
Slider {
id: slider
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property string label: ""
property real controlHeight: height + (sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0)
height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control.
y: sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0
style: SliderStyle {
groove: Rectangle {
implicitWidth: 50
implicitHeight: hifi.dimensions.sliderGrooveHeight
radius: height / 2
color: isLightColorScheme ? hifi.colors.sliderGutterLight : hifi.colors.sliderGutterDark
Rectangle {
width: parent.height - 2
height: slider.value * slider.width - 1
radius: height / 2
anchors {
top: parent.top
topMargin: width + 1
left: parent.left
leftMargin: 1
}
transformOrigin: Item.TopLeft
rotation: -90
gradient: Gradient {
GradientStop { position: 0.0; color: hifi.colors.blueAccent }
GradientStop { position: 1.0; color: hifi.colors.primaryHighlight }
}
}
}
handle: Rectangle {
implicitWidth: hifi.dimensions.sliderHandleSize
implicitHeight: hifi.dimensions.sliderHandleSize
radius: height / 2
border.width: 1
border.color: isLightColorScheme ? hifi.colors.sliderBorderLight : hifi.colors.sliderBorderDark
gradient: Gradient {
GradientStop {
position: 0.0
color: pressed || hovered
? (isLightColorScheme ? hifi.colors.sliderDarkStart : hifi.colors.sliderLightStart )
: (isLightColorScheme ? hifi.colors.sliderLightStart : hifi.colors.sliderDarkStart )
}
GradientStop {
position: 1.0
color: pressed || hovered
? (isLightColorScheme ? hifi.colors.sliderDarkFinish : hifi.colors.sliderLightFinish )
: (isLightColorScheme ? hifi.colors.sliderLightFinish : hifi.colors.sliderDarkFinish )
}
}
Rectangle {
height: parent.height - 2
width: height
radius: height / 2
anchors.centerIn: parent
color: hifi.colors.transparent
border.width: 1
border.color: hifi.colors.black
}
}
}
HifiControls.Label {
id: sliderLabel
text: slider.label
colorScheme: slider.colorScheme
anchors.left: parent.left
anchors.bottom: parent.top
anchors.bottomMargin: 2
visible: label != ""
}
}

View file

@ -0,0 +1,79 @@
//
// SpinBox.qml
//
// Created by David Rowe on 26 Feb 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
SpinBox {
id: spinBox
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property string label: ""
property real controlHeight: height + (spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0)
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
font.family: firaSansSemiBold.name
font.pixelSize: hifi.fontSizes.textFieldInput
height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control.
y: spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0
style: SpinBoxStyle {
background: Rectangle {
color: isLightColorScheme
? (spinBox.focus ? hifi.colors.white : hifi.colors.lightGray)
: (spinBox.focus ? hifi.colors.black : hifi.colors.baseGrayShadow)
border.color: hifi.colors.primaryHighlight
border.width: spinBox.focus ? 1 : 0
}
textColor: isLightColorScheme
? (spinBox.focus ? hifi.colors.black : hifi.colors.lightGray)
: (spinBox.focus ? hifi.colors.white : hifi.colors.lightGrayText)
selectedTextColor: hifi.colors.black
selectionColor: hifi.colors.primaryHighlight
horizontalAlignment: Qt.AlignLeft
padding.left: hifi.dimensions.textPadding
padding.right: hifi.dimensions.spinnerSize
incrementControl: HiFiGlyphs {
id: incrementButton
text: hifi.glyphs.caratUp
x: 6
y: 2
size: hifi.dimensions.spinnerSize
color: styleData.upPressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray
}
decrementControl: HiFiGlyphs {
text: hifi.glyphs.caratDn
x: 6
y: -3
size: hifi.dimensions.spinnerSize
color: styleData.downPressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray
}
}
HifiControls.Label {
id: spinBoxLabel
text: spinBox.label
colorScheme: spinBox.colorScheme
anchors.left: parent.left
anchors.bottom: parent.top
anchors.bottomMargin: 4
visible: label != ""
}
}

View file

@ -1,65 +0,0 @@
//
// StaticSection.qml
//
// Created by David Rowe on 16 Feb 2016
// Copyright 2016 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
//
import QtQuick 2.5
import "../styles-uit"
Column {
property string name: "Static Section"
property bool hasSeparator: false
spacing: hifi.dimensions.contentSpacing.y
anchors {
left: parent.left
leftMargin: hifi.dimensions.contentMargin.x
right: parent.right
rightMargin: hifi.dimensions.contentMargin.x
}
VerticalSpacer { }
Item {
visible: hasSeparator
anchors.top: sectionName.top
Rectangle {
width: frame.width
height: 1
color: hifi.colors.baseGrayShadow
x: -hifi.dimensions.contentMargin.x
anchors.bottom: highlight.top
}
Rectangle {
id: highlight
width: frame.width
height: 1
color: hifi.colors.baseGrayHighlight
x: -hifi.dimensions.contentMargin.x
anchors.bottom: parent.top
}
}
RalewayRegular {
id: sectionName
text: parent.name
size: hifi.fontSizes.sectionName
font.capitalization: Font.AllUppercase
color: hifi.colors.lightGrayText
verticalAlignment: Text.AlignBottom
height: {
if (hasSeparator) {
hifi.dimensions.contentMargin.y
}
}
}
}

View file

@ -13,25 +13,31 @@ import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
TextField {
id: textField
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property string label: ""
property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height : 0)
placeholderText: textField.placeholderText
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
font.family: firaSansSemiBold.name
font.pixelSize: hifi.fontSizes.textFieldInput
height: implicitHeight + 4 // Make surrounding box higher so that highlight is vertically centered.
placeholderText: textField.label // Instead of separate label (see below).
y: textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0
style: TextFieldStyle {
textColor: textField.colorScheme == hifi.colorSchemes.light
textColor: isLightColorScheme
? (textField.focus ? hifi.colors.black : hifi.colors.lightGray)
: (textField.focus ? hifi.colors.white : hifi.colors.lightGrayText)
background: Rectangle {
color: textField.colorScheme == hifi.colorSchemes.light
color: isLightColorScheme
? (textField.focus ? hifi.colors.white : hifi.colors.lightGray)
: (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow)
border.color: hifi.colors.primaryHighlight
@ -44,16 +50,13 @@ TextField {
padding.right: hifi.dimensions.textPadding
}
/*
// Separate label instead of placeholderText.
RalewaySemibold {
HifiControls.Label {
id: textFieldLabel
text: textField.label
size: hifi.fontSizes.inputLabel
color: hifi.colors.lightGrayText
colorScheme: textField.colorScheme
anchors.left: parent.left
anchors.bottom: parent.top
anchors.bottomMargin: 4
visible: label != ""
}
*/
}

View file

@ -55,8 +55,8 @@ TreeView {
alternateBackgroundColor: parent.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
branchDelegate: HiFiGlyphs {
text: styleData.isExpanded ? hifi.glyphs.disclosureCollapse : hifi.glyphs.disclosureExpand
size: hifi.fontSizes.tableText * 2.5
text: styleData.isExpanded ? hifi.glyphs.caratDn : hifi.glyphs.caratR
size: hifi.fontSizes.carat
color: colorScheme == hifi.colorSchemes.light
? (styleData.selected
? hifi.colors.black

View file

@ -14,5 +14,5 @@ import "../styles-uit"
Item {
width: 1 // Must be non-zero
height: hifi.dimensions.contentSpacing.y
height: hifi.dimensions.controlInterlineHeight
}

View file

@ -1,10 +1,19 @@
//
// PreferencesDialog.qml
//
// Created by Bradley Austin Davis on 24 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import Qt.labs.settings 1.0
import "../controls" as HifiControls
import "../windows"
import "../controls-uit" as HifiControls
import "../styles-uit"
import "../windows-uit"
import "preferences"
Window {
@ -16,6 +25,9 @@ Window {
height: 577
property var sections: []
property var showCategories: []
minSize: Qt.vector2d(400, 500)
HifiConstants { id: hifi }
function saveAll() {
for (var i = 0; i < sections.length; ++i) {
@ -33,10 +45,8 @@ Window {
destroy();
}
Rectangle {
anchors.fill: parent
clip: true
color: "white"
Column {
width: pane.contentWidth
Component {
id: sectionBuilder
@ -64,45 +74,45 @@ Window {
}
if (sections.length) {
sections[0].expanded = true;
// Default sections to expanded/collapsed as appropriate for dialog.
if (sections.length === 1) {
sections[0].collapsable = false
sections[0].expanded = true
} else {
for (i = 0; i < sections.length; i++) {
sections[i].collapsable = true;
sections[i].expanded = true;
}
}
sections[0].isFirst = true;
sections[sections.length - 1].isLast = true;
}
}
Flickable {
id: flickable
clip: true
interactive: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: dialogButtons.top
anchors.bottomMargin: 8
contentHeight: prefControls.height
contentWidth: parent.width
Column {
id: prefControls
anchors.left: parent.left
anchors.right: parent.right
}
Column {
id: prefControls
width: pane.contentWidth
}
Row {
id: dialogButtons
anchors { bottom: parent.bottom; right: parent.right; margins: 8 }
}
Button {
text: "Cancel";
onClicked: root.restoreAll();
}
footer: Row {
anchors {
right: parent.right;
rightMargin: hifi.dimensions.contentMargin.x
verticalCenter: parent.verticalCenter
}
spacing: hifi.dimensions.contentSpacing.x
Button {
text: "Save all changes"
onClicked: root.saveAll();
}
HifiControls.Button {
text: "Save changes"
color: hifi.buttons.blue
onClicked: root.saveAll()
}
HifiControls.Button {
text: "Cancel"
color: hifi.buttons.white
onClicked: root.restoreAll()
}
}
}

View file

@ -1,15 +1,25 @@
//
// AvatarPreference.qml
//
// Created by Bradley Austin Davis on 22 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../../dialogs"
import "../../controls-uit"
Preference {
id: root
property alias buttonText: button.text
property alias text: dataTextField.text
property alias buttonText: button.text
property alias placeholderText: dataTextField.placeholderText
property real spacing: 8
property var browser;
height: labelText.height + Math.max(dataTextField.height, button.height) + spacing
height: control.height + hifi.dimensions.controlInterlineHeight
Component.onCompleted: {
dataTextField.text = preference.value;
@ -41,40 +51,48 @@ Preference {
preference.save();
}
Text {
id: labelText
color: enabled ? "black" : "gray"
text: root.label
}
TextField {
id: dataTextField
placeholderText: root.placeholderText
text: preference.value
style: TextFieldStyle { renderType: Text.QtRendering }
Item {
id: control
anchors {
top: labelText.bottom
left: parent.left
right: button.left
topMargin: root.spacing
rightMargin: root.spacing
right: parent.right
bottom: parent.bottom
}
}
height: Math.max(dataTextField.controlHeight, button.height)
Component {
id: avatarBrowserBuilder;
AvatarBrowser { }
}
Button {
id: button
anchors { right: parent.right; verticalCenter: dataTextField.verticalCenter }
text: "Browse"
onClicked: {
root.browser = avatarBrowserBuilder.createObject(desktop);
root.browser.windowDestroyed.connect(function(){
root.browser = null;
})
TextField {
id: dataTextField
placeholderText: root.placeholderText
text: preference.value
label: root.label
anchors {
left: parent.left
right: button.left
rightMargin: hifi.dimensions.contentSpacing.x
bottom: parent.bottom
}
colorScheme: hifi.colorSchemes.dark
}
Component {
id: avatarBrowserBuilder;
AvatarBrowser { }
}
Button {
id: button
text: "Browse"
anchors {
right: parent.right
verticalCenter: dataTextField.verticalCenter
}
onClicked: {
root.browser = avatarBrowserBuilder.createObject(desktop);
root.browser.windowDestroyed.connect(function(){
root.browser = null;
})
}
}
}
}

View file

@ -1,16 +1,23 @@
//
// BrowsablePreference.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../../dialogs"
import "../../controls-uit"
Preference {
id: root
property alias buttonText: button.text
property alias text: dataTextField.text
property alias placeholderText: dataTextField.placeholderText
property real spacing: 8
height: labelText.height + Math.max(dataTextField.height, button.height) + spacing
height: control.height + hifi.dimensions.controlInterlineHeight
Component.onCompleted: {
dataTextField.text = preference.value;
@ -21,42 +28,49 @@ Preference {
preference.save();
}
Text {
id: labelText
color: enabled ? "black" : "gray"
text: root.label
}
TextField {
id: dataTextField
placeholderText: root.placeholderText
text: preference.value
style: TextFieldStyle { renderType: Text.QtRendering }
Item {
id: control
anchors {
top: labelText.bottom
left: parent.left
right: button.left
topMargin: root.spacing
rightMargin: root.spacing
right: parent.right
bottom: parent.bottom
}
}
height: Math.max(dataTextField.controlHeight, button.height)
Component {
id: fileBrowserBuilder;
FileDialog { selectDirectory: true }
}
TextField {
id: dataTextField
Button {
id: button
anchors { right: parent.right; verticalCenter: dataTextField.verticalCenter }
text: preference.browseLabel
onClicked: {
var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) });
browser.selectedFile.connect(function(fileUrl){
console.log(fileUrl);
dataTextField.text = fileDialogHelper.urlToPath(fileUrl);
});
anchors {
left: parent.left
right: button.left
rightMargin: hifi.dimensions.contentSpacing.x
bottom: parent.bottom
}
label: root.label
placeholderText: root.placeholderText
colorScheme: hifi.colorSchemes.dark
}
Component {
id: fileBrowserBuilder;
FileDialog { selectDirectory: true }
}
Button {
id: button
text: preference.browseLabel
anchors {
right: parent.right
verticalCenter: dataTextField.verticalCenter
}
onClicked: {
var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) });
browser.selectedFile.connect(function(fileUrl){
console.log(fileUrl);
dataTextField.text = fileDialogHelper.urlToPath(fileUrl);
});
}
}
}
}

View file

@ -1,16 +1,29 @@
//
// ButtonPreference.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4 as Original
import "../../controls-uit"
Preference {
id: root
height: button.height
height: button.height + hifi.dimensions.controlInterlineHeight
Component.onCompleted: button.text = preference.name;
function save() { }
Original.Button {
Button {
id: button
onClicked: preference.trigger()
width: 180
anchors.bottom: parent.bottom
}
}

View file

@ -1,10 +1,20 @@
//
// CheckBoxPreference.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../../controls"
import "../../controls-uit"
Preference {
id: root
height: checkBox.implicitHeight
height: spacer.height + Math.max(hifi.dimensions.controlLineHeight, checkBox.implicitHeight)
Component.onCompleted: {
checkBox.checked = preference.value;
@ -16,9 +26,25 @@ Preference {
preference.save();
}
Item {
id: spacer
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: isFirstCheckBox ? hifi.dimensions.controlInterlineHeight : 0
}
CheckBox {
id: checkBox
anchors.fill: parent
anchors {
top: spacer.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
text: root.label
colorScheme: hifi.colorSchemes.dark
}
}

View file

@ -1,14 +1,26 @@
//
// ComboBoxPreference.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../../controls-uit" as HiFiControls
import "../../styles-uit"
Preference {
id: root
property real spacing: 8
height: labelText.height + dataComboBox.height + spacing
height: control.height + hifi.dimensions.controlInterlineHeight
Component.onCompleted: {
dataComboBox.currentIndex = dataComboBox.find(preference.value);
dataComboBox.currentIndex = dataComboBox.comboBox.find(preference.value);
}
function save() {
@ -16,22 +28,38 @@ Preference {
preference.save();
}
Text {
id: labelText
color: enabled ? "black" : "gray"
text: root.label
}
ComboBox {
id: dataComboBox
model: preference.items
style: ComboBoxStyle { renderType: Text.QtRendering }
Item {
id: control
anchors {
top: labelText.bottom
left: parent.left
right: parent.right
topMargin: root.spacing
rightMargin: root.spacing
bottom: parent.bottom
}
height: Math.max(labelText.height, dataComboBox.controlHeight)
HiFiControls.Label {
id: labelText
text: root.label + ":"
colorScheme: hifi.colorSchemes.dark
anchors {
left: parent.left
right: dataComboBox.left
rightMargin: hifi.dimensions.labelPadding
verticalCenter: parent.verticalCenter
}
horizontalAlignment: Text.AlignRight
wrapMode: Text.Wrap
}
HiFiControls.ComboBox {
id: dataComboBox
model: preference.items
width: 150
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
colorScheme: hifi.colorSchemes.dark
}
}
}

View file

@ -1,11 +1,21 @@
//
// EditablePreference.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../../dialogs"
import "../../controls-uit"
Preference {
id: root
property real spacing: 8
height: labelText.height + dataTextField.height + spacing
height: dataTextField.controlHeight + hifi.dimensions.controlInterlineHeight
Component.onCompleted: {
dataTextField.text = preference.value;
@ -16,22 +26,16 @@ Preference {
preference.save();
}
Text {
id: labelText
color: enabled ? "black" : "gray"
text: root.label
}
TextField {
id: dataTextField
placeholderText: preference.placeholderText
style: TextFieldStyle { renderType: Text.QtRendering }
label: root.label
colorScheme: hifi.colorSchemes.dark
anchors {
top: labelText.bottom
left: parent.left
right: parent.right
topMargin: root.spacing
rightMargin: root.spacing
bottom: parent.bottom
}
}
}

View file

@ -1,3 +1,13 @@
//
// Preference.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
@ -6,6 +16,7 @@ Item {
anchors { left: parent.left; right: parent.right }
property var preference;
property string label: preference ? preference.name : "";
property bool isFirstCheckBox;
Component.onCompleted: {
if (preference) {
preference.load();

View file

@ -1,20 +1,33 @@
//
// Section.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import Hifi 1.0
import "../../controls" as VrControls
import "../../controls-uit" as HiFiControls
import "../../styles-uit"
import "."
Preference {
id: root
property bool collapsable: true
property bool expanded: false
property bool isFirst: false
property bool isLast: false
property string name: "Header"
property real spacing: 8
readonly property alias toggle: toggle
readonly property alias header: header
default property alias preferences: contentContainer.children
HifiConstants { id: hifi }
function saveAll() {
for (var i = 0; i < d.preferences.length; ++i) {
var preference = d.preferences[i];
@ -29,47 +42,24 @@ Preference {
}
}
clip: true
children: [ toggle, header, contentContainer ]
height: expanded ? header.height + contentContainer.height + root.spacing * 3
: Math.max(toggle.height, header.height) + root.spacing * 2
Behavior on height { PropertyAnimation {} }
children: [ contentContainer ]
height: contentContainer.height + (root.isLast ? 2 * hifi.dimensions.contentSpacing.y : 0)
Component.onCompleted: d.buildPreferences();
function toggleExpanded() {
root.expanded = !root.expanded;
}
VrControls.FontAwesome {
id: toggle
width: root.collapsable ? height : 0
anchors { left: parent.left; top: parent.top; margins: root.spacing }
visible: root.collapsable
enabled: root.collapsable
rotation: root.expanded ? 0 : -90
text: "\uf078"
Behavior on rotation { PropertyAnimation {} }
MouseArea { anchors.fill: parent; onClicked: root.toggleExpanded() }
}
Text {
id: header
anchors { left: toggle.right; top: parent.top; leftMargin: root.spacing * 2; margins: root.spacing }
font.bold: true
font.pointSize: 16
color: "#0e7077"
text: root.name
MouseArea { anchors.fill: parent; onClicked: root.toggleExpanded() }
}
Column {
HiFiControls.ContentSection {
id: contentContainer
spacing: root.spacing
anchors { left: toggle.right; top: header.bottom; topMargin: root.spacing; right: parent.right; margins: root.spacing }
enabled: root.expanded
visible: root.expanded
clip: true
name: root.name
isFirst: root.isFirst
isCollapsible: root.collapsable
isCollapsed: !root.expanded
anchors {
left: parent.left
right: parent.right
margins: 0
}
}
QtObject {
@ -83,6 +73,7 @@ Preference {
property var buttonBuilder: Component { ButtonPreference { } }
property var comboBoxBuilder: Component { ComboBoxPreference { } }
property var preferences: []
property int checkBoxCount: 0
function buildPreferences() {
var categoryPreferences = Preferences.preferencesByCategory[root.name];
@ -99,40 +90,49 @@ Preference {
var builder;
switch (preference.type) {
case Preference.Editable:
checkBoxCount = 0;
builder = editableBuilder;
break;
case Preference.Browsable:
checkBoxCount = 0;
builder = browsableBuilder;
break;
case Preference.Spinner:
checkBoxCount = 0;
builder = spinnerBuilder;
break;
case Preference.Slider:
checkBoxCount = 0;
builder = sliderBuilder;
break;
case Preference.Checkbox:
checkBoxCount++;
console.log("####### checkBoxCount = " + checkBoxCount);
builder = checkboxBuilder;
break;
case Preference.Avatar:
checkBoxCount = 0;
builder = avatarBuilder;
break;
case Preference.Button:
checkBoxCount = 0;
builder = buttonBuilder;
break;
case Preference.ComboBox:
checkBoxCount = 0;
builder = comboBoxBuilder;
break;
};
if (builder) {
preferences.push(builder.createObject(contentContainer, { preference: preference }));
preferences.push(builder.createObject(contentContainer, { preference: preference, isFirstCheckBox: (checkBoxCount === 1) }));
}
}
}

View file

@ -1,10 +1,22 @@
//
// SpinBoxPreference.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../../dialogs"
import "../../controls-uit"
Preference {
id: root
property alias slider: slider
height: slider.height
height: control.height + hifi.dimensions.controlInterlineHeight
Component.onCompleted: {
slider.value = preference.value;
@ -15,16 +27,38 @@ Preference {
preference.save();
}
Text {
text: root.label
color: enabled ? "black" : "gray"
anchors.verticalCenter: slider.verticalCenter
}
Item {
id: control
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: Math.max(labelText.height, slider.height)
Slider {
id: slider
value: preference.value
width: 130
anchors { right: parent.right }
Label {
id: labelText
text: root.label + ":"
colorScheme: hifi.colorSchemes.dark
anchors {
left: parent.left
right: slider.left
rightMargin: hifi.dimensions.labelPadding
verticalCenter: parent.verticalCenter
}
horizontalAlignment: Text.AlignRight
wrapMode: Text.Wrap
}
Slider {
id: slider
value: preference.value
width: 130
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
colorScheme: hifi.colorSchemes.dark
}
}
}

View file

@ -1,10 +1,21 @@
//
// SpinBoxPreference.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../../controls-uit"
Preference {
id: root
property alias spinner: spinner
height: spinner.height
height: control.height + hifi.dimensions.controlInterlineHeight
Component.onCompleted: {
spinner.value = preference.value;
@ -15,18 +26,40 @@ Preference {
preference.save();
}
Text {
text: root.label
color: root.enabled ? "black" : "gray"
anchors.verticalCenter: spinner.verticalCenter
}
Item {
id: control
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: Math.max(spinnerLabel.height, spinner.controlHeight)
SpinBox {
id: spinner
decimals: preference.decimals
minimumValue: preference.min
maximumValue: preference.max
width: 100
anchors { right: parent.right }
Label {
id: spinnerLabel
text: root.label + ":"
colorScheme: hifi.colorSchemes.dark
anchors {
left: parent.left
right: spinner.left
rightMargin: hifi.dimensions.labelPadding
verticalCenter: parent.verticalCenter
}
horizontalAlignment: Text.AlignRight
wrapMode: Text.Wrap
}
SpinBox {
id: spinner
decimals: preference.decimals
minimumValue: preference.min
maximumValue: preference.max
width: 100
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
colorScheme: hifi.colorSchemes.dark
}
}
}

View file

@ -6,7 +6,7 @@ import "../../dialogs"
PreferencesDialog {
id: root
objectName: "AudioPreferencesDialog"
title: "Audio Preferences"
title: "Audio Settings"
showCategories: ["Audio"]
property var settings: Settings {
category: root.objectName

View file

@ -6,7 +6,7 @@ import "../../dialogs"
PreferencesDialog {
id: root
objectName: "AvatarPreferencesDialog"
title: "Avatar Preferences"
title: "Avatar Settings"
showCategories: [ "Avatar Basics", "Avatar Tuning", "Avatar Camera" ]
property var settings: Settings {
category: root.objectName

View file

@ -1,3 +1,13 @@
//
// PreferencesDialog.qml
//
// Created by Bradley Austin Davis on 24 Jan 2016
// Copyright 2015 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
//
import QtQuick 2.5
import Qt.labs.settings 1.0
@ -6,7 +16,7 @@ import "../../dialogs"
PreferencesDialog {
id: root
objectName: "GeneralPreferencesDialog"
title: "General Preferences"
title: "General Settings"
showCategories: ["Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers"]
property var settings: Settings {
category: root.objectName

View file

@ -6,7 +6,7 @@ import "../../dialogs"
PreferencesDialog {
id: root
objectName: "GraphicsPreferencesDialog"
title: "Graphics Preferences"
title: "Graphics Settings"
showCategories: ["Graphics"]
property var settings: Settings {
category: root.objectName

View file

@ -6,7 +6,7 @@ import "../../dialogs"
PreferencesDialog {
id: root
objectName: "LodPreferencesDialog"
title: "Level of Detail preferences"
title: "LOD Settings"
showCategories: ["Level of Detail Tuning"]
property var settings: Settings {
category: root.objectName

View file

@ -24,7 +24,7 @@ Window {
resizable: true
destroyOnInvisible: true
x: 40; y: 40
implicitWidth: 384; implicitHeight: 640
implicitWidth: 400; implicitHeight: 695
minSize: Qt.vector2d(200, 300)
HifiConstants { id: hifi }
@ -87,8 +87,11 @@ Window {
Column {
width: pane.contentWidth
HifiControls.StaticSection {
HifiControls.ContentSection {
name: "Currently Running"
isFirst: true
HifiControls.VerticalSpacer {}
Row {
spacing: hifi.dimensions.contentSpacing.x
@ -106,6 +109,8 @@ Window {
}
}
HifiControls.VerticalSpacer {}
HifiControls.Table {
tableModel: runningScriptsModel
height: 185
@ -113,11 +118,16 @@ Window {
anchors.left: parent.left
anchors.right: parent.right
}
HifiControls.VerticalSpacer {
height: 2 // Table view draws a little taller than it's height.
}
}
HifiControls.StaticSection {
HifiControls.ContentSection {
name: "Load Scripts"
hasSeparator: true
HifiControls.VerticalSpacer {}
Row {
spacing: hifi.dimensions.contentSpacing.x
@ -161,18 +171,21 @@ Window {
}
}
HifiControls.VerticalSpacer {}
HifiControls.TextField {
id: filterEdit
anchors.left: parent.left
anchors.right: parent.right
focus: true
colorScheme: hifi.colorSchemes.dark
//placeholderText: "filter"
label: "Filter"
placeholderText: "filter"
onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i")
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
}
HifiControls.VerticalSpacer {}
HifiControls.Tree {
id: treeView
height: 155
@ -182,6 +195,8 @@ Window {
anchors.right: parent.right
}
HifiControls.VerticalSpacer {}
HifiControls.TextField {
id: selectedScript
anchors.left: parent.left

View file

@ -48,11 +48,13 @@ Item {
// Other colors
readonly property color white: "#ffffff"
readonly property color gray: "#808080"
readonly property color black: "#000000"
// Semitransparent
readonly property color white50: "#80ffffff"
readonly property color white30: "#4dffffff"
readonly property color white25: "#40ffffff"
readonly property color transparent: "#00ffffff"
// Control specific colors
readonly property color tableRowLightOdd: white50
@ -61,6 +63,26 @@ Item {
readonly property color tableRowDarkEven: "#a6181818"
readonly property color tableScrollHandle: "#707070"
readonly property color tableScrollBackground: "#323232"
readonly property color checkboxLightStart: "#ffffff"
readonly property color checkboxLightFinish: "#afafaf"
readonly property color checkboxDarkStart: "#7d7d7d"
readonly property color checkboxDarkFinish: "#6b6a6b"
readonly property color checkboxChecked: primaryHighlight
readonly property color checkboxCheckedBorder: "#36cdff"
readonly property color sliderGutterLight: "#d4d4d4"
readonly property color sliderGutterDark: "#252525"
readonly property color sliderBorderLight: "#afafaf"
readonly property color sliderBorderDark: "#7d7d7d"
readonly property color sliderLightStart: "#ffffff"
readonly property color sliderLightFinish: "#afafaf"
readonly property color sliderDarkStart: "#7d7d7d"
readonly property color sliderDarkFinish: "#6b6a6b"
readonly property color dropDownPressedLight: "#d4d4d4"
readonly property color dropDownPressedDark: "#afafaf"
readonly property color dropDownLightStart: "#ffffff"
readonly property color dropDownLightFinish: "#afafaf"
readonly property color dropDownDarkStart: "#7d7d7d"
readonly property color dropDownDarkFinish: "#6b6a6b"
}
Item {
@ -76,39 +98,54 @@ Item {
readonly property real borderWidth: largeScreen ? 2 : 1
readonly property vector2d contentMargin: Qt.vector2d(12, 24)
readonly property vector2d contentSpacing: Qt.vector2d(8, 12)
readonly property real labelPadding: 40
readonly property real textPadding: 8
readonly property real sliderHandleSize: 18
readonly property real sliderGrooveHeight: 8
readonly property real spinnerSize: 42
readonly property real tablePadding: 12
readonly property real tableRowHeight: largeScreen ? 26 : 23
readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30)
readonly property real modalDialogTitleHeight: 40
readonly property real controlLineHeight: 29 // Height of spinbox control on 1920 x 1080 monitor
readonly property real controlInterlineHeight: 22 // 75% of controlLineHeight
}
Item {
id: fontSizes // In pixels
readonly property real overlayTitle: dimensions.largeScreen? 18 : 14
readonly property real tabName: dimensions.largeScreen? 12 : 10
readonly property real sectionName: dimensions.largeScreen? 12 : 10
readonly property real inputLabel: dimensions.largeScreen? 14 : 10
readonly property real textFieldInput: dimensions.largeScreen? 15 : 12
readonly property real tableText: dimensions.largeScreen? 15 : 12
readonly property real buttonLabel: dimensions.largeScreen? 13 : 9
readonly property real iconButton: dimensions.largeScreen? 13 : 9
readonly property real listItem: dimensions.largeScreen? 15 : 11
readonly property real tabularData: dimensions.largeScreen? 15 : 11
readonly property real logs: dimensions.largeScreen? 16 : 12
readonly property real code: dimensions.largeScreen? 16 : 12
readonly property real rootMenu: dimensions.largeScreen? 15 : 11
readonly property real menuItem: dimensions.largeScreen? 15 : 11
readonly property real shortcutText: dimensions.largeScreen? 13 : 9
readonly property real overlayTitle: dimensions.largeScreen ? 18 : 14
readonly property real tabName: dimensions.largeScreen ? 12 : 10
readonly property real sectionName: dimensions.largeScreen ? 12 : 10
readonly property real inputLabel: dimensions.largeScreen ? 14 : 10
readonly property real textFieldInput: dimensions.largeScreen ? 15 : 12
readonly property real tableText: dimensions.largeScreen ? 15 : 12
readonly property real buttonLabel: dimensions.largeScreen ? 13 : 9
readonly property real iconButton: dimensions.largeScreen ? 13 : 9
readonly property real listItem: dimensions.largeScreen ? 15 : 11
readonly property real tabularData: dimensions.largeScreen ? 15 : 11
readonly property real logs: dimensions.largeScreen ? 16 : 12
readonly property real code: dimensions.largeScreen ? 16 : 12
readonly property real rootMenu: dimensions.largeScreen ? 15 : 11
readonly property real menuItem: dimensions.largeScreen ? 15 : 11
readonly property real shortcutText: dimensions.largeScreen ? 13 : 9
readonly property real carat: dimensions.largeScreen ? 38 : 30
readonly property real disclosureButton: dimensions.largeScreen ? 20 : 15
}
Item {
id: glyphs
readonly property string backward: "E"
readonly property string caratDn: "5"
readonly property string caratR: "3"
readonly property string caratUp: "6"
readonly property string close: "w"
readonly property string closeInverted: "x"
readonly property string closeSmall: "C"
readonly property string disclosureButtonCollapse: "M"
readonly property string disclosureButtonExpand: "L"
readonly property string disclosureCollapse: "Z"
readonly property string disclosureExpand: "B"
readonly property string forward: "D"
readonly property string pin: "y"
readonly property string pinInverted: "z"
readonly property string reloadSmall: "a"

View file

@ -99,8 +99,8 @@ Frame {
DropShadow {
source: titleText
anchors.fill: titleText
horizontalOffset: 1
verticalOffset: 1
horizontalOffset: 2
verticalOffset: 2
samples: 2
color: hifi.colors.baseGrayShadow60
visible: (window && window.focus)

View file

@ -58,6 +58,8 @@ Fadable {
// The content to place inside the window, determined by the client
default property var content
property var footer: Item { } // Optional static footer at the bottom of the dialog.
function setDefaultFocus() {} // Default function; can be overridden by dialogs.
property var rectifier: Timer {
@ -125,7 +127,8 @@ Fadable {
// Scrollable window content.
property var pane: Item {
property bool isScrolling: scrollView.height < scrollView.contentItem.height
property int contentWidth: scrollView.width - (isScrolling ? 11 : 0)
property int contentWidth: scrollView.width - (isScrolling ? 10 : 0)
property int scrollHeight: scrollView.height
anchors.fill: parent
anchors.rightMargin: isScrolling ? 11 : 0
@ -162,6 +165,7 @@ Fadable {
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
anchors.fill: parent
anchors.rightMargin: parent.isScrolling ? 1 : 0
anchors.bottomMargin: footer.height > 0 ? footerPane.height : 0
style: ScrollViewStyle {
@ -203,7 +207,46 @@ Fadable {
}
}
}
Rectangle {
// Optional non-scrolling footer.
id: footerPane
anchors {
left: parent.left
bottom: parent.bottom
}
width: parent.contentWidth
height: footer.height + 2 * hifi.dimensions.contentSpacing.y
color: hifi.colors.baseGray
visible: footer.height > 0
Item {
// Horizontal rule.
anchors.fill: parent
Rectangle {
width: parent.width
height: 1
y: 1 // Stop displaying content just above horizontal rule/=.
color: hifi.colors.baseGrayShadow
}
Rectangle {
width: parent.width
height: 1
y: 2
color: hifi.colors.baseGrayHighlight
}
}
Item {
anchors.fill: parent
anchors.topMargin: 3 // Horizontal rule.
children: [ footer ]
}
}
}
children: [ swallower, frame, pane, activator ]
Component.onCompleted: { raise(); setDefaultFocus(); }

View file

@ -544,7 +544,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle()));
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived);
// update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one
const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000;
@ -581,6 +580,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle);
// set the account manager's root URL and trigger a login request if we don't have the access token
accountManager.setIsAgent(true);
accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
UserActivityLogger::getInstance().launch(applicationVersion());
@ -889,9 +889,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
SpacemouseManager::getInstance().init();
#endif
auto& packetReceiver = nodeList->getPacketReceiver();
packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket");
// If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity,
@ -3819,7 +3816,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
// Setup the current Zone Entity lighting
{
auto stage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(stage->getSunLight(), stage->getSkybox()->getCubemap());
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(stage->getSunLight());
}
{
@ -3955,29 +3952,10 @@ void Application::clearDomainOctreeDetails() {
void Application::domainChanged(const QString& domainHostname) {
updateWindowTitle();
clearDomainOctreeDetails();
_domainConnectionRefusals.clear();
// disable physics until we have enough information about our new location to not cause craziness.
_physicsEnabled = false;
}
void Application::handleDomainConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message) {
// Read deny reason from packet
quint16 reasonSize;
message->readPrimitive(&reasonSize);
QString reason = QString::fromUtf8(message->readWithoutCopy(reasonSize));
// output to the log so the user knows they got a denied connection request
// and check and signal for an access token so that we can make sure they are logged in
qCDebug(interfaceapp) << "The domain-server denied a connection request: " << reason;
qCDebug(interfaceapp) << "You may need to re-log to generate a keypair so you can provide a username signature.";
if (!_domainConnectionRefusals.contains(reason)) {
_domainConnectionRefusals.append(reason);
emit domainConnectionRefused(reason);
}
AccountManager::getInstance().checkAndSignalForAccessToken();
}
void Application::resettingDomain() {
_notifiedPacketVersionMismatchThisDomain = false;
@ -4517,33 +4495,6 @@ void Application::openUrl(const QUrl& url) {
}
}
void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject) {
// from the domain-handler, figure out the satoshi cost per voxel and per meter cubed
const QString VOXEL_SETTINGS_KEY = "voxels";
const QString PER_VOXEL_COST_KEY = "per-voxel-credits";
const QString PER_METER_CUBED_COST_KEY = "per-meter-cubed-credits";
const QString VOXEL_WALLET_UUID = "voxel-wallet";
const QJsonObject& voxelObject = domainSettingsObject[VOXEL_SETTINGS_KEY].toObject();
qint64 satoshisPerVoxel = 0;
qint64 satoshisPerMeterCubed = 0;
QUuid voxelWalletUUID;
if (!domainSettingsObject.isEmpty()) {
float perVoxelCredits = (float) voxelObject[PER_VOXEL_COST_KEY].toDouble();
float perMeterCubedCredits = (float) voxelObject[PER_METER_CUBED_COST_KEY].toDouble();
satoshisPerVoxel = (qint64) floorf(perVoxelCredits * SATOSHIS_PER_CREDIT);
satoshisPerMeterCubed = (qint64) floorf(perMeterCubedCredits * SATOSHIS_PER_CREDIT);
voxelWalletUUID = QUuid(voxelObject[VOXEL_WALLET_UUID].toString());
}
qCDebug(interfaceapp) << "Octree edits costs are" << satoshisPerVoxel << "per octree cell and" << satoshisPerMeterCubed << "per meter cubed";
qCDebug(interfaceapp) << "Destination wallet UUID for edit payments is" << voxelWalletUUID;
}
void Application::loadDialog() {
auto scriptEngines = DependencyManager::get<ScriptEngines>();
QString fileNameString = OffscreenUi::getOpenFileName(

View file

@ -227,7 +227,6 @@ signals:
void svoImportRequested(const QString& url);
void checkBackgroundDownloads();
void domainConnectionRefused(const QString& reason);
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
@ -297,9 +296,6 @@ private slots:
void activeChanged(Qt::ApplicationState state);
void domainSettingsReceived(const QJsonObject& domainSettingsObject);
void handleDomainConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message);
void notifyPacketVersionMismatch();
void loadSettings();
@ -476,7 +472,6 @@ private:
typedef bool (Application::* AcceptURLMethod)(const QString &);
static const QHash<QString, AcceptURLMethod> _acceptedExtensions;
QList<QString> _domainConnectionRefusals;
glm::uvec2 _renderResolution;
int _maxOctreePPS = DEFAULT_MAX_OCTREE_PPS;

View file

@ -22,11 +22,8 @@
#include <QStandardPaths>
#include <QVBoxLayout>
#include "DataServerAccountInfo.h"
#include "Menu.h"
Q_DECLARE_METATYPE(DataServerAccountInfo)
static const QString RUNNING_MARKER_FILENAME = "Interface.running";
void CrashHandler::checkForAndHandleCrash() {
@ -57,7 +54,7 @@ CrashHandler::Action CrashHandler::promptUserForAction() {
layout->addWidget(label);
QRadioButton* option1 = new QRadioButton("Reset all my settings");
QRadioButton* option2 = new QRadioButton("Reset my settings but retain login and avatar info.");
QRadioButton* option2 = new QRadioButton("Reset my settings but retain avatar info.");
QRadioButton* option3 = new QRadioButton("Continue with my current settings");
option3->setChecked(true);
layout->addWidget(option1);
@ -79,7 +76,7 @@ CrashHandler::Action CrashHandler::promptUserForAction() {
return CrashHandler::DELETE_INTERFACE_INI;
}
if (option2->isChecked()) {
return CrashHandler::RETAIN_LOGIN_AND_AVATAR_INFO;
return CrashHandler::RETAIN_AVATAR_INFO;
}
}
@ -88,7 +85,7 @@ CrashHandler::Action CrashHandler::promptUserForAction() {
}
void CrashHandler::handleCrash(CrashHandler::Action action) {
if (action != CrashHandler::DELETE_INTERFACE_INI && action != CrashHandler::RETAIN_LOGIN_AND_AVATAR_INFO) {
if (action != CrashHandler::DELETE_INTERFACE_INI && action != CrashHandler::RETAIN_AVATAR_INFO) {
// CrashHandler::DO_NOTHING or unexpected value
return;
}
@ -101,18 +98,13 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
const QString DISPLAY_NAME_KEY = "displayName";
const QString FULL_AVATAR_URL_KEY = "fullAvatarURL";
const QString FULL_AVATAR_MODEL_NAME_KEY = "fullAvatarModelName";
const QString ACCOUNTS_GROUP = "accounts";
QString displayName;
QUrl fullAvatarURL;
QString fullAvatarModelName;
QUrl address;
QMap<QString, DataServerAccountInfo> accounts;
if (action == CrashHandler::RETAIN_LOGIN_AND_AVATAR_INFO) {
// Read login and avatar info
qRegisterMetaType<DataServerAccountInfo>("DataServerAccountInfo");
qRegisterMetaTypeStreamOperators<DataServerAccountInfo>("DataServerAccountInfo");
if (action == CrashHandler::RETAIN_AVATAR_INFO) {
// Read avatar info
// Location and orientation
settings.beginGroup(ADDRESS_MANAGER_GROUP);
@ -125,13 +117,6 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
fullAvatarURL = settings.value(FULL_AVATAR_URL_KEY).toUrl();
fullAvatarModelName = settings.value(FULL_AVATAR_MODEL_NAME_KEY).toString();
settings.endGroup();
// Accounts
settings.beginGroup(ACCOUNTS_GROUP);
foreach(const QString& key, settings.allKeys()) {
accounts.insert(key, settings.value(key).value<DataServerAccountInfo>());
}
settings.endGroup();
}
// Delete Interface.ini
@ -140,8 +125,8 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
settingsFile.remove();
}
if (action == CrashHandler::RETAIN_LOGIN_AND_AVATAR_INFO) {
// Write login and avatar info
if (action == CrashHandler::RETAIN_AVATAR_INFO) {
// Write avatar info
// Location and orientation
settings.beginGroup(ADDRESS_MANAGER_GROUP);
@ -154,13 +139,6 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
settings.setValue(FULL_AVATAR_URL_KEY, fullAvatarURL);
settings.setValue(FULL_AVATAR_MODEL_NAME_KEY, fullAvatarModelName);
settings.endGroup();
// Accounts
settings.beginGroup(ACCOUNTS_GROUP);
foreach(const QString& key, accounts.keys()) {
settings.setValue(key, QVariant::fromValue(accounts.value(key)));
}
settings.endGroup();
}
}

View file

@ -25,7 +25,7 @@ public:
private:
enum Action {
DELETE_INTERFACE_INI,
RETAIN_LOGIN_AND_AVATAR_INFO,
RETAIN_AVATAR_INFO,
DO_NOTHING
};

View file

@ -31,7 +31,6 @@ MainWindow::MainWindow(QWidget* parent) :
_windowState("WindowState", 0)
{
setAcceptDrops(true);
_trayIcon.show();
}
void MainWindow::restoreGeometry() {

View file

@ -13,7 +13,6 @@
#define __hifi__MainWindow__
#include <QMainWindow>
#include <QSystemTrayIcon>
#include <SettingHandle.h>
@ -43,7 +42,6 @@ protected:
private:
Setting::Handle<QRect> _windowGeometry;
Setting::Handle<int> _windowState;
QSystemTrayIcon _trayIcon;
};
#endif /* defined(__hifi__MainWindow__) */

View file

@ -342,9 +342,9 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename
void ModelPackager::listTextures() {
_textures.clear();
foreach (const FBXMaterial mat, _geometry->materials) {
if (!mat.diffuseTexture.filename.isEmpty() && mat.diffuseTexture.content.isEmpty() &&
!_textures.contains(mat.diffuseTexture.filename)) {
_textures << mat.diffuseTexture.filename;
if (!mat.albedoTexture.filename.isEmpty() && mat.albedoTexture.content.isEmpty() &&
!_textures.contains(mat.albedoTexture.filename)) {
_textures << mat.albedoTexture.filename;
}
if (!mat.normalTexture.filename.isEmpty() && mat.normalTexture.content.isEmpty() &&
!_textures.contains(mat.normalTexture.filename)) {

View file

@ -25,7 +25,7 @@
WindowScriptingInterface::WindowScriptingInterface() {
const DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
connect(&domainHandler, &DomainHandler::connectedToDomain, this, &WindowScriptingInterface::domainChanged);
connect(qApp, &Application::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused);
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused);
connect(qApp, &Application::svoImportRequested, [this](const QString& urlString) {
static const QMetaMethod svoImportRequestedSignal =

View file

@ -36,8 +36,7 @@ void setupPreferences() {
{
auto getter = [=]()->QString {return myAvatar->getDisplayName(); };
auto setter = [=](const QString& value) { myAvatar->setDisplayName(value); };
const QString label = "Avatar display name <font color=\"#909090\">(optional)</font>";
auto preference = new EditPreference(AVATAR_BASICS, label, getter, setter);
auto preference = new EditPreference(AVATAR_BASICS, "Avatar display name (optional)", getter, setter);
preference->setPlaceholderText("Not showing a name");
preferences->addPreference(preference);
}
@ -45,8 +44,7 @@ void setupPreferences() {
{
auto getter = [=]()->QString {return myAvatar->getCollisionSoundURL(); };
auto setter = [=](const QString& value) { myAvatar->setCollisionSoundURL(value); };
const QString label = "Avatar collision sound URL <font color=\"#909090\">(optional)</font>";
auto preference = new EditPreference(AVATAR_BASICS, label, getter, setter);
auto preference = new EditPreference(AVATAR_BASICS, "Avatar collision sound URL (optional)", getter, setter);
preference->setPlaceholderText("Enter the URL of a sound to play when you bump into something");
preferences->addPreference(preference);
}
@ -54,18 +52,18 @@ void setupPreferences() {
{
auto getter = [=]()->QString { return myAvatar->getFullAvatarURLFromPreferences().toString(); };
auto setter = [=](const QString& value) { myAvatar->useFullAvatarURL(value, ""); };
auto preference = new AvatarPreference(AVATAR_BASICS, "Appearance: ", getter, setter);
auto preference = new AvatarPreference(AVATAR_BASICS, "Appearance", getter, setter);
preferences->addPreference(preference);
}
{
auto getter = [=]()->bool {return myAvatar->getSnapTurn(); };
auto setter = [=](bool value) { myAvatar->setSnapTurn(value); };
preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Snap Turn when in HMD", getter, setter));
preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Snap turn when in HMD", getter, setter));
}
{
auto getter = []()->QString { return Snapshot::snapshotsLocation.get(); };
auto setter = [](const QString& value) { Snapshot::snapshotsLocation.set(value); };
auto preference = new BrowsePreference("Snapshots", "Place my Snapshots here:", getter, setter);
auto preference = new BrowsePreference("Snapshots", "Put my snapshots here", getter, setter);
preferences->addPreference(preference);
}
@ -73,7 +71,7 @@ void setupPreferences() {
{
auto getter = []()->QString { return DependencyManager::get<ScriptEngines>()->getScriptsLocation(); };
auto setter = [](const QString& value) { DependencyManager::get<ScriptEngines>()->setScriptsLocation(value); };
preferences->addPreference(new BrowsePreference("Scripts", "Load scripts from this directory:", getter, setter));
preferences->addPreference(new BrowsePreference("Scripts", "Load scripts from this directory", getter, setter));
}
preferences->addPreference(new ButtonPreference("Scripts", "Load Default Scripts", [] {
@ -83,14 +81,14 @@ void setupPreferences() {
{
auto getter = []()->bool {return !Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger); };
auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableActivityLogger, !value); };
preferences->addPreference(new CheckPreference("Privacy", "Send Data", getter, setter));
preferences->addPreference(new CheckPreference("Privacy", "Send data", getter, setter));
}
static const QString LOD_TUNING("Level of Detail Tuning");
{
auto getter = []()->float { return DependencyManager::get<LODManager>()->getDesktopLODDecreaseFPS(); };
auto setter = [](float value) { DependencyManager::get<LODManager>()->setDesktopLODDecreaseFPS(value); };
auto preference = new SpinnerPreference(LOD_TUNING, "Minimum Desktop FPS", getter, setter);
auto preference = new SpinnerPreference(LOD_TUNING, "Minimum desktop FPS", getter, setter);
preference->setMin(0);
preference->setMax(120);
preference->setStep(1);
@ -138,7 +136,7 @@ void setupPreferences() {
{
auto getter = [=]()->float { return myAvatar->getUniformScale(); };
auto setter = [=](float value) { myAvatar->setTargetScaleVerbose(value); }; // The hell?
auto preference = new SpinnerPreference(AVATAR_TUNING, "Avatar scale <font color=\"#909090\">(default is 1.0)</font>", getter, setter);
auto preference = new SpinnerPreference(AVATAR_TUNING, "Avatar scale (default is 1.0)", getter, setter);
preference->setMin(0.01f);
preference->setMax(99.9f);
preference->setDecimals(2);
@ -170,7 +168,7 @@ void setupPreferences() {
{
auto getter = [=]()->QString { return myAvatar->getAnimGraphUrl().toString(); };
auto setter = [=](const QString& value) { myAvatar->setAnimGraphUrl(value); };
auto preference = new EditPreference(AVATAR_TUNING, "Avatar Animation JSON", getter, setter);
auto preference = new EditPreference(AVATAR_TUNING, "Avatar animation JSON", getter, setter);
preference->setPlaceholderText("default");
preferences->addPreference(preference);
}
@ -179,7 +177,7 @@ void setupPreferences() {
{
auto getter = [=]()->float { return myAvatar->getPitchSpeed(); };
auto setter = [=](float value) { myAvatar->setPitchSpeed(value); };
auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera Pitch Speed (degrees/second)", getter, setter);
auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera pitch speed (degrees/second)", getter, setter);
preference->setMin(1.0f);
preference->setMax(360.0f);
preferences->addPreference(preference);
@ -187,7 +185,7 @@ void setupPreferences() {
{
auto getter = [=]()->float { return myAvatar->getYawSpeed(); };
auto setter = [=](float value) { myAvatar->setYawSpeed(value); };
auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera Yaw Speed (degrees/second)", getter, setter);
auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera yaw speed (degrees/second)", getter, setter);
preference->setMin(1.0f);
preference->setMax(360.0f);
preferences->addPreference(preference);
@ -197,13 +195,13 @@ void setupPreferences() {
{
auto getter = []()->bool {return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getDynamicJitterBuffers(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setDynamicJitterBuffers(value); };
preferences->addPreference(new CheckPreference(AUDIO, "Enable Dynamic Jitter Buffers", getter, setter));
preferences->addPreference(new CheckPreference(AUDIO, "Enable dynamic jitter buffers", getter, setter));
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getDesiredJitterBufferFrames(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setStaticDesiredJitterBufferFrames(value); };
auto preference = new SpinnerPreference(AUDIO, "Static Jitter Buffer Frames", getter, setter);
auto preference = new SpinnerPreference(AUDIO, "Static jitter buffer frames", getter, setter);
preference->setMin(0);
preference->setMax(10000);
preference->setStep(1);
@ -212,7 +210,7 @@ void setupPreferences() {
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getMaxFramesOverDesired(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setMaxFramesOverDesired(value); };
auto preference = new SpinnerPreference(AUDIO, "Max Frames Over Desired", getter, setter);
auto preference = new SpinnerPreference(AUDIO, "Max frames over desired", getter, setter);
preference->setMax(10000);
preference->setStep(1);
preferences->addPreference(preference);
@ -220,12 +218,12 @@ void setupPreferences() {
{
auto getter = []()->bool {return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getUseStDevForJitterCalc(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setUseStDevForJitterCalc(value); };
preferences->addPreference(new CheckPreference(AUDIO, "Use Stddev for Dynamic Jitter Calc", getter, setter));
preferences->addPreference(new CheckPreference(AUDIO, "Use standard deviation for dynamic jitter calc", getter, setter));
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getWindowStarveThreshold(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setWindowStarveThreshold(value); };
auto preference = new SpinnerPreference(AUDIO, "Window A Starve Threshold", getter, setter);
auto preference = new SpinnerPreference(AUDIO, "Window A starve threshold", getter, setter);
preference->setMax(10000);
preference->setStep(1);
preferences->addPreference(preference);
@ -233,7 +231,7 @@ void setupPreferences() {
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getWindowSecondsForDesiredCalcOnTooManyStarves(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setWindowSecondsForDesiredCalcOnTooManyStarves(value); };
auto preference = new SpinnerPreference(AUDIO, "Window A (raise desired on N starves) Seconds)", getter, setter);
auto preference = new SpinnerPreference(AUDIO, "Window A (raise desired on N starves) seconds", getter, setter);
preference->setMax(10000);
preference->setStep(1);
preferences->addPreference(preference);
@ -241,7 +239,7 @@ void setupPreferences() {
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getWindowSecondsForDesiredReduction(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setWindowSecondsForDesiredReduction(value); };
auto preference = new SpinnerPreference(AUDIO, "Window B (desired ceiling) Seconds", getter, setter);
auto preference = new SpinnerPreference(AUDIO, "Window B (desired ceiling) seconds", getter, setter);
preference->setMax(10000);
preference->setStep(1);
preferences->addPreference(preference);
@ -249,12 +247,12 @@ void setupPreferences() {
{
auto getter = []()->bool {return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getRepetitionWithFade(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setRepetitionWithFade(value); };
preferences->addPreference(new CheckPreference(AUDIO, "Repetition with Fade", getter, setter));
preferences->addPreference(new CheckPreference(AUDIO, "Repetition with fade", getter, setter));
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getOutputBufferSize(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->setOutputBufferSize(value); };
auto preference = new SpinnerPreference(AUDIO, "Output Buffer Initial Size (frames)", getter, setter);
auto preference = new SpinnerPreference(AUDIO, "Output buffer initial size (frames)", getter, setter);
preference->setMin(1);
preference->setMax(20);
preference->setStep(1);
@ -263,13 +261,13 @@ void setupPreferences() {
{
auto getter = []()->bool {return DependencyManager::get<AudioClient>()->getOutputStarveDetectionEnabled(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionEnabled(value); };
auto preference = new CheckPreference(AUDIO, "Output Starve Detection (Automatic Buffer Size Increase)", getter, setter);
auto preference = new CheckPreference(AUDIO, "Output starve detection (automatic buffer size increase)", getter, setter);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getOutputStarveDetectionThreshold(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionThreshold(value); };
auto preference = new SpinnerPreference(AUDIO, "Output Starve Detection Threshold", getter, setter);
auto preference = new SpinnerPreference(AUDIO, "Output starve detection threshold", getter, setter);
preference->setMin(1);
preference->setMax(500);
preference->setStep(1);
@ -278,7 +276,7 @@ void setupPreferences() {
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getOutputStarveDetectionPeriod(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionPeriod(value); };
auto preference = new SpinnerPreference(AUDIO, "Output Starve Detection Period (ms)", getter, setter);
auto preference = new SpinnerPreference(AUDIO, "Output starve detection period (ms)", getter, setter);
preference->setMin(1);
preference->setMax((float)999999999);
preference->setStep(1);
@ -299,7 +297,7 @@ void setupPreferences() {
{
auto getter = []()->float { return qApp->getApplicationCompositor().getHmdUIAngularSize(); };
auto setter = [](float value) { qApp->getApplicationCompositor().setHmdUIAngularSize(value); };
auto preference = new SpinnerPreference("HMD", "User Interface Horizontal Angular Size (degrees)", getter, setter);
auto preference = new SpinnerPreference("HMD", "UI horizontal angular size (degrees)", getter, setter);
preference->setMin(30);
preference->setMax(160);
preference->setStep(1);
@ -310,7 +308,7 @@ void setupPreferences() {
{
auto getter = []()->float { return controller::InputDevice::getReticleMoveSpeed(); };
auto setter = [](float value) { controller::InputDevice::setReticleMoveSpeed(value); };
auto preference = new SpinnerPreference("Sixense Controllers", "Reticle Movement Speed", getter, setter);
auto preference = new SpinnerPreference("Sixense Controllers", "Reticle movement speed", getter, setter);
preference->setMin(0);
preference->setMax(100);
preference->setStep(1);
@ -325,7 +323,7 @@ void setupPreferences() {
{
auto getter = [ambientOcclusionConfig]()->QString { return ambientOcclusionConfig->getPreset(); };
auto setter = [ambientOcclusionConfig](QString preset) { ambientOcclusionConfig->setPreset(preset); };
auto preference = new ComboBoxPreference(RENDER, "Ambient Occlusion", getter, setter);
auto preference = new ComboBoxPreference(RENDER, "Ambient occlusion", getter, setter);
preference->setItems(ambientOcclusionConfig->getPresetList());
preferences->addPreference(preference);
}

View file

@ -11,8 +11,6 @@
#include "Base3DOverlay.h"
#include <QScriptValue>
#include <RegisteredMetaTypes.h>
#include <SharedUtil.h>
@ -41,103 +39,78 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
{
}
void Base3DOverlay::setProperties(const QScriptValue& properties) {
void Base3DOverlay::setProperties(const QVariantMap& properties) {
Overlay::setProperties(properties);
QScriptValue drawInFront = properties.property("drawInFront");
auto drawInFront = properties["drawInFront"];
if (drawInFront.isValid()) {
bool value = drawInFront.toVariant().toBool();
bool value = drawInFront.toBool();
setDrawInFront(value);
}
QScriptValue position = properties.property("position");
auto position = properties["position"];
// if "position" property was not there, check to see if they included aliases: point, p1
if (!position.isValid()) {
position = properties.property("p1");
position = properties["p1"];
if (!position.isValid()) {
position = properties.property("point");
position = properties["point"];
}
}
if (position.isValid()) {
QScriptValue x = position.property("x");
QScriptValue y = position.property("y");
QScriptValue z = position.property("z");
if (x.isValid() && y.isValid() && z.isValid()) {
glm::vec3 newPosition;
newPosition.x = x.toVariant().toFloat();
newPosition.y = y.toVariant().toFloat();
newPosition.z = z.toVariant().toFloat();
setPosition(newPosition);
}
setPosition(vec3FromVariant(position));
}
if (properties.property("lineWidth").isValid()) {
setLineWidth(properties.property("lineWidth").toVariant().toFloat());
if (properties["lineWidth"].isValid()) {
setLineWidth(properties["lineWidth"].toFloat());
}
QScriptValue rotation = properties.property("rotation");
auto rotation = properties["rotation"];
if (rotation.isValid()) {
glm::quat newRotation;
// size, scale, dimensions is special, it might just be a single scalar, or it might be a vector, check that here
QScriptValue x = rotation.property("x");
QScriptValue y = rotation.property("y");
QScriptValue z = rotation.property("z");
QScriptValue w = rotation.property("w");
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
newRotation.x = x.toVariant().toFloat();
newRotation.y = y.toVariant().toFloat();
newRotation.z = z.toVariant().toFloat();
newRotation.w = w.toVariant().toFloat();
setRotation(newRotation);
}
setRotation(quatFromVariant(rotation));
}
if (properties.property("isSolid").isValid()) {
setIsSolid(properties.property("isSolid").toVariant().toBool());
if (properties["isSolid"].isValid()) {
setIsSolid(properties["isSolid"].toBool());
}
if (properties.property("isFilled").isValid()) {
setIsSolid(properties.property("isSolid").toVariant().toBool());
if (properties["isFilled"].isValid()) {
setIsSolid(properties["isSolid"].toBool());
}
if (properties.property("isWire").isValid()) {
setIsSolid(!properties.property("isWire").toVariant().toBool());
if (properties["isWire"].isValid()) {
setIsSolid(!properties["isWire"].toBool());
}
if (properties.property("solid").isValid()) {
setIsSolid(properties.property("solid").toVariant().toBool());
if (properties["solid"].isValid()) {
setIsSolid(properties["solid"].toBool());
}
if (properties.property("filled").isValid()) {
setIsSolid(properties.property("filled").toVariant().toBool());
if (properties["filled"].isValid()) {
setIsSolid(properties["filled"].toBool());
}
if (properties.property("wire").isValid()) {
setIsSolid(!properties.property("wire").toVariant().toBool());
if (properties["wire"].isValid()) {
setIsSolid(!properties["wire"].toBool());
}
if (properties.property("isDashedLine").isValid()) {
setIsDashedLine(properties.property("isDashedLine").toVariant().toBool());
if (properties["isDashedLine"].isValid()) {
setIsDashedLine(properties["isDashedLine"].toBool());
}
if (properties.property("dashed").isValid()) {
setIsDashedLine(properties.property("dashed").toVariant().toBool());
if (properties["dashed"].isValid()) {
setIsDashedLine(properties["dashed"].toBool());
}
if (properties.property("ignoreRayIntersection").isValid()) {
setIgnoreRayIntersection(properties.property("ignoreRayIntersection").toVariant().toBool());
if (properties["ignoreRayIntersection"].isValid()) {
setIgnoreRayIntersection(properties["ignoreRayIntersection"].toBool());
}
}
QScriptValue Base3DOverlay::getProperty(const QString& property) {
QVariant Base3DOverlay::getProperty(const QString& property) {
if (property == "position" || property == "start" || property == "p1" || property == "point") {
return vec3toScriptValue(_scriptEngine, getPosition());
return vec3toVariant(getPosition());
}
if (property == "lineWidth") {
return _lineWidth;
}
if (property == "rotation") {
return quatToScriptValue(_scriptEngine, getRotation());
return quatToVariant(getRotation());
}
if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filed") {
return _isSolid;

View file

@ -52,8 +52,8 @@ public:
virtual AABox getBounds() const = 0;
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal);

View file

@ -18,19 +18,19 @@ Billboard3DOverlay::Billboard3DOverlay(const Billboard3DOverlay* billboard3DOver
{
}
void Billboard3DOverlay::setProperties(const QScriptValue &properties) {
void Billboard3DOverlay::setProperties(const QVariantMap& properties) {
Planar3DOverlay::setProperties(properties);
PanelAttachable::setProperties(properties);
Billboardable::setProperties(properties);
}
QScriptValue Billboard3DOverlay::getProperty(const QString &property) {
QScriptValue value;
value = Billboardable::getProperty(_scriptEngine, property);
QVariant Billboard3DOverlay::getProperty(const QString &property) {
QVariant value;
value = Billboardable::getProperty(property);
if (value.isValid()) {
return value;
}
value = PanelAttachable::getProperty(_scriptEngine, property);
value = PanelAttachable::getProperty(property);
if (value.isValid()) {
return value;
}

View file

@ -23,8 +23,8 @@ public:
Billboard3DOverlay() {}
Billboard3DOverlay(const Billboard3DOverlay* billboard3DOverlay);
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
protected:
virtual void applyTransformTo(Transform& transform, bool force = false);

View file

@ -14,18 +14,18 @@
#include <Application.h>
#include <Transform.h>
void Billboardable::setProperties(const QScriptValue &properties) {
QScriptValue isFacingAvatar = properties.property("isFacingAvatar");
void Billboardable::setProperties(const QVariantMap& properties) {
auto isFacingAvatar = properties["isFacingAvatar"];
if (isFacingAvatar.isValid()) {
setIsFacingAvatar(isFacingAvatar.toVariant().toBool());
setIsFacingAvatar(isFacingAvatar.toBool());
}
}
QScriptValue Billboardable::getProperty(QScriptEngine* scriptEngine, const QString &property) {
QVariant Billboardable::getProperty(const QString &property) {
if (property == "isFacingAvatar") {
return isFacingAvatar();
}
return QScriptValue();
return QVariant();
}
void Billboardable::pointTransformAtCamera(Transform& transform, glm::quat offsetRotation) {

View file

@ -12,11 +12,9 @@
#ifndef hifi_Billboardable_h
#define hifi_Billboardable_h
#include <QScriptValue>
#include <glm/gtc/quaternion.hpp>
#include <QVariant>
class QScriptEngine;
class QString;
class Transform;
@ -26,8 +24,8 @@ public:
void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; }
protected:
void setProperties(const QScriptValue& properties);
QScriptValue getProperty(QScriptEngine* scriptEngine, const QString& property);
void setProperties(const QVariantMap& properties);
QVariant getProperty(const QString& property);
void pointTransformAtCamera(Transform& transform, glm::quat offsetRotation = {1, 0, 0, 0});

View file

@ -286,83 +286,76 @@ const render::ShapeKey Circle3DOverlay::getShapeKey() {
return builder.build();
}
void Circle3DOverlay::setProperties(const QScriptValue &properties) {
void Circle3DOverlay::setProperties(const QVariantMap& properties) {
Planar3DOverlay::setProperties(properties);
QScriptValue startAt = properties.property("startAt");
QVariant startAt = properties["startAt"];
if (startAt.isValid()) {
setStartAt(startAt.toVariant().toFloat());
setStartAt(startAt.toFloat());
}
QScriptValue endAt = properties.property("endAt");
QVariant endAt = properties["endAt"];
if (endAt.isValid()) {
setEndAt(endAt.toVariant().toFloat());
setEndAt(endAt.toFloat());
}
QScriptValue outerRadius = properties.property("radius");
QVariant outerRadius = properties["radius"];
if (!outerRadius.isValid()) {
outerRadius = properties.property("outerRadius");
outerRadius = properties["outerRadius"];
}
if (outerRadius.isValid()) {
setOuterRadius(outerRadius.toVariant().toFloat());
setOuterRadius(outerRadius.toFloat());
}
QScriptValue innerRadius = properties.property("innerRadius");
QVariant innerRadius = properties["innerRadius"];
if (innerRadius.isValid()) {
setInnerRadius(innerRadius.toVariant().toFloat());
setInnerRadius(innerRadius.toFloat());
}
QScriptValue hasTickMarks = properties.property("hasTickMarks");
QVariant hasTickMarks = properties["hasTickMarks"];
if (hasTickMarks.isValid()) {
setHasTickMarks(hasTickMarks.toVariant().toBool());
setHasTickMarks(hasTickMarks.toBool());
}
QScriptValue majorTickMarksAngle = properties.property("majorTickMarksAngle");
QVariant majorTickMarksAngle = properties["majorTickMarksAngle"];
if (majorTickMarksAngle.isValid()) {
setMajorTickMarksAngle(majorTickMarksAngle.toVariant().toFloat());
setMajorTickMarksAngle(majorTickMarksAngle.toFloat());
}
QScriptValue minorTickMarksAngle = properties.property("minorTickMarksAngle");
QVariant minorTickMarksAngle = properties["minorTickMarksAngle"];
if (minorTickMarksAngle.isValid()) {
setMinorTickMarksAngle(minorTickMarksAngle.toVariant().toFloat());
setMinorTickMarksAngle(minorTickMarksAngle.toFloat());
}
QScriptValue majorTickMarksLength = properties.property("majorTickMarksLength");
QVariant majorTickMarksLength = properties["majorTickMarksLength"];
if (majorTickMarksLength.isValid()) {
setMajorTickMarksLength(majorTickMarksLength.toVariant().toFloat());
setMajorTickMarksLength(majorTickMarksLength.toFloat());
}
QScriptValue minorTickMarksLength = properties.property("minorTickMarksLength");
QVariant minorTickMarksLength = properties["minorTickMarksLength"];
if (minorTickMarksLength.isValid()) {
setMinorTickMarksLength(minorTickMarksLength.toVariant().toFloat());
setMinorTickMarksLength(minorTickMarksLength.toFloat());
}
QScriptValue majorTickMarksColor = properties.property("majorTickMarksColor");
bool valid;
auto majorTickMarksColor = properties["majorTickMarksColor"];
if (majorTickMarksColor.isValid()) {
QScriptValue red = majorTickMarksColor.property("red");
QScriptValue green = majorTickMarksColor.property("green");
QScriptValue blue = majorTickMarksColor.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
_majorTickMarksColor.red = red.toVariant().toInt();
_majorTickMarksColor.green = green.toVariant().toInt();
_majorTickMarksColor.blue = blue.toVariant().toInt();
auto color = xColorFromVariant(majorTickMarksColor, valid);
if (valid) {
_majorTickMarksColor = color;
}
}
QScriptValue minorTickMarksColor = properties.property("minorTickMarksColor");
auto minorTickMarksColor = properties["minorTickMarksColor"];
if (minorTickMarksColor.isValid()) {
QScriptValue red = minorTickMarksColor.property("red");
QScriptValue green = minorTickMarksColor.property("green");
QScriptValue blue = minorTickMarksColor.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
_minorTickMarksColor.red = red.toVariant().toInt();
_minorTickMarksColor.green = green.toVariant().toInt();
_minorTickMarksColor.blue = blue.toVariant().toInt();
auto color = xColorFromVariant(majorTickMarksColor, valid);
if (valid) {
_minorTickMarksColor = color;
}
}
}
QScriptValue Circle3DOverlay::getProperty(const QString& property) {
QVariant Circle3DOverlay::getProperty(const QString& property) {
if (property == "startAt") {
return _startAt;
}
@ -394,10 +387,10 @@ QScriptValue Circle3DOverlay::getProperty(const QString& property) {
return _minorTickMarksLength;
}
if (property == "majorTickMarksColor") {
return xColorToScriptValue(_scriptEngine, _majorTickMarksColor);
return xColorToVariant(_majorTickMarksColor);
}
if (property == "minorTickMarksColor") {
return xColorToScriptValue(_scriptEngine, _minorTickMarksColor);
return xColorToVariant(_minorTickMarksColor);
}
return Planar3DOverlay::getProperty(property);

View file

@ -26,8 +26,8 @@ public:
virtual void render(RenderArgs* args);
virtual const render::ShapeKey getShapeKey() override;
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
float getStartAt() const { return _startAt; }
float getEndAt() const { return _endAt; }

View file

@ -11,8 +11,6 @@
// include this before QGLWidget, which includes an earlier version of OpenGL
#include "Cube3DOverlay.h"
#include <QScriptValue>
#include <SharedUtil.h>
#include <StreamUtils.h>
#include <GeometryCache.h>
@ -110,18 +108,18 @@ Cube3DOverlay* Cube3DOverlay::createClone() const {
return new Cube3DOverlay(this);
}
void Cube3DOverlay::setProperties(const QScriptValue& properties) {
void Cube3DOverlay::setProperties(const QVariantMap& properties) {
Volume3DOverlay::setProperties(properties);
QScriptValue borderSize = properties.property("borderSize");
auto borderSize = properties["borderSize"];
if (borderSize.isValid()) {
float value = borderSize.toVariant().toFloat();
float value = borderSize.toFloat();
setBorderSize(value);
}
}
QScriptValue Cube3DOverlay::getProperty(const QString& property) {
QVariant Cube3DOverlay::getProperty(const QString& property) {
if (property == "borderSize") {
return _borderSize;
}

View file

@ -32,8 +32,8 @@ public:
void setBorderSize(float value) { _borderSize = value; }
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
private:
float _borderSize;

View file

@ -11,10 +11,7 @@
#include "Grid3DOverlay.h"
#include <QScriptValue>
#include <OctreeConstants.h>
#include <DependencyManager.h>
#include <GeometryCache.h>
#include <PathUtils.h>
@ -92,24 +89,24 @@ const render::ShapeKey Grid3DOverlay::getShapeKey() {
return render::ShapeKey::Builder().withOwnPipeline();
}
void Grid3DOverlay::setProperties(const QScriptValue& properties) {
void Grid3DOverlay::setProperties(const QVariantMap& properties) {
Planar3DOverlay::setProperties(properties);
if (properties.property("followCamera").isValid()) {
_followCamera = properties.property("followCamera").toVariant().toBool();
if (properties["followCamera"].isValid()) {
_followCamera = properties["followCamera"].toBool();
}
if (properties.property("majorGridEvery").isValid()) {
_majorGridEvery = properties.property("majorGridEvery").toVariant().toInt();
if (properties["majorGridEvery"].isValid()) {
_majorGridEvery = properties["majorGridEvery"].toInt();
}
if (properties.property("minorGridEvery").isValid()) {
_minorGridEvery = properties.property("minorGridEvery").toVariant().toFloat();
if (properties["minorGridEvery"].isValid()) {
_minorGridEvery = properties["minorGridEvery"].toFloat();
}
updateGrid();
}
QScriptValue Grid3DOverlay::getProperty(const QString& property) {
QVariant Grid3DOverlay::getProperty(const QString& property) {
if (property == "followCamera") {
return _followCamera;
}

View file

@ -28,8 +28,8 @@ public:
virtual void render(RenderArgs* args);
virtual const render::ShapeKey getShapeKey() override;
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual Grid3DOverlay* createClone() const;

View file

@ -12,8 +12,6 @@
#include "Image3DOverlay.h"
#include <QScriptValue>
#include <DependencyManager.h>
#include <GeometryCache.h>
#include <gpu/Batch.h>
@ -114,41 +112,42 @@ const render::ShapeKey Image3DOverlay::getShapeKey() {
return builder.build();
}
void Image3DOverlay::setProperties(const QScriptValue &properties) {
void Image3DOverlay::setProperties(const QVariantMap& properties) {
Billboard3DOverlay::setProperties(properties);
QScriptValue urlValue = properties.property("url");
auto urlValue = properties["url"];
if (urlValue.isValid()) {
QString newURL = urlValue.toVariant().toString();
QString newURL = urlValue.toString();
if (newURL != _url) {
setURL(newURL);
}
}
QScriptValue subImageBounds = properties.property("subImage");
if (subImageBounds.isValid()) {
if (subImageBounds.isNull()) {
auto subImageBoundsVar = properties["subImage"];
if (subImageBoundsVar.isValid()) {
if (subImageBoundsVar.isNull()) {
_fromImage = QRect();
} else {
QRect oldSubImageRect = _fromImage;
QRect subImageRect = _fromImage;
if (subImageBounds.property("x").isValid()) {
subImageRect.setX(subImageBounds.property("x").toVariant().toInt());
auto subImageBounds = subImageBoundsVar.toMap();
if (subImageBounds["x"].isValid()) {
subImageRect.setX(subImageBounds["x"].toInt());
} else {
subImageRect.setX(oldSubImageRect.x());
}
if (subImageBounds.property("y").isValid()) {
subImageRect.setY(subImageBounds.property("y").toVariant().toInt());
if (subImageBounds["y"].isValid()) {
subImageRect.setY(subImageBounds["y"].toInt());
} else {
subImageRect.setY(oldSubImageRect.y());
}
if (subImageBounds.property("width").isValid()) {
subImageRect.setWidth(subImageBounds.property("width").toVariant().toInt());
if (subImageBounds["width"].isValid()) {
subImageRect.setWidth(subImageBounds["width"].toInt());
} else {
subImageRect.setWidth(oldSubImageRect.width());
}
if (subImageBounds.property("height").isValid()) {
subImageRect.setHeight(subImageBounds.property("height").toVariant().toInt());
if (subImageBounds["height"].isValid()) {
subImageRect.setHeight(subImageBounds["height"].toInt());
} else {
subImageRect.setHeight(oldSubImageRect.height());
}
@ -156,21 +155,21 @@ void Image3DOverlay::setProperties(const QScriptValue &properties) {
}
}
QScriptValue emissiveValue = properties.property("emissive");
auto emissiveValue = properties["emissive"];
if (emissiveValue.isValid()) {
_emissive = emissiveValue.toBool();
}
}
QScriptValue Image3DOverlay::getProperty(const QString& property) {
QVariant Image3DOverlay::getProperty(const QString& property) {
if (property == "url") {
return _url;
}
if (property == "subImage") {
return qRectToScriptValue(_scriptEngine, _fromImage);
return _fromImage;
}
if (property == "offsetPosition") {
return vec3toScriptValue(_scriptEngine, getOffsetPosition());
return vec3toVariant(getOffsetPosition());
}
if (property == "emissive") {
return _emissive;

View file

@ -37,8 +37,8 @@ public:
void setURL(const QString& url);
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; }
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal);

View file

@ -64,56 +64,41 @@ void Line3DOverlay::render(RenderArgs* args) {
}
const render::ShapeKey Line3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder();
auto builder = render::ShapeKey::Builder().withoutCullFace();
if (getAlpha() != 1.0f) {
builder.withTranslucent();
}
return builder.build();
}
void Line3DOverlay::setProperties(const QScriptValue& properties) {
void Line3DOverlay::setProperties(const QVariantMap& properties) {
Base3DOverlay::setProperties(properties);
QScriptValue start = properties.property("start");
auto start = properties["start"];
// if "start" property was not there, check to see if they included aliases: startPoint
if (!start.isValid()) {
start = properties.property("startPoint");
start = properties["startPoint"];
}
if (start.isValid()) {
QScriptValue x = start.property("x");
QScriptValue y = start.property("y");
QScriptValue z = start.property("z");
if (x.isValid() && y.isValid() && z.isValid()) {
glm::vec3 newStart;
newStart.x = x.toVariant().toFloat();
newStart.y = y.toVariant().toFloat();
newStart.z = z.toVariant().toFloat();
setStart(newStart);
}
setStart(vec3FromVariant(start));
}
QScriptValue end = properties.property("end");
auto end = properties["end"];
// if "end" property was not there, check to see if they included aliases: endPoint
if (!end.isValid()) {
end = properties.property("endPoint");
end = properties["endPoint"];
}
if (end.isValid()) {
QScriptValue x = end.property("x");
QScriptValue y = end.property("y");
QScriptValue z = end.property("z");
if (x.isValid() && y.isValid() && z.isValid()) {
glm::vec3 newEnd;
newEnd.x = x.toVariant().toFloat();
newEnd.y = y.toVariant().toFloat();
newEnd.z = z.toVariant().toFloat();
setEnd(newEnd);
}
setEnd(vec3FromVariant(end));
}
}
QScriptValue Line3DOverlay::getProperty(const QString& property) {
QVariant Line3DOverlay::getProperty(const QString& property) {
if (property == "start" || property == "startPoint" || property == "p1") {
return vec3toVariant(_start);
}
if (property == "end" || property == "endPoint" || property == "p2") {
return vec3toScriptValue(_scriptEngine, _end);
return vec3toVariant(_end);
}
return Base3DOverlay::getProperty(property);

View file

@ -35,8 +35,8 @@ public:
void setStart(const glm::vec3& start) { _start = start; }
void setEnd(const glm::vec3& end) { _end = end; }
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual Line3DOverlay* createClone() const;

View file

@ -84,7 +84,7 @@ void ModelOverlay::render(RenderArgs* args) {
}
}
void ModelOverlay::setProperties(const QScriptValue &properties) {
void ModelOverlay::setProperties(const QVariantMap& properties) {
auto position = getPosition();
auto rotation = getRotation();
auto scale = getDimensions();
@ -105,16 +105,16 @@ void ModelOverlay::setProperties(const QScriptValue &properties) {
}
}
QScriptValue urlValue = properties.property("url");
if (urlValue.isValid() && urlValue.isString()) {
auto urlValue = properties["url"];
if (urlValue.isValid() && urlValue.canConvert<QString>()) {
_url = urlValue.toString();
_updateModel = true;
_isLoaded = false;
}
QScriptValue texturesValue = properties.property("textures");
if (texturesValue.isValid() && texturesValue.toVariant().canConvert(QVariant::Map)) {
QVariantMap textureMap = texturesValue.toVariant().toMap();
auto texturesValue = properties["textures"];
if (texturesValue.isValid() && texturesValue.canConvert(QVariant::Map)) {
QVariantMap textureMap = texturesValue.toMap();
foreach(const QString& key, textureMap.keys()) {
QUrl newTextureURL = textureMap[key].toUrl();
@ -129,22 +129,22 @@ void ModelOverlay::setProperties(const QScriptValue &properties) {
}
}
QScriptValue ModelOverlay::getProperty(const QString& property) {
QVariant ModelOverlay::getProperty(const QString& property) {
if (property == "url") {
return _url.toString();
}
if (property == "dimensions" || property == "scale" || property == "size") {
return vec3toScriptValue(_scriptEngine, _model.getScaleToFitDimensions());
return vec3toVariant(_model.getScaleToFitDimensions());
}
if (property == "textures") {
if (_modelTextures.size() > 0) {
QScriptValue textures = _scriptEngine->newObject();
QVariantMap textures;
foreach(const QString& key, _modelTextures.keys()) {
textures.setProperty(key, _modelTextures[key].toString());
textures[key] = _modelTextures[key].toString();
}
return textures;
} else {
return QScriptValue();
return QVariant();
}
}

View file

@ -27,9 +27,9 @@ public:
virtual void update(float deltatime);
virtual void render(RenderArgs* args);
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal);
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo);

View file

@ -52,70 +52,68 @@ Overlay::Overlay(const Overlay* overlay) :
_colorPulse(overlay->_colorPulse),
_color(overlay->_color),
_visible(overlay->_visible),
_anchor(overlay->_anchor),
_scriptEngine(NULL)
_anchor(overlay->_anchor)
{
}
void Overlay::init(QScriptEngine* scriptEngine) {
_scriptEngine = scriptEngine;
}
Overlay::~Overlay() {
}
void Overlay::setProperties(const QScriptValue& properties) {
QScriptValue color = properties.property("color");
xColorFromScriptValue(properties.property("color"), _color);
void Overlay::setProperties(const QVariantMap& properties) {
bool valid;
auto color = xColorFromVariant(properties["color"], valid);
if (valid) {
_color = color;
}
if (properties.property("alpha").isValid()) {
setAlpha(properties.property("alpha").toVariant().toFloat());
if (properties["alpha"].isValid()) {
setAlpha(properties["alpha"].toFloat());
}
if (properties.property("glowLevel").isValid()) {
setGlowLevel(properties.property("glowLevel").toVariant().toFloat());
if (properties["glowLevel"].isValid()) {
setGlowLevel(properties["glowLevel"].toFloat());
}
if (properties.property("pulseMax").isValid()) {
setPulseMax(properties.property("pulseMax").toVariant().toFloat());
if (properties["pulseMax"].isValid()) {
setPulseMax(properties["pulseMax"].toFloat());
}
if (properties.property("pulseMin").isValid()) {
setPulseMin(properties.property("pulseMin").toVariant().toFloat());
if (properties["pulseMin"].isValid()) {
setPulseMin(properties["pulseMin"].toFloat());
}
if (properties.property("pulsePeriod").isValid()) {
setPulsePeriod(properties.property("pulsePeriod").toVariant().toFloat());
if (properties["pulsePeriod"].isValid()) {
setPulsePeriod(properties["pulsePeriod"].toFloat());
}
if (properties.property("glowLevelPulse").isValid()) {
setGlowLevelPulse(properties.property("glowLevelPulse").toVariant().toFloat());
if (properties["glowLevelPulse"].isValid()) {
setGlowLevelPulse(properties["glowLevelPulse"].toFloat());
}
if (properties.property("alphaPulse").isValid()) {
setAlphaPulse(properties.property("alphaPulse").toVariant().toFloat());
if (properties["alphaPulse"].isValid()) {
setAlphaPulse(properties["alphaPulse"].toFloat());
}
if (properties.property("colorPulse").isValid()) {
setColorPulse(properties.property("colorPulse").toVariant().toFloat());
if (properties["colorPulse"].isValid()) {
setColorPulse(properties["colorPulse"].toFloat());
}
if (properties.property("visible").isValid()) {
bool visible = properties.property("visible").toVariant().toBool();
if (properties["visible"].isValid()) {
bool visible = properties["visible"].toBool();
setVisible(visible);
}
if (properties.property("anchor").isValid()) {
QString property = properties.property("anchor").toVariant().toString();
if (properties["anchor"].isValid()) {
QString property = properties["anchor"].toString();
if (property == "MyAvatar") {
setAnchor(MY_AVATAR);
}
}
}
QScriptValue Overlay::getProperty(const QString& property) {
QVariant Overlay::getProperty(const QString& property) {
if (property == "color") {
return xColorToScriptValue(_scriptEngine, _color);
return xColorToVariant(_color);
}
if (property == "alpha") {
return _alpha;
@ -148,7 +146,7 @@ QScriptValue Overlay::getProperty(const QString& property) {
return _anchor == MY_AVATAR ? "MyAvatar" : "";
}
return QScriptValue();
return QVariant();
}
xColor Overlay::getColor() {

View file

@ -15,9 +15,6 @@
#include <SharedUtil.h> // for xColor
#include <render/Scene.h>
class QScriptEngine;
class QScriptValue;
class Overlay : public QObject {
Q_OBJECT
@ -34,7 +31,6 @@ public:
Overlay();
Overlay(const Overlay* overlay);
~Overlay();
void init(QScriptEngine* scriptEngine);
virtual void update(float deltatime) {}
virtual void render(RenderArgs* args) = 0;
@ -82,9 +78,9 @@ public:
void setColorPulse(float value) { _colorPulse = value; }
void setAlphaPulse(float value) { _alphaPulse = value; }
virtual void setProperties(const QScriptValue& properties);
virtual void setProperties(const QVariantMap& properties);
virtual Overlay* createClone() const = 0;
virtual QScriptValue getProperty(const QString& property);
virtual QVariant getProperty(const QString& property);
render::ItemID getRenderItemID() const { return _renderItemID; }
void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; }
@ -112,8 +108,6 @@ protected:
xColor _color;
bool _visible; // should the overlay be drawn at all
Anchor _anchor;
QScriptEngine* _scriptEngine;
};
namespace render {

View file

@ -23,49 +23,44 @@ AABox Overlay2D::getBounds() const {
glm::vec3(_bounds.width(), _bounds.height(), 0.01f));
}
void Overlay2D::setProperties(const QScriptValue& properties) {
void Overlay2D::setProperties(const QVariantMap& properties) {
Overlay::setProperties(properties);
QScriptValue bounds = properties.property("bounds");
auto bounds = properties["bounds"];
if (bounds.isValid()) {
QRect boundsRect;
boundsRect.setX(bounds.property("x").toVariant().toInt());
boundsRect.setY(bounds.property("y").toVariant().toInt());
boundsRect.setWidth(bounds.property("width").toVariant().toInt());
boundsRect.setHeight(bounds.property("height").toVariant().toInt());
setBounds(boundsRect);
bool valid;
auto rect = qRectFromVariant(bounds, valid);
setBounds(rect);
} else {
QRect oldBounds = _bounds;
QRect newBounds = oldBounds;
if (properties.property("x").isValid()) {
newBounds.setX(properties.property("x").toVariant().toInt());
if (properties["x"].isValid()) {
newBounds.setX(properties["x"].toInt());
} else {
newBounds.setX(oldBounds.x());
}
if (properties.property("y").isValid()) {
newBounds.setY(properties.property("y").toVariant().toInt());
if (properties["y"].isValid()) {
newBounds.setY(properties["y"].toInt());
} else {
newBounds.setY(oldBounds.y());
}
if (properties.property("width").isValid()) {
newBounds.setWidth(properties.property("width").toVariant().toInt());
if (properties["width"].isValid()) {
newBounds.setWidth(properties["width"].toInt());
} else {
newBounds.setWidth(oldBounds.width());
}
if (properties.property("height").isValid()) {
newBounds.setHeight(properties.property("height").toVariant().toInt());
if (properties["height"].isValid()) {
newBounds.setHeight(properties["height"].toInt());
} else {
newBounds.setHeight(oldBounds.height());
}
setBounds(newBounds);
//qDebug() << "set bounds to " << getBounds();
}
}
QScriptValue Overlay2D::getProperty(const QString& property) {
QVariant Overlay2D::getProperty(const QString& property) {
if (property == "bounds") {
return qRectToScriptValue(_scriptEngine, _bounds);
return qRectToVariant(_bounds);
}
if (property == "x") {
return _bounds.x();

View file

@ -40,8 +40,8 @@ public:
void setHeight(int height) { _bounds.setHeight(height); }
void setBounds(const QRect& bounds) { _bounds = bounds; }
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
protected:
QRect _bounds; // where on the screen to draw

View file

@ -26,26 +26,27 @@ PropertyBinding::PropertyBinding(QString avatar, QUuid entity) :
{
}
QScriptValue propertyBindingToScriptValue(QScriptEngine* engine, const PropertyBinding& value) {
QScriptValue obj = engine->newObject();
QVariant propertyBindingToVariant(const PropertyBinding& value) {
QVariantMap obj;
if (value.avatar == "MyAvatar") {
obj.setProperty("avatar", "MyAvatar");
obj["avatar"] = "MyAvatar";
} else if (!value.entity.isNull()) {
obj.setProperty("entity", engine->newVariant(value.entity));
obj["entity"] = value.entity;
}
return obj;
}
void propertyBindingFromScriptValue(const QScriptValue& object, PropertyBinding& value) {
QScriptValue avatar = object.property("avatar");
QScriptValue entity = object.property("entity");
void propertyBindingFromVariant(const QVariant& objectVar, PropertyBinding& value) {
auto object = objectVar.toMap();
auto avatar = object["avatar"];
auto entity = object["entity"];
if (avatar.isValid() && !avatar.isNull()) {
value.avatar = avatar.toVariant().toString();
value.avatar = avatar.toString();
} else if (entity.isValid() && !entity.isNull()) {
value.entity = entity.toVariant().toUuid();
value.entity = entity.toUuid();
}
}
@ -62,103 +63,82 @@ void OverlayPanel::removeChild(unsigned int childId) {
}
}
QScriptValue OverlayPanel::getProperty(const QString &property) {
QVariant OverlayPanel::getProperty(const QString &property) {
if (property == "anchorPosition") {
return vec3toScriptValue(_scriptEngine, getAnchorPosition());
return vec3toVariant(getAnchorPosition());
}
if (property == "anchorPositionBinding") {
return propertyBindingToScriptValue(_scriptEngine,
PropertyBinding(_anchorPositionBindMyAvatar ?
return propertyBindingToVariant(PropertyBinding(_anchorPositionBindMyAvatar ?
"MyAvatar" : "",
_anchorPositionBindEntity));
}
if (property == "anchorRotation") {
return quatToScriptValue(_scriptEngine, getAnchorRotation());
return quatToVariant(getAnchorRotation());
}
if (property == "anchorRotationBinding") {
return propertyBindingToScriptValue(_scriptEngine,
PropertyBinding(_anchorRotationBindMyAvatar ?
return propertyBindingToVariant(PropertyBinding(_anchorRotationBindMyAvatar ?
"MyAvatar" : "",
_anchorRotationBindEntity));
}
if (property == "anchorScale") {
return vec3toScriptValue(_scriptEngine, getAnchorScale());
return vec3toVariant(getAnchorScale());
}
if (property == "visible") {
return getVisible();
}
if (property == "children") {
QScriptValue array = _scriptEngine->newArray(_children.length());
QVariantList array;
for (int i = 0; i < _children.length(); i++) {
array.setProperty(i, _children[i]);
array.append(_children[i]);
}
return array;
}
QScriptValue value = Billboardable::getProperty(_scriptEngine, property);
auto value = Billboardable::getProperty(property);
if (value.isValid()) {
return value;
}
return PanelAttachable::getProperty(_scriptEngine, property);
return PanelAttachable::getProperty(property);
}
void OverlayPanel::setProperties(const QScriptValue &properties) {
void OverlayPanel::setProperties(const QVariantMap& properties) {
PanelAttachable::setProperties(properties);
Billboardable::setProperties(properties);
QScriptValue anchorPosition = properties.property("anchorPosition");
if (anchorPosition.isValid() &&
anchorPosition.property("x").isValid() &&
anchorPosition.property("y").isValid() &&
anchorPosition.property("z").isValid()) {
glm::vec3 newPosition;
vec3FromScriptValue(anchorPosition, newPosition);
setAnchorPosition(newPosition);
auto anchorPosition = properties["anchorPosition"];
if (anchorPosition.isValid()) {
setAnchorPosition(vec3FromVariant(anchorPosition));
}
QScriptValue anchorPositionBinding = properties.property("anchorPositionBinding");
auto anchorPositionBinding = properties["anchorPositionBinding"];
if (anchorPositionBinding.isValid()) {
PropertyBinding binding = {};
propertyBindingFromScriptValue(anchorPositionBinding, binding);
propertyBindingFromVariant(anchorPositionBinding, binding);
_anchorPositionBindMyAvatar = binding.avatar == "MyAvatar";
_anchorPositionBindEntity = binding.entity;
}
QScriptValue anchorRotation = properties.property("anchorRotation");
if (anchorRotation.isValid() &&
anchorRotation.property("x").isValid() &&
anchorRotation.property("y").isValid() &&
anchorRotation.property("z").isValid() &&
anchorRotation.property("w").isValid()) {
glm::quat newRotation;
quatFromScriptValue(anchorRotation, newRotation);
setAnchorRotation(newRotation);
auto anchorRotation = properties["anchorRotation"];
if (anchorRotation.isValid()) {
setAnchorRotation(quatFromVariant(anchorRotation));
}
QScriptValue anchorRotationBinding = properties.property("anchorRotationBinding");
auto anchorRotationBinding = properties["anchorRotationBinding"];
if (anchorRotationBinding.isValid()) {
PropertyBinding binding = {};
propertyBindingFromScriptValue(anchorPositionBinding, binding);
propertyBindingFromVariant(anchorPositionBinding, binding);
_anchorRotationBindMyAvatar = binding.avatar == "MyAvatar";
_anchorRotationBindEntity = binding.entity;
}
QScriptValue anchorScale = properties.property("anchorScale");
auto anchorScale = properties["anchorScale"];
if (anchorScale.isValid()) {
if (anchorScale.property("x").isValid() &&
anchorScale.property("y").isValid() &&
anchorScale.property("z").isValid()) {
glm::vec3 newScale;
vec3FromScriptValue(anchorScale, newScale);
setAnchorScale(newScale);
} else {
setAnchorScale(anchorScale.toVariant().toFloat());
}
setAnchorScale(vec3FromVariant(anchorScale));
}
QScriptValue visible = properties.property("visible");
auto visible = properties["visible"];
if (visible.isValid()) {
setVisible(visible.toVariant().toBool());
setVisible(visible.toBool());
}
}

View file

@ -16,7 +16,6 @@
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <QScriptValue>
#include <QUuid>
#include "PanelAttachable.h"
@ -30,8 +29,8 @@ public:
QUuid entity;
};
QScriptValue propertyBindingToScriptValue(QScriptEngine* engine, const PropertyBinding& value);
void propertyBindingFromScriptValue(const QScriptValue& object, PropertyBinding& value);
QVariant propertyBindingToVariant(const PropertyBinding& value);
void propertyBindingFromVariant(const QVariant& object, PropertyBinding& value);
class OverlayPanel : public QObject, public PanelAttachable, public Billboardable {
@ -60,8 +59,8 @@ public:
void removeChild(unsigned int childId);
unsigned int popLastChild() { return _children.takeLast(); }
QScriptValue getProperty(const QString& property);
void setProperties(const QScriptValue& properties);
void setProperties(const QVariantMap& properties);
QVariant getProperty(const QString& property);
virtual void applyTransformTo(Transform& transform, bool force = false);

View file

@ -153,7 +153,7 @@ Overlay::Pointer Overlays::getOverlay(unsigned int id) const {
return nullptr;
}
unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) {
unsigned int Overlays::addOverlay(const QString& type, const QVariant& properties) {
Overlay::Pointer thisOverlay = nullptr;
if (type == ImageOverlay::TYPE) {
@ -187,15 +187,13 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
}
if (thisOverlay) {
thisOverlay->setProperties(properties);
thisOverlay->setProperties(properties.toMap());
return addOverlay(thisOverlay);
}
return 0;
}
unsigned int Overlays::addOverlay(Overlay::Pointer overlay) {
overlay->init(_scriptEngine);
QWriteLocker lock(&_lock);
unsigned int thisID = _nextOverlayID;
_nextOverlayID++;
@ -228,7 +226,7 @@ unsigned int Overlays::cloneOverlay(unsigned int id) {
return 0; // Not found
}
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
bool Overlays::editOverlay(unsigned int id, const QVariant& properties) {
QWriteLocker lock(&_lock);
Overlay::Pointer thisOverlay = getOverlay(id);
@ -236,7 +234,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
if (thisOverlay->is3D()) {
render::ItemKey oldItemKey = render::payloadGetKey(thisOverlay);
thisOverlay->setProperties(properties);
thisOverlay->setProperties(properties.toMap());
render::ItemKey itemKey = render::payloadGetKey(thisOverlay);
if (itemKey != oldItemKey) {
@ -249,7 +247,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
}
}
} else {
thisOverlay->setProperties(properties);
thisOverlay->setProperties(properties.toMap());
}
return true;
@ -380,36 +378,21 @@ OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& prop
return result;
}
OverlayPropertyResult::OverlayPropertyResult() :
value(QScriptValue())
{
OverlayPropertyResult::OverlayPropertyResult() {
}
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& result)
{
if (!result.value.isValid()) {
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value) {
if (!value.value.isValid()) {
return QScriptValue::UndefinedValue;
}
QScriptValue object = engine->newObject();
if (result.value.isObject()) {
QScriptValueIterator it(result.value);
while (it.hasNext()) {
it.next();
object.setProperty(it.name(), QScriptValue(it.value().toString()));
}
} else {
object = result.value;
}
return object;
return engine->newVariant(value.value);
}
void OverlayPropertyResultFromScriptValue(const QScriptValue& value, OverlayPropertyResult& result)
{
result.value = value;
void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value) {
value.value = object.toVariant();
}
RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray) {
float bestDistance = std::numeric_limits<float>::max();
bool bestIsFront = false;
@ -456,7 +439,7 @@ RayToOverlayIntersectionResult::RayToOverlayIntersectionResult() :
}
QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) {
QScriptValue obj = engine->newObject();
auto obj = engine->newObject();
obj.setProperty("intersects", value.intersects);
obj.setProperty("overlayID", value.overlayID);
obj.setProperty("distance", value.distance);
@ -488,18 +471,19 @@ QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine,
break;
}
obj.setProperty("face", faceName);
QScriptValue intersection = vec3toScriptValue(engine, value.intersection);
auto intersection = vec3toScriptValue(engine, value.intersection);
obj.setProperty("intersection", intersection);
obj.setProperty("extraInfo", value.extraInfo);
return obj;
}
void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, RayToOverlayIntersectionResult& value) {
value.intersects = object.property("intersects").toVariant().toBool();
value.overlayID = object.property("overlayID").toVariant().toInt();
value.distance = object.property("distance").toVariant().toFloat();
void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& objectVar, RayToOverlayIntersectionResult& value) {
QVariantMap object = objectVar.toVariant().toMap();
value.intersects = object["intersects"].toBool();
value.overlayID = object["overlayID"].toInt();
value.distance = object["distance"].toFloat();
QString faceName = object.property("face").toVariant().toString();
QString faceName = object["face"].toString();
if (faceName == "MIN_X_FACE") {
value.face = MIN_X_FACE;
} else if (faceName == "MAX_X_FACE") {
@ -515,11 +499,15 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
} else {
value.face = UNKNOWN_FACE;
};
QScriptValue intersection = object.property("intersection");
auto intersection = object["intersection"];
if (intersection.isValid()) {
vec3FromScriptValue(intersection, value.intersection);
bool valid;
auto newIntersection = vec3FromVariant(intersection, valid);
if (valid) {
value.intersection = newIntersection;
}
}
value.extraInfo = object.property("extraInfo").toVariant().toString();
value.extraInfo = object["extraInfo"].toString();
}
bool Overlays::isLoaded(unsigned int id) {
@ -556,16 +544,16 @@ unsigned int Overlays::addPanel(OverlayPanel::Pointer panel) {
return thisID;
}
unsigned int Overlays::addPanel(const QScriptValue& properties) {
unsigned int Overlays::addPanel(const QVariant& properties) {
OverlayPanel::Pointer panel = std::make_shared<OverlayPanel>();
panel->init(_scriptEngine);
panel->setProperties(properties);
panel->setProperties(properties.toMap());
return addPanel(panel);
}
void Overlays::editPanel(unsigned int panelId, const QScriptValue& properties) {
void Overlays::editPanel(unsigned int panelId, const QVariant& properties) {
if (_panels.contains(panelId)) {
_panels[panelId]->setProperties(properties);
_panels[panelId]->setProperties(properties.toMap());
}
}

View file

@ -31,7 +31,7 @@ class PickRay;
class OverlayPropertyResult {
public:
OverlayPropertyResult();
QScriptValue value;
QVariant value;
};
Q_DECLARE_METATYPE(OverlayPropertyResult);
@ -75,7 +75,7 @@ public:
public slots:
/// adds an overlay with the specific properties
unsigned int addOverlay(const QString& type, const QScriptValue& properties);
unsigned int addOverlay(const QString& type, const QVariant& properties);
/// adds an overlay that's already been created
unsigned int addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
@ -86,7 +86,7 @@ public slots:
/// edits an overlay updating only the included properties, will return the identified OverlayID in case of
/// successful edit, if the input id is for an unknown overlay this function will have no effect
bool editOverlay(unsigned int id, const QScriptValue& properties);
bool editOverlay(unsigned int id, const QVariant& properties);
/// deletes a particle
void deleteOverlay(unsigned int id);
@ -122,10 +122,10 @@ public slots:
unsigned int addPanel(OverlayPanel::Pointer panel);
/// creates and adds a panel based on a set of properties
unsigned int addPanel(const QScriptValue& properties);
unsigned int addPanel(const QVariant& properties);
/// edit the properties of a panel
void editPanel(unsigned int panelId, const QScriptValue& properties);
void editPanel(unsigned int panelId, const QVariant& properties);
/// get a property of a panel
OverlayPropertyResult getPanelProperty(unsigned int panelId, const QString& property);

View file

@ -8,8 +8,6 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QScriptValueIterator>
#include <limits>
#include <typeinfo>

View file

@ -23,53 +23,38 @@ bool PanelAttachable::getParentVisible() const {
}
}
QScriptValue PanelAttachable::getProperty(QScriptEngine* scriptEngine, const QString &property) {
QVariant PanelAttachable::getProperty(const QString& property) {
if (property == "offsetPosition") {
return vec3toScriptValue(scriptEngine, getOffsetPosition());
return vec3toVariant(getOffsetPosition());
}
if (property == "offsetRotation") {
return quatToScriptValue(scriptEngine, getOffsetRotation());
return quatToVariant(getOffsetRotation());
}
if (property == "offsetScale") {
return vec3toScriptValue(scriptEngine, getOffsetScale());
return vec3toVariant(getOffsetScale());
}
return QScriptValue();
return QVariant();
}
void PanelAttachable::setProperties(const QScriptValue &properties) {
QScriptValue offsetPosition = properties.property("offsetPosition");
if (offsetPosition.isValid() &&
offsetPosition.property("x").isValid() &&
offsetPosition.property("y").isValid() &&
offsetPosition.property("z").isValid()) {
glm::vec3 newPosition;
vec3FromScriptValue(offsetPosition, newPosition);
setOffsetPosition(newPosition);
}
QScriptValue offsetRotation = properties.property("offsetRotation");
if (offsetRotation.isValid() &&
offsetRotation.property("x").isValid() &&
offsetRotation.property("y").isValid() &&
offsetRotation.property("z").isValid() &&
offsetRotation.property("w").isValid()) {
glm::quat newRotation;
quatFromScriptValue(offsetRotation, newRotation);
setOffsetRotation(newRotation);
}
QScriptValue offsetScale = properties.property("offsetScale");
if (offsetScale.isValid()) {
if (offsetScale.property("x").isValid() &&
offsetScale.property("y").isValid() &&
offsetScale.property("z").isValid()) {
glm::vec3 newScale;
vec3FromScriptValue(offsetScale, newScale);
setOffsetScale(newScale);
} else {
setOffsetScale(offsetScale.toVariant().toFloat());
void PanelAttachable::setProperties(const QVariantMap& properties) {
auto offsetPosition = properties["offsetPosition"];
bool valid;
if (offsetPosition.isValid()) {
glm::vec3 newPosition = vec3FromVariant(offsetPosition, valid);
if (valid) {
setOffsetPosition(newPosition);
}
}
auto offsetRotation = properties["offsetRotation"];
if (offsetRotation.isValid()) {
setOffsetRotation(quatFromVariant(offsetRotation));
}
auto offsetScale = properties["offsetScale"];
if (offsetScale.isValid()) {
setOffsetScale(vec3FromVariant(offsetScale));
}
}
void PanelAttachable::applyTransformTo(Transform& transform, bool force) {

View file

@ -57,8 +57,8 @@ public:
void setOffsetScale(const glm::vec3& scale) { _offset.setScale(scale); }
protected:
QScriptValue getProperty(QScriptEngine* scriptEngine, const QString& property);
void setProperties(const QScriptValue& properties);
void setProperties(const QVariantMap& properties);
QVariant getProperty(const QString& property);
/// set position, rotation and scale on transform based on offsets, and parent panel offsets
/// if force is false, only apply transform if it hasn't been applied in the last .1 seconds

View file

@ -35,57 +35,27 @@ AABox Planar3DOverlay::getBounds() const {
return AABox(extents);
}
void Planar3DOverlay::setProperties(const QScriptValue& properties) {
void Planar3DOverlay::setProperties(const QVariantMap& properties) {
Base3DOverlay::setProperties(properties);
QScriptValue dimensions = properties.property("dimensions");
auto dimensions = properties["dimensions"];
// if "dimensions" property was not there, check to see if they included aliases: scale
if (!dimensions.isValid()) {
dimensions = properties.property("scale");
dimensions = properties["scale"];
if (!dimensions.isValid()) {
dimensions = properties.property("size");
dimensions = properties["size"];
}
}
if (dimensions.isValid()) {
bool validDimensions = false;
glm::vec2 newDimensions;
QScriptValue x = dimensions.property("x");
QScriptValue y = dimensions.property("y");
if (x.isValid() && y.isValid()) {
newDimensions.x = x.toVariant().toFloat();
newDimensions.y = y.toVariant().toFloat();
validDimensions = true;
} else {
QScriptValue width = dimensions.property("width");
QScriptValue height = dimensions.property("height");
if (width.isValid() && height.isValid()) {
newDimensions.x = width.toVariant().toFloat();
newDimensions.y = height.toVariant().toFloat();
validDimensions = true;
}
}
// size, scale, dimensions is special, it might just be a single scalar, check that here
if (!validDimensions && dimensions.isNumber()) {
float size = dimensions.toVariant().toFloat();
newDimensions.x = size;
newDimensions.y = size;
validDimensions = true;
}
if (validDimensions) {
setDimensions(newDimensions);
}
setDimensions(vec2FromVariant(dimensions));
}
}
QScriptValue Planar3DOverlay::getProperty(const QString& property) {
QVariant Planar3DOverlay::getProperty(const QString& property) {
if (property == "dimensions" || property == "scale" || property == "size") {
return vec2toScriptValue(_scriptEngine, getDimensions());
return vec2toVariant(getDimensions());
}
return Base3DOverlay::getProperty(property);

View file

@ -26,8 +26,8 @@ public:
void setDimensions(float value) { _dimensions = glm::vec2(value); }
void setDimensions(const glm::vec2& value) { _dimensions = value; }
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal);

View file

@ -57,7 +57,7 @@ QmlOverlay::~QmlOverlay() {
}
}
void QmlOverlay::setProperties(const QScriptValue& properties) {
void QmlOverlay::setProperties(const QVariantMap& properties) {
Overlay2D::setProperties(properties);
auto bounds = _bounds;
std::weak_ptr<QQuickItem> weakQmlElement;
@ -71,7 +71,7 @@ void QmlOverlay::setProperties(const QScriptValue& properties) {
_qmlElement->setHeight(bounds.height());
}
});
QMetaObject::invokeMethod(_qmlElement.get(), "updatePropertiesFromScript", Q_ARG(QVariant, properties.toVariant()));
QMetaObject::invokeMethod(_qmlElement.get(), "updatePropertiesFromScript", Q_ARG(QVariant, properties));
}
void QmlOverlay::render(RenderArgs* args) {

View file

@ -28,7 +28,7 @@ public:
// Cannot fetch properties from QML based overlays due to race conditions
bool supportsGetProperty() const override { return false; }
void setProperties(const QScriptValue& properties) override;
void setProperties(const QVariantMap& properties) override;
void render(RenderArgs* args) override;
private:

View file

@ -96,7 +96,7 @@ const render::ShapeKey Rectangle3DOverlay::getShapeKey() {
return builder.build();
}
void Rectangle3DOverlay::setProperties(const QScriptValue &properties) {
void Rectangle3DOverlay::setProperties(const QVariantMap& properties) {
Planar3DOverlay::setProperties(properties);
}

View file

@ -25,7 +25,7 @@ public:
~Rectangle3DOverlay();
virtual void render(RenderArgs* args);
virtual const render::ShapeKey getShapeKey() override;
virtual void setProperties(const QScriptValue& properties);
void setProperties(const QVariantMap& properties) override;
virtual Rectangle3DOverlay* createClone() const;
private:

View file

@ -121,57 +121,54 @@ const render::ShapeKey Text3DOverlay::getShapeKey() {
return builder.build();
}
void Text3DOverlay::setProperties(const QScriptValue& properties) {
void Text3DOverlay::setProperties(const QVariantMap& properties) {
Billboard3DOverlay::setProperties(properties);
QScriptValue text = properties.property("text");
auto text = properties["text"];
if (text.isValid()) {
setText(text.toVariant().toString());
setText(text.toString());
}
QScriptValue textAlpha = properties.property("textAlpha");
auto textAlpha = properties["textAlpha"];
if (textAlpha.isValid()) {
setTextAlpha(textAlpha.toVariant().toFloat());
setTextAlpha(textAlpha.toFloat());
}
QScriptValue backgroundColor = properties.property("backgroundColor");
bool valid;
auto backgroundColor = properties["backgroundColor"];
if (backgroundColor.isValid()) {
QScriptValue red = backgroundColor.property("red");
QScriptValue green = backgroundColor.property("green");
QScriptValue blue = backgroundColor.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
_backgroundColor.red = red.toVariant().toInt();
_backgroundColor.green = green.toVariant().toInt();
_backgroundColor.blue = blue.toVariant().toInt();
auto color = xColorFromVariant(backgroundColor, valid);
if (valid) {
_backgroundColor = color;
}
}
if (properties.property("backgroundAlpha").isValid()) {
setAlpha(properties.property("backgroundAlpha").toVariant().toFloat());
if (properties["backgroundAlpha"].isValid()) {
setAlpha(properties["backgroundAlpha"].toFloat());
}
if (properties.property("lineHeight").isValid()) {
setLineHeight(properties.property("lineHeight").toVariant().toFloat());
if (properties["lineHeight"].isValid()) {
setLineHeight(properties["lineHeight"].toFloat());
}
if (properties.property("leftMargin").isValid()) {
setLeftMargin(properties.property("leftMargin").toVariant().toFloat());
if (properties["leftMargin"].isValid()) {
setLeftMargin(properties["leftMargin"].toFloat());
}
if (properties.property("topMargin").isValid()) {
setTopMargin(properties.property("topMargin").toVariant().toFloat());
if (properties["topMargin"].isValid()) {
setTopMargin(properties["topMargin"].toFloat());
}
if (properties.property("rightMargin").isValid()) {
setRightMargin(properties.property("rightMargin").toVariant().toFloat());
if (properties["rightMargin"].isValid()) {
setRightMargin(properties["rightMargin"].toFloat());
}
if (properties.property("bottomMargin").isValid()) {
setBottomMargin(properties.property("bottomMargin").toVariant().toFloat());
if (properties["bottomMargin"].isValid()) {
setBottomMargin(properties["bottomMargin"].toFloat());
}
}
QScriptValue Text3DOverlay::getProperty(const QString& property) {
QVariant Text3DOverlay::getProperty(const QString& property) {
if (property == "text") {
return _text;
}
@ -179,7 +176,7 @@ QScriptValue Text3DOverlay::getProperty(const QString& property) {
return _textAlpha;
}
if (property == "backgroundColor") {
return xColorToScriptValue(_scriptEngine, _backgroundColor);
return xColorToVariant(_backgroundColor);
}
if (property == "backgroundAlpha") {
return Billboard3DOverlay::getProperty("alpha");

View file

@ -53,8 +53,8 @@ public:
void setRightMargin(float margin) { _rightMargin = margin; }
void setBottomMargin(float margin) { _bottomMargin = margin; }
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
QSizeF textSize(const QString& test) const; // Meters

View file

@ -26,67 +26,27 @@ AABox Volume3DOverlay::getBounds() const {
return AABox(extents);
}
void Volume3DOverlay::setProperties(const QScriptValue& properties) {
void Volume3DOverlay::setProperties(const QVariantMap& properties) {
Base3DOverlay::setProperties(properties);
QScriptValue dimensions = properties.property("dimensions");
auto dimensions = properties["dimensions"];
// if "dimensions" property was not there, check to see if they included aliases: scale
if (!dimensions.isValid()) {
dimensions = properties.property("scale");
dimensions = properties["scale"];
if (!dimensions.isValid()) {
dimensions = properties.property("size");
dimensions = properties["size"];
}
}
if (dimensions.isValid()) {
bool validDimensions = false;
glm::vec3 newDimensions;
QScriptValue x = dimensions.property("x");
QScriptValue y = dimensions.property("y");
QScriptValue z = dimensions.property("z");
if (x.isValid() && x.isNumber() &&
y.isValid() && y.isNumber() &&
z.isValid() && z.isNumber()) {
newDimensions.x = x.toNumber();
newDimensions.y = y.toNumber();
newDimensions.z = z.toNumber();
validDimensions = true;
} else {
QScriptValue width = dimensions.property("width");
QScriptValue height = dimensions.property("height");
QScriptValue depth = dimensions.property("depth");
if (width.isValid() && width.isNumber() &&
height.isValid() && height.isNumber() &&
depth.isValid() && depth.isNumber()) {
newDimensions.x = width.toNumber();
newDimensions.y = height.toNumber();
newDimensions.z = depth.toNumber();
validDimensions = true;
}
}
// size, scale, dimensions is special, it might just be a single scalar, check that here
if (!validDimensions && dimensions.isNumber()) {
float size = dimensions.toNumber();
newDimensions.x = size;
newDimensions.y = size;
newDimensions.z = size;
validDimensions = true;
}
if (validDimensions) {
setDimensions(newDimensions);
}
setDimensions(vec3FromVariant(dimensions));
}
}
QScriptValue Volume3DOverlay::getProperty(const QString& property) {
QVariant Volume3DOverlay::getProperty(const QString& property) {
if (property == "dimensions" || property == "scale" || property == "size") {
return vec3toScriptValue(_scriptEngine, getDimensions());
return vec3toVariant(getDimensions());
}
return Base3DOverlay::getProperty(property);

View file

@ -26,8 +26,8 @@ public:
void setDimensions(float value) { _localBoundingBox.setBox(glm::vec3(-value / 2.0f), value); }
void setDimensions(const glm::vec3& value) { _localBoundingBox.setBox(-value / 2.0f, value); }
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
BoxFace& face, glm::vec3& surfaceNormal);

Some files were not shown because too many files have changed in this diff Show more