Merge branch 'master' of https://github.com/highfidelity/hifi into low-latency-audio

This commit is contained in:
Ken Cooke 2016-08-29 12:38:17 -07:00
commit 28a99a7a03
337 changed files with 10705 additions and 3617 deletions

View file

@ -18,6 +18,7 @@
* [oglplus](http://oglplus.org/) ~> 0.63 * [oglplus](http://oglplus.org/) ~> 0.63
* [OpenVR](https://github.com/ValveSoftware/openvr) ~> 0.91 (Win32 only) * [OpenVR](https://github.com/ValveSoftware/openvr) ~> 0.91 (Win32 only)
* [Polyvox](http://www.volumesoffun.com/) ~> 0.2.1 * [Polyvox](http://www.volumesoffun.com/) ~> 0.2.1
* [QuaZip](http://sourceforge.net/projects/quazip/files/quazip/) ~> 0.7.1
* [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3 * [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3
* [soxr](http://soxr.sourceforge.net) ~> 0.1.1 * [soxr](http://soxr.sourceforge.net) ~> 0.1.1
* [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3 * [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3

View file

@ -66,6 +66,9 @@ else ()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter")
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -Woverloaded-virtual -Wdouble-promotion") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -Woverloaded-virtual -Wdouble-promotion")
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "5.1") # gcc 5.1 and on have suggest-override
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
endif ()
endif () endif ()
endif(WIN32) endif(WIN32)
@ -201,6 +204,7 @@ set_property(DIRECTORY PROPERTY EP_PREFIX ${EXTERNAL_PROJECT_PREFIX})
setup_externals_binary_dir() setup_externals_binary_dir()
option(USE_NSIGHT "Attempt to find the nSight libraries" 1) option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
option(GET_QUAZIP "Get QuaZip library automatically as external project" 1)
if (WIN32) if (WIN32)

View file

@ -392,7 +392,6 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) {
const int16_t* nextSoundOutput = NULL; const int16_t* nextSoundOutput = NULL;
if (_avatarSound) { if (_avatarSound) {
const QByteArray& soundByteArray = _avatarSound->getByteArray(); const QByteArray& soundByteArray = _avatarSound->getByteArray();
nextSoundOutput = reinterpret_cast<const int16_t*>(soundByteArray.data() nextSoundOutput = reinterpret_cast<const int16_t*>(soundByteArray.data()
+ _numAvatarSoundSentBytes); + _numAvatarSoundSentBytes);
@ -442,6 +441,10 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) {
audioPacket->writePrimitive(headOrientation); audioPacket->writePrimitive(headOrientation);
} else if (nextSoundOutput) { } else if (nextSoundOutput) {
// write the codec
QString codecName;
audioPacket->writeString(codecName);
// assume scripted avatar audio is mono and set channel flag to zero // assume scripted avatar audio is mono and set channel flag to zero
audioPacket->writePrimitive((quint8)0); audioPacket->writePrimitive((quint8)0);

View file

@ -52,10 +52,10 @@ public:
float getLastReceivedAudioLoudness() const { return _lastReceivedAudioLoudness; } float getLastReceivedAudioLoudness() const { return _lastReceivedAudioLoudness; }
QUuid getSessionUUID() const; QUuid getSessionUUID() const;
virtual void aboutToFinish(); virtual void aboutToFinish() override;
public slots: public slots:
void run(); void run() override;
void playAvatarSound(SharedSoundPointer avatarSound) { setAvatarSound(avatarSound); } void playAvatarSound(SharedSoundPointer avatarSound) { setAvatarSound(avatarSound); }
private slots: private slots:

View file

@ -24,27 +24,27 @@ public:
AssignmentAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity); AssignmentAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity);
virtual ~AssignmentAction(); virtual ~AssignmentAction();
virtual void removeFromSimulation(EntitySimulationPointer simulation) const; virtual void removeFromSimulation(EntitySimulationPointer simulation) const override;
virtual EntityItemWeakPointer getOwnerEntity() const { return _ownerEntity; } virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; }
virtual void setOwnerEntity(const EntityItemPointer ownerEntity) { _ownerEntity = ownerEntity; } virtual void setOwnerEntity(const EntityItemPointer ownerEntity) override { _ownerEntity = ownerEntity; }
virtual bool updateArguments(QVariantMap arguments); virtual bool updateArguments(QVariantMap arguments) override;
virtual QVariantMap getArguments(); virtual QVariantMap getArguments() override;
virtual QByteArray serialize() const; virtual QByteArray serialize() const override;
virtual void deserialize(QByteArray serializedArguments); virtual void deserialize(QByteArray serializedArguments) override;
private: private:
QByteArray _data; QByteArray _data;
protected: protected:
virtual glm::vec3 getPosition(); virtual glm::vec3 getPosition() override;
virtual void setPosition(glm::vec3 position); virtual void setPosition(glm::vec3 position) override;
virtual glm::quat getRotation(); virtual glm::quat getRotation() override;
virtual void setRotation(glm::quat rotation); virtual void setRotation(glm::quat rotation) override;
virtual glm::vec3 getLinearVelocity(); virtual glm::vec3 getLinearVelocity() override;
virtual void setLinearVelocity(glm::vec3 linearVelocity); virtual void setLinearVelocity(glm::vec3 linearVelocity) override;
virtual glm::vec3 getAngularVelocity(); virtual glm::vec3 getAngularVelocity() override;
virtual void setAngularVelocity(glm::vec3 angularVelocity); virtual void setAngularVelocity(glm::vec3 angularVelocity) override;
bool _active; bool _active;
EntityItemWeakPointer _ownerEntity; EntityItemWeakPointer _ownerEntity;

View file

@ -22,8 +22,8 @@ public:
virtual EntityActionPointer factory(EntityActionType type, virtual EntityActionPointer factory(EntityActionType type,
const QUuid& id, const QUuid& id,
EntityItemPointer ownerEntity, EntityItemPointer ownerEntity,
QVariantMap arguments); QVariantMap arguments) override;
virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data); virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data) override;
}; };
#endif // hifi_AssignmentActionFactory_h #endif // hifi_AssignmentActionFactory_h

View file

@ -26,7 +26,7 @@ public:
AssetServer(ReceivedMessage& message); AssetServer(ReceivedMessage& message);
public slots: public slots:
void run(); void run() override;
private slots: private slots:
void completeSetup(); void completeSetup();
@ -35,9 +35,9 @@ private slots:
void handleAssetGet(QSharedPointer<ReceivedMessage> packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer<ReceivedMessage> packet, SharedNodePointer senderNode);
void handleAssetUpload(QSharedPointer<ReceivedMessage> packetList, SharedNodePointer senderNode); void handleAssetUpload(QSharedPointer<ReceivedMessage> packetList, SharedNodePointer senderNode);
void handleAssetMappingOperation(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode); void handleAssetMappingOperation(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void sendStatsPacket(); void sendStatsPacket() override;
private: private:
using Mappings = QVariantHash; using Mappings = QVariantHash;

View file

@ -27,7 +27,7 @@ class SendAssetTask : public QRunnable {
public: public:
SendAssetTask(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& sendToNode, const QDir& resourcesDir); SendAssetTask(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& sendToNode, const QDir& resourcesDir);
void run(); void run() override;
private: private:
QSharedPointer<ReceivedMessage> _message; QSharedPointer<ReceivedMessage> _message;

View file

@ -27,9 +27,9 @@ class Node;
class UploadAssetTask : public QRunnable { class UploadAssetTask : public QRunnable {
public: public:
UploadAssetTask(QSharedPointer<ReceivedMessage> message, QSharedPointer<Node> senderNode, const QDir& resourcesDir); UploadAssetTask(QSharedPointer<ReceivedMessage> message, QSharedPointer<Node> senderNode, const QDir& resourcesDir);
void run(); void run() override;
private: private:
QSharedPointer<ReceivedMessage> _receivedMessage; QSharedPointer<ReceivedMessage> _receivedMessage;
QSharedPointer<Node> _senderNode; QSharedPointer<Node> _senderNode;

View file

@ -35,9 +35,9 @@ public:
public slots: public slots:
/// threaded run of assignment /// threaded run of assignment
void run(); void run() override;
void sendStatsPacket(); void sendStatsPacket() override;
static const InboundAudioStream::Settings& getStreamSettings() { return _streamSettings; } static const InboundAudioStream::Settings& getStreamSettings() { return _streamSettings; }

View file

@ -49,17 +49,17 @@ public:
// removes an AudioHRTF object for a given stream // removes an AudioHRTF object for a given stream
void removeHRTFForStream(const QUuid& nodeID, const QUuid& streamID = QUuid()); void removeHRTFForStream(const QUuid& nodeID, const QUuid& streamID = QUuid());
int parseData(ReceivedMessage& message); int parseData(ReceivedMessage& message) override;
void checkBuffersBeforeFrameSend(); void checkBuffersBeforeFrameSend();
void removeDeadInjectedStreams(); void removeDeadInjectedStreams();
QJsonObject getAudioStreamStats(); QJsonObject getAudioStreamStats();
void sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode); void sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode);
void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; } void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; }
quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; } quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; }

View file

@ -25,7 +25,7 @@ private:
AvatarAudioStream(const AvatarAudioStream&); AvatarAudioStream(const AvatarAudioStream&);
AvatarAudioStream& operator= (const AvatarAudioStream&); AvatarAudioStream& operator= (const AvatarAudioStream&);
int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples); int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) override;
}; };
#endif // hifi_AvatarAudioStream_h #endif // hifi_AvatarAudioStream_h

View file

@ -27,11 +27,11 @@ public:
~AvatarMixer(); ~AvatarMixer();
public slots: public slots:
/// runs the avatar mixer /// runs the avatar mixer
void run(); void run() override;
void nodeKilled(SharedNodePointer killedNode); void nodeKilled(SharedNodePointer killedNode);
void sendStatsPacket(); void sendStatsPacket() override;
private slots: private slots:
void handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode); void handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
@ -45,14 +45,14 @@ private slots:
private: private:
void broadcastAvatarData(); void broadcastAvatarData();
void parseDomainServerSettings(const QJsonObject& domainSettings); void parseDomainServerSettings(const QJsonObject& domainSettings);
QThread _broadcastThread; QThread _broadcastThread;
p_high_resolution_clock::time_point _lastFrameTimestamp; p_high_resolution_clock::time_point _lastFrameTimestamp;
float _trailingSleepRatio { 1.0f }; float _trailingSleepRatio { 1.0f };
float _performanceThrottlingRatio { 0.0f }; float _performanceThrottlingRatio { 0.0f };
int _sumListeners { 0 }; int _sumListeners { 0 };
int _numStatFrames { 0 }; int _numStatFrames { 0 };
int _sumIdentityPackets { 0 }; int _sumIdentityPackets { 0 };

View file

@ -25,7 +25,8 @@ class AssignmentParentFinder : public SpatialParentFinder {
public: public:
AssignmentParentFinder(EntityTreePointer tree) : _tree(tree) { } AssignmentParentFinder(EntityTreePointer tree) : _tree(tree) { }
virtual ~AssignmentParentFinder() { } virtual ~AssignmentParentFinder() { }
virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success, SpatialParentTree* entityTree = nullptr) const; virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success,
SpatialParentTree* entityTree = nullptr) const override;
protected: protected:
EntityTreePointer _tree; EntityTreePointer _tree;

View file

@ -18,7 +18,7 @@
class EntityNodeData : public OctreeQueryNode { class EntityNodeData : public OctreeQueryNode {
public: public:
virtual PacketType getMyPacketType() const { return PacketType::EntityData; } virtual PacketType getMyPacketType() const override { return PacketType::EntityData; }
quint64 getLastDeletedEntitiesSentAt() const { return _lastDeletedEntitiesSentAt; } quint64 getLastDeletedEntitiesSentAt() const { return _lastDeletedEntitiesSentAt; }
void setLastDeletedEntitiesSentAt(quint64 sentAt) { _lastDeletedEntitiesSentAt = sentAt; } void setLastDeletedEntitiesSentAt(quint64 sentAt) { _lastDeletedEntitiesSentAt = sentAt; }

View file

@ -24,9 +24,9 @@ public:
MessagesMixer(ReceivedMessage& message); MessagesMixer(ReceivedMessage& message);
public slots: public slots:
void run(); void run() override;
void nodeKilled(SharedNodePointer killedNode); void nodeKilled(SharedNodePointer killedNode);
void sendStatsPacket(); void sendStatsPacket() override;
private slots: private slots:
void handleMessages(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode); void handleMessages(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);

View file

@ -74,15 +74,15 @@ public:
NodeToSenderStatsMap getSingleSenderStats() { QReadLocker locker(&_senderStatsLock); return _singleSenderStats; } NodeToSenderStatsMap getSingleSenderStats() { QReadLocker locker(&_senderStatsLock); return _singleSenderStats; }
virtual void terminating() { _shuttingDown = true; ReceivedPacketProcessor::terminating(); } virtual void terminating() override { _shuttingDown = true; ReceivedPacketProcessor::terminating(); }
protected: protected:
virtual void processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode); virtual void processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) override;
virtual unsigned long getMaxWait() const; virtual unsigned long getMaxWait() const override;
virtual void preProcess(); virtual void preProcess() override;
virtual void midProcess(); virtual void midProcess() override;
private: private:
int sendNackPackets(); int sendNackPackets();

View file

@ -47,7 +47,7 @@ public:
protected: protected:
/// Implements generic processing behavior for this thread. /// Implements generic processing behavior for this thread.
virtual bool process(); virtual bool process() override;
private: private:
int handlePacketSend(SharedNodePointer node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent, bool dontSuppressDuplicate = false); int handlePacketSend(SharedNodePointer node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent, bool dontSuppressDuplicate = false);

View file

@ -1063,6 +1063,12 @@ void OctreeServer::readConfiguration() {
_wantBackup = !noBackup; _wantBackup = !noBackup;
qDebug() << "wantBackup=" << _wantBackup; qDebug() << "wantBackup=" << _wantBackup;
if (!readOptionString("backupDirectoryPath", settingsSectionObject, _backupDirectoryPath)) {
_backupDirectoryPath = "";
}
qDebug() << "backupDirectoryPath=" << _backupDirectoryPath;
readOptionBool(QString("persistFileDownload"), settingsSectionObject, _persistFileDownload); readOptionBool(QString("persistFileDownload"), settingsSectionObject, _persistFileDownload);
qDebug() << "persistFileDownload=" << _persistFileDownload; qDebug() << "persistFileDownload=" << _persistFileDownload;
@ -1160,25 +1166,25 @@ void OctreeServer::domainSettingsRequestComplete() {
// If persist filename does not exist, let's see if there is one beside the application binary // If persist filename does not exist, let's see if there is one beside the application binary
// If there is, let's copy it over to our target persist directory // If there is, let's copy it over to our target persist directory
QDir persistPath { _persistFilePath }; QDir persistPath { _persistFilePath };
QString absoluteFilePath = persistPath.absolutePath(); QString persistAbsoluteFilePath = persistPath.absolutePath();
if (persistPath.isRelative()) { if (persistPath.isRelative()) {
// if the domain settings passed us a relative path, make an absolute path that is relative to the // if the domain settings passed us a relative path, make an absolute path that is relative to the
// default data directory // default data directory
absoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath); persistAbsoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath);
} }
static const QString ENTITY_PERSIST_EXTENSION = ".json.gz"; static const QString ENTITY_PERSIST_EXTENSION = ".json.gz";
// force the persist file to end with .json.gz // force the persist file to end with .json.gz
if (!absoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) { if (!persistAbsoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) {
absoluteFilePath += ENTITY_PERSIST_EXTENSION; persistAbsoluteFilePath += ENTITY_PERSIST_EXTENSION;
} else { } else {
// make sure the casing of .json.gz is correct // make sure the casing of .json.gz is correct
absoluteFilePath.replace(ENTITY_PERSIST_EXTENSION, ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive); persistAbsoluteFilePath.replace(ENTITY_PERSIST_EXTENSION, ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive);
} }
if (!QFile::exists(absoluteFilePath)) { if (!QFile::exists(persistAbsoluteFilePath)) {
qDebug() << "Persist file does not exist, checking for existence of persist file next to application"; qDebug() << "Persist file does not exist, checking for existence of persist file next to application";
static const QString OLD_DEFAULT_PERSIST_FILENAME = "resources/models.json.gz"; static const QString OLD_DEFAULT_PERSIST_FILENAME = "resources/models.json.gz";
@ -1204,7 +1210,7 @@ void OctreeServer::domainSettingsRequestComplete() {
pathToCopyFrom = oldDefaultPersistPath; pathToCopyFrom = oldDefaultPersistPath;
} }
QDir persistFileDirectory { QDir::cleanPath(absoluteFilePath + "/..") }; QDir persistFileDirectory { QDir::cleanPath(persistAbsoluteFilePath + "/..") };
if (!persistFileDirectory.exists()) { if (!persistFileDirectory.exists()) {
qDebug() << "Creating data directory " << persistFileDirectory.absolutePath(); qDebug() << "Creating data directory " << persistFileDirectory.absolutePath();
@ -1212,16 +1218,46 @@ void OctreeServer::domainSettingsRequestComplete() {
} }
if (shouldCopy) { if (shouldCopy) {
qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << absoluteFilePath; qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << persistAbsoluteFilePath;
QFile::copy(pathToCopyFrom, absoluteFilePath); QFile::copy(pathToCopyFrom, persistAbsoluteFilePath);
} else { } else {
qDebug() << "No existing persist file found"; qDebug() << "No existing persist file found";
} }
} }
auto persistFileDirectory = QFileInfo(persistAbsoluteFilePath).absolutePath();
if (_backupDirectoryPath.isEmpty()) {
// Use the persist file's directory to store backups
_backupDirectoryPath = persistFileDirectory;
} else {
// The backup directory has been set.
// If relative, make it relative to the entities directory in the application data directory
// If absolute, no resolution is necessary
QDir backupDirectory { _backupDirectoryPath };
QString absoluteBackupDirectory;
if (backupDirectory.isRelative()) {
absoluteBackupDirectory = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_backupDirectoryPath);
absoluteBackupDirectory = QDir(absoluteBackupDirectory).absolutePath();
} else {
absoluteBackupDirectory = backupDirectory.absolutePath();
}
backupDirectory = QDir(absoluteBackupDirectory);
if (!backupDirectory.exists()) {
if (backupDirectory.mkpath(".")) {
qDebug() << "Created backup directory";
} else {
qDebug() << "ERROR creating backup directory, using persist file directory";
_backupDirectoryPath = persistFileDirectory;
}
} else {
_backupDirectoryPath = absoluteBackupDirectory;
}
}
qDebug() << "Backups will be stored in: " << _backupDirectoryPath;
// now set up PersistThread // now set up PersistThread
_persistThread = new OctreePersistThread(_tree, absoluteFilePath, _persistInterval, _persistThread = new OctreePersistThread(_tree, persistAbsoluteFilePath, _backupDirectoryPath, _persistInterval,
_wantBackup, _settings, _debugTimestampNow, _persistAsFileType); _wantBackup, _settings, _debugTimestampNow, _persistAsFileType);
_persistThread->initialize(true); _persistThread->initialize(true);
} }

View file

@ -120,16 +120,16 @@ public:
static int howManyThreadsDidHandlePacketSend(quint64 since = 0); static int howManyThreadsDidHandlePacketSend(quint64 since = 0);
static int howManyThreadsDidCallWriteDatagram(quint64 since = 0); static int howManyThreadsDidCallWriteDatagram(quint64 since = 0);
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler); bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) override;
virtual void aboutToFinish(); virtual void aboutToFinish() override;
public slots: public slots:
/// runs the octree server assignment /// runs the octree server assignment
void run(); void run() override;
virtual void nodeAdded(SharedNodePointer node); virtual void nodeAdded(SharedNodePointer node);
virtual void nodeKilled(SharedNodePointer node); virtual void nodeKilled(SharedNodePointer node);
void sendStatsPacket(); void sendStatsPacket() override;
private slots: private slots:
void domainSettingsRequestComplete(); void domainSettingsRequestComplete();
@ -172,6 +172,7 @@ protected:
QString _persistFilePath; QString _persistFilePath;
QString _persistAsFileType; QString _persistAsFileType;
QString _backupDirectoryPath;
int _packetsPerClientPerInterval; int _packetsPerClientPerInterval;
int _packetsTotalPerInterval; int _packetsTotalPerInterval;
OctreePointer _tree; // this IS a reaveraging tree OctreePointer _tree; // this IS a reaveraging tree

