diff --git a/examples/users.js b/examples/users.js index 2bc69d1638..f6406efe60 100644 --- a/examples/users.js +++ b/examples/users.js @@ -44,7 +44,16 @@ var usersWindow = (function () { scrollbarBar2D, scrollbarBackgroundHeight, scrollbarBarHeight, - VISIBILITY_SPACER_2D = 12, // Space between list of users and visibility controls + FRIENDS_BUTTON_SPACER_2D = 12, // Space before add/remove friends button + FRIENDS_BUTTON_SVG = HIFI_PUBLIC_BUCKET + "images/tools/add-remove-friends.svg", + FRIENDS_BUTTON_SVG_WIDTH = 107, + FRIENDS_BUTTON_SVG_HEIGHT = 27, + FRIENDS_BUTTON_WIDTH_2D = FRIENDS_BUTTON_SVG_WIDTH, + FRIENDS_BUTTON_HEIGHT_2D = FRIENDS_BUTTON_SVG_HEIGHT, + FRIENDS_BUTTON_COLOR_2D = { red: 255, green: 255, blue: 255 }, + FRIENDS_BUTTON_ALPHA_2D = 0.9, + friendsButton2D, + VISIBILITY_SPACER_2D = 12, // Space between before visibility controls visibilityHeading2D, VISIBILITY_RADIO_SPACE = 16, visibilityControls2D, @@ -68,8 +77,6 @@ var usersWindow = (function () { myVisibility, VISIBILITY_VALUES = ["all", "friends", "none"], - visibilityInterval, - VISIBILITY_POLL_INTERVAL = 5000, // ms = 5s MENU_NAME = "Tools", MENU_ITEM = "Users Online", @@ -107,11 +114,12 @@ var usersWindow = (function () { // Reserve 5 lines for window heading plus visibility heading and controls // Subtract windowLineSpacing for both end of user list and end of controls - nonUsersHeight = 5 * windowLineHeight - 2 * windowLineSpacing + VISIBILITY_SPACER_2D + WINDOW_MARGIN_2D - + WINDOW_BASE_MARGIN_2D; + nonUsersHeight = 5 * windowLineHeight - 2 * windowLineSpacing + + FRIENDS_BUTTON_SPACER_2D + FRIENDS_BUTTON_HEIGHT_2D + + VISIBILITY_SPACER_2D + WINDOW_MARGIN_2D + WINDOW_BASE_MARGIN_2D; // Limit window to height of viewport minus VU meter and mirror if displayed - windowHeight = linesOfUsers.length * windowLineHeight + nonUsersHeight; + windowHeight = linesOfUsers.length * windowLineHeight - windowLineSpacing + nonUsersHeight; // DJRTODO: - windowLineSpacing or not? maxWindowHeight = viewportHeight - AUDIO_METER_HEIGHT; if (isMirrorDisplay && !isFullscreenMirror) { maxWindowHeight -= MIRROR_HEIGHT; @@ -119,7 +127,7 @@ var usersWindow = (function () { windowHeight = Math.max(Math.min(windowHeight, maxWindowHeight), nonUsersHeight); // Corresponding number of users to actually display - numUsersToDisplay = Math.max(Math.floor((windowHeight - nonUsersHeight) / windowLineHeight), 0); + numUsersToDisplay = Math.max(Math.round((windowHeight - nonUsersHeight) / windowLineHeight), 0); // DJRTODO: .floor or .round? isUsingScrollbars = 0 < numUsersToDisplay && numUsersToDisplay < linesOfUsers.length; if (isUsingScrollbars) { firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay)); @@ -153,6 +161,12 @@ var usersWindow = (function () { Overlays.editOverlay(scrollbarBar2D, { y: scrollbarBarPosition.y }); + + Overlays.editOverlay(friendsButton2D, { + y: viewportHeight - FRIENDS_BUTTON_HEIGHT_2D - VISIBILITY_SPACER_2D + - 4 * windowLineHeight + windowLineSpacing - WINDOW_BASE_MARGIN_2D + }); + Overlays.editOverlay(visibilityHeading2D, { y: viewportHeight - 4 * windowLineHeight + windowLineSpacing - WINDOW_BASE_MARGIN_2D }); @@ -302,15 +316,6 @@ var usersWindow = (function () { usersTimer = Script.setTimeout(pollUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay. }; - function pollVisibility() { - var currentVisibility = myVisibility; - - myVisibility = GlobalServices.findableBy; - if (myVisibility !== currentVisibility) { - updateVisibilityControls(); - } - } - function updateOverlayVisibility() { var i; @@ -319,6 +324,7 @@ var usersWindow = (function () { Overlays.editOverlay(minimizeButton2D, { visible: isVisible }); Overlays.editOverlay(scrollbarBackground2D, { visible: isVisible && isUsingScrollbars && !isMinimized }); Overlays.editOverlay(scrollbarBar2D, { visible: isVisible && isUsingScrollbars && !isMinimized }); + Overlays.editOverlay(friendsButton2D, { visible: isVisible && !isMinimized }); Overlays.editOverlay(visibilityHeading2D, { visible: isVisible && !isMinimized }); for (i = 0; i < visibilityControls2D.length; i += 1) { Overlays.editOverlay(visibilityControls2D[i].radioOverlay, { visible: isVisible && !isMinimized }); @@ -339,6 +345,7 @@ var usersWindow = (function () { } updateOverlayVisibility(); + } function setMinimized(minimized) { @@ -355,6 +362,16 @@ var usersWindow = (function () { } } + function onFindableByChanged(event) { + var i; + + for (i = 0; i < visibilityControls2D.length; i += 1) { + visibilityControls2D[i].selected = event === VISIBILITY_VALUES[i]; + } + + updateVisibilityControls(); + } + function onMousePressEvent(event) { var clickedOverlay, numLinesBefore, @@ -365,7 +382,6 @@ var usersWindow = (function () { lineClicked, userClicked, i, - visibilityChanged, delta; if (!isVisible) { @@ -399,22 +415,13 @@ var usersWindow = (function () { return; } - visibilityChanged = false; for (i = 0; i < visibilityControls2D.length; i += 1) { // Don't need to test radioOverlay if it us under textOverlay. if (clickedOverlay === visibilityControls2D[i].textOverlay && event.x <= visibilityControls2D[i].optionWidth) { GlobalServices.findableBy = VISIBILITY_VALUES[i]; - visibilityChanged = true; + return; } } - if (visibilityChanged) { - for (i = 0; i < visibilityControls2D.length; i += 1) { - // Don't need to handle radioOverlay if it us under textOverlay. - visibilityControls2D[i].selected = clickedOverlay === visibilityControls2D[i].textOverlay; - } - updateVisibilityControls(); - return; - } if (clickedOverlay === minimizeButton2D) { setMinimized(!isMinimized); @@ -447,6 +454,10 @@ var usersWindow = (function () { updateUsersDisplay(); return; } + + if (clickedOverlay === friendsButton2D) { + GlobalServices.editFriends(); + } } function onMouseMoveEvent(event) { @@ -585,6 +596,17 @@ var usersWindow = (function () { visible: isVisible && isUsingScrollbars && !isMinimized }); + friendsButton2D = Overlays.addOverlay("image", { + x: WINDOW_MARGIN_2D, + y: viewportHeight, + width: FRIENDS_BUTTON_WIDTH_2D, + height: FRIENDS_BUTTON_HEIGHT_2D, + imageURL: FRIENDS_BUTTON_SVG, + subImage: { x: 0, y: 0, width: FRIENDS_BUTTON_SVG_WIDTH, height: FRIENDS_BUTTON_SVG_HEIGHT }, + color: FRIENDS_BUTTON_COLOR_2D, + alpha: FRIENDS_BUTTON_ALPHA_2D + }); + visibilityHeading2D = Overlays.addOverlay("text", { x: WINDOW_MARGIN_2D, y: viewportHeight, @@ -678,9 +700,9 @@ var usersWindow = (function () { }); Menu.menuItemEvent.connect(onMenuItemEvent); - Script.update.connect(onScriptUpdate); + GlobalServices.findableByChanged.connect(onFindableByChanged); - visibilityInterval = Script.setInterval(pollVisibility, VISIBILITY_POLL_INTERVAL); + Script.update.connect(onScriptUpdate); pollUsers(); @@ -691,13 +713,13 @@ var usersWindow = (function () { Menu.removeMenuItem(MENU_NAME, MENU_ITEM); - Script.clearInterval(visibilityInterval); Script.clearTimeout(usersTimer); Overlays.deleteOverlay(windowPane2D); Overlays.deleteOverlay(windowHeading2D); Overlays.deleteOverlay(minimizeButton2D); Overlays.deleteOverlay(scrollbarBackground2D); Overlays.deleteOverlay(scrollbarBar2D); + Overlays.deleteOverlay(friendsButton2D); Overlays.deleteOverlay(visibilityHeading2D); for (i = 0; i <= visibilityControls2D.length; i += 1) { Overlays.deleteOverlay(visibilityControls2D[i].textOverlay); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b19a7850c2..a8f9efd672 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -309,7 +309,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _isVSyncOn(true), _aboutToQuit(false), _notifiedPacketVersionMismatchThisDomain(false), - _domainConnectionRefusals(QList()) + _domainConnectionRefusals(QList()), + _friendsWindow(NULL) { #ifdef Q_OS_WIN installNativeEventFilter(&MyNativeEventFilter::getInstance()); @@ -4287,3 +4288,21 @@ void Application::checkSkeleton() { _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); } } + +void Application::showFriendsWindow() { + const QString FRIENDS_WINDOW_TITLE = "Add/Remove Friends"; + const QString FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends"; + const int FRIENDS_WINDOW_WIDTH = 290; + const int FRIENDS_WINDOW_HEIGHT = 500; + if (!_friendsWindow) { + _friendsWindow = new WebWindowClass(FRIENDS_WINDOW_TITLE, FRIENDS_WINDOW_URL, FRIENDS_WINDOW_WIDTH, + FRIENDS_WINDOW_HEIGHT, false); + connect(_friendsWindow, &WebWindowClass::closed, this, &Application::friendsWindowClosed); + } + _friendsWindow->setVisible(true); +} + +void Application::friendsWindowClosed() { + delete _friendsWindow; + _friendsWindow = NULL; +} diff --git a/interface/src/Application.h b/interface/src/Application.h index 80e2d9e8de..e9b8deff55 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -52,6 +52,7 @@ #include "avatar/MyAvatar.h" #include "devices/SixenseManager.h" #include "scripting/ControllerScriptingInterface.h" +#include "scripting/WebWindowClass.h" #include "ui/BandwidthDialog.h" #include "ui/HMDToolsDialog.h" #include "ui/ModelsBrowser.h" @@ -68,8 +69,6 @@ #include "ui/ToolWindow.h" #include "octree/OctreeFade.h" #include "octree/OctreePacketProcessor.h" - - #include "UndoStackScriptingInterface.h" @@ -367,7 +366,9 @@ public slots: void loadDefaultScripts(); void toggleRunningScriptsWidget(); void saveScripts(); - + void showFriendsWindow(); + void friendsWindowClosed(); + void packageModel(); void openUrl(const QUrl& url); @@ -471,6 +472,7 @@ private: MainWindow* _window; ToolWindow* _toolWindow; + WebWindowClass* _friendsWindow; DatagramProcessor* _datagramProcessor; diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 13697ff8be..6622a27145 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -24,7 +24,7 @@ const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::All; DiscoverabilityManager::DiscoverabilityManager() : _mode("discoverabilityMode", DEFAULT_DISCOVERABILITY_MODE) { - + qRegisterMetaType("Discoverability::Mode"); } const QString API_USER_LOCATION_PATH = "/api/v1/user/location"; @@ -93,5 +93,7 @@ void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discov // if we just got set to no discoverability, make sure that we delete our location in DB removeLocation(); } + + emit discoverabilityModeChanged(discoverabilityMode); } } \ No newline at end of file diff --git a/interface/src/DiscoverabilityManager.h b/interface/src/DiscoverabilityManager.h index 1dac7d63eb..9daa9408f8 100644 --- a/interface/src/DiscoverabilityManager.h +++ b/interface/src/DiscoverabilityManager.h @@ -35,7 +35,10 @@ public slots: Discoverability::Mode getDiscoverabilityMode() { return static_cast(_mode.get()); } void setDiscoverabilityMode(Discoverability::Mode discoverabilityMode); - + +signals: + void discoverabilityModeChanged(Discoverability::Mode discoverabilityMode); + private: DiscoverabilityManager(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 920f18a73b..f95ffddbfb 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -152,6 +152,32 @@ Menu::Menu() { addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, Qt::Key_Backslash, dialogsManager.data(), SLOT(showIRCLink())); + addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0, + qApp, SLOT(showFriendsWindow())); + + QMenu* visibilityMenu = toolsMenu->addMenu("I Am Visible To"); + { + QActionGroup* visibilityGroup = new QActionGroup(toolsMenu); + auto discoverabilityManager = DependencyManager::get(); + + QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All, + this, SLOT(setVisibility())); + visibilityGroup->addAction(visibleToEveryone); + + QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends, + this, SLOT(setVisibility())); + visibilityGroup->addAction(visibleToFriends); + + QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne, + 0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None, + this, SLOT(setVisibility())); + visibilityGroup->addAction(visibleToNoOne); + + connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, + this, &Menu::visibilityChanged); + } addActionToQMenuAndActionHash(toolsMenu, MenuOption::ToolWindow, @@ -950,3 +976,29 @@ bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { } return false; }; + +void Menu::setVisibility() { + auto discoverabilityManager = DependencyManager::get(); + + if (Menu::getInstance()->isOptionChecked(MenuOption::VisibleToEveryone)) { + discoverabilityManager->setDiscoverabilityMode(Discoverability::All); + } else if (Menu::getInstance()->isOptionChecked(MenuOption::VisibleToFriends)) { + discoverabilityManager->setDiscoverabilityMode(Discoverability::Friends); + } else if (Menu::getInstance()->isOptionChecked(MenuOption::VisibleToNoOne)) { + discoverabilityManager->setDiscoverabilityMode(Discoverability::None); + } else { + qDebug() << "ERROR Menu::setVisibility() called with unrecognized value."; + } +} + +void Menu::visibilityChanged(Discoverability::Mode discoverabilityMode) { + if (discoverabilityMode == Discoverability::All) { + setIsOptionChecked(MenuOption::VisibleToEveryone, true); + } else if (discoverabilityMode == Discoverability::Friends) { + setIsOptionChecked(MenuOption::VisibleToFriends, true); + } else if (discoverabilityMode == Discoverability::None) { + setIsOptionChecked(MenuOption::VisibleToNoOne, true); + } else { + qDebug() << "ERROR Menu::visibilityChanged() called with unrecognized value."; + } +} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 54d3af8880..db126a3c9b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -21,6 +21,8 @@ #include +#include "DiscoverabilityManager.h" + class Settings; class Menu : public QMenuBar { @@ -64,6 +66,9 @@ public slots: bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); +private slots: + void setVisibility(); + private: static Menu* _instance; Menu(); @@ -94,12 +99,14 @@ private: int findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem); int positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition); + void visibilityChanged(Discoverability::Mode discoverabilityMode); QHash _actionHash; }; namespace MenuOption { const QString AboutApp = "About Interface"; + const QString AddRemoveFriends = "Add/Remove Friends..."; const QString AddressBar = "Show Address Bar"; const QString AlignForearmsWithWrists = "Align Forearms with Wrists"; const QString AlternateIK = "Alternate IK"; @@ -246,6 +253,9 @@ namespace MenuOption { const QString TurnWithHead = "Turn using Head"; const QString PackageModel = "Package Model..."; const QString Visage = "Visage"; + const QString VisibleToEveryone = "Everyone"; + const QString VisibleToFriends = "Friends"; + const QString VisibleToNoOne = "No one"; const QString Wireframe = "Wireframe"; } diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index d39da47e78..26bee34d75 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -24,6 +24,10 @@ GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() { _downloading = false; connect(Application::getInstance(), &Application::renderingInWorldInterface, this, &GlobalServicesScriptingInterface::checkDownloadInfo); + + auto discoverabilityManager = DependencyManager::get(); + connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, + this, &GlobalServicesScriptingInterface::discoverabilityModeChanged); } GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() { @@ -45,16 +49,24 @@ void GlobalServicesScriptingInterface::loggedOut() { emit GlobalServicesScriptingInterface::disconnected(QString("logout")); } + +QString GlobalServicesScriptingInterface::findableByString(Discoverability::Mode discoverabilityMode) const { + if (discoverabilityMode == Discoverability::None) { + return "none"; + } else if (discoverabilityMode == Discoverability::Friends) { + return "friends"; + } else if (discoverabilityMode == Discoverability::All) { + return "all"; + } else { + qDebug() << "GlobalServices findableByString called with an unrecognized value."; + return ""; + } +} + + QString GlobalServicesScriptingInterface::getFindableBy() const { auto discoverabilityManager = DependencyManager::get(); - - if (discoverabilityManager->getDiscoverabilityMode() == Discoverability::None) { - return "none"; - } else if (discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends) { - return "friends"; - } else { - return "all"; - } + return findableByString(discoverabilityManager->getDiscoverabilityMode()); } void GlobalServicesScriptingInterface::setFindableBy(const QString& discoverabilityMode) { @@ -71,6 +83,10 @@ void GlobalServicesScriptingInterface::setFindableBy(const QString& discoverabil } } +void GlobalServicesScriptingInterface::discoverabilityModeChanged(Discoverability::Mode discoverabilityMode) { + emit findableByChanged(findableByString(discoverabilityMode)); +} + DownloadInfoResult::DownloadInfoResult() : downloading(QList()), pending(0.0f) @@ -123,3 +139,7 @@ void GlobalServicesScriptingInterface::checkDownloadInfo() { void GlobalServicesScriptingInterface::updateDownloadInfo() { emit downloadInfoChanged(getDownloadInfo()); } + +void GlobalServicesScriptingInterface::editFriends() { + QMetaObject::invokeMethod(Application::getInstance(), "showFriendsWindow"); +} diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index a39219ba40..e38bfc0eb6 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -45,6 +45,7 @@ public: public slots: DownloadInfoResult getDownloadInfo(); void updateDownloadInfo(); + void editFriends(); private slots: void loggedOut(); @@ -52,17 +53,21 @@ private slots: QString getFindableBy() const; void setFindableBy(const QString& discoverabilityMode); + void discoverabilityModeChanged(Discoverability::Mode discoverabilityMode); signals: void connected(); void disconnected(const QString& reason); void myUsernameChanged(const QString& username); void downloadInfoChanged(DownloadInfoResult info); + void findableByChanged(const QString& discoverabilityMode); private: GlobalServicesScriptingInterface(); ~GlobalServicesScriptingInterface(); + QString findableByString(Discoverability::Mode discoverabilityMode) const; + bool _downloading; }; diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index 31bd4029ac..1c9fced619 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -54,26 +54,27 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid _windowWidget = dockWidget; } else { + auto dialogWidget = new QDialog(Application::getInstance()->getWindow(), Qt::Window); + dialogWidget->setWindowTitle(title); + dialogWidget->setMinimumSize(width, height); + connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed); - _windowWidget = new QWidget(Application::getInstance()->getWindow(), Qt::Window); - _windowWidget->setWindowTitle(title); - _windowWidget->setMinimumSize(width, height); - - auto layout = new QVBoxLayout(_windowWidget); + auto layout = new QVBoxLayout(dialogWidget); layout->setContentsMargins(0, 0, 0, 0); - _windowWidget->setLayout(layout); + dialogWidget->setLayout(layout); - _webView = new QWebView(_windowWidget); + _webView = new QWebView(dialogWidget); layout->addWidget(_webView); addEventBridgeToWindowObject(); + + _windowWidget = dialogWidget; } _webView->setPage(new DataWebPage()); _webView->setUrl(url); - connect(this, &WebWindowClass::destroyed, _windowWidget, &QWidget::deleteLater); connect(_webView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared, this, &WebWindowClass::addEventBridgeToWindowObject); @@ -82,6 +83,10 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid WebWindowClass::~WebWindowClass() { } +void WebWindowClass::hasClosed() { + emit closed(); +} + void WebWindowClass::addEventBridgeToWindowObject() { _webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge); } @@ -92,6 +97,7 @@ void WebWindowClass::setVisible(bool visible) { QMetaObject::invokeMethod( Application::getInstance()->getToolWindow(), "setVisible", Qt::AutoConnection, Q_ARG(bool, visible)); } else { + QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection); QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection); } } @@ -107,6 +113,7 @@ void WebWindowClass::setURL(const QString& url) { } void WebWindowClass::raise() { + QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection); QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection); } diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h index 429b054966..f5a292874c 100644 --- a/interface/src/scripting/WebWindowClass.h +++ b/interface/src/scripting/WebWindowClass.h @@ -49,6 +49,12 @@ public slots: ScriptEventBridge* getEventBridge() const { return _eventBridge; } void addEventBridgeToWindowObject(); +signals: + void closed(); + +private slots: + void hasClosed(); + private: QWidget* _windowWidget; QWebView* _webView; diff --git a/libraries/audio/src/AudioInjectorLocalBuffer.cpp b/libraries/audio/src/AudioInjectorLocalBuffer.cpp index 6cbe56adb7..1b2d44fe24 100644 --- a/libraries/audio/src/AudioInjectorLocalBuffer.cpp +++ b/libraries/audio/src/AudioInjectorLocalBuffer.cpp @@ -59,6 +59,8 @@ qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) { if (!_shouldLoop && bytesRead == bytesToEnd) { // we hit the end of the buffer, emit a signal emit bufferEmpty(); + } else if (_shouldLoop && _currentOffset == _rawAudioArray.size()) { + _currentOffset = 0; } return bytesRead; @@ -80,7 +82,7 @@ qint64 AudioInjectorLocalBuffer::recursiveReadFromFront(char* data, qint64 maxSi // check if we need to call ourselves again and pull from the front again if (bytesRead < maxSize) { - return bytesRead + recursiveReadFromFront(data, maxSize); + return bytesRead + recursiveReadFromFront(data + bytesRead, maxSize - bytesRead); } else { _currentOffset = bytesRead; return bytesRead; diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 6f149bb203..834c6a531f 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -77,7 +77,7 @@ void Sound::downloadFinished(QNetworkReply* reply) { // since it's raw the only way for us to know that is if the file was called .stereo.raw if (reply->url().fileName().toLower().endsWith("stereo.raw")) { _isStereo = true; - qDebug() << "Processing sound from" << reply->url() << "as stereo audio file."; + qDebug() << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << reply->url() << "as stereo audio file."; } // Process as RAW file @@ -99,15 +99,14 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) { // we want to convert it to the format that the audio-mixer wants // which is signed, 16-bit, 24Khz - int numSourceSamples = rawAudioByteArray.size() / sizeof(int16_t); + int numSourceSamples = rawAudioByteArray.size() / sizeof(AudioConstants::AudioSample); - int numDestinationBytes = rawAudioByteArray.size() / 2; - if (_isStereo && numSourceSamples % 4 != 0) { - numDestinationBytes += 1; + int numDestinationBytes = rawAudioByteArray.size() / sizeof(AudioConstants::AudioSample); + if (_isStereo && numSourceSamples % 2 != 0) { + numDestinationBytes += sizeof(AudioConstants::AudioSample); } _byteArray.resize(numDestinationBytes); - int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data(); int16_t* destinationSamples = (int16_t*) _byteArray.data(); @@ -121,7 +120,6 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) { destinationSamples[i / 2] = (sourceSamples[i] + sourceSamples[i + 2]) / 2; destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] + sourceSamples[i + 3]) / 2; } - } } else { for (int i = 1; i < numSourceSamples; i += 2) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index c4b12f2059..16ece64a4d 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -662,11 +662,23 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char if (senderNode->getCanRez()) { // this is a new entity... assign a new entityID entityItemID = assignEntityID(entityItemID); + if (wantEditLogging()) { + qDebug() << "User [" << senderNode->getUUID() << "] adding entity."; + qDebug() << " properties:" << properties; + } EntityItem* newEntity = addEntity(entityItemID, properties); if (newEntity) { newEntity->markAsChangedOnServer(); notifyNewlyCreatedEntity(*newEntity, senderNode); + if (wantEditLogging()) { + qDebug() << "User [" << senderNode->getUUID() << "] added entity. ID:" + << newEntity->getEntityItemID(); + qDebug() << " properties:" << properties; + } + } + } else { + qDebug() << "User without 'rez rights' [" << senderNode->getUUID() << "] attempted to add an entity."; } } } diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 85ea09b5ef..e07d62fe83 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1916,8 +1916,10 @@ bool Octree::readFromStream(unsigned long streamLength, QDataStream& inputStream device->ungetChar(firstChar); if (firstChar == (char) PacketTypeEntityData) { + qDebug() << "Reading from SVO Stream length:" << streamLength; return readSVOFromStream(streamLength, inputStream); } else { + qDebug() << "Reading from JSON Stream length:" << streamLength; return readJSONFromStream(streamLength, inputStream); } } @@ -2053,12 +2055,14 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr } bool Octree::readJSONFromStream(unsigned long streamLength, QDataStream& inputStream) { - char *rawData = new char[streamLength]; + char* rawData = new char[streamLength + 1]; // allocate enough room to null terminate inputStream.readRawData(rawData, streamLength); - QJsonDocument d = QJsonDocument::fromJson(rawData); - QVariant v = d.toVariant(); - QVariantMap m = v.toMap(); - readFromMap(m); + rawData[streamLength] = 0; // make sure we null terminate this string + + QJsonDocument asDocument = QJsonDocument::fromJson(rawData); + QVariant asVariant = asDocument.toVariant(); + QVariantMap asMap = asVariant.toMap(); + readFromMap(asMap); delete rawData; return true; }