55
cmake/externals/quazip/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,55 @@
set(EXTERNAL_NAME quazip)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
cmake_policy(SET CMP0046 OLD)
include(ExternalProject)
if (WIN32)
# windows shell does not like backslashes expanded on the command line,
# so convert all backslashes in the QT path to forward slashes
string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH})
elseif ($ENV{QT_CMAKE_PREFIX_PATH})
set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH})
endif ()
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://s3-us-west-1.amazonaws.com/hifi-production/dependencies/quazip-0.7.2.zip
URL_MD5 2955176048a31262c09259ca8d309d19
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_PREFIX_PATH=${QT_CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_NAME_DIR:PATH=<INSTALL_DIR>/lib -DZLIB_ROOT=${ZLIB_ROOT} -DCMAKE_POSITION_INDEPENDENT_CODE=ON
LOG_DOWNLOAD 1
LOG_CONFIGURE 1
LOG_BUILD 1
)
add_dependencies(quazip zlib)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES
FOLDER "hidden/externals"
INSTALL_NAME_DIR ${INSTALL_DIR}/lib
BUILD_WITH_INSTALL_RPATH True)
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INSTALL_DIR}/include CACHE PATH "List of QuaZip include directories")
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIR} CACHE PATH "List of QuaZip include directories")
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${INSTALL_DIR}/lib CACHE FILEPATH "Location of QuaZip DLL")
if (APPLE)
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.1.0.0.dylib CACHE FILEPATH "Location of QuaZip release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5d.1.0.0.dylib CACHE FILEPATH "Location of QuaZip release library")
elseif (WIN32)
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/quazip5.lib CACHE FILEPATH "Location of QuaZip release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/quazip5d.lib CACHE FILEPATH "Location of QuaZip release library")
else ()
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5d.so CACHE FILEPATH "Location of QuaZip release library")
endif ()
include(SelectLibraryConfigurations)
select_library_configurations(${EXTERNAL_NAME_UPPER})
# Force selected libraries into the cache
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE FILEPATH "Location of QuaZip libraries")
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of QuaZip libraries")

View file

@ -0,0 +1,16 @@
#
# Copyright 2015 High Fidelity, Inc.
# Created by Leonardo Murillo on 2015/11/20
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
macro(TARGET_QUAZIP)
add_dependency_external_projects(quazip)
find_package(QuaZip REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${QUAZIP_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES})
if (WIN32)
add_paths_to_fixup_libs(${QUAZIP_DLL_PATH})
endif ()
endmacro()

View file

@ -0,0 +1,29 @@
#
# FindQuaZip.h
# StackManagerQt/cmake/modules
#
# Created by Mohammed Nafees.
# Copyright (c) 2014 High Fidelity. All rights reserved.
#
# QUAZIP_FOUND - QuaZip library was found
# QUAZIP_INCLUDE_DIR - Path to QuaZip include dir
# QUAZIP_INCLUDE_DIRS - Path to QuaZip and zlib include dir (combined from QUAZIP_INCLUDE_DIR + ZLIB_INCLUDE_DIR)
# QUAZIP_LIBRARIES - List of QuaZip libraries
# QUAZIP_ZLIB_INCLUDE_DIR - The include dir of zlib headers
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("quazip")
if (WIN32)
find_path(QUAZIP_INCLUDE_DIRS quazip.h PATH_SUFFIXES include/quazip HINTS ${QUAZIP_SEARCH_DIRS})
elseif (APPLE)
find_path(QUAZIP_INCLUDE_DIRS quazip.h PATH_SUFFIXES include/quazip HINTS ${QUAZIP_SEARCH_DIRS})
else ()
find_path(QUAZIP_INCLUDE_DIRS quazip.h PATH_SUFFIXES quazip HINTS ${QUAZIP_SEARCH_DIRS})
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(QUAZIP DEFAULT_MSG QUAZIP_INCLUDE_DIRS)
mark_as_advanced(QUAZIP_INCLUDE_DIRS QUAZIP_SEARCH_DIRS)

View file

@ -1108,6 +1108,14 @@
"default": "models.json.gz", "default": "models.json.gz",
"advanced": true "advanced": true
}, },
{
"name": "backupDirectoryPath",
"label": "Entities Backup Directory Path",
"help": "The path to the directory to store backups in.<br/>If this path is relative it will be relative to the application data directory.",
"placeholder": "",
"default": "",
"advanced": true
},
{ {
"name": "persistInterval", "name": "persistInterval",
"label": "Save Check Interval", "label": "Save Check Interval",

View file

@ -509,9 +509,7 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username,
} }
} else { } else {
if (!senderSockAddr.isNull()) { if (!senderSockAddr.isNull()) {
qDebug() << "Insufficient data to decrypt username signature - denying connection."; qDebug() << "Insufficient data to decrypt username signature - delaying connection.";
sendConnectionDeniedPacket("Insufficient data", senderSockAddr,
DomainHandler::ConnectionRefusedReason::LoginError);
} }
} }

View file

@ -118,8 +118,8 @@ DomainServer::DomainServer(int argc, char* argv[]) :
setupNodeListAndAssignments(); setupNodeListAndAssignments();
if (_type == MetaverseDomain) { if (_type != NonMetaverse) {
// if we have a metaverse domain, we'll need an access token to heartbeat handle auto-networking // if we have a metaverse domain, we'll use an access token for API calls
resetAccountManagerAccessToken(); resetAccountManagerAccessToken();
} }
@ -469,8 +469,8 @@ bool DomainServer::resetAccountManagerAccessToken() {
if (accessTokenVariant && accessTokenVariant->canConvert(QMetaType::QString)) { if (accessTokenVariant && accessTokenVariant->canConvert(QMetaType::QString)) {
accessToken = accessTokenVariant->toString(); accessToken = accessTokenVariant->toString();
} else { } else {
qDebug() << "A domain-server feature that requires authentication is enabled but no access token is present."; qWarning() << "No access token is present. Some operations that use the metaverse API will fail.";
qDebug() << "Set an access token via the web interface, in your user or master config" qDebug() << "Set an access token via the web interface, in your user config"
<< "at keypath metaverse.access_token or in your ENV at key DOMAIN_SERVER_ACCESS_TOKEN"; << "at keypath metaverse.access_token or in your ENV at key DOMAIN_SERVER_ACCESS_TOKEN";
// clear any existing access token from AccountManager // clear any existing access token from AccountManager
@ -480,7 +480,7 @@ bool DomainServer::resetAccountManagerAccessToken() {
} }
} else { } else {
qDebug() << "Using access token from DOMAIN_SERVER_ACCESS_TOKEN in env. This overrides any access token present" qDebug() << "Using access token from DOMAIN_SERVER_ACCESS_TOKEN in env. This overrides any access token present"
<< " in the user or master config."; << " in the user config.";
} }
// give this access token to the AccountManager // give this access token to the AccountManager

View file

@ -50,8 +50,8 @@ public:
static int const EXIT_CODE_REBOOT; static int const EXIT_CODE_REBOOT;
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false); bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
public slots: public slots:
/// Called by NodeList to inform us a node has been added /// Called by NodeList to inform us a node has been added

View file

@ -22,7 +22,11 @@
}, },
{ "from": "OculusTouch.LT", "to": "Standard.LT" }, { "from": "OculusTouch.LT", "to": "Standard.LT" },
{ "from": "OculusTouch.LS", "to": "Standard.LS" }, { "from": "OculusTouch.LS", "to": "Standard.LS" },
{ "from": "OculusTouch.LeftGrip", "to": "Standard.LeftGrip" }, { "from": "OculusTouch.LeftGrip", "to": "Standard.LTClick",
"peek": true,
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
},
{ "from": "OculusTouch.LeftGrip", "to": "Standard.LT" },
{ "from": "OculusTouch.LeftHand", "to": "Standard.LeftHand" }, { "from": "OculusTouch.LeftHand", "to": "Standard.LeftHand" },
{ "from": "OculusTouch.RY", "to": "Standard.RY", { "from": "OculusTouch.RY", "to": "Standard.RY",
@ -38,7 +42,11 @@
}, },
{ "from": "OculusTouch.RT", "to": "Standard.RT" }, { "from": "OculusTouch.RT", "to": "Standard.RT" },
{ "from": "OculusTouch.RS", "to": "Standard.RS" }, { "from": "OculusTouch.RS", "to": "Standard.RS" },
{ "from": "OculusTouch.RightGrip", "to": "Standard.RightGrip" }, { "from": "OculusTouch.RightGrip", "to": "Standard.LTClick",
"peek": true,
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
},
{ "from": "OculusTouch.RightGrip", "to": "Standard.RT" },
{ "from": "OculusTouch.RightHand", "to": "Standard.RightHand" }, { "from": "OculusTouch.RightHand", "to": "Standard.RightHand" },
{ "from": "OculusTouch.LeftApplicationMenu", "to": "Standard.Back" }, { "from": "OculusTouch.LeftApplicationMenu", "to": "Standard.Back" },
@ -59,4 +67,3 @@
] ]
} }

View file

@ -11,7 +11,7 @@
[ [
{ "type": "deadZone", "min": 0.15 }, { "type": "deadZone", "min": 0.15 },
"constrainToInteger", "constrainToInteger",
{ "type": "pulse", "interval": 0.5 }, { "type": "pulse", "interval": 0.25 },
{ "type": "scale", "scale": 22.5 } { "type": "scale", "scale": 22.5 }
] ]
}, },

View file

@ -4,8 +4,8 @@
{ "from": "Vive.LY", "when": "Vive.LSY", "filters": ["invert"], "to": "Standard.LY" }, { "from": "Vive.LY", "when": "Vive.LSY", "filters": ["invert"], "to": "Standard.LY" },
{ "from": "Vive.LX", "when": "Vive.LSX", "to": "Standard.LX" }, { "from": "Vive.LX", "when": "Vive.LSX", "to": "Standard.LX" },
{ {
"from": "Vive.LT", "to": "Standard.LT", "from": "Vive.LT", "to": "Standard.LT",
"filters": [ "filters": [
{ "type": "deadZone", "min": 0.05 } { "type": "deadZone", "min": 0.05 }
] ]
}, },
@ -18,8 +18,8 @@
{ "from": "Vive.RY", "when": "Vive.RSY", "filters": ["invert"], "to": "Standard.RY" }, { "from": "Vive.RY", "when": "Vive.RSY", "filters": ["invert"], "to": "Standard.RY" },
{ "from": "Vive.RX", "when": "Vive.RSX", "to": "Standard.RX" }, { "from": "Vive.RX", "when": "Vive.RSX", "to": "Standard.RX" },
{ {
"from": "Vive.RT", "to": "Standard.RT", "from": "Vive.RT", "to": "Standard.RT",
"filters": [ "filters": [
{ "type": "deadZone", "min": 0.05 } { "type": "deadZone", "min": 0.05 }
] ]
}, },
@ -37,4 +37,4 @@
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand" }, { "from": "Vive.LeftHand", "to": "Standard.LeftHand" },
{ "from": "Vive.RightHand", "to": "Standard.RightHand" } { "from": "Vive.RightHand", "to": "Standard.RightHand" }
] ]
} }

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<path d="M25.9,20.6c0.29,0.15,0.47,0.38,0.48,0.72c0,0.7,0.1,2.92,0.08,3.62c1,0.3,3.61,1.19,4.56,1.45
c0.15,0.01,0.27,0.03,0.38,0.09c0.2,0.1,0.33,0.3,0.36,0.58c0.01,0.11,0.02,0.22,0.02,0.33c-0.03,1.5,0.01,1.08-0.05,2.58
c-0.06,1.55-0.78,2.72-2.21,3.34c-1.12,0.49-2.01,0.57-2.92,0.1c-0.25-0.13-0.5-0.3-0.76-0.51c-1.46-1.21-2.95-2.39-4.42-3.59
c-0.37-0.3-0.48-0.75-0.29-1.15c0.19-0.39,0.63-0.61,1.05-0.49c0.06,0.02,0.12,0.04,0.18,0.07c0.1,0.05,0.19,0.11,0.27,0.18
c0.64,0.51,1,1.02,1.63,1.53c0,0,0.01,0,0.01,0.01c0.01,0.01,0.04,0.01,0.09,0.04c0-0.12,0.01-0.23,0.01-0.33
c0.06-2.53,0.12-5.06,0.18-7.59c0.01-0.36,0.06-0.69,0.37-0.92c0.28-0.2,0.58-0.25,0.89-0.12C25.85,20.57,25.88,20.58,25.9,20.6
M26.64,19.16c-0.06-0.03-0.12-0.06-0.18-0.09c-0.83-0.36-1.74-0.25-2.48,0.3c-1,0.73-1.03,1.83-1.04,2.19
c-0.04,1.54-0.07,3.11-0.11,4.64c-0.07-0.02-0.13-0.05-0.2-0.07c-1.17-0.34-2.41,0.22-2.96,1.33c-0.26,0.53-0.32,1.14-0.18,1.71
c0.14,0.55,0.45,1.03,0.91,1.4c0.49,0.4,0.98,0.8,1.46,1.18c0.97,0.78,1.97,1.59,2.94,2.4c0.35,0.29,0.7,0.52,1.05,0.71
c1.72,0.88,3.28,0.39,4.3-0.06c1.96-0.86,3.09-2.55,3.18-4.76c0.03-0.89,0.04-1.13,0.04-1.47c0-0.23,0-0.51,0.01-1.13
c0-0.18,0-0.37-0.03-0.56c-0.1-0.82-0.54-1.49-1.23-1.84c-0.25-0.13-0.53-0.21-0.82-0.25c-0.56-0.16-1.57-0.49-2.48-0.79
c-0.27-0.09-0.53-0.17-0.78-0.25c-0.01-0.34-0.02-0.7-0.03-1.06C28.02,22.12,28,21.58,28,21.31
C27.99,20.39,27.49,19.59,26.64,19.16L26.64,19.16z"/>
</g>
<path d="M33.4,17.76l-2.87-2.64l-0.13,1.65c-1.42-0.61-3.13-0.95-4.95-0.95c-1.91,0-3.66,0.37-5.06,1.04l-0.23-1.76l-2.73,2.79
l3.35,2l-0.22-1.66c1.27-0.71,3.01-1.11,4.89-1.11c1.8,0,3.52,0.37,4.84,1.03l-0.14,1.79L33.4,17.76z"/>
<g>
<path class="st0" d="M25.64,19.86c0.29,0.15,0.47,0.38,0.48,0.72c0,0.7,0.1,2.92,0.08,3.62c1,0.3,3.61,1.19,4.56,1.45
c0.16,0.04,0.28,0.08,0.39,0.13c0.2,0.1,0.31,0.26,0.35,0.54c0.01,0.11,0.02,0.22,0.02,0.33c-0.03,1.5,0.01,1.08-0.05,2.58
c-0.06,1.55-0.78,2.72-2.21,3.34c-1.12,0.49-2.01,0.57-2.92,0.1c-0.25-0.13-0.5-0.3-0.76-0.51c-1.46-1.21-2.95-2.39-4.42-3.59
c-0.37-0.3-0.48-0.75-0.29-1.15c0.19-0.39,0.63-0.61,1.05-0.49c0.06,0.02,0.12,0.04,0.18,0.07c0.1,0.05,0.19,0.11,0.27,0.18
c0.64,0.51,1,1.02,1.63,1.53c0,0,0.01,0,0.01,0.01c0.01,0.01,0.04,0.01,0.09,0.04c0-0.12,0.01-0.23,0.01-0.33
c0.06-2.53,0.12-5.06,0.18-7.59c0.01-0.36,0.06-0.69,0.37-0.92c0.28-0.2,0.58-0.25,0.89-0.12C25.59,19.83,25.62,19.84,25.64,19.86
M26.38,18.42c-0.06-0.03-0.12-0.06-0.18-0.09c-0.83-0.36-1.74-0.25-2.48,0.3c-1,0.73-1.03,1.83-1.04,2.19
c-0.04,1.54-0.07,3.11-0.11,4.64c-0.07-0.02-0.13-0.05-0.2-0.07c-1.17-0.34-2.41,0.22-2.96,1.33c-0.26,0.53-0.32,1.14-0.18,1.71
c0.14,0.55,0.45,1.03,0.91,1.4c0.49,0.4,0.98,0.8,1.46,1.18c0.97,0.78,1.97,1.59,2.94,2.4c0.35,0.29,0.7,0.52,1.05,0.71
c1.72,0.88,3.28,0.39,4.3-0.06c1.96-0.86,3.09-2.55,3.18-4.76c0.03-0.89,0.04-1.13,0.04-1.47c0-0.23,0-0.51,0.01-1.13
c0-0.18,0-0.37-0.03-0.56c-0.1-0.82-0.45-1.41-1.13-1.76c-0.25-0.13-0.61-0.24-0.91-0.32c-0.56-0.16-1.57-0.49-2.48-0.79
c-0.27-0.09-0.53-0.17-0.78-0.25c-0.01-0.34-0.02-0.7-0.03-1.06c-0.02-0.57-0.03-1.11-0.04-1.38
C27.73,19.65,27.23,18.85,26.38,18.42L26.38,18.42z"/>
</g>
<path class="st0" d="M33.14,17.02l-2.87-2.64l-0.13,1.65c-1.42-0.61-3.13-0.95-4.95-0.95c-1.91,0-3.66,0.37-5.06,1.04l-0.23-1.76
l-2.73,2.79l3.35,2l-0.22-1.66c1.27-0.71,3.01-1.11,4.89-1.11c1.8,0,3.52,0.37,4.84,1.03l-0.14,1.79L33.14,17.02z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -1,81 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="utf-8"?>
<svg <!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
xmlns:dc="http://purl.org/dc/elements/1.1/" <svg version="1.1"
xmlns:cc="http://creativecommons.org/ns#" id="svg4136" inkscape:version="0.91 r13725" sodipodi:docname="address-bar.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1440 200"
xmlns:svg="http://www.w3.org/2000/svg" style="enable-background:new 0 0 1440 200;" xml:space="preserve">
xmlns="http://www.w3.org/2000/svg" <style type="text/css">
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" .st0{fill:#1E1E1E;}
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" .st1{fill:#E6E7E8;}
version="1.1" .st2{fill:#FFFFFF;}
width="1440" </style>
height="200" <path class="st0" d="M1428.61,172H11.46c-6.27,0-11.39-5.13-11.39-11.39V49.58c0-6.27,5.13-11.39,11.39-11.39h1417.15
data-icon="map-marker" c6.27,0,11.39,5.13,11.39,11.39v111.03C1440,166.87,1434.87,172,1428.61,172z"/>
data-container-transform="translate(24)" <path class="st1" d="M1428.61,165.81H11.46c-6.27,0-11.39-5.13-11.39-11.39V43.39c0-6.27,5.13-11.39,11.39-11.39h1417.15
viewBox="0 0 1440 200" c6.27,0,11.39,5.13,11.39,11.39v111.03C1440,160.68,1434.87,165.81,1428.61,165.81z"/>
id="svg4136" <path class="st2" d="M1133.24,165.81H417.95c-4.47,0-8.12-3.65-8.12-8.12V40.11c0-4.47,3.65-8.12,8.12-8.12h715.28
inkscape:version="0.91 r13725" c4.47,0,8.12,3.65,8.12,8.12v117.57C1141.36,162.15,1137.7,165.81,1133.24,165.81z"/>
sodipodi:docname="address-bar.svg">
<metadata
id="metadata4144">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4142" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1536"
inkscape:window-height="687"
id="namedview4140"
showgrid="false"
inkscape:zoom="0.61319416"
inkscape:cx="670.06567"
inkscape:cy="52.468468"
inkscape:window-x="105"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg4136" />
<rect
style="fill:#ededed;fill-opacity:1;stroke:none;stroke-linejoin:round;stroke-opacity:1"
id="rect4141"
width="1280"
height="140"
x="160"
y="30"
rx="16.025024"
ry="17.019567" />
<rect
style="fill:#dadada;fill-opacity:1;stroke:#cbcbcb;stroke-width:0.35830048;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
id="rect4135"
width="328.72031"
height="139.64169"
x="150.33546"
y="30.179144"
rx="18.876532"
ry="20.609974" />
<circle
style="fill:#b8b8b8;fill-opacity:1;stroke:none;stroke-opacity:1"
id="path4146"
cx="100"
cy="100"
r="100" />
<path
d="m 100,36.000005 c -22.1,0 -40,17.9 -40,39.999995 0,30 40,88 40,88 0,0 40,-58 40,-88 0,-22.099995 -17.9,-39.999995 -40,-39.999995 z m 0,22 c 9.9,0 18,8.099995 18,17.999995 0,9.9 -8.1,18 -18,18 -9.9,0 -18,-8.1 -18,-18 0,-9.9 8.1,-17.999995 18,-17.999995 z"
id="path4138"
inkscape:connector-curvature="0" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
<style type="text/css">
.st0{fill:#414042;}
.st1{fill:#CCCCCC;}
.st2{fill:#1398BB;}
.st3{fill:#31D8FF;}
</style>
<g id="Layer_1">
<path class="st0" d="M33.72,85.08l-9.15-9.15l-0.74-0.74l0.74-0.74l9.35-9.35c0.59-0.59,0.59-1.56,0-2.15
c-0.29-0.29-0.67-0.45-1.08-0.45c-0.41,0-0.79,0.16-1.08,0.45L19.52,75.19l12.04,12.04c0.29,0.29,0.67,0.45,1.08,0.45
c0.41,0,0.79-0.16,1.08-0.45C34.31,86.64,34.31,85.67,33.72,85.08z"/>
<path class="st1" d="M33.72,33.45l-9.15-9.15l-0.74-0.74l0.74-0.74l9.35-9.35c0.59-0.59,0.59-1.56,0-2.15
c-0.29-0.29-0.67-0.45-1.08-0.45c-0.41,0-0.79,0.16-1.08,0.45L19.52,23.56L31.56,35.6c0.29,0.29,0.67,0.45,1.08,0.45
c0.41,0,0.79-0.16,1.08-0.45C34.31,35.01,34.31,34.04,33.72,33.45z"/>
<path class="st2" d="M17.99,124.82l12.78,12.78c1,1,2.63,1,3.63,0c1-1,1-2.63,0-3.63l-9.15-9.15l9.35-9.35c1-1,1-2.63,0-3.63
c-1-1-2.63-1-3.63,0L17.99,124.82z"/>
<path class="st3" d="M32.79,112.13c0.41,0,0.79,0.16,1.08,0.45c0.59,0.59,0.59,1.56,0,2.15l-9.35,9.35l-0.74,0.74l0.74,0.74
l9.15,9.15c0.59,0.59,0.59,1.56,0,2.15c-0.29,0.29-0.67,0.45-1.08,0.45c-0.41,0-0.79-0.16-1.08-0.45l-12.04-12.04l12.24-12.24
C32,112.29,32.38,112.13,32.79,112.13 M32.79,111.08c-0.66,0-1.31,0.25-1.82,0.75l-12.98,12.98l12.78,12.78
c0.5,0.5,1.16,0.75,1.82,0.75c0.66,0,1.31-0.25,1.82-0.75c1-1,1-2.63,0-3.63l-9.15-9.15l9.35-9.35c1-1,1-2.63,0-3.63
C34.1,111.34,33.44,111.08,32.79,111.08L32.79,111.08z"/>
</g>
<g id="Layer_2">
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
<style type="text/css">
.st0{fill:#414042;}
.st1{fill:#CCCCCC;}
.st2{fill:#1398BB;}
.st3{fill:#31D8FF;}
</style>
<g id="Layer_1">
<path class="st0" d="M21.12,62.95c-0.29-0.29-0.67-0.45-1.08-0.45c-0.41,0-0.79,0.16-1.08,0.45c-0.59,0.59-0.59,1.56,0,2.15
l9.35,9.35l0.74,0.74l-0.74,0.74l-9.15,9.15c-0.59,0.59-0.59,1.56,0,2.15c0.29,0.29,0.67,0.45,1.08,0.45
c0.41,0,0.79-0.16,1.08-0.45l12.04-12.04L21.12,62.95z"/>
<path class="st1" d="M21.12,11.32c-0.29-0.29-0.67-0.45-1.08-0.45c-0.41,0-0.79,0.16-1.08,0.45c-0.59,0.59-0.59,1.56,0,2.15
l9.35,9.35l0.74,0.74l-0.74,0.74l-9.15,9.15c-0.59,0.59-0.59,1.56,0,2.15c0.29,0.29,0.67,0.45,1.08,0.45
c0.41,0,0.79-0.16,1.08-0.45l12.04-12.04L21.12,11.32z"/>
<path class="st2" d="M34.9,124.82L22.11,137.6c-1,1-2.63,1-3.63,0c-1-1-1-2.63,0-3.63l9.15-9.15l-9.35-9.35c-1-1-1-2.63,0-3.63
c1-1,2.63-1,3.63,0L34.9,124.82z"/>
<path class="st3" d="M20.1,112.13c0.41,0,0.79,0.16,1.08,0.45l12.24,12.24l-12.04,12.04c-0.29,0.29-0.67,0.45-1.08,0.45
c-0.41,0-0.79-0.16-1.08-0.45c-0.59-0.59-0.59-1.56,0-2.15l9.15-9.15l0.74-0.74l-0.74-0.74l-9.35-9.35c-0.59-0.59-0.59-1.56,0-2.15
C19.31,112.29,19.69,112.13,20.1,112.13 M20.1,111.08c-0.66,0-1.31,0.25-1.82,0.75c-1,1-1,2.63,0,3.63l9.35,9.35l-9.15,9.15
c-1,1-1,2.63,0,3.63c0.5,0.5,1.16,0.75,1.82,0.75s1.31-0.25,1.82-0.75l12.78-12.78l-12.98-12.98
C21.41,111.34,20.76,111.08,20.1,111.08L20.1,111.08z"/>
</g>
<g id="Layer_2">
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
<style type="text/css">
.st0{fill:#414042;}
.st1{fill:#CCCCCC;}
.st2{fill:#1398BB;}
.st3{fill:#31D8FF;}
</style>
<g id="Layer_1">
<g>
<path class="st0" d="M36.75,71.26c-0.05-0.31-0.22-0.57-0.47-0.76l-10.72-7.73l-8.21,5.71l0,0l0,0l-2.98,1.99
c-0.26,0.17-0.43,0.43-0.5,0.74c-0.06,0.3,0,0.61,0.17,0.87c0.22,0.32,0.58,0.52,0.97,0.52c0.23,0,0.45-0.07,0.64-0.19l2.99-1.99
l6.62-4.61l0.28-0.2l0.28,0.2l9.11,6.57c0.2,0.14,0.43,0.22,0.68,0.22c0.37,0,0.73-0.18,0.94-0.48
C36.73,71.88,36.8,71.57,36.75,71.26z"/>
<path class="st0" d="M23.59,79.62c0-1.13,0.97-2.03,2.1-2.03c1.13,0,2.1,0.93,2.1,2.06v6.06h7.58v-8.97l-3.28-2.41l-6.46-4.68
l-6.88,4.64l-3.23,2.1v9.32h8.07V79.62z"/>
</g>
<g>
<path class="st1" d="M36.75,19.64c-0.05-0.31-0.22-0.57-0.47-0.76l-10.72-7.73l-8.21,5.71l0,0l0,0l-2.98,1.99
c-0.26,0.17-0.43,0.43-0.5,0.74c-0.06,0.3,0,0.61,0.17,0.87c0.22,0.32,0.58,0.52,0.97,0.52c0.23,0,0.45-0.07,0.64-0.19l2.99-1.99
l6.62-4.61l0.28-0.2l0.28,0.2l9.11,6.57c0.2,0.14,0.43,0.22,0.68,0.22c0.37,0,0.73-0.18,0.94-0.48
C36.73,20.25,36.8,19.94,36.75,19.64z"/>
<path class="st1" d="M23.59,27.99c0-1.13,0.97-2.03,2.1-2.03c1.13,0,2.1,0.93,2.1,2.06v6.06h7.58v-8.97l-3.28-2.41l-6.46-4.68
l-6.88,4.64l-3.23,2.1v9.32h8.07V27.99z"/>
</g>
<g>
<path class="st2" d="M15,122.61c-0.53,0-1.05-0.26-1.37-0.73c-0.5-0.76-0.3-1.78,0.46-2.28l2.98-1.99l8.5-5.91l11,7.93
c0.74,0.53,0.9,1.56,0.37,2.3c-0.53,0.74-1.56,0.9-2.3,0.37l-9.11-6.57l-6.63,4.61l-3,1.99C15.63,122.52,15.31,122.61,15,122.61z"
/>
<path class="st2" d="M35.6,122.69c-0.36,0-0.71-0.11-1.01-0.33l-9.07-6.53l-6.58,4.58l-3,2c-0.28,0.19-0.61,0.29-0.95,0.29
c-0.58,0-1.12-0.29-1.44-0.77c-0.53-0.79-0.31-1.87,0.48-2.39l2.98-1.99l8.54-5.94l11.05,7.96c0.37,0.27,0.62,0.67,0.69,1.12
c0.07,0.46-0.03,0.91-0.3,1.29c-0.27,0.37-0.67,0.62-1.12,0.69C35.79,122.68,35.7,122.69,35.6,122.69z M25.53,115.63l9.16,6.6
c0.34,0.24,0.75,0.34,1.17,0.28s0.77-0.29,1.02-0.63c0.24-0.34,0.34-0.75,0.28-1.17c-0.07-0.41-0.29-0.77-0.63-1.02l-10.96-7.9
l-8.45,5.88l-2.98,1.99c-0.72,0.48-0.91,1.45-0.44,2.17c0.29,0.44,0.78,0.7,1.3,0.7c0.31,0,0.61-0.09,0.87-0.26l3-1.99
L25.53,115.63z"/>
</g>
<path class="st3" d="M36.62,119.56l-11.05-7.96l-8.54,5.94l-2.98,1.99c-0.79,0.53-1.01,1.6-0.48,2.39
c0.32,0.48,0.86,0.77,1.44,0.77c0.34,0,0.67-0.1,0.95-0.29l3-2l6.58-4.58l9.07,6.53c0.3,0.21,0.64,0.33,1.01,0.33
c0.55,0,1.08-0.27,1.4-0.72C37.56,121.2,37.39,120.12,36.62,119.56z M17.39,118.07l8.17-5.68l10.68,7.7
c0.23,0.17,0.39,0.42,0.43,0.7c0.05,0.28-0.02,0.57-0.19,0.8c-0.2,0.28-0.53,0.45-0.88,0.45c-0.23,0-0.45-0.07-0.63-0.2l-9.44-6.8
l-6.95,4.83l-2.99,1.99c-0.18,0.12-0.38,0.18-0.6,0.18c-0.36,0-0.7-0.18-0.9-0.48c-0.16-0.24-0.22-0.53-0.16-0.81
c0.06-0.28,0.22-0.53,0.46-0.69L17.39,118.07z"/>
<path class="st2" d="M23.59,129.14c0-1.13,0.97-2.03,2.1-2.03c1.13,0,2.1,0.93,2.1,2.06v6.06h7.58v-8.97l-3.28-2.41l-6.46-4.68
l-6.88,4.64l-3.23,2.1v9.32h8.07V129.14z"/>
</g>
<g id="Layer_2">
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
<style type="text/css">
.st0{fill:#414042;}
.st1{fill:#CCCCCC;}
.st2{fill:#1398BB;}
.st3{fill:#31D8FF;}
</style>
<g id="Layer_1">
<path class="st0" d="M25.71,59.91c-4.83,0-8.75,3.92-8.75,8.75c0,4.83,8.75,16.5,8.75,16.5s8.75-11.67,8.75-16.5
C34.46,63.83,30.54,59.91,25.71,59.91z M25.71,72.53c-2.48,0-4.5-2.01-4.5-4.5c0-2.48,2.01-4.5,4.5-4.5s4.5,2.01,4.5,4.5
C30.2,70.52,28.19,72.53,25.71,72.53z"/>
<path class="st0" d="M36.43,86.1H14.28c-0.49,0-0.9,0.39-0.9,0.89c0,0.49,0.4,0.89,0.9,0.89h22.15c0.49,0,0.9-0.39,0.9-0.89
C37.32,86.49,36.92,86.1,36.43,86.1z"/>
<path class="st1" d="M25.71,8.28c-4.83,0-8.75,3.92-8.75,8.75c0,4.83,8.75,16.5,8.75,16.5s8.75-11.67,8.75-16.5
C34.46,12.2,30.54,8.28,25.71,8.28z M25.71,20.91c-2.48,0-4.5-2.01-4.5-4.5c0-2.48,2.01-4.5,4.5-4.5s4.5,2.01,4.5,4.5
C30.2,18.89,28.19,20.91,25.71,20.91z"/>
<path class="st1" d="M36.43,34.47H14.28c-0.49,0-0.9,0.39-0.9,0.89s0.4,0.89,0.9,0.89h22.15c0.49,0,0.9-0.39,0.9-0.89
S36.92,34.47,36.43,34.47z"/>
<path class="st2" d="M25.71,109.66c-4.83,0-8.75,3.92-8.75,8.75c0,4.83,8.75,16.5,8.75,16.5s8.75-11.67,8.75-16.5
C34.46,113.57,30.54,109.66,25.71,109.66z M25.71,122.28c-2.48,0-4.5-2.01-4.5-4.5c0-2.48,2.01-4.5,4.5-4.5s4.5,2.01,4.5,4.5
C30.2,120.27,28.19,122.28,25.71,122.28z"/>
<path class="st2" d="M36.43,138.33H14.28c-0.85,0-1.54-0.69-1.54-1.54s0.69-1.54,1.54-1.54h22.15c0.85,0,1.54,0.69,1.54,1.54
S37.28,138.33,36.43,138.33z"/>
<path class="st3" d="M36.43,135.89c0.49,0,0.9,0.4,0.9,0.9c0,0.49-0.4,0.9-0.9,0.9H14.28c-0.49,0-0.9-0.4-0.9-0.9
c0-0.49,0.4-0.9,0.9-0.9H36.43 M36.43,135.25H14.28c-0.85,0-1.54,0.69-1.54,1.54c0,0.85,0.69,1.54,1.54,1.54h22.15
c0.85,0,1.54-0.69,1.54-1.54C37.97,135.94,37.28,135.25,36.43,135.25L36.43,135.25z"/>
</g>
<g id="Layer_2">
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
<style type="text/css">
.st0{fill:#414042;}
.st1{fill:#CCCCCC;}
.st2{fill:#1398BB;}
.st3{fill:#31D8FF;}
</style>
<g id="Layer_1">
<circle class="st0" cx="26.54" cy="69.8" r="4.44"/>
<path class="st0" d="M34.87,82.89c0.01-0.01,0.02-0.02,0.03-0.03v-1.86c0-2.68-2.33-4.77-5-4.77h-6.42c-2.68,0-4.85,2.09-4.85,4.77
v1.88H34.87z"/>
<path class="st0" d="M44.17,67.05c0-3.97-3.22-7.19-7.19-7.19H16.67c-3.97,0-7.19,3.22-7.19,7.19v14.18c0,3.97,3.22,7.19,7.19,7.19
h20.31c3.97,0,7.19-3.22,7.19-7.19V67.05z M42.39,81.32c0,3.03-2.46,5.49-5.49,5.49H16.58c-3.03,0-5.49-2.46-5.49-5.49v-14.2
c0-3.03,2.46-5.49,5.49-5.49h20.33c3.03,0,5.49,2.46,5.49,5.49V81.32z"/>
<circle class="st1" cx="26.54" cy="18.17" r="4.44"/>
<path class="st1" d="M34.87,31.26c0.01-0.01,0.02-0.02,0.03-0.03v-1.86c0-2.68-2.33-4.77-5-4.77h-6.42c-2.68,0-4.85,2.09-4.85,4.77
v1.88H34.87z"/>
<path class="st1" d="M44.17,15.42c0-3.97-3.22-7.19-7.19-7.19H16.67c-3.97,0-7.19,3.22-7.19,7.19V29.6c0,3.97,3.22,7.19,7.19,7.19
h20.31c3.97,0,7.19-3.22,7.19-7.19V15.42z M42.39,29.69c0,3.03-2.46,5.49-5.49,5.49H16.58c-3.03,0-5.49-2.46-5.49-5.49V15.5
c0-3.03,2.46-5.49,5.49-5.49h20.33c3.03,0,5.49,2.46,5.49,5.49V29.69z"/>
<circle class="st2" cx="26.52" cy="119.45" r="4.44"/>
<path class="st2" d="M34.85,132.54c0.01-0.01,0.02-0.02,0.03-0.03v-1.86c0-2.68-2.33-4.77-5-4.77h-6.42
c-2.68,0-4.85,2.09-4.85,4.77v1.88H34.85z"/>
<g>
<path class="st2" d="M36.9,138.76H16.6c-4.32,0-7.83-3.51-7.83-7.83v-14.16c0-4.32,3.51-7.83,7.83-7.83h20.3
c4.32,0,7.83,3.51,7.83,7.83v14.16C44.73,135.25,41.22,138.76,36.9,138.76z M16.6,111.93c-2.67,0-4.84,2.17-4.84,4.84v14.16
c0,2.67,2.17,4.84,4.84,4.84h20.3c2.67,0,4.84-2.17,4.84-4.84v-14.16c0-2.67-2.17-4.84-4.84-4.84H16.6z"/>
<path class="st3" d="M36.9,109.58c3.96,0,7.19,3.22,7.19,7.19v14.16c0,3.96-3.22,7.19-7.19,7.19H16.6c-3.96,0-7.19-3.22-7.19-7.19
v-14.16c0-3.96,3.22-7.19,7.19-7.19H36.9 M16.6,136.42h20.3c3.02,0,5.49-2.46,5.49-5.49v-14.16c0-3.02-2.46-5.49-5.49-5.49H16.6
c-3.02,0-5.49,2.46-5.49,5.49v14.16C11.11,133.95,13.57,136.42,16.6,136.42 M36.9,108.93H16.6c-4.32,0-7.83,3.51-7.83,7.83v14.16
c0,4.32,3.51,7.83,7.83,7.83h20.3c4.32,0,7.83-3.51,7.83-7.83v-14.16C44.73,112.45,41.22,108.93,36.9,108.93L36.9,108.93z
M16.6,135.77c-2.67,0-4.84-2.17-4.84-4.84v-14.16c0-2.67,2.17-4.84,4.84-4.84h20.3c2.67,0,4.84,2.17,4.84,4.84v14.16
c0,2.67-2.17,4.84-4.84,4.84H16.6L16.6,135.77z"/>
</g>
</g>
<g id="Layer_2">
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -14,6 +14,8 @@ import "controls"
import "styles" import "styles"
import "windows" import "windows"
import "hifi" import "hifi"
import "hifi/toolbars"
import "controls-uit" as HifiControls
Window { Window {
id: root id: root
@ -45,50 +47,80 @@ Window {
anchors.centerIn = parent; anchors.centerIn = parent;
} }
function resetAfterTeleport() {
storyCardFrame.shown = root.shown = false;
}
function goCard(card) { function goCard(card) {
addressLine.text = card.userStory.name; if (addressBarDialog.useFeed) {
storyCardHTML.url = addressBarDialog.metaverseServerUrl + "/user_stories/" + card.storyId;
storyCardFrame.shown = true;
return;
}
addressLine.text = card.hifiUrl;
toggleOrGo(true); toggleOrGo(true);
} }
property var allDomains: []; property var allPlaces: [];
property var suggestionChoices: []; property var allStories: [];
property var domainsBaseUrl: null;
property int cardWidth: 200; property int cardWidth: 200;
property int cardHeight: 152; property int cardHeight: 152;
property string metaverseBase: addressBarDialog.metaverseServerUrl + "/api/v1/";
AddressBarDialog { AddressBarDialog {
id: addressBarDialog id: addressBarDialog
implicitWidth: backgroundImage.width implicitWidth: backgroundImage.width
implicitHeight: backgroundImage.height implicitHeight: backgroundImage.height
// The buttons have their button state changed on hover, so we have to manually fix them up here
onBackEnabledChanged: backArrow.buttonState = addressBarDialog.backEnabled ? 1 : 0;
onForwardEnabledChanged: forwardArrow.buttonState = addressBarDialog.forwardEnabled ? 1 : 0;
onUseFeedChanged: updateFeedState();
onReceivedHifiSchemeURL: resetAfterTeleport();
Row { ListModel { id: suggestions }
ListView {
id: scroll
width: backgroundImage.width; width: backgroundImage.width;
height: cardHeight;
spacing: hifi.layout.spacing;
clip: true;
anchors { anchors {
bottom: backgroundImage.top; bottom: backgroundImage.top;
bottomMargin: 2 * hifi.layout.spacing; bottomMargin: 2 * hifi.layout.spacing;
right: backgroundImage.right; horizontalCenter: backgroundImage.horizontalCenter
rightMargin: -104; // FIXME
} }
spacing: hifi.layout.spacing; model: suggestions;
Card { orientation: ListView.Horizontal;
id: s0; delegate: Card {
width: cardWidth; width: cardWidth;
height: cardHeight; height: cardHeight;
goFunction: goCard goFunction: goCard;
userName: model.username;
placeName: model.place_name;
hifiUrl: model.place_name + model.path;
imageUrl: model.image_url;
thumbnail: model.thumbnail_url;
action: model.action;
timestamp: model.created_at;
onlineUsers: model.online_users;
storyId: model.metaverseId;
hoverThunk: function () { ListView.view.currentIndex = index; }
unhoverThunk: function () { ListView.view.currentIndex = -1; }
} }
Card { highlightMoveDuration: -1;
id: s1; highlightMoveVelocity: -1;
width: cardWidth; highlight: Rectangle { color: "transparent"; border.width: 4; border.color: "#1DB5ED"; z: 1; }
height: cardHeight; leftMargin: 50; // Start the first item over by about the same amount as the last item peeks through on the other side.
goFunction: goCard rightMargin: 50;
} }
Card { Image { // Just a visual indicator that the user can swipe the cards over to see more.
id: s2; source: "../images/Swipe-Icon-single.svg"
width: cardWidth; width: 50;
height: cardHeight; visible: suggestions.count > 3;
goFunction: goCard anchors {
right: scroll.right;
verticalCenter: scroll.verticalCenter;
} }
} }
Image { Image {
id: backgroundImage id: backgroundImage
source: "../images/address-bar.svg" source: "../images/address-bar.svg"
@ -97,64 +129,43 @@ Window {
property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area
property int inputAreaStep: (height - inputAreaHeight) / 2 property int inputAreaStep: (height - inputAreaHeight) / 2
Image { ToolbarButton {
id: homeButton id: homeButton
source: "../images/home-button.svg" imageURL: "../images/home.svg"
width: 29 buttonState: 1
height: 26 defaultState: 1
hoverState: 2
onClicked: addressBarDialog.loadHome();
anchors { anchors {
left: parent.left left: parent.left
leftMargin: parent.height + 2 * hifi.layout.spacing leftMargin: homeButton.width / 2
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
addressBarDialog.loadHome()
}
}
} }
Image { ToolbarButton {
id: backArrow id: backArrow;
source: addressBarDialog.backEnabled ? "../images/left-arrow.svg" : "../images/left-arrow-disabled.svg" imageURL: "../images/backward.svg";
width: 22 hoverState: addressBarDialog.backEnabled ? 2 : 0;
height: 26 defaultState: addressBarDialog.backEnabled ? 1 : 0;
buttonState: addressBarDialog.backEnabled ? 1 : 0;
onClicked: addressBarDialog.loadBack();
anchors { anchors {
left: homeButton.right left: homeButton.right
leftMargin: 2 * hifi.layout.spacing
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
addressBarDialog.loadBack()
}
}
} }
ToolbarButton {
Image { id: forwardArrow;
id: forwardArrow imageURL: "../images/forward.svg";
source: addressBarDialog.forwardEnabled ? "../images/right-arrow.svg" : "../images/right-arrow-disabled.svg" hoverState: addressBarDialog.forwardEnabled ? 2 : 0;
width: 22 defaultState: addressBarDialog.forwardEnabled ? 1 : 0;
height: 26 buttonState: addressBarDialog.forwardEnabled ? 1 : 0;
onClicked: addressBarDialog.loadForward();
anchors { anchors {
left: backArrow.right left: backArrow.right
leftMargin: 2 * hifi.layout.spacing
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
addressBarDialog.loadForward()
}
}
} }
// FIXME replace with TextField // FIXME replace with TextField
@ -162,20 +173,80 @@ Window {
id: addressLine id: addressLine
focus: true focus: true
anchors { anchors {
fill: parent top: parent.top
leftMargin: parent.height + parent.height + hifi.layout.spacing * 7 bottom: parent.bottom
rightMargin: hifi.layout.spacing * 2 left: forwardArrow.right
right: placesButton.left
leftMargin: forwardArrow.width
rightMargin: placesButton.width
topMargin: parent.inputAreaStep + hifi.layout.spacing topMargin: parent.inputAreaStep + hifi.layout.spacing
bottomMargin: parent.inputAreaStep + hifi.layout.spacing bottomMargin: parent.inputAreaStep + hifi.layout.spacing
} }
font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.75 font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.75
helperText: "Go to: place, @user, /path, network address" helperText: "Go to: place, @user, /path, network address"
helperPixelSize: font.pixelSize * 0.75
helperItalic: true
onTextChanged: filterChoicesByText() onTextChanged: filterChoicesByText()
} }
// These two are radio buttons.
ToolbarButton {
id: placesButton
imageURL: "../images/places.svg"
buttonState: 1
defaultState: addressBarDialog.useFeed ? 0 : 1;
hoverState: addressBarDialog.useFeed ? 2 : -1;
onClicked: addressBarDialog.useFeed ? toggleFeed() : identity()
anchors {
right: feedButton.left;
bottom: addressLine.bottom;
}
}
ToolbarButton {
id: feedButton;
imageURL: "../images/snap-feed.svg";
buttonState: 0
defaultState: addressBarDialog.useFeed ? 1 : 0;
hoverState: addressBarDialog.useFeed ? -1 : 2;
onClicked: addressBarDialog.useFeed ? identity() : toggleFeed();
anchors {
right: parent.right;
bottom: addressLine.bottom;
rightMargin: feedButton.width / 2
}
}
}
Window {
width: 938;
height: 625;
scale: 0.8 // Reset scale of Window to 1.0 (counteract address bar's scale value of 1.25)
HifiControls.WebView {
anchors.fill: parent;
id: storyCardHTML;
}
id: storyCardFrame;
shown: false;
destroyOnCloseButton: false;
pinnable: false;
anchors {
verticalCenter: backgroundImage.verticalCenter;
horizontalCenter: scroll.horizontalCenter;
}
} }
} }
function toggleFeed() {
addressBarDialog.useFeed = !addressBarDialog.useFeed;
updateFeedState();
}
function updateFeedState() {
placesButton.buttonState = addressBarDialog.useFeed ? 0 : 1;
feedButton.buttonState = addressBarDialog.useFeed ? 1 : 0;
filterChoicesByText();
}
function getRequest(url, cb) { // cb(error, responseOfCorrectContentType) of url. General for 'get' text/html/json, but without redirects. function getRequest(url, cb) { // cb(error, responseOfCorrectContentType) of url. General for 'get' text/html/json, but without redirects.
// TODO: make available to other .qml. // TODO: make available to other .qml.
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
@ -200,133 +271,217 @@ Window {
request.open("GET", url, true); request.open("GET", url, true);
request.send(); request.send();
} }
// call iterator(element, icb) once for each element of array, and then cb(error) when icb(error) has been called by each iterator. function asyncMap(array, iterator, cb) {
// short-circuits if error. Note that iterator MUST be an asynchronous function. (Use setTimeout if necessary.) // call iterator(element, icb) once for each element of array, and then cb(error, mappedResult)
function asyncEach(array, iterator, cb) { // when icb(error, mappedElement) has been called by each iterator.
var count = array.length; // Calls to iterator are overlapped and may call icb in any order, but the mappedResults are collected in the same
function icb(error) { // order as the elements of the array.
if (!--count || error) { // Short-circuits if error. Note that iterator MUST be an asynchronous function. (Use setTimeout if necessary.)
count = -1; // don't cb multiple times (e.g., if error) var count = array.length, results = [];
cb(error);
}
}
if (!count) { if (!count) {
return cb(); return cb(null, results);
} }
array.forEach(function (element) { array.forEach(function (element, index) {
iterator(element, icb); if (count < 0) { // don't keep iterating after we short-circuit
return;
}
iterator(element, function (error, mapped) {
results[index] = mapped;
if (error || !--count) {
count = 0; // don't cb multiple times if error
cb(error, results);
}
});
}); });
} }
// Example:
/*asyncMap([0, 1, 2, 3, 4, 5, 6], function (elt, icb) {
console.log('called', elt);
setTimeout(function () {
console.log('answering', elt);
icb(null, elt);
}, Math.random() * 1000);
}, console.log); */
function identity(x) { function identity(x) {
return x; return x;
} }
function addPictureToDomain(domainInfo, cb) { // asynchronously add thumbnail and lobby to domainInfo, if available, and cb(error) function handleError(url, error, data, cb) { // cb(error) and answer truthy if needed, else falsey
// This requests data for all the names at once, and just uses the first one to come back. if (!error && (data.status === 'success')) {
// We might change this to check one at a time, which would be less requests and more latency. return;
asyncEach([domainInfo.name].concat(domainInfo.names || null).filter(identity), function (name, icb) { }
var url = "https://metaverse.highfidelity.com/api/v1/places/" + name; if (!error) { // Create a message from the data
getRequest(url, function (error, json) { error = data.status + ': ' + data.error;
var previews = !error && json.data.place.previews; }
if (previews) { if (typeof(error) === 'string') { // Make a proper Error object
if (!domainInfo.thumbnail) { // just grab the first one error = new Error(error);
domainInfo.thumbnail = previews.thumbnail; }
} error.message += ' in ' + url; // Include the url.
if (!domainInfo.lobby) { cb(error);
domainInfo.lobby = previews.lobby; return true;
}
}
icb(error);
});
}, cb);
} }
function getDomains(options, cb) { // cb(error, arrayOfData) function getPlace(placeData, cb) { // cb(error, side-effected-placeData), after adding path, thumbnails, and description
if (!options.page) { var url = metaverseBase + 'places/' + placeData.place_name;
options.page = 1; getRequest(url, function (error, data) {
} if (handleError(url, error, data, cb)) {
if (!domainsBaseUrl) {
var domainsOptions = [
'open', // published hours handle now
'active', // has at least one person connected. FIXME: really want any place that is verified accessible.
// FIXME: really want places I'm allowed in, not just open ones.
'restriction=open', // Not by whitelist, etc. FIXME: If logged in, add hifi to the restriction options, in order to include places that require login.
// FIXME add maturity
'protocol=' + encodeURIComponent(AddressManager.protocolVersion()),
'sort_by=users',
'sort_order=desc',
];
domainsBaseUrl = "https://metaverse.highfidelity.com/api/v1/domains/all?" + domainsOptions.join('&');
}
var url = domainsBaseUrl + "&page=" + options.page + "&users=" + options.minUsers + "-" + options.maxUsers;
getRequest(url, function (error, json) {
if (!error && (json.status !== 'success')) {
error = new Error("Bad response: " + JSON.stringify(json));
}
if (error) {
error.message += ' for ' + url;
return cb(error);
}
var domains = json.data.domains;
if (json.current_page < json.total_pages) {
options.page++;
return getDomains(options, function (error, others) {
cb(error, domains.concat(others));
});
}
cb(null, domains);
});
}
function filterChoicesByText() {
function fill1(target, data) {
if (!data) {
target.visible = false;
return; return;
} }
console.log('suggestion:', JSON.stringify(data)); var place = data.data.place, previews = place.previews;
target.userStory = data; placeData.path = place.path;
target.image.source = data.lobby || target.defaultPicture; if (previews && previews.thumbnail) {
target.placeText = data.name; placeData.thumbnail_url = previews.thumbnail;
target.usersText = data.online_users + ((data.online_users === 1) ? ' user' : ' users');
target.visible = true;
}
var words = addressLine.text.toUpperCase().split(/\s+/).filter(identity);
var filtered = !words.length ? suggestionChoices : allDomains.filter(function (domain) {
var text = domain.names.concat(domain.tags).join(' ');
if (domain.description) {
text += domain.description;
} }
text = text.toUpperCase(); if (place.description) {
return words.every(function (word) { placeData.description = place.description;
return text.indexOf(word) >= 0; placeData.searchText += ' ' + place.description.toUpperCase();
}
cb(error, placeData);
});
}
function makeModelData(data, optionalPlaceName) { // create a new obj from data
// ListModel elements will only ever have those properties that are defined by the first obj that is added.
// So here we make sure that we have all the properties we need, regardless of whether it is a place data or user story.
var name = optionalPlaceName || data.place_name,
tags = data.tags || [data.action, data.username],
description = data.description || "",
thumbnail_url = data.thumbnail_url || "",
image_url = thumbnail_url;
if (data.details) {
try {
image_url = JSON.parse(data.details).image_url || thumbnail_url;
} catch (e) {
console.log(name, "has bad details", data.details);
}
}
return {
place_name: name,
username: data.username || "",
path: data.path || "",
created_at: data.created_at || "",
action: data.action || "",
thumbnail_url: thumbnail_url,
image_url: image_url,
metaverseId: (data.id || "").toString(), // Some are strings from server while others are numbers. Model objects require uniformity.
tags: tags,
description: description,
online_users: data.online_users || 0,
searchText: [name].concat(tags, description || []).join(' ').toUpperCase()
}
}
function mapDomainPlaces(domain, cb) { // cb(error, arrayOfDomainPlaceData)
function addPlace(name, icb) {
getPlace(makeModelData(domain, name), icb);
}
// IWBNI we could get these results in order with most-recent-entered first.
// In any case, we don't really need to preserve the domain.names order in the results.
asyncMap(domain.names || [], addPlace, cb);
}
function suggestable(place) {
if (addressBarDialog.useFeed) {
return true;
}
return (place.place_name !== AddressManager.hostname) // Not our entry, but do show other entry points to current domain.
&& place.thumbnail_url
&& place.online_users // at least one present means it's actually online
&& place.online_users <= 20;
}
function getDomainPage(pageNumber, cb) { // cb(error) after all pages of domain data have been added to model
// Each page of results is processed completely before we start on the next page.
// For each page of domains, we process each domain in parallel, and for each domain, process each place name in parallel.
// This gives us minimum latency within the page, but we do preserve the order within the page by using asyncMap and
// only appending the collected results.
var params = [
'open', // published hours handle now
// TBD: should determine if place is actually running?
'restriction=open', // Not by whitelist, etc. TBD: If logged in, add hifi to the restriction options, in order to include places that require login?
// TBD: add maturity?
'protocol=' + encodeURIComponent(AddressManager.protocolVersion()),
'sort_by=users',
'sort_order=desc',
'page=' + pageNumber
];
var url = metaverseBase + 'domains/all?' + params.join('&');
getRequest(url, function (error, data) {
if (handleError(url, error, data, cb)) {
return;
}
asyncMap(data.data.domains, mapDomainPlaces, function (error, pageResults) {
if (error) {
return cb(error);
}
// pageResults is now [ [ placeDataOneForDomainOne, placeDataTwoForDomainOne, ...], [ placeDataTwoForDomainTwo...] ]
pageResults.forEach(function (domainResults) {
allPlaces = allPlaces.concat(domainResults);
if (!addressLine.text && !addressBarDialog.useFeed) { // Don't add if the user is already filtering
domainResults.forEach(function (place) {
if (suggestable(place)) {
suggestions.append(place);
}
});
}
});
if (data.current_page < data.total_pages) {
return getDomainPage(pageNumber + 1, cb);
}
cb();
}); });
}); });
fill1(s0, filtered[0]); }
fill1(s1, filtered[1]); function getUserStoryPage(pageNumber, cb) { // cb(error) after all pages of domain data have been added to model
fill1(s2, filtered[2]); var url = metaverseBase + 'user_stories?page=' + pageNumber;
getRequest(url, function (error, data) {
if (handleError(url, error, data, cb)) {
return;
}
var stories = data.user_stories.map(function (story) { // explicit single-argument function
return makeModelData(story);
});
allStories = allStories.concat(stories);
if (!addressLine.text && addressBarDialog.useFeed) { // Don't add if the user is already filtering
stories.forEach(function (story) {
suggestions.append(story);
});
}
if ((data.current_page < data.total_pages) && (data.current_page <= 10)) { // just 10 pages = 100 stories for now
return getUserStoryPage(pageNumber + 1, cb);
}
cb();
});
}
function filterChoicesByText() {
suggestions.clear();
var words = addressLine.text.toUpperCase().split(/\s+/).filter(identity),
data = addressBarDialog.useFeed ? allStories : allPlaces;
function matches(place) {
if (!words.length) {
return suggestable(place);
}
return words.every(function (word) {
return place.searchText.indexOf(word) >= 0;
});
}
data.forEach(function (place) {
if (matches(place)) {
suggestions.append(place);
}
});
} }
function fillDestinations() { function fillDestinations() {
allDomains = suggestionChoices = []; allPlaces = [];
getDomains({minUsers: 0, maxUsers: 20}, function (error, domains) { allStories = [];
if (error) { suggestions.clear();
console.log('domain query failed:', error); getDomainPage(1, function (error) {
return filterChoicesByText(); console.log('domain query', error || 'ok', allPlaces.length);
} });
var here = AddressManager.hostname; // don't show where we are now. getUserStoryPage(1, function (error) {
allDomains = domains.filter(function (domain) { return domain.name !== here; }); console.log('user stories query', error || 'ok', allStories.length);
// Whittle down suggestions to those that have at least one user, and try to get pictures.
suggestionChoices = allDomains.filter(function (domain) { return domain.online_users; });
asyncEach(domains, addPictureToDomain, function (error) {
if (error) {
console.log('place picture query failed:', error);
}
// Whittle down more by requiring a picture.
suggestionChoices = suggestionChoices.filter(function (domain) { return domain.lobby; });
filterChoicesByText();
});
}); });
} }

View file

@ -218,16 +218,22 @@ ScrollingWindow {
onIconChanged: { onIconChanged: {
console.log("New icon: " + icon) console.log("New icon: " + icon)
} }
onNewViewRequested:{ onNewViewRequested: {
var component = Qt.createComponent("Browser.qml"); var component = Qt.createComponent("Browser.qml");
var newWindow = component.createObject(desktop); var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView) request.openIn(newWindow.webView)
} }
Component.onCompleted: {
desktop.initWebviewProfileHandlers(webview.profile)
}
//profile: desktop.browserProfile //profile: desktop.browserProfile
} }
} // item } // item
Keys.onPressed: { Keys.onPressed: {
switch(event.key) { switch(event.key) {
case Qt.Key_L: case Qt.Key_L:

View file

@ -48,7 +48,7 @@ Item {
} }
} }
MenuItem { InfoItem {
id: mainTextContainer id: mainTextContainer
anchors { anchors {
top: parent.top top: parent.top

View file

@ -78,7 +78,7 @@ Item {
placeholderText: "Choose your own" placeholderText: "Choose your own"
} }
MenuItem { InfoItem {
id: termsContainer id: termsContainer
anchors { anchors {
top: textField.bottom top: textField.bottom

View file

@ -44,7 +44,7 @@ Item {
} }
} }
MenuItem { InfoItem {
id: mainTextContainer id: mainTextContainer
anchors { anchors {
top: parent.top top: parent.top

View file

@ -0,0 +1,103 @@
//
// MarketplaceComboBox.qml
//
// Created by Elisa Lupin-Jimenez on 3 Aug 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 QtWebChannel 1.0
import QtWebEngine 1.1
import QtWebSockets 1.0
import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel
import "controls"
import "controls-uit" as Controls
import "styles"
import "styles-uit"
Rectangle {
HifiConstants { id: hifi }
id: marketplaceComboBox
anchors.fill: parent
color: hifi.colors.baseGrayShadow
property var currentUrl: "https://metaverse.highfidelity.com/marketplace"
Controls.WebView {
id: webview
url: currentUrl
anchors.top: switchMarketView.bottom
width: parent.width
height: parent.height - 40
focus: true
Timer {
id: zipTimer
running: false
repeat: false
interval: 1500
property var handler;
onTriggered: handler();
}
property var autoCancel: 'var element = $("a.btn.cancel");
element.click();'
onNewViewRequested: {
var component = Qt.createComponent("Browser.qml");
var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView);
if (File.isZippedFbx(desktop.currentUrl)) {
zipTimer.handler = function() {
newWindow.destroy();
runJavaScript(autoCancel);
}
zipTimer.start();
}
}
property var simpleDownload: 'var element = $("a.download-file");
element.removeClass("download-file");
element.removeAttr("download");'
onLinkHovered: {
desktop.currentUrl = hoveredUrl;
// add an error message for non-fbx files
if (File.isZippedFbx(desktop.currentUrl)) {
runJavaScript(simpleDownload, function(){console.log("ran the JS");});
}
}
}
Controls.ComboBox {
id: switchMarketView
anchors.top: parent.top
anchors.right: parent.right
colorScheme: hifi.colorSchemes.dark
width: 200
height: 40
visible: true
model: ["Marketplace", "Clara.io"]
onCurrentIndexChanged: {
if (currentIndex === 0) { webview.url = "https://metaverse.highfidelity.com/marketplace"; }
if (currentIndex === 1) { webview.url = "https://clara.io/library"; }
}
}
Controls.Label {
id: switchMarketLabel
anchors.verticalCenter: switchMarketView.verticalCenter
anchors.right: switchMarketView.left
color: hifi.colors.white
text: "Explore interesting content from: "
}
}

View file

@ -1,13 +1,16 @@
import QtQuick 2.3 import QtQuick 2.3
import QtQuick.Controls 1.2 import QtQuick.Controls 1.4
import QtWebChannel 1.0 import QtWebChannel 1.0
import QtWebEngine 1.1
import QtWebSockets 1.0 import QtWebSockets 1.0
import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel
import "windows" as Windows import "windows" as Windows
import "controls" import "controls"
import "controls-uit" as Controls
import "styles" import "styles"
import "styles-uit"
Windows.Window { Windows.Window {
id: root id: root
@ -23,6 +26,8 @@ Windows.Window {
property var eventBridge; property var eventBridge;
property var component; property var component;
property var dynamicContent; property var dynamicContent;
onSourceChanged: { onSourceChanged: {
if (dynamicContent) { if (dynamicContent) {
dynamicContent.destroy(); dynamicContent.destroy();

View file

@ -1,10 +0,0 @@
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtWebEngine 1.1
WebEngineView {
id: root
anchors.fill: parent
objectName: "webview"
url: "about:blank"
}

View file

@ -21,6 +21,8 @@ Original.Button {
width: 120 width: 120
height: hifi.dimensions.controlLineHeight height: hifi.dimensions.controlLineHeight
HifiConstants { id: hifi }
style: ButtonStyle { style: ButtonStyle {
background: Rectangle { background: Rectangle {

View file

@ -18,6 +18,7 @@ import "." as VrControls
FocusScope { FocusScope {
id: root id: root
HifiConstants { id: hifi }
property alias model: comboBox.model; property alias model: comboBox.model;
property alias comboBox: comboBox property alias comboBox: comboBox

View file

@ -13,6 +13,7 @@ import QtQuick 2.5
import "../styles-uit" import "../styles-uit"
RalewaySemiBold { RalewaySemiBold {
HifiConstants { id: hifi }
property int colorScheme: hifi.colorSchemes.light property int colorScheme: hifi.colorSchemes.light
size: hifi.fontSizes.inputLabel size: hifi.fontSizes.inputLabel

View file

@ -25,6 +25,8 @@ WebEngineView {
}); });
} }
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6 // FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
Timer { Timer {
id: urlReplacementTimer id: urlReplacementTimer
@ -59,11 +61,6 @@ WebEngineView {
} }
} }
onNewViewRequested:{
var component = Qt.createComponent("../Browser.qml");
var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView)
}
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6 // This breaks the webchannel used for passing messages. Fixed in Qt 5.6
// See https://bugreports.qt.io/browse/QTBUG-49521 // See https://bugreports.qt.io/browse/QTBUG-49521

View file

@ -12,6 +12,8 @@ Original.TextInput {
verticalAlignment: Original.TextInput.AlignVCenter verticalAlignment: Original.TextInput.AlignVCenter
font.family: hifi.fonts.fontFamily font.family: hifi.fonts.fontFamily
font.pixelSize: hifi.fonts.pixelSize font.pixelSize: hifi.fonts.pixelSize
property int helperPixelSize: font.pixelSize
property bool helperItalic: false
/* /*
Original.Rectangle { Original.Rectangle {
@ -23,7 +25,8 @@ Original.TextInput {
*/ */
Text { Text {
anchors.fill: parent anchors.fill: parent
font.pixelSize: parent.font.pixelSize font.pixelSize: helperPixelSize
font.italic: helperItalic
font.family: parent.font.family font.family: parent.font.family
verticalAlignment: parent.verticalAlignment verticalAlignment: parent.verticalAlignment
horizontalAlignment: parent.horizontalAlignment horizontalAlignment: parent.horizontalAlignment

View file

@ -55,9 +55,11 @@ WebEngineView {
} }
onNewViewRequested:{ onNewViewRequested:{
if (desktop) {
var component = Qt.createComponent("../Browser.qml"); var component = Qt.createComponent("../Browser.qml");
var newWindow = component.createObject(desktop); var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView) request.openIn(newWindow.webView);
}
} }
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6 // This breaks the webchannel used for passing messages. Fixed in Qt 5.6

View file

@ -17,28 +17,69 @@ import QtGraphicalEffects 1.0
import "../styles-uit" import "../styles-uit"
Rectangle { Rectangle {
property string userName: "";
property string placeName: "";
property string action: "";
property string timestamp: "";
property string hifiUrl: "";
property string thumbnail: defaultThumbnail;
property string imageUrl: "";
property var goFunction: null; property var goFunction: null;
property var userStory: null; property string storyId: "";
property alias image: lobby;
property alias placeText: place.text; property string timePhrase: pastTime(timestamp);
property alias usersText: users.text; property string actionPhrase: makeActionPhrase(action);
property int onlineUsers: 0;
property bool isUserStory: userName && !onlineUsers;
property int textPadding: 20; property int textPadding: 20;
property int textSize: 24; property int textSize: 24;
property string defaultPicture: "../../images/default-domain.gif"; property int textSizeSmall: 18;
property string defaultThumbnail: Qt.resolvedUrl("../../images/default-domain.gif");
HifiConstants { id: hifi } HifiConstants { id: hifi }
function pastTime(timestamp) { // Answer a descriptive string
timestamp = new Date(timestamp);
var then = timestamp.getTime(),
now = Date.now(),
since = now - then,
ONE_MINUTE = 1000 * 60,
ONE_HOUR = ONE_MINUTE * 60,
hours = since / ONE_HOUR,
minutes = (hours % 1) * 60;
if (hours > 24) {
return timestamp.toDateString();
}
if (hours > 1) {
return Math.floor(hours).toString() + ' hr ' + Math.floor(minutes) + ' min ago';
}
if (minutes >= 2) {
return Math.floor(minutes).toString() + ' min ago';
}
return 'about a minute ago';
}
function makeActionPhrase(actionLabel) {
switch (actionLabel) {
case "snapshot":
return "took a snapshot";
default:
return "unknown"
}
}
Image { Image {
id: lobby; id: lobby;
width: parent.width; width: parent.width;
height: parent.height; height: parent.height;
source: defaultPicture; source: thumbnail || defaultThumbnail;
fillMode: Image.PreserveAspectCrop; fillMode: Image.PreserveAspectCrop;
// source gets filled in later // source gets filled in later
anchors.verticalCenter: parent.verticalCenter; anchors.verticalCenter: parent.verticalCenter;
anchors.left: parent.left; anchors.left: parent.left;
onStatusChanged: { onStatusChanged: {
if (status == Image.Error) { if (status == Image.Error) {
console.log("source: " + source + ": failed to load " + JSON.stringify(userStory)); console.log("source: " + source + ": failed to load " + hifiUrl);
source = defaultPicture; source = defaultThumbnail;
} }
} }
} }
@ -69,6 +110,7 @@ Rectangle {
} }
RalewaySemiBold { RalewaySemiBold {
id: place; id: place;
text: isUserStory ? "" : placeName;
color: hifi.colors.white; color: hifi.colors.white;
size: textSize; size: textSize;
anchors { anchors {
@ -79,7 +121,8 @@ Rectangle {
} }
RalewayRegular { RalewayRegular {
id: users; id: users;
size: textSize; text: isUserStory ? timePhrase : (onlineUsers + ((onlineUsers === 1) ? ' person' : ' people'));
size: textSizeSmall;
color: hifi.colors.white; color: hifi.colors.white;
anchors { anchors {
bottom: parent.bottom; bottom: parent.bottom;
@ -87,10 +130,18 @@ Rectangle {
margins: textPadding; margins: textPadding;
} }
} }
// These two can be supplied to provide hover behavior.
// For example, AddressBarDialog provides functions that set the current list view item
// to that which is being hovered over.
property var hoverThunk: function () { };
property var unhoverThunk: function () { };
MouseArea { MouseArea {
id: zmouseArea;
anchors.fill: parent; anchors.fill: parent;
acceptedButtons: Qt.LeftButton; acceptedButtons: Qt.LeftButton;
onClicked: goFunction(parent); onClicked: goFunction(parent);
hoverEnabled: true; hoverEnabled: true;
onEntered: hoverThunk();
onExited: unhoverThunk();
} }
} }

View file

@ -20,6 +20,8 @@ OriginalDesktop.Desktop {
onEntered: ApplicationCompositor.reticleOverDesktop = true onEntered: ApplicationCompositor.reticleOverDesktop = true
onExited: ApplicationCompositor.reticleOverDesktop = false onExited: ApplicationCompositor.reticleOverDesktop = false
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
} }
// The tool window, one instance // The tool window, one instance
@ -71,6 +73,39 @@ OriginalDesktop.Desktop {
}); });
} }
// Accept a download through the webview
property bool webViewProfileSetup: false
property string currentUrl: ""
property string adaptedPath: ""
property string tempDir: ""
function initWebviewProfileHandlers(profile) {
console.log("The webview url in desktop is: " + currentUrl);
if (webViewProfileSetup) return;
webViewProfileSetup = true;
profile.downloadRequested.connect(function(download){
console.log("Download start: " + download.state);
adaptedPath = File.convertUrlToPath(currentUrl);
tempDir = File.getTempDir();
console.log("Temp dir created: " + tempDir);
download.path = tempDir + "/" + adaptedPath;
console.log("Path where object should download: " + download.path);
download.accept();
if (download.state === WebEngineDownloadItem.DownloadInterrupted) {
console.log("download failed to complete");
}
})
profile.downloadFinished.connect(function(download){
if (download.state === WebEngineDownloadItem.DownloadCompleted) {
File.runUnzip(download.path, currentUrl);
} else {
console.log("The download was corrupted, state: " + download.state);
}
})
}
// Create or fetch a toolbar with the given name // Create or fetch a toolbar with the given name
function getToolbar(name) { function getToolbar(name) {
var result = toolbars[name]; var result = toolbars[name];

View file

@ -1,5 +1,5 @@
// //
// MenuItem.qml // InfoItem.qml
// //
// Created by Clement on 7/18/16 // Created by Clement on 7/18/16
// Copyright 2016 High Fidelity, Inc. // Copyright 2016 High Fidelity, Inc.

View file

@ -57,6 +57,7 @@
#include <display-plugins/DisplayPlugin.h> #include <display-plugins/DisplayPlugin.h>
#include <EntityScriptingInterface.h> #include <EntityScriptingInterface.h>
#include <ErrorDialog.h> #include <ErrorDialog.h>
#include <FileScriptingInterface.h>
#include <Finally.h> #include <Finally.h>
#include <FramebufferCache.h> #include <FramebufferCache.h>
#include <gpu/Batch.h> #include <gpu/Batch.h>
@ -1067,70 +1068,23 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// 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 // 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>(); auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity,
[this, entityScriptingInterface](const EntityItemID& entityItemID, const MouseEvent& event) { [this](const EntityItemID& entityItemID, const PointerEvent& event) {
if (_keyboardFocusedItem != entityItemID) { setKeyboardFocusEntity(entityItemID);
_keyboardFocusedItem = UNKNOWN_ENTITY_ID;
auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
if (EntityTypes::Web == properties.getType() && !properties.getLocked() && properties.getVisible()) {
auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(entityItemID);
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get());
if (webEntity) {
webEntity->setProxyWindow(_window->windowHandle());
if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent();
}
_keyboardFocusedItem = entityItemID;
_lastAcceptedKeyPress = usecTimestampNow();
if (_keyboardFocusHighlightID < 0 || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {
_keyboardFocusHighlight = new Cube3DOverlay();
_keyboardFocusHighlight->setAlpha(1.0f);
_keyboardFocusHighlight->setBorderSize(1.0f);
_keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 });
_keyboardFocusHighlight->setIsSolid(false);
_keyboardFocusHighlight->setPulseMin(0.5);
_keyboardFocusHighlight->setPulseMax(1.0);
_keyboardFocusHighlight->setColorPulse(1.0);
_keyboardFocusHighlight->setIgnoreRayIntersection(true);
_keyboardFocusHighlight->setDrawInFront(true);
}
_keyboardFocusHighlight->setRotation(webEntity->getRotation());
_keyboardFocusHighlight->setPosition(webEntity->getPosition());
_keyboardFocusHighlight->setDimensions(webEntity->getDimensions() * 1.05f);
_keyboardFocusHighlight->setVisible(true);
_keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight);
}
}
if (_keyboardFocusedItem == UNKNOWN_ENTITY_ID && _keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
}
}
}); });
connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [=](const EntityItemID& entityItemID) {
[=](const EntityItemID& entityItemID) { if (entityItemID == _keyboardFocusedItem.get()) {
if (entityItemID == _keyboardFocusedItem) { setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
_keyboardFocusedItem = UNKNOWN_ENTITY_ID;
if (_keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
}
} }
}); });
// If the user clicks somewhere where there is NO entity at all, we will release focus // If the user clicks somewhere where there is NO entity at all, we will release focus
connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, [=]() {
[=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event) { setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
_keyboardFocusedItem = UNKNOWN_ENTITY_ID;
if (_keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
}
}); });
connect(this, &Application::aboutToQuit, [=]() { connect(this, &Application::aboutToQuit, [=]() {
_keyboardFocusedItem = UNKNOWN_ENTITY_ID; setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
if (_keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
}
}); });
// Add periodic checks to send user activity data // Add periodic checks to send user activity data
@ -1138,10 +1092,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
static int SEND_STATS_INTERVAL_MS = 10000; static int SEND_STATS_INTERVAL_MS = 10000;
static int NEARBY_AVATAR_RADIUS_METERS = 10; static int NEARBY_AVATAR_RADIUS_METERS = 10;
static glm::vec3 lastAvatarPosition = getMyAvatar()->getPosition();
static glm::mat4 lastHMDHeadPose = getHMDSensorPose();
static controller::Pose lastLeftHandPose = getMyAvatar()->getLeftHandPose();
static controller::Pose lastRightHandPose = getMyAvatar()->getRightHandPose();
// Periodically send fps as a user activity event // Periodically send fps as a user activity event
QTimer* sendStatsTimer = new QTimer(this); QTimer* sendStatsTimer = new QTimer(this);
sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS); sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS);
connect(sendStatsTimer, &QTimer::timeout, this, [this]() { connect(sendStatsTimer, &QTimer::timeout, this, [this]() {
QJsonObject properties = {}; QJsonObject properties = {};
MemoryInfo memInfo; MemoryInfo memInfo;
if (getMemoryInfo(memInfo)) { if (getMemoryInfo(memInfo)) {
@ -1183,6 +1143,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false; properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false;
glm::vec3 avatarPosition = getMyAvatar()->getPosition();
properties["avatar_has_moved"] = lastAvatarPosition != avatarPosition;
lastAvatarPosition = avatarPosition;
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
auto entityActivityTracking = entityScriptingInterface->getActivityTracking();
entityScriptingInterface->resetActivityTracking();
properties["added_entity_cnt"] = entityActivityTracking.addedEntityCount;
properties["deleted_entity_cnt"] = entityActivityTracking.deletedEntityCount;
properties["edited_entity_cnt"] = entityActivityTracking.editedEntityCount;
auto hmdHeadPose = getHMDSensorPose();
properties["hmd_head_pose_changed"] = isHMDMode() && (hmdHeadPose != lastHMDHeadPose);
lastHMDHeadPose = hmdHeadPose;
auto leftHandPose = getMyAvatar()->getLeftHandPose();
auto rightHandPose = getMyAvatar()->getRightHandPose();
// controller::Pose considers two poses to be different if either are invalid. In our case, we actually
// want to consider the pose to be unchanged if it was invalid and still is invalid, so we check that first.
properties["hand_pose_changed"] =
((leftHandPose.valid || lastLeftHandPose.valid) && (leftHandPose != lastLeftHandPose))
|| ((rightHandPose.valid || lastRightHandPose.valid) && (rightHandPose != lastRightHandPose));
lastLeftHandPose = leftHandPose;
lastRightHandPose = rightHandPose;
UserActivityLogger::getInstance().logAction("stats", properties); UserActivityLogger::getInstance().logAction("stats", properties);
}); });
sendStatsTimer->start(); sendStatsTimer->start();
@ -1235,7 +1220,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
_defaultSkyboxAmbientTexture = textureCache->getImageTexture(skyboxAmbientUrl, NetworkTexture::CUBE_TEXTURE, { { "generateIrradiance", true } }); _defaultSkyboxAmbientTexture = textureCache->getImageTexture(skyboxAmbientUrl, NetworkTexture::CUBE_TEXTURE, { { "generateIrradiance", true } });
_defaultSkybox->setCubemap(_defaultSkyboxTexture); _defaultSkybox->setCubemap(_defaultSkyboxTexture);
_defaultSkybox->setColor({ 1.0, 1.0, 1.0 });
EntityItem::setEntitiesShouldFadeFunction([this]() {
SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer);
return entityServerNode && !isPhysicsEnabled();
});
// After all of the constructor is completed, then set firstRun to false. // After all of the constructor is completed, then set firstRun to false.
Setting::Handle<bool> firstRun{ Settings::firstRun, true }; Setting::Handle<bool> firstRun{ Settings::firstRun, true };
@ -1367,11 +1356,13 @@ void Application::cleanupBeforeQuit() {
// FIXME: once we move to shared pointer for the INputDevice we shoud remove this naked delete: // FIXME: once we move to shared pointer for the INputDevice we shoud remove this naked delete:
_applicationStateDevice.reset(); _applicationStateDevice.reset();
if (_keyboardFocusHighlightID > 0) { {
getOverlays().deleteOverlay(_keyboardFocusHighlightID); if (_keyboardFocusHighlightID > 0) {
_keyboardFocusHighlightID = -1; getOverlays().deleteOverlay(_keyboardFocusHighlightID);
_keyboardFocusHighlightID = -1;
}
_keyboardFocusHighlight = nullptr;
} }
_keyboardFocusHighlight = nullptr;
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
@ -1492,6 +1483,7 @@ void Application::initializeGL() {
_glWidget->makeCurrent(); _glWidget->makeCurrent();
_chromiumShareContext = new OffscreenGLCanvas(); _chromiumShareContext = new OffscreenGLCanvas();
_chromiumShareContext->setObjectName("ChromiumShareContext");
_chromiumShareContext->create(_glWidget->context()->contextHandle()); _chromiumShareContext->create(_glWidget->context()->contextHandle());
_chromiumShareContext->makeCurrent(); _chromiumShareContext->makeCurrent();
qt_gl_set_global_share_context(_chromiumShareContext->getContext()); qt_gl_set_global_share_context(_chromiumShareContext->getContext());
@ -1538,6 +1530,7 @@ void Application::initializeGL() {
_idleLoopStdev.reset(); _idleLoopStdev.reset();
_offscreenContext = new OffscreenGLCanvas(); _offscreenContext = new OffscreenGLCanvas();
_offscreenContext->setObjectName("MainThreadContext");
_offscreenContext->create(_glWidget->context()->contextHandle()); _offscreenContext->create(_glWidget->context()->contextHandle());
_offscreenContext->makeCurrent(); _offscreenContext->makeCurrent();
@ -1587,6 +1580,9 @@ void Application::initializeUi() {
rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance());
rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data()); rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data()); rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
FileScriptingInterface* fileDownload = new FileScriptingInterface(engine);
rootContext->setContextProperty("File", fileDownload);
connect(fileDownload, &FileScriptingInterface::unzipSuccess, this, &Application::showAssetServerWidget);
rootContext->setContextProperty("MyAvatar", getMyAvatar()); rootContext->setContextProperty("MyAvatar", getMyAvatar());
rootContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data()); rootContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data());
rootContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data()); rootContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
@ -2033,7 +2029,6 @@ bool Application::importJSONFromURL(const QString& urlString) {
} }
bool Application::importSVOFromURL(const QString& urlString) { bool Application::importSVOFromURL(const QString& urlString) {
emit svoImportRequested(urlString); emit svoImportRequested(urlString);
return true; return true;
} }
@ -2086,16 +2081,16 @@ bool Application::event(QEvent* event) {
return true; return true;
} }
if (!_keyboardFocusedItem.isInvalidID()) { {
switch (event->type()) { if (!_keyboardFocusedItem.get().isInvalidID()) {
switch (event->type()) {
case QEvent::KeyPress: case QEvent::KeyPress:
case QEvent::KeyRelease: { case QEvent::KeyRelease: {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
auto entity = entityScriptingInterface->getEntityTree()->findEntityByID(_keyboardFocusedItem); auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedItem.get());
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get()); if (entity && entity->getEventHandler()) {
if (webEntity && webEntity->getEventHandler()) {
event->setAccepted(false); event->setAccepted(false);
QCoreApplication::sendEvent(webEntity->getEventHandler(), event); QCoreApplication::sendEvent(entity->getEventHandler(), event);
if (event->isAccepted()) { if (event->isAccepted()) {
_lastAcceptedKeyPress = usecTimestampNow(); _lastAcceptedKeyPress = usecTimestampNow();
return true; return true;
@ -2106,6 +2101,7 @@ bool Application::event(QEvent* event) {
default: default:
break; break;
}
} }
} }
@ -2157,13 +2153,15 @@ bool Application::event(QEvent* event) {
// handle custom URL // handle custom URL
if (event->type() == QEvent::FileOpen) { if (event->type() == QEvent::FileOpen) {
QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event); QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
QUrl url = fileEvent->url(); QUrl url = fileEvent->url();
if (!url.isEmpty()) { if (!url.isEmpty()) {
QString urlString = url.toString(); QString urlString = url.toString();
if (canAcceptURL(urlString)) { if (canAcceptURL(urlString)) {
return acceptURL(urlString); return acceptURL(urlString);
} }
} }
@ -2304,7 +2302,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
} else if (isOption && !isShifted && !isMeta) { } else if (isOption && !isShifted && !isMeta) {
Menu::getInstance()->triggerOption(MenuOption::ScriptEditor); Menu::getInstance()->triggerOption(MenuOption::ScriptEditor);
} else if (!isOption && !isShifted && isMeta) { } else if (!isOption && !isShifted && isMeta) {
takeSnapshot(); takeSnapshot(true);
} }
break; break;
@ -2655,7 +2653,10 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
event->screenPos(), button, event->screenPos(), button,
buttons, event->modifiers()); buttons, event->modifiers());
getEntities()->mouseMoveEvent(&mappedEvent); if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() ||
getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y()))) {
getEntities()->mouseMoveEvent(&mappedEvent);
}
_controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it // if one of our scripts have asked to capture this event, then stop processing it
@ -2945,14 +2946,6 @@ void Application::idle(float nsecsElapsed) {
_simCounter.increment(); _simCounter.increment();
PerformanceTimer perfTimer("idle"); PerformanceTimer perfTimer("idle");
// Drop focus from _keyboardFocusedItem if no keyboard messages for 30 seconds
if (!_keyboardFocusedItem.isInvalidID()) {
const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus
quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress;
if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) {
_keyboardFocusedItem = UNKNOWN_ENTITY_ID;
}
}
// Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
// details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing // details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing
@ -2966,6 +2959,27 @@ void Application::idle(float nsecsElapsed) {
static const float BIGGEST_DELTA_TIME_SECS = 0.25f; static const float BIGGEST_DELTA_TIME_SECS = 0.25f;
update(glm::clamp(secondsSinceLastUpdate, 0.0f, BIGGEST_DELTA_TIME_SECS)); update(glm::clamp(secondsSinceLastUpdate, 0.0f, BIGGEST_DELTA_TIME_SECS));
} }
// Drop focus from _keyboardFocusedItem if no keyboard messages for 30 seconds
{
if (!_keyboardFocusedItem.get().isInvalidID()) {
const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus
quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress;
if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) {
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
} else {
// update position of highlight overlay
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedItem.get());
if (entity && _keyboardFocusHighlight) {
_keyboardFocusHighlight->setRotation(entity->getRotation());
_keyboardFocusHighlight->setPosition(entity->getPosition());
}
}
}
}
{ {
PerformanceTimer perfTimer("pluginIdle"); PerformanceTimer perfTimer("pluginIdle");
PerformanceWarning warn(showWarnings, "Application::idle()... pluginIdle()"); PerformanceWarning warn(showWarnings, "Application::idle()... pluginIdle()");
@ -3550,6 +3564,54 @@ void Application::rotationModeChanged() const {
} }
} }
QUuid Application::getKeyboardFocusEntity() const {
return _keyboardFocusedItem.get();
}
void Application::setKeyboardFocusEntity(QUuid id) {
EntityItemID entityItemID(id);
setKeyboardFocusEntity(entityItemID);
}
void Application::setKeyboardFocusEntity(EntityItemID entityItemID) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
if (_keyboardFocusedItem.get() != entityItemID) {
_keyboardFocusedItem.set(UNKNOWN_ENTITY_ID);
auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
if (!properties.getLocked() && properties.getVisible()) {
auto entity = getEntities()->getTree()->findEntityByID(entityItemID);
if (entity && entity->wantsKeyboardFocus()) {
entity->setProxyWindow(_window->windowHandle());
if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent();
}
_keyboardFocusedItem.set(entityItemID);
_lastAcceptedKeyPress = usecTimestampNow();
if (_keyboardFocusHighlightID < 0 || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {
_keyboardFocusHighlight = new Cube3DOverlay();
_keyboardFocusHighlight->setAlpha(1.0f);
_keyboardFocusHighlight->setBorderSize(1.0f);
_keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 });
_keyboardFocusHighlight->setIsSolid(false);
_keyboardFocusHighlight->setPulseMin(0.5);
_keyboardFocusHighlight->setPulseMax(1.0);
_keyboardFocusHighlight->setColorPulse(1.0);
_keyboardFocusHighlight->setIgnoreRayIntersection(true);
_keyboardFocusHighlight->setDrawInFront(false);
}
_keyboardFocusHighlight->setRotation(entity->getRotation());
_keyboardFocusHighlight->setPosition(entity->getPosition());
_keyboardFocusHighlight->setDimensions(entity->getDimensions() * 1.05f);
_keyboardFocusHighlight->setVisible(true);
_keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight);
}
}
if (_keyboardFocusedItem.get() == UNKNOWN_ENTITY_ID && _keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
}
}
}
void Application::updateDialogs(float deltaTime) const { void Application::updateDialogs(float deltaTime) const {
PerformanceTimer perfTimer("updateDialogs"); PerformanceTimer perfTimer("updateDialogs");
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
@ -4253,43 +4315,55 @@ namespace render {
auto backgroundMode = skyStage->getBackgroundMode(); auto backgroundMode = skyStage->getBackgroundMode();
switch (backgroundMode) { switch (backgroundMode) {
case model::SunSkyStage::SKY_DEFAULT: {
static const glm::vec3 DEFAULT_SKYBOX_COLOR{ 255.0f / 255.0f, 220.0f / 255.0f, 194.0f / 255.0f };
static const float DEFAULT_SKYBOX_INTENSITY{ 0.2f };
static const float DEFAULT_SKYBOX_AMBIENT_INTENSITY{ 2.0f };
static const glm::vec3 DEFAULT_SKYBOX_DIRECTION{ 0.0f, 0.0f, -1.0f };
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
auto sceneKeyLight = scene->getKeyLight();
scene->setSunModelEnable(false);
sceneKeyLight->setColor(DEFAULT_SKYBOX_COLOR);
sceneKeyLight->setIntensity(DEFAULT_SKYBOX_INTENSITY);
sceneKeyLight->setAmbientIntensity(DEFAULT_SKYBOX_AMBIENT_INTENSITY);
sceneKeyLight->setDirection(DEFAULT_SKYBOX_DIRECTION);
// fall through: render a skybox (if available), or the defaults (if requested)
}
case model::SunSkyStage::SKY_BOX: { case model::SunSkyStage::SKY_BOX: {
auto skybox = skyStage->getSkybox(); auto skybox = skyStage->getSkybox();
if (skybox) { if (!skybox->empty()) {
PerformanceTimer perfTimer("skybox"); PerformanceTimer perfTimer("skybox");
skybox->render(batch, args->getViewFrustum()); skybox->render(batch, args->getViewFrustum());
break; break;
} }
// fall through: render defaults (if requested)
} }
// Fall through: if no skybox is available, render the SKY_DOME case model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE: {
case model::SunSkyStage::SKY_DOME: { if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) { auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage();
static const glm::vec3 DEFAULT_SKYBOX_COLOR { 255.0f / 255.0f, 220.0f / 255.0f, 194.0f / 255.0f }; auto sceneKeyLight = scene->getKeyLight();
static const float DEFAULT_SKYBOX_INTENSITY { 0.2f }; auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
static const float DEFAULT_SKYBOX_AMBIENT_INTENSITY { 2.0f }; // set the ambient sphere uniformly - the defaultSkyboxAmbientTexture has peaks that cause flashing when turning
static const glm::vec3 DEFAULT_SKYBOX_DIRECTION { 0.0f, 0.0f, -1.0f }; sceneKeyLight->setAmbientSphere(DependencyManager::get<TextureCache>()->getWhiteTexture()->getIrradiance());
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage(); // fall through: render defaults skybox
auto sceneKeyLight = scene->getKeyLight(); } else {
scene->setSunModelEnable(false); break;
sceneKeyLight->setColor(DEFAULT_SKYBOX_COLOR); }
sceneKeyLight->setIntensity(DEFAULT_SKYBOX_INTENSITY);
sceneKeyLight->setAmbientIntensity(DEFAULT_SKYBOX_AMBIENT_INTENSITY);
sceneKeyLight->setDirection(DEFAULT_SKYBOX_DIRECTION);
auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
qApp->getDefaultSkybox()->render(batch, args->getViewFrustum());
}
} }
case model::SunSkyStage::SKY_DEFAULT_TEXTURE:
if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
qApp->getDefaultSkybox()->render(batch, args->getViewFrustum());
}
break; break;
// Any other cases require no extra rendering
case model::SunSkyStage::NO_BACKGROUND: case model::SunSkyStage::NO_BACKGROUND:
default: default:
// this line intentionally left blank
break; break;
} }
} }
@ -4503,7 +4577,7 @@ void Application::clearDomainOctreeDetails() {
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage(); auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
_recentlyClearedDomain = true; _recentlyClearedDomain = true;
} }
@ -4853,6 +4927,7 @@ bool Application::canAcceptURL(const QString& urlString) const {
bool Application::acceptURL(const QString& urlString, bool defaultUpload) { bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
if (urlString.startsWith(HIFI_URL_SCHEME)) { if (urlString.startsWith(HIFI_URL_SCHEME)) {
// this is a hifi URL - have the AddressManager handle it // this is a hifi URL - have the AddressManager handle it
emit receivedHifiSchemeURL(urlString);
QMetaObject::invokeMethod(DependencyManager::get<AddressManager>().data(), "handleLookupString", QMetaObject::invokeMethod(DependencyManager::get<AddressManager>().data(), "handleLookupString",
Qt::AutoConnection, Q_ARG(const QString&, urlString)); Qt::AutoConnection, Q_ARG(const QString&, urlString));
return true; return true;
@ -4901,7 +4976,7 @@ bool Application::askToSetAvatarUrl(const QString& url) {
modelLicense = simpleWordWrap(modelLicense, MAX_CHARACTERS_PER_LINE); modelLicense = simpleWordWrap(modelLicense, MAX_CHARACTERS_PER_LINE);
agreeToLicence = QMessageBox::Yes == OffscreenUi::question("Avatar Usage License", agreeToLicence = QMessageBox::Yes == OffscreenUi::question("Avatar Usage License",
modelLicense + "\nDo you argee to these terms?", modelLicense + "\nDo you agree to these terms?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
} }
@ -4960,7 +5035,6 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
} }
bool Application::askToWearAvatarAttachmentUrl(const QString& url) { bool Application::askToWearAvatarAttachmentUrl(const QString& url) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest = QNetworkRequest(url); QNetworkRequest networkRequest = QNetworkRequest(url);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
@ -5058,11 +5132,11 @@ void Application::toggleRunningScriptsWidget() const {
//} //}
} }
void Application::showAssetServerWidget(QString filePath) { void Application::showAssetServerWidget(QString filePath) {
if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) { if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) {
return; return;
} }
static const QUrl url { "AssetServer.qml" }; static const QUrl url { "AssetServer.qml" };
auto startUpload = [=](QQmlContext* context, QObject* newObject){ auto startUpload = [=](QQmlContext* context, QObject* newObject){
@ -5129,15 +5203,24 @@ void Application::toggleLogDialog() {
} }
} }
void Application::takeSnapshot() { void Application::takeSnapshot(bool notify, float aspectRatio) {
QMediaPlayer* player = new QMediaPlayer(); postLambdaEvent([notify, aspectRatio, this] {
QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); QMediaPlayer* player = new QMediaPlayer();
player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath())); QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav");
player->play(); player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
player->play();
QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot()); QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio));
emit DependencyManager::get<WindowScriptingInterface>()->snapshotTaken(path); emit DependencyManager::get<WindowScriptingInterface>()->snapshotTaken(path, notify);
});
}
void Application::shareSnapshot(const QString& path) {
postLambdaEvent([path] {
// not much to do here, everything is done in snapshot code...
Snapshot::uploadSnapshot(path);
});
} }
float Application::getRenderResolutionScale() const { float Application::getRenderResolutionScale() const {
@ -5602,3 +5685,48 @@ bool Application::makeRenderingContextCurrent() {
bool Application::isForeground() const { bool Application::isForeground() const {
return _isForeground && !_window->isMinimized(); return _isForeground && !_window->isMinimized();
} }
void Application::sendMousePressOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->mousePressOnEntity(entityItemID, event);
}
void Application::sendMouseMoveOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->mouseMoveOnEntity(entityItemID, event);
}
void Application::sendMouseReleaseOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->mouseReleaseOnEntity(entityItemID, event);
}
void Application::sendClickDownOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->clickDownOnEntity(entityItemID, event);
}
void Application::sendHoldingClickOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->holdingClickOnEntity(entityItemID, event);
}
void Application::sendClickReleaseOnEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->clickReleaseOnEntity(entityItemID, event);
}
void Application::sendHoverEnterEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->hoverEnterEntity(entityItemID, event);
}
void Application::sendHoverOverEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->hoverOverEntity(entityItemID, event);
}
void Application::sendHoverLeaveEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->hoverLeaveEntity(entityItemID, event);
}

View file

@ -43,6 +43,7 @@
#include <ViewFrustum.h> #include <ViewFrustum.h>
#include <AbstractUriHandler.h> #include <AbstractUriHandler.h>
#include <shared/RateCounter.h> #include <shared/RateCounter.h>
#include <ThreadSafeValueCache.h>
#include "avatar/MyAvatar.h" #include "avatar/MyAvatar.h"
#include "Bookmarks.h" #include "Bookmarks.h"
@ -249,11 +250,26 @@ public:
float getAvatarSimrate() const { return _avatarSimCounter.rate(); } float getAvatarSimrate() const { return _avatarSimCounter.rate(); }
float getAverageSimsPerSecond() const { return _simCounter.rate(); } float getAverageSimsPerSecond() const { return _simCounter.rate(); }
void takeSnapshot(bool notify, float aspectRatio = 0.0f);
void shareSnapshot(const QString& filename);
model::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; } model::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; }
gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; } gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; }
gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; } gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; }
Q_INVOKABLE void sendMousePressOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendMouseMoveOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendMouseReleaseOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendClickDownOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoldingClickOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendClickReleaseOnEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoverEnterEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoverOverEntity(QUuid id, PointerEvent event);
Q_INVOKABLE void sendHoverLeaveEntity(QUuid id, PointerEvent event);
signals: signals:
void svoImportRequested(const QString& url); void svoImportRequested(const QString& url);
@ -263,6 +279,7 @@ signals:
void activeDisplayPluginChanged(); void activeDisplayPluginChanged();
void uploadRequest(QString path); void uploadRequest(QString path);
void receivedHifiSchemeURL(const QString& url);
public slots: public slots:
QVector<EntityItemID> pasteEntities(float x, float y, float z); QVector<EntityItemID> pasteEntities(float x, float y, float z);
@ -319,6 +336,10 @@ public slots:
static void runTests(); static void runTests();
QUuid getKeyboardFocusEntity() const; // thread-safe
void setKeyboardFocusEntity(QUuid id);
void setKeyboardFocusEntity(EntityItemID entityItemID);
private slots: private slots:
void showDesktop(); void showDesktop();
void clearDomainOctreeDetails(); void clearDomainOctreeDetails();
@ -379,8 +400,6 @@ private:
int sendNackPackets(); int sendNackPackets();
void takeSnapshot();
MyAvatar* getMyAvatar() const; MyAvatar* getMyAvatar() const;
void checkSkeleton() const; void checkSkeleton() const;
@ -531,7 +550,7 @@ private:
DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface(); DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface();
EntityItemID _keyboardFocusedItem; ThreadSafeValueCache<EntityItemID> _keyboardFocusedItem;
quint64 _lastAcceptedKeyPress = 0; quint64 _lastAcceptedKeyPress = 0;
bool _isForeground = true; // starts out assumed to be in foreground bool _isForeground = true; // starts out assumed to be in foreground
bool _inPaint = false; bool _inPaint = false;

View file

@ -27,10 +27,6 @@ void ConnectionMonitor::init() {
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &ConnectionMonitor::disconnectedFromDomain); connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &ConnectionMonitor::disconnectedFromDomain);
connect(&domainHandler, &DomainHandler::connectedToDomain, this, &ConnectionMonitor::connectedToDomain); connect(&domainHandler, &DomainHandler::connectedToDomain, this, &ConnectionMonitor::connectedToDomain);
// Connect to AddressManager::hostChanged
auto addressManager = DependencyManager::get<AddressManager>();
connect(addressManager.data(), &AddressManager::hostChanged, this, &ConnectionMonitor::hostChanged);
_timer.setSingleShot(true); _timer.setSingleShot(true);
_timer.setInterval(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS); _timer.setInterval(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
_timer.start(); _timer.start();
@ -46,7 +42,3 @@ void ConnectionMonitor::disconnectedFromDomain() {
void ConnectionMonitor::connectedToDomain(const QString& name) { void ConnectionMonitor::connectedToDomain(const QString& name) {
_timer.stop(); _timer.stop();
} }
void ConnectionMonitor::hostChanged(const QString& name) {
_timer.start();
}

View file

@ -25,7 +25,6 @@ public:
private slots: private slots:
void disconnectedFromDomain(); void disconnectedFromDomain();
void connectedToDomain(const QString& name); void connectedToDomain(const QString& name);
void hostChanged(const QString& name);
private: private:
QTimer _timer; QTimer _timer;

View file

@ -48,7 +48,7 @@ signals:
protected: protected:
void rollFileIfNecessary(QFile& file, bool notifyListenersIfRolled = true); void rollFileIfNecessary(QFile& file, bool notifyListenersIfRolled = true);
virtual bool processQueueItems(const Queue& messages); virtual bool processQueueItems(const Queue& messages) override;
private: private:
const FileLogger& _logger; const FileLogger& _logger;

View file

@ -21,9 +21,9 @@ public:
virtual EntityActionPointer factory(EntityActionType type, virtual EntityActionPointer factory(EntityActionType type,
const QUuid& id, const QUuid& id,
EntityItemPointer ownerEntity, EntityItemPointer ownerEntity,
QVariantMap arguments); QVariantMap arguments) override;
virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity,
QByteArray data); QByteArray data) override;
}; };
#endif // hifi_InterfaceActionFactory_h #endif // hifi_InterfaceActionFactory_h

View file

@ -21,7 +21,8 @@ class InterfaceParentFinder : public SpatialParentFinder {
public: public:
InterfaceParentFinder() { } InterfaceParentFinder() { }
virtual ~InterfaceParentFinder() { } virtual ~InterfaceParentFinder() { }
virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success, SpatialParentTree* entityTree = nullptr) const; virtual SpatiallyNestableWeakPointer find(QUuid parentID, bool& success,
SpatialParentTree* entityTree = nullptr) const override;
}; };
#endif // hifi_InterfaceParentFinder_h #endif // hifi_InterfaceParentFinder_h

View file

@ -137,7 +137,7 @@ namespace MenuOption {
const QString Overlays = "Overlays"; const QString Overlays = "Overlays";
const QString PackageModel = "Package Model..."; const QString PackageModel = "Package Model...";
const QString Pair = "Pair"; const QString Pair = "Pair";
const QString PhysicsShowHulls = "Draw Collision Hulls"; const QString PhysicsShowHulls = "Draw Collision Shapes";
const QString PhysicsShowOwned = "Highlight Simulation Ownership"; const QString PhysicsShowOwned = "Highlight Simulation Ownership";
const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString PipelineWarnings = "Log Render Pipeline Warnings";
const QString Preferences = "General..."; const QString Preferences = "General...";

View file

@ -24,23 +24,23 @@ class QPushButton;
class ModelSelector : public QDialog { class ModelSelector : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
ModelSelector(); ModelSelector();
QFileInfo getFileInfo() const; QFileInfo getFileInfo() const;
FSTReader::ModelType getModelType() const; FSTReader::ModelType getModelType() const;
public slots: public slots:
virtual void accept(); virtual void accept() override;
private slots: private slots:
void browse(); void browse();
private: private:
QFileInfo _modelFile; QFileInfo _modelFile;
QPushButton* _browseButton; QPushButton* _browseButton;
QComboBox* _modelType; QComboBox* _modelType;
}; };
#endif // hifi_ModelSelector_h #endif // hifi_ModelSelector_h

View file

@ -26,7 +26,7 @@ public:
}; };
protected: protected:
void highlightBlock(const QString& text); void highlightBlock(const QString& text) override;
void highlightKeywords(const QString& text); void highlightKeywords(const QString& text);
void formatComments(const QString& text); void formatComments(const QString& text);
void formatQuotedText(const QString& text); void formatQuotedText(const QString& text);

View file

@ -59,6 +59,8 @@ const float DISPLAYNAME_ALPHA = 1.0f;
const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f); const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
const int SENSOR_TO_WORLD_MATRIX_INDEX = 65534;
namespace render { namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
return ItemKey::Builder::opaqueShape(); return ItemKey::Builder::opaqueShape();
@ -851,15 +853,33 @@ glm::vec3 Avatar::getDefaultJointTranslation(int index) const {
} }
glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const { glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
glm::quat rotation; if (index == SENSOR_TO_WORLD_MATRIX_INDEX) {
_skeletonModel->getAbsoluteJointRotationInRigFrame(index, rotation); glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
return Quaternions::Y_180 * rotation; bool success;
Transform avatarTransform;
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
return glmExtractRotation(invAvatarMat * sensorToWorldMatrix);
} else {
glm::quat rotation;
_skeletonModel->getAbsoluteJointRotationInRigFrame(index, rotation);
return Quaternions::Y_180 * rotation;
}
} }
glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const { glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
glm::vec3 translation; if (index == SENSOR_TO_WORLD_MATRIX_INDEX) {
_skeletonModel->getAbsoluteJointTranslationInRigFrame(index, translation); glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
return Quaternions::Y_180 * translation; bool success;
Transform avatarTransform;
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
return extractTranslation(invAvatarMat * sensorToWorldMatrix);
} else {
glm::vec3 translation;
_skeletonModel->getAbsoluteJointTranslationInRigFrame(index, translation);
return Quaternions::Y_180 * translation;
}
} }
int Avatar::getJointIndex(const QString& name) const { int Avatar::getJointIndex(const QString& name) const {

View file

@ -367,7 +367,7 @@ void AvatarManager::addAvatarToSimulation(Avatar* avatar) {
ShapeInfo shapeInfo; ShapeInfo shapeInfo;
avatar->computeShapeInfo(shapeInfo); avatar->computeShapeInfo(shapeInfo);
btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
if (shape) { if (shape) {
// we don't add to the simulation now, we put it on a list to be added later // we don't add to the simulation now, we put it on a list to be added later
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);

View file

@ -17,7 +17,7 @@
#include "AvatarMotionState.h" #include "AvatarMotionState.h"
#include "BulletUtil.h" #include "BulletUtil.h"
AvatarMotionState::AvatarMotionState(Avatar* avatar, btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { AvatarMotionState::AvatarMotionState(Avatar* avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
assert(_avatar); assert(_avatar);
_type = MOTIONSTATE_TYPE_AVATAR; _type = MOTIONSTATE_TYPE_AVATAR;
if (_shape) { if (_shape) {
@ -47,7 +47,7 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const {
} }
// virtual and protected // virtual and protected
btCollisionShape* AvatarMotionState::computeNewShape() { const btCollisionShape* AvatarMotionState::computeNewShape() {
ShapeInfo shapeInfo; ShapeInfo shapeInfo;
_avatar->computeShapeInfo(shapeInfo); _avatar->computeShapeInfo(shapeInfo);
return getShapeManager()->getShape(shapeInfo); return getShapeManager()->getShape(shapeInfo);

View file

@ -20,7 +20,7 @@ class Avatar;
class AvatarMotionState : public ObjectMotionState { class AvatarMotionState : public ObjectMotionState {
public: public:
AvatarMotionState(Avatar* avatar, btCollisionShape* shape); AvatarMotionState(Avatar* avatar, const btCollisionShape* shape);
virtual PhysicsMotionType getMotionType() const override { return _motionType; } virtual PhysicsMotionType getMotionType() const override { return _motionType; }
@ -72,7 +72,7 @@ protected:
~AvatarMotionState(); ~AvatarMotionState();
virtual bool isReadyToComputeShape() const override { return true; } virtual bool isReadyToComputeShape() const override { return true; }
virtual btCollisionShape* computeNewShape() override; virtual const btCollisionShape* computeNewShape() override;
// The AvatarMotionState keeps a RAW backpointer to its Avatar because all AvatarMotionState // The AvatarMotionState keeps a RAW backpointer to its Avatar because all AvatarMotionState
// instances are "owned" by their corresponding Avatar instance and are deleted in the Avatar dtor. // instances are "owned" by their corresponding Avatar instance and are deleted in the Avatar dtor.

View file

@ -82,12 +82,12 @@ public:
void setDeltaRoll(float roll) { _deltaRoll = roll; } void setDeltaRoll(float roll) { _deltaRoll = roll; }
float getDeltaRoll() const { return _deltaRoll; } float getDeltaRoll() const { return _deltaRoll; }
virtual void setFinalYaw(float finalYaw); virtual void setFinalYaw(float finalYaw) override;
virtual void setFinalPitch(float finalPitch); virtual void setFinalPitch(float finalPitch) override;
virtual void setFinalRoll(float finalRoll); virtual void setFinalRoll(float finalRoll) override;
virtual float getFinalPitch() const; virtual float getFinalPitch() const override;
virtual float getFinalYaw() const; virtual float getFinalYaw() const override;
virtual float getFinalRoll() const; virtual float getFinalRoll() const override;
void relax(float deltaTime); void relax(float deltaTime);

View file

@ -107,7 +107,6 @@ MyAvatar::MyAvatar(RigPointer rig) :
_hmdSensorOrientation(), _hmdSensorOrientation(),
_hmdSensorPosition(), _hmdSensorPosition(),
_bodySensorMatrix(), _bodySensorMatrix(),
_sensorToWorldMatrix(),
_goToPending(false), _goToPending(false),
_goToPosition(), _goToPosition(),
_goToOrientation(), _goToOrientation(),
@ -511,10 +510,8 @@ void MyAvatar::simulate(float deltaTime) {
updateAvatarEntities(); updateAvatarEntities();
} }
// thread-safe // As far as I know no HMD system supports a play area of a kilometer in radius.
glm::mat4 MyAvatar::getSensorToWorldMatrix() const { static const float MAX_HMD_ORIGIN_DISTANCE = 1000.0f;
return _sensorToWorldMatrixCache.get();
}
// Pass a recent sample of the HMD to the avatar. // Pass a recent sample of the HMD to the avatar.
// This can also update the avatar's position to follow the HMD // This can also update the avatar's position to follow the HMD
@ -522,7 +519,15 @@ glm::mat4 MyAvatar::getSensorToWorldMatrix() const {
void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
// update the sensorMatrices based on the new hmd pose // update the sensorMatrices based on the new hmd pose
_hmdSensorMatrix = hmdSensorMatrix; _hmdSensorMatrix = hmdSensorMatrix;
_hmdSensorPosition = extractTranslation(hmdSensorMatrix); auto newHmdSensorPosition = extractTranslation(hmdSensorMatrix);
if (newHmdSensorPosition != _hmdSensorPosition &&
glm::length(newHmdSensorPosition) > MAX_HMD_ORIGIN_DISTANCE) {
qWarning() << "Invalid HMD sensor position " << newHmdSensorPosition;
// Ignore unreasonable HMD sensor data
return;
}
_hmdSensorPosition = newHmdSensorPosition;
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix); _hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
_hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation); _hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation);
} }

View file

@ -79,8 +79,6 @@ class MyAvatar : public Avatar {
Q_PROPERTY(controller::Pose leftHandTipPose READ getLeftHandTipPose) Q_PROPERTY(controller::Pose leftHandTipPose READ getLeftHandTipPose)
Q_PROPERTY(controller::Pose rightHandTipPose READ getRightHandTipPose) Q_PROPERTY(controller::Pose rightHandTipPose READ getRightHandTipPose)
Q_PROPERTY(glm::mat4 sensorToWorldMatrix READ getSensorToWorldMatrix)
Q_PROPERTY(float energy READ getEnergy WRITE setEnergy) Q_PROPERTY(float energy READ getEnergy WRITE setEnergy)
Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled) Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled)
@ -110,9 +108,6 @@ public:
const glm::quat& getHMDSensorOrientation() const { return _hmdSensorOrientation; } const glm::quat& getHMDSensorOrientation() const { return _hmdSensorOrientation; }
const glm::vec2& getHMDSensorFacingMovingAverage() const { return _hmdSensorFacingMovingAverage; } const glm::vec2& getHMDSensorFacingMovingAverage() const { return _hmdSensorFacingMovingAverage; }
// thread safe
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
Q_INVOKABLE void setOrientationVar(const QVariant& newOrientationVar); Q_INVOKABLE void setOrientationVar(const QVariant& newOrientationVar);
Q_INVOKABLE QVariant getOrientationVar() const; Q_INVOKABLE QVariant getOrientationVar() const;
@ -415,6 +410,10 @@ private:
bool _useSnapTurn { true }; bool _useSnapTurn { true };
bool _clearOverlayWhenMoving { true }; bool _clearOverlayWhenMoving { true };
// working copy of sensorToWorldMatrix.
// See AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
glm::mat4 _sensorToWorldMatrix;
// cache of the current HMD sensor position and orientation // cache of the current HMD sensor position and orientation
// in sensor space. // in sensor space.
glm::mat4 _hmdSensorMatrix; glm::mat4 _hmdSensorMatrix;
@ -427,10 +426,6 @@ private:
// in sensor space. // in sensor space.
glm::mat4 _bodySensorMatrix; glm::mat4 _bodySensorMatrix;
// used to transform any sensor into world space, including the _hmdSensorMat, or hand controllers.
glm::mat4 _sensorToWorldMatrix;
ThreadSafeValueCache<glm::mat4> _sensorToWorldMatrixCache { glm::mat4() };
struct FollowHelper { struct FollowHelper {
FollowHelper(); FollowHelper();

View file

@ -27,26 +27,26 @@
class DdeFaceTracker : public FaceTracker, public Dependency { class DdeFaceTracker : public FaceTracker, public Dependency {
Q_OBJECT Q_OBJECT
SINGLETON_DEPENDENCY SINGLETON_DEPENDENCY
public:
virtual void init();
virtual void reset();
virtual void update(float deltaTime);
virtual bool isActive() const; public:
virtual bool isTracking() const; virtual void init() override;
virtual void reset() override;
virtual void update(float deltaTime) override;
virtual bool isActive() const override;
virtual bool isTracking() const override;
float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); } float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); }
float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); } float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); }
float getLeftEyeOpen() const { return getBlendshapeCoefficient(_leftEyeOpenIndex); } float getLeftEyeOpen() const { return getBlendshapeCoefficient(_leftEyeOpenIndex); }
float getRightEyeOpen() const { return getBlendshapeCoefficient(_rightEyeOpenIndex); } float getRightEyeOpen() const { return getBlendshapeCoefficient(_rightEyeOpenIndex); }
float getBrowDownLeft() const { return getBlendshapeCoefficient(_browDownLeftIndex); } float getBrowDownLeft() const { return getBlendshapeCoefficient(_browDownLeftIndex); }
float getBrowDownRight() const { return getBlendshapeCoefficient(_browDownRightIndex); } float getBrowDownRight() const { return getBlendshapeCoefficient(_browDownRightIndex); }
float getBrowUpCenter() const { return getBlendshapeCoefficient(_browUpCenterIndex); } float getBrowUpCenter() const { return getBlendshapeCoefficient(_browUpCenterIndex); }
float getBrowUpLeft() const { return getBlendshapeCoefficient(_browUpLeftIndex); } float getBrowUpLeft() const { return getBlendshapeCoefficient(_browUpLeftIndex); }
float getBrowUpRight() const { return getBlendshapeCoefficient(_browUpRightIndex); } float getBrowUpRight() const { return getBlendshapeCoefficient(_browUpRightIndex); }
float getMouthSize() const { return getBlendshapeCoefficient(_jawOpenIndex); } float getMouthSize() const { return getBlendshapeCoefficient(_jawOpenIndex); }
float getMouthSmileLeft() const { return getBlendshapeCoefficient(_mouthSmileLeftIndex); } float getMouthSmileLeft() const { return getBlendshapeCoefficient(_mouthSmileLeftIndex); }
float getMouthSmileRight() const { return getBlendshapeCoefficient(_mouthSmileRightIndex); } float getMouthSmileRight() const { return getBlendshapeCoefficient(_mouthSmileRightIndex); }
@ -55,7 +55,7 @@ public:
void setEyeClosingThreshold(float eyeClosingThreshold); void setEyeClosingThreshold(float eyeClosingThreshold);
public slots: public slots:
void setEnabled(bool enabled); void setEnabled(bool enabled) override;
void calibrate(); void calibrate();
private slots: private slots:
@ -77,18 +77,18 @@ private:
QHostAddress _host; QHostAddress _host;
quint16 _serverPort; quint16 _serverPort;
quint16 _controlPort; quint16 _controlPort;
float getBlendshapeCoefficient(int index) const; float getBlendshapeCoefficient(int index) const;
void decodePacket(const QByteArray& buffer); void decodePacket(const QByteArray& buffer);
// sockets // sockets
QUdpSocket _udpSocket; QUdpSocket _udpSocket;
quint64 _lastReceiveTimestamp; quint64 _lastReceiveTimestamp;
bool _reset; bool _reset;
glm::vec3 _referenceTranslation; glm::vec3 _referenceTranslation;
glm::quat _referenceRotation; glm::quat _referenceRotation;
int _leftBlinkIndex; int _leftBlinkIndex;
int _rightBlinkIndex; int _rightBlinkIndex;
int _leftEyeDownIndex; int _leftEyeDownIndex;
@ -103,10 +103,10 @@ private:
int _browUpCenterIndex; int _browUpCenterIndex;
int _browUpLeftIndex; int _browUpLeftIndex;
int _browUpRightIndex; int _browUpRightIndex;
int _mouthSmileLeftIndex; int _mouthSmileLeftIndex;
int _mouthSmileRightIndex; int _mouthSmileRightIndex;
int _jawOpenIndex; int _jawOpenIndex;
QVector<float> _coefficients; QVector<float> _coefficients;

View file

@ -34,12 +34,12 @@ class Faceshift : public FaceTracker, public Dependency {
public: public:
#ifdef HAVE_FACESHIFT #ifdef HAVE_FACESHIFT
// If we don't have faceshift, use the base class' methods // If we don't have faceshift, use the base class' methods
virtual void init(); virtual void init() override;
virtual void update(float deltaTime); virtual void update(float deltaTime) override;
virtual void reset(); virtual void reset() override;
virtual bool isActive() const; virtual bool isActive() const override;
virtual bool isTracking() const; virtual bool isTracking() const override;
#endif #endif
bool isConnectedOrConnecting() const; bool isConnectedOrConnecting() const;
@ -49,7 +49,7 @@ public:
// these pitch/yaw angles are in degrees // these pitch/yaw angles are in degrees
float getEyeGazeLeftPitch() const { return _eyeGazeLeftPitch; } float getEyeGazeLeftPitch() const { return _eyeGazeLeftPitch; }
float getEyeGazeLeftYaw() const { return _eyeGazeLeftYaw; } float getEyeGazeLeftYaw() const { return _eyeGazeLeftYaw; }
float getEyeGazeRightPitch() const { return _eyeGazeRightPitch; } float getEyeGazeRightPitch() const { return _eyeGazeRightPitch; }
float getEyeGazeRightYaw() const { return _eyeGazeRightYaw; } float getEyeGazeRightYaw() const { return _eyeGazeRightYaw; }
@ -67,10 +67,10 @@ public:
float getMouthSize() const { return getBlendshapeCoefficient(_jawOpenIndex); } float getMouthSize() const { return getBlendshapeCoefficient(_jawOpenIndex); }
float getMouthSmileLeft() const { return getBlendshapeCoefficient(_mouthSmileLeftIndex); } float getMouthSmileLeft() const { return getBlendshapeCoefficient(_mouthSmileLeftIndex); }
float getMouthSmileRight() const { return getBlendshapeCoefficient(_mouthSmileRightIndex); } float getMouthSmileRight() const { return getBlendshapeCoefficient(_mouthSmileRightIndex); }
QString getHostname() { return _hostname.get(); } QString getHostname() { return _hostname.get(); }
void setHostname(const QString& hostname); void setHostname(const QString& hostname);
void updateFakeCoefficients(float leftBlink, void updateFakeCoefficients(float leftBlink,
float rightBlink, float rightBlink,
float browUp, float browUp,
@ -79,76 +79,76 @@ public:
float mouth3, float mouth3,
float mouth4, float mouth4,
QVector<float>& coefficients) const; QVector<float>& coefficients) const;
signals: signals:
void connectionStateChanged(); void connectionStateChanged();
public slots: public slots:
void setEnabled(bool enabled); void setEnabled(bool enabled) override;
private slots: private slots:
void connectSocket(); void connectSocket();
void noteConnected(); void noteConnected();
void noteError(QAbstractSocket::SocketError error); void noteError(QAbstractSocket::SocketError error);
void readPendingDatagrams(); void readPendingDatagrams();
void readFromSocket(); void readFromSocket();
void noteDisconnected(); void noteDisconnected();
private: private:
Faceshift(); Faceshift();
virtual ~Faceshift() {} virtual ~Faceshift() {}
void send(const std::string& message); void send(const std::string& message);
void receive(const QByteArray& buffer); void receive(const QByteArray& buffer);
QTcpSocket _tcpSocket; QTcpSocket _tcpSocket;
QUdpSocket _udpSocket; QUdpSocket _udpSocket;
#ifdef HAVE_FACESHIFT #ifdef HAVE_FACESHIFT
fs::fsBinaryStream _stream; fs::fsBinaryStream _stream;
#endif #endif
bool _tcpEnabled = true; bool _tcpEnabled = true;
int _tcpRetryCount = 0; int _tcpRetryCount = 0;
bool _tracking = false; bool _tracking = false;
quint64 _lastReceiveTimestamp = 0; quint64 _lastReceiveTimestamp = 0;
quint64 _lastMessageReceived = 0; quint64 _lastMessageReceived = 0;
float _averageFrameTime = STARTING_FACESHIFT_FRAME_TIME; float _averageFrameTime = STARTING_FACESHIFT_FRAME_TIME;
glm::vec3 _headAngularVelocity = glm::vec3(0.0f); glm::vec3 _headAngularVelocity = glm::vec3(0.0f);
glm::vec3 _headLinearVelocity = glm::vec3(0.0f); glm::vec3 _headLinearVelocity = glm::vec3(0.0f);
glm::vec3 _lastHeadTranslation = glm::vec3(0.0f); glm::vec3 _lastHeadTranslation = glm::vec3(0.0f);
glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f); glm::vec3 _filteredHeadTranslation = glm::vec3(0.0f);
// degrees // degrees
float _eyeGazeLeftPitch = 0.0f; float _eyeGazeLeftPitch = 0.0f;
float _eyeGazeLeftYaw = 0.0f; float _eyeGazeLeftYaw = 0.0f;
float _eyeGazeRightPitch = 0.0f; float _eyeGazeRightPitch = 0.0f;
float _eyeGazeRightYaw = 0.0f; float _eyeGazeRightYaw = 0.0f;
// degrees // degrees
float _longTermAverageEyePitch = 0.0f; float _longTermAverageEyePitch = 0.0f;
float _longTermAverageEyeYaw = 0.0f; float _longTermAverageEyeYaw = 0.0f;
bool _longTermAverageInitialized = false; bool _longTermAverageInitialized = false;
Setting::Handle<QString> _hostname; Setting::Handle<QString> _hostname;
// see http://support.faceshift.com/support/articles/35129-export-of-blendshapes // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
int _leftBlinkIndex = 0; int _leftBlinkIndex = 0;
int _rightBlinkIndex = 1; int _rightBlinkIndex = 1;
int _leftEyeOpenIndex = 8; int _leftEyeOpenIndex = 8;
int _rightEyeOpenIndex = 9; int _rightEyeOpenIndex = 9;
// Brows // Brows
int _browDownLeftIndex = 14; int _browDownLeftIndex = 14;
int _browDownRightIndex = 15; int _browDownRightIndex = 15;
int _browUpCenterIndex = 16; int _browUpCenterIndex = 16;
int _browUpLeftIndex = 17; int _browUpLeftIndex = 17;
int _browUpRightIndex = 18; int _browUpRightIndex = 18;
int _mouthSmileLeftIndex = 28; int _mouthSmileLeftIndex = 28;
int _mouthSmileRightIndex = 29; int _mouthSmileRightIndex = 29;
int _jawOpenIndex = 21; int _jawOpenIndex = 21;
}; };

View file

@ -33,7 +33,7 @@ public:
bool isActive() const { return _active; } bool isActive() const { return _active; }
virtual void update(); virtual void update() override;
protected: protected:
Leapmotion(); Leapmotion();

View file

@ -26,6 +26,11 @@ bool AccountScriptingInterface::isLoggedIn() {
return accountManager->isLoggedIn(); return accountManager->isLoggedIn();
} }
bool AccountScriptingInterface::checkAndSignalForAccessToken() {
auto accountManager = DependencyManager::get<AccountManager>();
return accountManager->checkAndSignalForAccessToken();
}
QString AccountScriptingInterface::getUsername() { QString AccountScriptingInterface::getUsername() {
auto accountManager = DependencyManager::get<AccountManager>(); auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->isLoggedIn()) { if (accountManager->isLoggedIn()) {

View file

@ -26,6 +26,7 @@ public slots:
static AccountScriptingInterface* getInstance(); static AccountScriptingInterface* getInstance();
QString getUsername(); QString getUsername();
bool isLoggedIn(); bool isLoggedIn();
bool checkAndSignalForAccessToken();
}; };
#endif // hifi_AccountScriptingInterface_h #endif // hifi_AccountScriptingInterface_h

View file

@ -33,16 +33,16 @@ class InputController : public controller::InputController {
public: public:
InputController(int deviceTrackerId, int subTrackerId, QObject* parent = NULL); InputController(int deviceTrackerId, int subTrackerId, QObject* parent = NULL);
virtual void update(); virtual void update() override;
virtual Key getKey() const; virtual Key getKey() const override;
public slots: public slots:
virtual bool isActive() const { return _isActive; } virtual bool isActive() const override { return _isActive; }
virtual glm::vec3 getAbsTranslation() const { return _eventCache.absTranslation; } virtual glm::vec3 getAbsTranslation() const override { return _eventCache.absTranslation; }
virtual glm::quat getAbsRotation() const { return _eventCache.absRotation; } virtual glm::quat getAbsRotation() const override { return _eventCache.absRotation; }
virtual glm::vec3 getLocTranslation() const { return _eventCache.locTranslation; } virtual glm::vec3 getLocTranslation() const override { return _eventCache.locTranslation; }
virtual glm::quat getLocRotation() const { return _eventCache.locRotation; } virtual glm::quat getLocRotation() const override { return _eventCache.locRotation; }
private: private:

View file

@ -17,6 +17,8 @@
#include "Application.h" #include "Application.h"
#include "MainWindow.h" #include "MainWindow.h"
#include <display-plugins/CompositorHelper.h> #include <display-plugins/CompositorHelper.h>
#include <DependencyManager.h>
#include <OffscreenUi.h>
int DesktopScriptingInterface::getWidth() { int DesktopScriptingInterface::getWidth() {
QSize size = qApp->getWindow()->windowHandle()->screen()->virtualSize(); QSize size = qApp->getWindow()->windowHandle()->screen()->virtualSize();
@ -31,3 +33,11 @@ void DesktopScriptingInterface::setOverlayAlpha(float alpha) {
qApp->getApplicationCompositor().setAlpha(alpha); qApp->getApplicationCompositor().setAlpha(alpha);
} }
void DesktopScriptingInterface::show(const QString& path, const QString& title) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "show", Qt::QueuedConnection, Q_ARG(QString, path), Q_ARG(QString, title));
return;
}
DependencyManager::get<OffscreenUi>()->show(path, title);
}

View file

@ -23,6 +23,7 @@ class DesktopScriptingInterface : public QObject, public Dependency {
public: public:
Q_INVOKABLE void setOverlayAlpha(float alpha); Q_INVOKABLE void setOverlayAlpha(float alpha);
Q_INVOKABLE void show(const QString& path, const QString& title);
int getWidth(); int getWidth();
int getHeight(); int getHeight();

View file

@ -26,3 +26,8 @@ void DialogsManagerScriptingInterface::toggleAddressBar() {
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(), QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
"toggleAddressBar", Qt::QueuedConnection); "toggleAddressBar", Qt::QueuedConnection);
} }
void DialogsManagerScriptingInterface::showFeed() {
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
"showFeed", Qt::QueuedConnection);
}

View file

@ -18,6 +18,7 @@ class DialogsManagerScriptingInterface : public QObject {
Q_OBJECT Q_OBJECT
public: public:
DialogsManagerScriptingInterface(); DialogsManagerScriptingInterface();
Q_INVOKABLE void showFeed();
public slots: public slots:
void toggleAddressBar(); void toggleAddressBar();

View file

@ -66,7 +66,7 @@ signals:
void closed(); void closed();
protected: protected:
virtual bool eventFilter(QObject* sender, QEvent* event); virtual bool eventFilter(QObject* sender, QEvent* event) override;
private slots: private slots:
void hasClosed(); void hasClosed();

View file

@ -96,7 +96,7 @@ void WindowScriptingInterface::alert(const QString& message) {
/// \param const QString& message message to display /// \param const QString& message message to display
/// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise /// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise
QScriptValue WindowScriptingInterface::confirm(const QString& message) { QScriptValue WindowScriptingInterface::confirm(const QString& message) {
return QScriptValue((QMessageBox::Yes == OffscreenUi::question("", message))); return QScriptValue((QMessageBox::Yes == OffscreenUi::question("", message, QMessageBox::Yes | QMessageBox::No)));
} }
/// Display a prompt with a text box /// Display a prompt with a text box
@ -203,3 +203,11 @@ void WindowScriptingInterface::copyToClipboard(const QString& text) {
qDebug() << "Copying"; qDebug() << "Copying";
QApplication::clipboard()->setText(text); QApplication::clipboard()->setText(text);
} }
void WindowScriptingInterface::takeSnapshot(bool notify, float aspectRatio) {
qApp->takeSnapshot(notify, aspectRatio);
}
void WindowScriptingInterface::shareSnapshot(const QString& path) {
qApp->shareSnapshot(path);
}

View file

@ -55,12 +55,15 @@ public slots:
QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
void showAssetServer(const QString& upload = ""); void showAssetServer(const QString& upload = "");
void copyToClipboard(const QString& text); void copyToClipboard(const QString& text);
void takeSnapshot(bool notify = true, float aspectRatio = 0.0f);
void shareSnapshot(const QString& path);
signals: signals:
void domainChanged(const QString& domainHostname); void domainChanged(const QString& domainHostname);
void svoImportRequested(const QString& url); void svoImportRequested(const QString& url);
void domainConnectionRefused(const QString& reasonMessage, int reasonCode); void domainConnectionRefused(const QString& reasonMessage, int reasonCode);
void snapshotTaken(const QString& path); void snapshotTaken(const QString& path, bool notify);
void snapshotShared(const QString& error);
private slots: private slots:
WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height); WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height);

View file

@ -38,6 +38,8 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare
}); });
_backEnabled = !(DependencyManager::get<AddressManager>()->getBackStack().isEmpty()); _backEnabled = !(DependencyManager::get<AddressManager>()->getBackStack().isEmpty());
_forwardEnabled = !(DependencyManager::get<AddressManager>()->getForwardStack().isEmpty()); _forwardEnabled = !(DependencyManager::get<AddressManager>()->getForwardStack().isEmpty());
connect(DependencyManager::get<DialogsManager>().data(), &DialogsManager::setUseFeed, this, &AddressBarDialog::setUseFeed);
connect(qApp, &Application::receivedHifiSchemeURL, this, &AddressBarDialog::receivedHifiSchemeURL);
} }
void AddressBarDialog::loadAddress(const QString& address, bool fromSuggestions) { void AddressBarDialog::loadAddress(const QString& address, bool fromSuggestions) {

View file

@ -14,21 +14,30 @@
#define hifi_AddressBarDialog_h #define hifi_AddressBarDialog_h
#include <OffscreenQmlDialog.h> #include <OffscreenQmlDialog.h>
#include <NetworkingConstants.h>
class AddressBarDialog : public OffscreenQmlDialog { class AddressBarDialog : public OffscreenQmlDialog {
Q_OBJECT Q_OBJECT
HIFI_QML_DECL HIFI_QML_DECL
Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged) Q_PROPERTY(bool backEnabled READ backEnabled NOTIFY backEnabledChanged)
Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged) Q_PROPERTY(bool forwardEnabled READ forwardEnabled NOTIFY forwardEnabledChanged)
Q_PROPERTY(bool useFeed READ useFeed WRITE setUseFeed NOTIFY useFeedChanged)
Q_PROPERTY(QString metaverseServerUrl READ metaverseServerUrl NOTIFY metaverseServerUrlChanged)
public: public:
AddressBarDialog(QQuickItem* parent = nullptr); AddressBarDialog(QQuickItem* parent = nullptr);
bool backEnabled() { return _backEnabled; } bool backEnabled() { return _backEnabled; }
bool forwardEnabled() { return _forwardEnabled; } bool forwardEnabled() { return _forwardEnabled; }
bool useFeed() { return _useFeed; }
void setUseFeed(bool useFeed) { if (_useFeed != useFeed) { _useFeed = useFeed; emit useFeedChanged(); } }
QString metaverseServerUrl() { return NetworkingConstants::METAVERSE_SERVER_URL.toString(); }
signals: signals:
void backEnabledChanged(); void backEnabledChanged();
void forwardEnabledChanged(); void forwardEnabledChanged();
void useFeedChanged();
void receivedHifiSchemeURL(const QString& url);
void metaverseServerUrlChanged(); // While it is a constant, qml will complain about not seeing a change signal.
protected: protected:
void displayAddressOfflineMessage(); void displayAddressOfflineMessage();
@ -42,6 +51,7 @@ protected:
bool _backEnabled; bool _backEnabled;
bool _forwardEnabled; bool _forwardEnabled;
bool _useFeed { false };
}; };
#endif #endif

View file

@ -36,13 +36,13 @@ public:
AudioStatsDisplay(QFormLayout* form, QString text, unsigned colorRGBA); AudioStatsDisplay(QFormLayout* form, QString text, unsigned colorRGBA);
void updatedDisplay(QString str); void updatedDisplay(QString str);
void paint(); void paint();
private: private:
QString _strBuf; QString _strBuf;
QLabel* _label; QLabel* _label;
QString _text; QString _text;
unsigned _colorRGBA; unsigned _colorRGBA;
}; };
//dialog //dialog
@ -51,9 +51,9 @@ class AudioStatsDialog : public QDialog {
public: public:
AudioStatsDialog(QWidget* parent); AudioStatsDialog(QWidget* parent);
~AudioStatsDialog(); ~AudioStatsDialog();
void paintEvent(QPaintEvent*); void paintEvent(QPaintEvent*) override;
private: private:
// audio stats methods for rendering // audio stats methods for rendering
QVector<QString> _audioMixerStats; QVector<QString> _audioMixerStats;
@ -61,48 +61,47 @@ private:
QVector<QString> _upstreamMixerStats; QVector<QString> _upstreamMixerStats;
QVector<QString> _downstreamStats; QVector<QString> _downstreamStats;
QVector<QString> _upstreamInjectedStats; QVector<QString> _upstreamInjectedStats;
int _audioMixerID; int _audioMixerID;
int _upstreamClientID; int _upstreamClientID;
int _upstreamMixerID; int _upstreamMixerID;
int _downstreamID; int _downstreamID;
int _upstreamInjectedID; int _upstreamInjectedID;
QVector<QVector<AudioStatsDisplay*>> _audioDisplayChannels; QVector<QVector<AudioStatsDisplay*>> _audioDisplayChannels;
int addChannel(QFormLayout* form, QVector<QString>& stats, const unsigned color); int addChannel(QFormLayout* form, QVector<QString>& stats, const unsigned color);
void updateStats(QVector<QString>& stats, const int channelID); void updateStats(QVector<QString>& stats, const int channelID);
void renderStats(); void renderStats();
void clearAllChannels(); void clearAllChannels();
void renderAudioStreamStats(const AudioStreamStats* streamStats, QVector<QString>* audioStreamstats, bool isDownstreamStats); void renderAudioStreamStats(const AudioStreamStats* streamStats, QVector<QString>* audioStreamstats, bool isDownstreamStats);
const AudioIOStats* _stats; const AudioIOStats* _stats;
QFormLayout* _form; QFormLayout* _form;
bool _isEnabled; bool _isEnabled;
bool _shouldShowInjectedStreams; bool _shouldShowInjectedStreams;
signals: signals:
void closed(); void closed();
public slots: public slots:
void reject(); void reject() override;
void updateTimerTimeout(); void updateTimerTimeout();
protected: protected:
// Emits a 'closed' signal when this dialog is closed. // Emits a 'closed' signal when this dialog is closed.
void closeEvent(QCloseEvent*); void closeEvent(QCloseEvent*) override;
private: private:
QTimer* averageUpdateTimer = new QTimer(this); QTimer* averageUpdateTimer = new QTimer(this);
}; };

View file

@ -57,7 +57,7 @@ public:
BandwidthDialog(QWidget* parent); BandwidthDialog(QWidget* parent);
~BandwidthDialog(); ~BandwidthDialog();
void paintEvent(QPaintEvent*); void paintEvent(QPaintEvent*) override;
private: private:
BandwidthChannelDisplay* _audioChannelDisplay; BandwidthChannelDisplay* _audioChannelDisplay;
@ -77,14 +77,14 @@ signals:
public slots: public slots:
void reject(); void reject() override;
void updateTimerTimeout(); void updateTimerTimeout();
protected: protected:
// Emits a 'closed' signal when this dialog is closed. // Emits a 'closed' signal when this dialog is closed.
void closeEvent(QCloseEvent*); void closeEvent(QCloseEvent*) override;
private: private:
QTimer* averageUpdateTimer = new QTimer(this); QTimer* averageUpdateTimer = new QTimer(this);

View file

@ -21,19 +21,19 @@ class CachesSizeDialog : public QDialog {
public: public:
// Sets up the UI // Sets up the UI
CachesSizeDialog(QWidget* parent); CachesSizeDialog(QWidget* parent);
signals: signals:
void closed(); void closed();
public slots: public slots:
void reject(); void reject() override;
void confirmClicked(bool checked); void confirmClicked(bool checked);
void resetClicked(bool checked); void resetClicked(bool checked);
protected: protected:
// Emits a 'closed' signal when this dialog is closed. // Emits a 'closed' signal when this dialog is closed.
void closeEvent(QCloseEvent* event); void closeEvent(QCloseEvent* event) override;
private: private:
QDoubleSpinBox* _animations = nullptr; QDoubleSpinBox* _animations = nullptr;
QDoubleSpinBox* _geometries = nullptr; QDoubleSpinBox* _geometries = nullptr;
@ -42,4 +42,4 @@ private:
QDoubleSpinBox* _textures = nullptr; QDoubleSpinBox* _textures = nullptr;
}; };
#endif // hifi_CachesSizeDialog_h #endif // hifi_CachesSizeDialog_h

View file

@ -18,9 +18,9 @@ class DataWebPage : public QWebPage {
public: public:
DataWebPage(QObject* parent = 0); DataWebPage(QObject* parent = 0);
protected: protected:
void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID); void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID) override;
bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type); bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) override;
virtual QString userAgentForUrl(const QUrl& url) const; virtual QString userAgentForUrl(const QUrl& url) const override;
}; };
#endif // hifi_DataWebPage_h #endif // hifi_DataWebPage_h

View file

@ -54,6 +54,11 @@ void DialogsManager::showAddressBar() {
AddressBarDialog::show(); AddressBarDialog::show();
} }
void DialogsManager::showFeed() {
AddressBarDialog::show();
emit setUseFeed(true);
}
void DialogsManager::toggleDiskCacheEditor() { void DialogsManager::toggleDiskCacheEditor() {
maybeCreateDialog(_diskCacheEditor); maybeCreateDialog(_diskCacheEditor);
_diskCacheEditor->toggle(); _diskCacheEditor->toggle();

View file

@ -45,6 +45,7 @@ public:
public slots: public slots:
void toggleAddressBar(); void toggleAddressBar();
void showAddressBar(); void showAddressBar();
void showFeed();
void toggleDiskCacheEditor(); void toggleDiskCacheEditor();
void toggleLoginDialog(); void toggleLoginDialog();
void showLoginDialog(); void showLoginDialog();
@ -63,6 +64,7 @@ public slots:
signals: signals:
void addressBarToggled(); void addressBarToggled();
void addressBarShown(bool visible); void addressBarShown(bool visible);
void setUseFeed(bool useFeed);
private slots: private slots:
void hmdToolsClosed(); void hmdToolsClosed();

View file

@ -29,18 +29,18 @@ public:
QScreen* getLastApplicationScreen() const { return _previousScreen; } QScreen* getLastApplicationScreen() const { return _previousScreen; }
bool hasHMDScreen() const { return _hmdScreenNumber >= -1; } bool hasHMDScreen() const { return _hmdScreenNumber >= -1; }
void watchWindow(QWindow* window); void watchWindow(QWindow* window);
signals: signals:
void closed(); void closed();
public slots: public slots:
void reject(); void reject() override;
void screenCountChanged(int newCount); void screenCountChanged(int newCount);
protected: protected:
virtual void closeEvent(QCloseEvent*); // Emits a 'closed' signal when this dialog is closed. virtual void closeEvent(QCloseEvent*) override; // Emits a 'closed' signal when this dialog is closed.
virtual void showEvent(QShowEvent* event); virtual void showEvent(QShowEvent* event) override;
virtual void hideEvent(QHideEvent* event); virtual void hideEvent(QHideEvent* event) override;
private: private:
void centerCursorOnWidget(QWidget* widget); void centerCursorOnWidget(QWidget* widget);
@ -59,7 +59,7 @@ private:
QScreen* _previousDialogScreen{ nullptr }; QScreen* _previousDialogScreen{ nullptr };
QString _hmdPluginName; QString _hmdPluginName;
QString _defaultPluginName; QString _defaultPluginName;
QHash<QWindow*, HMDWindowWatcher*> _windowWatchers; QHash<QWindow*, HMDWindowWatcher*> _windowWatchers;
friend class HMDWindowWatcher; friend class HMDWindowWatcher;
}; };
@ -75,7 +75,7 @@ public:
public slots: public slots:
void windowScreenChanged(QScreen* screen); void windowScreenChanged(QScreen* screen);
void windowGeometryChanged(int arg); void windowGeometryChanged(int arg);
private: private:
QWindow* _window; QWindow* _window;
HMDToolsDialog* _hmdTools; HMDToolsDialog* _hmdTools;

View file

@ -40,9 +40,9 @@ public slots:
protected: protected:
void setAndSelectCommand(const QString& command); void setAndSelectCommand(const QString& command);
virtual bool eventFilter(QObject* sender, QEvent* event); virtual bool eventFilter(QObject* sender, QEvent* event) override;
virtual void mouseReleaseEvent(QMouseEvent* event); virtual void mouseReleaseEvent(QMouseEvent* event) override;
virtual void showEvent(QShowEvent* event); virtual void showEvent(QShowEvent* event) override;
protected slots: protected slots:
void scrollToBottom(); void scrollToBottom();

View file

@ -24,12 +24,12 @@ class LodToolsDialog : public QDialog {
public: public:
// Sets up the UI // Sets up the UI
LodToolsDialog(QWidget* parent); LodToolsDialog(QWidget* parent);
signals: signals:
void closed(); void closed();
public slots: public slots:
void reject(); void reject() override;
void sizeScaleValueChanged(int value); void sizeScaleValueChanged(int value);
void resetClicked(bool checked); void resetClicked(bool checked);
void reloadSliders(); void reloadSliders();
@ -38,7 +38,7 @@ public slots:
protected: protected:
// Emits a 'closed' signal when this dialog is closed. // Emits a 'closed' signal when this dialog is closed.
void closeEvent(QCloseEvent* event); void closeEvent(QCloseEvent* event) override;
private: private:
QSlider* _lodSize; QSlider* _lodSize;

View file

@ -30,7 +30,7 @@ public:
QString keyword; QString keyword;
protected: protected:
void highlightBlock(const QString &text); void highlightBlock(const QString &text) override;
private: private:
QTextCharFormat keywordFormat; QTextCharFormat keywordFormat;
@ -54,8 +54,8 @@ private slots:
void handleSearchTextChanged(const QString); void handleSearchTextChanged(const QString);
protected: protected:
void resizeEvent(QResizeEvent*); void resizeEvent(QResizeEvent*) override;
void showEvent(QShowEvent*); void showEvent(QShowEvent*) override;
private: private:
QPushButton* _searchButton; QPushButton* _searchButton;

View file

@ -33,15 +33,15 @@ signals:
void closed(); void closed();
public slots: public slots:
void reject(); void reject() override;
void moreless(const QString& link); void moreless(const QString& link);
protected: protected:
// State <- data model held by BandwidthMeter // State <- data model held by BandwidthMeter
void paintEvent(QPaintEvent*); void paintEvent(QPaintEvent*) override;
// Emits a 'closed' signal when this dialog is closed. // Emits a 'closed' signal when this dialog is closed.
void closeEvent(QCloseEvent*); void closeEvent(QCloseEvent*) override;
int AddStatItem(const char* caption, unsigned colorRGBA = DEFAULT_COLOR); int AddStatItem(const char* caption, unsigned colorRGBA = DEFAULT_COLOR);
void RemoveStatItem(int item); void RemoveStatItem(int item);

View file

@ -24,7 +24,7 @@ public:
int lineNumberAreaWidth(); int lineNumberAreaWidth();
protected: protected:
void resizeEvent(QResizeEvent* event); void resizeEvent(QResizeEvent* event) override;
private slots: private slots:
void updateLineNumberAreaWidth(int blockCount); void updateLineNumberAreaWidth(int blockCount);

View file

@ -35,8 +35,8 @@ signals:
void windowActivated(); void windowActivated();
protected: protected:
void closeEvent(QCloseEvent* event); void closeEvent(QCloseEvent* event) override;
virtual bool event(QEvent* event); virtual bool event(QEvent* event) override;
private: private:
Ui::ScriptEditorWindow* _ScriptEditorWindowUI; Ui::ScriptEditorWindow* _ScriptEditorWindowUI;

View file

@ -20,10 +20,10 @@ class ScriptLineNumberArea : public QWidget {
public: public:
ScriptLineNumberArea(ScriptEditBox* scriptEditBox); ScriptLineNumberArea(ScriptEditBox* scriptEditBox);
QSize sizeHint() const; QSize sizeHint() const override;
protected: protected:
void paintEvent(QPaintEvent* event); void paintEvent(QPaintEvent* event) override;
private: private:
ScriptEditBox* _scriptEditBox; ScriptEditBox* _scriptEditBox;

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