diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json
index f25e0cc3c4..5c0ea09939 100644
--- a/interface/resources/controllers/standard.json
+++ b/interface/resources/controllers/standard.json
@@ -9,6 +9,8 @@
"to": "Actions.StepYaw",
"filters":
[
+ { "type": "deadZone", "min": 0.15 },
+ "constrainToInteger",
{ "type": "pulse", "interval": 0.5 },
{ "type": "scale", "scale": 22.5 }
]
diff --git a/interface/resources/icons/hud-01.svg b/interface/resources/icons/hud-01.svg
new file mode 100644
index 0000000000..4929389268
--- /dev/null
+++ b/interface/resources/icons/hud-01.svg
@@ -0,0 +1,105 @@
+
+
+
diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml
index 241cd91611..e269a63cde 100644
--- a/interface/resources/qml/desktop/Desktop.qml
+++ b/interface/resources/qml/desktop/Desktop.qml
@@ -299,7 +299,7 @@ FocusScope {
if (pinned) {
// recalculate our non-pinned children
hiddenChildren = d.findMatchingChildren(desktop, function(child){
- return !d.isTopLevelWindow(child) && child.visible;
+ return !d.isTopLevelWindow(child) && child.visible && !child.pinned;
});
hiddenChildren.forEach(function(child){
diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml
index 59278a17b4..e127a235e6 100644
--- a/interface/resources/qml/hifi/Desktop.qml
+++ b/interface/resources/qml/hifi/Desktop.qml
@@ -4,11 +4,13 @@ import QtWebEngine 1.1;
import "../desktop"
import ".."
+import "."
Desktop {
id: desktop
MouseArea {
+ id: hoverWatch
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
@@ -47,7 +49,12 @@ Desktop {
}
}
+
+ ToggleHudButton {
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 32
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
}
-
diff --git a/interface/resources/qml/hifi/ToggleHudButton.qml b/interface/resources/qml/hifi/ToggleHudButton.qml
new file mode 100644
index 0000000000..6454f42305
--- /dev/null
+++ b/interface/resources/qml/hifi/ToggleHudButton.qml
@@ -0,0 +1,36 @@
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+
+import "../windows"
+
+Window {
+ //frame: HiddenFrame {}
+ hideBackground: true
+ resizable: false
+ destroyOnCloseButton: false
+ destroyOnHidden: false
+ closable: false
+ shown: true
+ pinned: true
+ width: 50
+ height: 50
+ clip: true
+ visible: true
+
+ Item {
+ width: 50
+ height: 50
+ Image {
+ y: desktop.pinned ? -50 : 0
+ id: hudToggleImage
+ source: "../../icons/hud-01.svg"
+ }
+ MouseArea {
+ readonly property string overlayMenuItem: "Overlays"
+ anchors.fill: parent
+ onClicked: MenuInterface.setIsOptionChecked(overlayMenuItem, !MenuInterface.isOptionChecked(overlayMenuItem))
+ }
+ }
+}
+
+
diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml
index 7dc7654d9a..e6be336657 100644
--- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml
+++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml
@@ -23,9 +23,9 @@ Window {
title: "Running Scripts"
resizable: true
destroyOnHidden: true
- implicitWidth: 400
+ implicitWidth: 424
implicitHeight: isHMD ? 695 : 728
- minSize: Qt.vector2d(200, 300)
+ minSize: Qt.vector2d(424, 300)
HifiConstants { id: hifi }
@@ -86,6 +86,11 @@ Window {
scripts.reloadAllScripts();
}
+ function loadDefaults() {
+ console.log("Load default scripts");
+ scripts.loadOneScript(scripts.defaultScriptsPath + "/defaultScripts.js");
+ }
+
function stopAll() {
console.log("Stop all scripts");
scripts.stopAllScripts();
@@ -104,13 +109,13 @@ Window {
spacing: hifi.dimensions.contentSpacing.x
HifiControls.Button {
- text: "Reload all"
+ text: "Reload All"
color: hifi.buttons.black
onClicked: reloadAll()
}
HifiControls.Button {
- text: "Stop all"
+ text: "Remove All"
color: hifi.buttons.red
onClicked: stopAll()
}
@@ -218,7 +223,6 @@ Window {
Row {
spacing: hifi.dimensions.contentSpacing.x
- anchors.right: parent.right
HifiControls.Button {
text: "from URL"
@@ -256,6 +260,12 @@ Window {
onTriggered: ApplicationInterface.loadDialog();
}
}
+
+ HifiControls.Button {
+ text: "Load Defaults"
+ color: hifi.buttons.black
+ onClicked: loadDefaults()
+ }
}
HifiControls.VerticalSpacer {}
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 8f4d80a86f..1e6f7ba995 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -19,6 +19,7 @@
#include
#include
+#include
#include
#include
@@ -197,7 +198,6 @@ static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check f
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
-static const QString INPUT_DEVICE_MENU_PREFIX = "Device: ";
Setting::Handle maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS);
const QHash Application::_acceptedExtensions {
@@ -999,7 +999,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
RenderableWebEntityItem* webEntity = dynamic_cast(entity.get());
if (webEntity) {
webEntity->setProxyWindow(_window->windowHandle());
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent();
}
_keyboardFocusedItem = entityItemID;
@@ -1152,9 +1152,7 @@ void Application::aboutToQuit() {
emit beforeAboutToQuit();
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
- QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
- QAction* action = Menu::getInstance()->getActionForOption(name);
- if (action->isChecked()) {
+ if (inputPlugin->isActive()) {
inputPlugin->deactivate();
}
}
@@ -1418,7 +1416,7 @@ void Application::initializeUi() {
rootContext->setContextProperty("Overlays", &_overlays);
rootContext->setContextProperty("Window", DependencyManager::get().data());
- rootContext->setContextProperty("Menu", MenuScriptingInterface::getInstance());
+ rootContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
rootContext->setContextProperty("Stats", Stats::getInstance());
rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data());
@@ -1476,7 +1474,6 @@ void Application::initializeUi() {
}
}
_window->setMenuBar(new Menu());
- updateInputModes();
auto compositorHelper = DependencyManager::get();
connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, [=] {
@@ -2024,7 +2021,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
}
if (hasFocus()) {
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->keyPressEvent(event);
}
@@ -2359,7 +2356,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
return;
}
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->keyReleaseEvent(event);
}
@@ -2391,9 +2388,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
void Application::focusOutEvent(QFocusEvent* event) {
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
foreach(auto inputPlugin, inputPlugins) {
- QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
- QAction* action = Menu::getInstance()->getActionForOption(name);
- if (action && action->isChecked()) {
+ if (inputPlugin->isActive()) {
inputPlugin->pluginFocusOutEvent();
}
}
@@ -2478,7 +2473,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
return;
}
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->mouseMoveEvent(event);
}
@@ -2515,7 +2510,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
if (hasFocus()) {
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->mousePressEvent(event);
}
@@ -2560,7 +2555,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
}
if (hasFocus()) {
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->mouseReleaseEvent(event);
}
@@ -2587,7 +2582,7 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
return;
}
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->touchUpdateEvent(event);
}
}
@@ -2605,7 +2600,7 @@ void Application::touchBeginEvent(QTouchEvent* event) {
return;
}
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->touchBeginEvent(event);
}
@@ -2622,7 +2617,7 @@ void Application::touchEndEvent(QTouchEvent* event) {
return;
}
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->touchEndEvent(event);
}
@@ -2638,7 +2633,7 @@ void Application::wheelEvent(QWheelEvent* event) const {
return;
}
- if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
+ if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->wheelEvent(event);
}
}
@@ -2771,9 +2766,7 @@ void Application::idle(float nsecsElapsed) {
getActiveDisplayPlugin()->idle();
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
foreach(auto inputPlugin, inputPlugins) {
- QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
- QAction* action = Menu::getInstance()->getActionForOption(name);
- if (action && action->isChecked()) {
+ if (inputPlugin->isActive()) {
inputPlugin->idle();
}
}
@@ -2957,6 +2950,27 @@ void Application::loadSettings() {
//DependencyManager::get()->setAutomaticLODAdjust(false);
Menu::getInstance()->loadSettings();
+
+ // If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.
+ auto pluginManager = PluginManager::getInstance();
+ auto plugins = pluginManager->getPreferredDisplayPlugins();
+ for (auto plugin : plugins) {
+ auto menu = Menu::getInstance();
+ if (auto action = menu->getActionForOption(plugin->getName())) {
+ action->setChecked(true);
+ action->trigger();
+ // Find and activated highest priority plugin, bail for the rest
+ break;
+ }
+ }
+
+ auto inputs = pluginManager->getInputPlugins();
+ for (auto plugin : inputs) {
+ if (!plugin->isActive()) {
+ plugin->activate();
+ }
+ }
+
getMyAvatar()->loadData();
_settingsLoaded = true;
@@ -4937,7 +4951,34 @@ void Application::postLambdaEvent(std::function f) {
}
}
-void Application::initPlugins() {
+void Application::initPlugins(const QStringList& arguments) {
+ QCommandLineOption display("display", "Preferred displays", "displays");
+ QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays");
+ QCommandLineOption disableInputs("disable-inputs", "Inputs to disable", "inputs");
+
+ QCommandLineParser parser;
+ parser.addOption(display);
+ parser.addOption(disableDisplays);
+ parser.addOption(disableInputs);
+ parser.parse(arguments);
+
+ if (parser.isSet(display)) {
+ auto preferredDisplays = parser.value(display).split(',', QString::SkipEmptyParts);
+ qInfo() << "Setting prefered display plugins:" << preferredDisplays;
+ PluginManager::getInstance()->setPreferredDisplayPlugins(preferredDisplays);
+ }
+
+ if (parser.isSet(disableDisplays)) {
+ auto disabledDisplays = parser.value(disableDisplays).split(',', QString::SkipEmptyParts);
+ qInfo() << "Disabling following display plugins:" << disabledDisplays;
+ PluginManager::getInstance()->disableDisplays(disabledDisplays);
+ }
+
+ if (parser.isSet(disableInputs)) {
+ auto disabledInputs = parser.value(disableInputs).split(',', QString::SkipEmptyParts);
+ qInfo() << "Disabling following input plugins:" << disabledInputs;
+ PluginManager::getInstance()->disableInputs(disabledInputs);
+ }
}
void Application::shutdownPlugins() {
@@ -5207,81 +5248,6 @@ void Application::updateDisplayMode() {
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
}
-static void addInputPluginToMenu(InputPluginPointer inputPlugin) {
- auto menu = Menu::getInstance();
- QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
- Q_ASSERT(!menu->menuItemExists(MenuOption::InputMenu, name));
-
- static QActionGroup* inputPluginGroup = nullptr;
- if (!inputPluginGroup) {
- inputPluginGroup = new QActionGroup(menu);
- inputPluginGroup->setExclusive(false);
- }
-
- auto parent = menu->getMenu(MenuOption::InputMenu);
- auto action = menu->addCheckableActionToQMenuAndActionHash(parent,
- name, 0, true, qApp,
- SLOT(updateInputModes()));
-
- inputPluginGroup->addAction(action);
- Q_ASSERT(menu->menuItemExists(MenuOption::InputMenu, name));
-}
-
-
-void Application::updateInputModes() {
- auto menu = Menu::getInstance();
- auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
- static std::once_flag once;
- std::call_once(once, [&] {
- foreach(auto inputPlugin, inputPlugins) {
- addInputPluginToMenu(inputPlugin);
- }
- });
- auto offscreenUi = DependencyManager::get();
-
- InputPluginList newInputPlugins;
- InputPluginList removedInputPlugins;
- foreach(auto inputPlugin, inputPlugins) {
- QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
- QAction* action = menu->getActionForOption(name);
-
- auto it = std::find(std::begin(_activeInputPlugins), std::end(_activeInputPlugins), inputPlugin);
- if (action->isChecked() && it == std::end(_activeInputPlugins)) {
- _activeInputPlugins.push_back(inputPlugin);
- newInputPlugins.push_back(inputPlugin);
- } else if (!action->isChecked() && it != std::end(_activeInputPlugins)) {
- _activeInputPlugins.erase(it);
- removedInputPlugins.push_back(inputPlugin);
- }
- }
-
- // A plugin was checked
- if (newInputPlugins.size() > 0) {
- foreach(auto newInputPlugin, newInputPlugins) {
- newInputPlugin->activate();
- //newInputPlugin->installEventFilter(qApp);
- //newInputPlugin->installEventFilter(offscreenUi.data());
- }
- }
- if (removedInputPlugins.size() > 0) { // A plugin was unchecked
- foreach(auto removedInputPlugin, removedInputPlugins) {
- removedInputPlugin->deactivate();
- //removedInputPlugin->removeEventFilter(qApp);
- //removedInputPlugin->removeEventFilter(offscreenUi.data());
- }
- }
-
- //if (newInputPlugins.size() > 0 || removedInputPlugins.size() > 0) {
- // if (!_currentInputPluginActions.isEmpty()) {
- // auto menu = Menu::getInstance();
- // foreach(auto itemInfo, _currentInputPluginActions) {
- // menu->removeMenuItem(itemInfo.first, itemInfo.second);
- // }
- // _currentInputPluginActions.clear();
- // }
- //}
-}
-
mat4 Application::getEyeProjection(int eye) const {
QMutexLocker viewLocker(&_viewMutex);
if (isHMDMode()) {
diff --git a/interface/src/Application.h b/interface/src/Application.h
index a17250a58e..f93434f581 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -101,7 +101,7 @@ public:
};
// FIXME? Empty methods, do we still need them?
- static void initPlugins();
+ static void initPlugins(const QStringList& arguments);
static void shutdownPlugins();
Application(int& argc, char** argv, QElapsedTimer& startup_time);
@@ -327,7 +327,6 @@ private slots:
void nodeKilled(SharedNodePointer node);
static void packetSent(quint64 length);
void updateDisplayMode();
- void updateInputModes();
void domainConnectionRefused(const QString& reasonMessage, int reason);
private:
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index a21aa71753..031564fa7a 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -403,12 +403,6 @@ Menu::Menu() {
// Developer > Avatar >>>
MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar");
- // Settings > Input Devices
- MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu, "Advanced");
- QActionGroup* inputModeGroup = new QActionGroup(inputModeMenu);
- inputModeGroup->setExclusive(false);
-
-
// Developer > Avatar > Face Tracking
MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking");
{
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index fcaf8e6caa..8081e27eb8 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -113,7 +113,6 @@ namespace MenuOption {
const QString Help = "Help...";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode";
- const QString InputMenu = "Developer>Avatar>Input Devices";
const QString ActionMotorControl = "Enable Default Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File...";
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index f48104235d..62772c6933 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -1214,7 +1214,10 @@ void MyAvatar::updateMotors() {
if (_characterController.getState() == CharacterController::State::Hover) {
motorRotation = getHead()->getCameraOrientation();
} else {
- motorRotation = getOrientation();
+ // non-hovering = walking: follow camera twist about vertical but not lift
+ // so we decompose camera's rotation and store the twist part in motorRotation
+ glm::quat liftRotation;
+ swingTwistDecomposition(getHead()->getCameraOrientation(), _worldUpDirection, liftRotation, motorRotation);
}
const float DEFAULT_MOTOR_TIMESCALE = 0.2f;
const float INVALID_MOTOR_TIMESCALE = 1.0e6f;
diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 13f9470fda..8fc0384aee 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -46,6 +46,12 @@ int main(int argc, const char* argv[]) {
bool instanceMightBeRunning = true;
+ QStringList arguments;
+ for (int i = 0; i < argc; ++i) {
+ arguments << argv[i];
+ }
+
+
#ifdef Q_OS_WIN
// Try to create a shared memory block - if it can't be created, there is an instance of
// interface already running. We only do this on Windows for now because of the potential
@@ -64,12 +70,6 @@ int main(int argc, const char* argv[]) {
// Try to connect - if we can't connect, interface has probably just gone down
if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) {
-
- QStringList arguments;
- for (int i = 0; i < argc; ++i) {
- arguments << argv[i];
- }
-
QCommandLineParser parser;
QCommandLineOption urlOption("url", "", "value");
parser.addOption(urlOption);
@@ -135,7 +135,7 @@ int main(int argc, const char* argv[]) {
// Oculus initialization MUST PRECEDE OpenGL context creation.
// The nature of the Application constructor means this has to be either here,
// or in the main window ctor, before GL startup.
- Application::initPlugins();
+ Application::initPlugins(arguments);
int exitCode;
{
diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp
index b0ef6c760d..b803080538 100644
--- a/interface/src/scripting/ClipboardScriptingInterface.cpp
+++ b/interface/src/scripting/ClipboardScriptingInterface.cpp
@@ -14,6 +14,10 @@
ClipboardScriptingInterface::ClipboardScriptingInterface() {
}
+glm::vec3 ClipboardScriptingInterface::getContentsDimensions() {
+ return qApp->getEntityClipboard()->getContentsDimensions();
+}
+
float ClipboardScriptingInterface::getClipboardContentsLargestDimension() {
return qApp->getEntityClipboard()->getContentsLargestDimension();
}
diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h
index 73bebd4836..4737a194df 100644
--- a/interface/src/scripting/ClipboardScriptingInterface.h
+++ b/interface/src/scripting/ClipboardScriptingInterface.h
@@ -22,6 +22,7 @@ signals:
void readyToImport();
public slots:
+ glm::vec3 getContentsDimensions(); /// returns the overall dimensions of everything on the blipboard
float getClipboardContentsLargestDimension(); /// returns the largest dimension of everything on the clipboard
bool importEntities(const QString& filename);
bool exportEntities(const QString& filename, const QVector& entityIDs);
diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp
index 16e4bd5437..ff7438bb17 100644
--- a/libraries/avatars/src/AvatarData.cpp
+++ b/libraries/avatars/src/AvatarData.cpp
@@ -632,13 +632,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
#endif
int numBytesRead = sourceBuffer - startPosition;
-
- if (numBytesRead != buffer.size()) {
- if (shouldLogError(now)) {
- qCWarning(avatars) << "AvatarData packet size mismatch: expected " << numBytesRead << " received " << buffer.size();
- }
- }
-
_averageBytesReceived.updateAverage(numBytesRead);
return numBytesRead;
}
@@ -1270,6 +1263,10 @@ static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments");
static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities");
static const QString JSON_AVATAR_SCALE = QStringLiteral("scale");
+static const QString JSON_AVATAR_VERSION = QStringLiteral("version");
+
+static const int JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION = 0;
+static const int JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION = 1;
QJsonValue toJsonValue(const JointData& joint) {
QJsonArray result;
@@ -1293,6 +1290,8 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
QJsonObject AvatarData::toJson() const {
QJsonObject root;
+ root[JSON_AVATAR_VERSION] = JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION;
+
if (!getSkeletonModelURL().isEmpty()) {
root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString();
}
@@ -1359,6 +1358,15 @@ QJsonObject AvatarData::toJson() const {
}
void AvatarData::fromJson(const QJsonObject& json) {
+
+ int version;
+ if (json.contains(JSON_AVATAR_VERSION)) {
+ version = json[JSON_AVATAR_VERSION].toInt();
+ } else {
+ // initial data did not have a version field.
+ version = JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION;
+ }
+
// The head setOrientation likes to overwrite the avatar orientation,
// so lets do the head first
// Most head data is relative to the avatar, and needs no basis correction,
@@ -1424,20 +1432,28 @@ void AvatarData::fromJson(const QJsonObject& json) {
// }
// }
- // Joint rotations are relative to the avatar, so they require no basis correction
if (json.contains(JSON_AVATAR_JOINT_ARRAY)) {
- QVector jointArray;
- QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray();
- jointArray.reserve(jointArrayJson.size());
- int i = 0;
- for (const auto& jointJson : jointArrayJson) {
- auto joint = jointDataFromJsonValue(jointJson);
- jointArray.push_back(joint);
- setJointData(i, joint.rotation, joint.translation);
- _jointData[i].rotationSet = true; // Have to do that to broadcast the avatar new pose
- i++;
+ if (version == JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION) {
+ // because we don't have the full joint hierarchy skeleton of the model,
+ // we can't properly convert from relative rotations into absolute rotations.
+ quint64 now = usecTimestampNow();
+ if (shouldLogError(now)) {
+ qCWarning(avatars) << "Version 0 avatar recordings not supported. using default rotations";
+ }
+ } else {
+ QVector jointArray;
+ QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray();
+ jointArray.reserve(jointArrayJson.size());
+ int i = 0;
+ for (const auto& jointJson : jointArrayJson) {
+ auto joint = jointDataFromJsonValue(jointJson);
+ jointArray.push_back(joint);
+ setJointData(i, joint.rotation, joint.translation);
+ _jointData[i].rotationSet = true; // Have to do that to broadcast the avatar new pose
+ i++;
+ }
+ setRawJointData(jointArray);
}
- setRawJointData(jointArray);
}
}
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp
index 15c2bffd80..d09fc60d9b 100644
--- a/libraries/entities/src/EntityScriptingInterface.cpp
+++ b/libraries/entities/src/EntityScriptingInterface.cpp
@@ -1121,6 +1121,27 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) {
return result;
}
+QVector EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
+ QVector result;
+ if (!_entityTree) {
+ return result;
+ }
+
+ EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID);
+ if (!entity) {
+ qDebug() << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID;
+ return result;
+ }
+
+ _entityTree->withReadLock([&] {
+ entity->forEachChild([&](SpatiallyNestablePointer child) {
+ result.push_back(child->getID());
+ });
+ });
+
+ return result;
+}
+
QVector EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) {
QVector result;
if (!_entityTree) {
diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h
index 2f5446874b..8ae6a77dab 100644
--- a/libraries/entities/src/EntityScriptingInterface.h
+++ b/libraries/entities/src/EntityScriptingInterface.h
@@ -171,6 +171,7 @@ public slots:
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
+ Q_INVOKABLE QVector getChildrenIDs(const QUuid& parentID);
Q_INVOKABLE QVector getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex);
signals:
diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index b85ee1dcf9..581e0a9568 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -1284,6 +1284,7 @@ class ContentsDimensionOperator : public RecurseOctreeOperator {
public:
virtual bool preRecursion(OctreeElementPointer element);
virtual bool postRecursion(OctreeElementPointer element) { return true; }
+ glm::vec3 getDimensions() const { return _contentExtents.size(); }
float getLargestDimension() const { return _contentExtents.largestDimension(); }
private:
Extents _contentExtents;
@@ -1295,6 +1296,12 @@ bool ContentsDimensionOperator::preRecursion(OctreeElementPointer element) {
return true;
}
+glm::vec3 EntityTree::getContentsDimensions() {
+ ContentsDimensionOperator theOperator;
+ recurseTreeWithOperator(&theOperator);
+ return theOperator.getDimensions();
+}
+
float EntityTree::getContentsLargestDimension() {
ContentsDimensionOperator theOperator;
recurseTreeWithOperator(&theOperator);
diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h
index 03b8a9b55a..a85624c9ae 100644
--- a/libraries/entities/src/EntityTree.h
+++ b/libraries/entities/src/EntityTree.h
@@ -207,6 +207,7 @@ public:
bool skipThoseWithBadParents) override;
virtual bool readFromMap(QVariantMap& entityDescription) override;
+ glm::vec3 getContentsDimensions();
float getContentsLargestDimension();
virtual void resetEditStats() override {
diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp
index 37a0f36d2f..a7baeb361b 100644
--- a/libraries/entities/src/EntityTreeElement.cpp
+++ b/libraries/entities/src/EntityTreeElement.cpp
@@ -55,7 +55,7 @@ void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) cons
if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
- = static_cast(extraEncodeData->value(this));
+ = static_cast((*extraEncodeData)[this]);
qCDebug(entities) << " encode data:" << entityTreeElementExtraEncodeData;
} else {
qCDebug(entities) << " encode data: MISSING!!";
@@ -97,7 +97,7 @@ bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamPa
if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
- = static_cast(extraEncodeData->value(this));
+ = static_cast((*extraEncodeData)[this]);
bool childCompleted = entityTreeElementExtraEncodeData->childCompleted[childIndex];
@@ -126,7 +126,7 @@ bool EntityTreeElement::alreadyFullyEncoded(EncodeBitstreamParams& params) const
if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
- = static_cast(extraEncodeData->value(this));
+ = static_cast((*extraEncodeData)[this]);
// If we know that ALL subtrees below us have already been recursed, then we don't
// need to recurse this child.
@@ -140,7 +140,7 @@ void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppen
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
if (extraEncodeData->contains(this)) {
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
- = static_cast(extraEncodeData->value(this));
+ = static_cast((*extraEncodeData)[this]);
if (childAppendState == OctreeElement::COMPLETED) {
entityTreeElementExtraEncodeData->childCompleted[childIndex] = true;
@@ -165,7 +165,7 @@ void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params) con
assert(extraEncodeData->contains(this));
EntityTreeElementExtraEncodeData* thisExtraEncodeData
- = static_cast(extraEncodeData->value(this));
+ = static_cast((*extraEncodeData)[this]);
// Note: this will be called when OUR element has finished running through encodeTreeBitstreamRecursion()
// which means, it's possible that our parent element hasn't finished encoding OUR data... so
@@ -241,7 +241,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
bool hadElementExtraData = false;
if (extraEncodeData && extraEncodeData->contains(this)) {
entityTreeElementExtraEncodeData =
- static_cast(extraEncodeData->value(this));
+ static_cast((*extraEncodeData)[this]);
hadElementExtraData = true;
} else {
// if there wasn't one already, then create one
@@ -268,7 +268,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
//assert(extraEncodeData);
//assert(extraEncodeData->contains(this));
- //entityTreeElementExtraEncodeData = static_cast(extraEncodeData->value(this));
+ //entityTreeElementExtraEncodeData = static_cast((*extraEncodeData)[this]);
LevelDetails elementLevel = packetData->startLevel();
diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp
index 388ca26482..14518ac37a 100644
--- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp
+++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp
@@ -396,6 +396,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
_renderer->_renderControl->_renderWindow = _proxyWindow;
+ connect(_renderer->_quickWindow, &QQuickWindow::focusObjectChanged, this, &OffscreenQmlSurface::onFocusObjectChanged);
+
// Create a QML engine.
_qmlEngine = new QQmlEngine;
if (!_qmlEngine->incubationController()) {
@@ -742,3 +744,21 @@ QVariant OffscreenQmlSurface::returnFromUiThread(std::function funct
return function();
}
+
+void OffscreenQmlSurface::onFocusObjectChanged(QObject* object) {
+ if (!object) {
+ setFocusText(false);
+ return;
+ }
+
+ QInputMethodQueryEvent query(Qt::ImEnabled);
+ qApp->sendEvent(object, &query);
+ setFocusText(query.value(Qt::ImEnabled).toBool());
+}
+
+void OffscreenQmlSurface::setFocusText(bool newFocusText) {
+ if (newFocusText != _focusText) {
+ _focusText = newFocusText;
+ emit focusTextChanged(_focusText);
+ }
+}
diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.h b/libraries/gl/src/gl/OffscreenQmlSurface.h
index 22a1b99fe6..1ce7276877 100644
--- a/libraries/gl/src/gl/OffscreenQmlSurface.h
+++ b/libraries/gl/src/gl/OffscreenQmlSurface.h
@@ -30,7 +30,7 @@ class OffscreenQmlRenderThread;
class OffscreenQmlSurface : public QObject {
Q_OBJECT
-
+ Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged)
public:
OffscreenQmlSurface();
virtual ~OffscreenQmlSurface();
@@ -55,6 +55,7 @@ public:
_mouseTranslator = mouseTranslator;
}
+ bool isFocusText() const { return _focusText; }
void pause();
void resume();
bool isPaused() const;
@@ -70,6 +71,8 @@ public:
signals:
void textureUpdated(unsigned int texture);
+ void focusObjectChanged(QObject* newFocus);
+ void focusTextChanged(bool focusText);
public slots:
void requestUpdate();
@@ -78,6 +81,7 @@ public slots:
protected:
bool filterEnabled(QObject* originalDestination, QEvent* event) const;
+ void setFocusText(bool newFocusText);
private:
QObject* finishQmlLoad(std::function f);
@@ -85,6 +89,7 @@ private:
private slots:
void updateQuick();
+ void onFocusObjectChanged(QObject* newFocus);
private:
friend class OffscreenQmlRenderThread;
@@ -97,6 +102,7 @@ private:
bool _render{ false };
bool _polish{ true };
bool _paused{ true };
+ bool _focusText { false };
uint8_t _maxFps{ 60 };
MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p.toPoint(); } };
QWindow* _proxyWindow { nullptr };
diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
index 4d59adb602..32c28af2ef 100644
--- a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
+++ b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp
@@ -25,7 +25,6 @@ InputPluginList getInputPlugins() {
for (int i = 0; PLUGIN_POOL[i]; ++i) {
InputPlugin* plugin = PLUGIN_POOL[i];
if (plugin->isSupported()) {
- plugin->init();
result.push_back(InputPluginPointer(plugin));
}
}
diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp
index eb6465aab2..7161132c5e 100644
--- a/libraries/plugins/src/plugins/PluginManager.cpp
+++ b/libraries/plugins/src/plugins/PluginManager.cpp
@@ -25,6 +25,50 @@ PluginManager* PluginManager::getInstance() {
return &_manager;
}
+QString getPluginNameFromMetaData(QJsonObject object) {
+ static const char* METADATA_KEY = "MetaData";
+ static const char* NAME_KEY = "name";
+
+ if (!object.contains(METADATA_KEY) || !object[METADATA_KEY].isObject()) {
+ return QString();
+ }
+
+ auto metaDataObject = object[METADATA_KEY].toObject();
+
+ if (!metaDataObject.contains(NAME_KEY) || !metaDataObject[NAME_KEY].isString()) {
+ return QString();
+ }
+
+ return metaDataObject[NAME_KEY].toString();
+}
+
+QString getPluginIIDFromMetaData(QJsonObject object) {
+ static const char* IID_KEY = "IID";
+
+ if (!object.contains(IID_KEY) || !object[IID_KEY].isString()) {
+ return QString();
+ }
+
+ return object[IID_KEY].toString();
+}
+
+QStringList preferredDisplayPlugins;
+QStringList disabledDisplays;
+QStringList disabledInputs;
+
+bool isDisabled(QJsonObject metaData) {
+ auto name = getPluginNameFromMetaData(metaData);
+ auto iid = getPluginIIDFromMetaData(metaData);
+
+ if (iid == DisplayProvider_iid) {
+ return disabledDisplays.contains(name);
+ } else if (iid == InputProvider_iid) {
+ return disabledInputs.contains(name);
+ }
+
+ return false;
+}
+
using Loader = QSharedPointer;
using LoaderList = QList;
@@ -43,11 +87,21 @@ const LoaderList& getLoadedPlugins() {
qDebug() << "Loading runtime plugins from " << pluginPath;
auto candidates = pluginDir.entryList();
for (auto plugin : candidates) {
- qDebug() << "Attempting plugins " << plugin;
+ qDebug() << "Attempting plugin" << qPrintable(plugin);
QSharedPointer loader(new QPluginLoader(pluginPath + plugin));
+
+ if (isDisabled(loader->metaData())) {
+ qWarning() << "Plugin" << qPrintable(plugin) << "is disabled";
+ // Skip this one, it's disabled
+ continue;
+ }
+
if (loader->load()) {
- qDebug() << "Plugins " << plugin << " success";
+ qDebug() << "Plugin" << qPrintable(plugin) << "loaded successfully";
loadedPlugins.push_back(loader);
+ } else {
+ qDebug() << "Plugin" << qPrintable(plugin) << "failed to load:";
+ qDebug() << " " << qPrintable(loader->errorString());
}
}
}
@@ -110,7 +164,9 @@ const InputPluginList& PluginManager::getInputPlugins() {
InputProvider* inputProvider = qobject_cast(loader->instance());
if (inputProvider) {
for (auto inputPlugin : inputProvider->getInputPlugins()) {
- inputPlugins.push_back(inputPlugin);
+ if (inputPlugin->isSupported()) {
+ inputPlugins.push_back(inputPlugin);
+ }
}
}
}
@@ -124,6 +180,40 @@ const InputPluginList& PluginManager::getInputPlugins() {
return inputPlugins;
}
+void PluginManager::setPreferredDisplayPlugins(const QStringList& displays) {
+ preferredDisplayPlugins = displays;
+}
+
+DisplayPluginList PluginManager::getPreferredDisplayPlugins() {
+ static DisplayPluginList displayPlugins;
+
+ static std::once_flag once;
+ std::call_once(once, [&] {
+ // Grab the built in plugins
+ auto plugins = getDisplayPlugins();
+
+ for (auto pluginName : preferredDisplayPlugins) {
+ auto it = std::find_if(plugins.begin(), plugins.end(), [&](DisplayPluginPointer plugin) {
+ return plugin->getName() == pluginName;
+ });
+ if (it != plugins.end()) {
+ displayPlugins.push_back(*it);
+ }
+ }
+ });
+
+ return displayPlugins;
+}
+
+
+void PluginManager::disableDisplays(const QStringList& displays) {
+ disabledDisplays << displays;
+}
+
+void PluginManager::disableInputs(const QStringList& inputs) {
+ disabledInputs << inputs;
+}
+
void PluginManager::saveSettings() {
saveInputPluginSettings(getInputPlugins());
}
diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h
index cf0b8efe64..2a94e6490b 100644
--- a/libraries/plugins/src/plugins/PluginManager.h
+++ b/libraries/plugins/src/plugins/PluginManager.h
@@ -13,11 +13,17 @@
class PluginManager : public QObject {
public:
- static PluginManager* getInstance();
- PluginManager();
+ static PluginManager* getInstance();
+ PluginManager();
- const DisplayPluginList& getDisplayPlugins();
- void disableDisplayPlugin(const QString& name);
- const InputPluginList& getInputPlugins();
- void saveSettings();
+ const DisplayPluginList& getDisplayPlugins();
+ const InputPluginList& getInputPlugins();
+
+ DisplayPluginList getPreferredDisplayPlugins();
+ void setPreferredDisplayPlugins(const QStringList& displays);
+
+ void disableDisplayPlugin(const QString& name);
+ void disableDisplays(const QStringList& displays);
+ void disableInputs(const QStringList& inputs);
+ void saveSettings();
};
diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp
index cad2a0286f..b2f23f5a04 100644
--- a/libraries/shared/src/SettingHandle.cpp
+++ b/libraries/shared/src/SettingHandle.cpp
@@ -28,7 +28,9 @@ Settings::~Settings() {
}
void Settings::remove(const QString& key) {
- _manager->remove(key);
+ if (key == "" || _manager->contains(key)) {
+ _manager->remove(key);
+ }
}
QStringList Settings::childGroups() const {
@@ -72,7 +74,9 @@ void Settings::endGroup() {
}
void Settings::setValue(const QString& name, const QVariant& value) {
- _manager->setValue(name, value);
+ if (_manager->value(name) != value) {
+ _manager->setValue(name, value);
+ }
}
QVariant Settings::value(const QString& name, const QVariant& defaultValue) const {
diff --git a/plugins/hifiNeuron/src/plugin.json b/plugins/hifiNeuron/src/plugin.json
index 0967ef424b..d153b5cebd 100644
--- a/plugins/hifiNeuron/src/plugin.json
+++ b/plugins/hifiNeuron/src/plugin.json
@@ -1 +1 @@
-{}
+{"name":"Neuron"}
diff --git a/plugins/hifiSdl2/src/plugin.json b/plugins/hifiSdl2/src/plugin.json
index 0967ef424b..a65846ecab 100644
--- a/plugins/hifiSdl2/src/plugin.json
+++ b/plugins/hifiSdl2/src/plugin.json
@@ -1 +1 @@
-{}
+{"name":"SDL2"}
diff --git a/plugins/hifiSixense/src/plugin.json b/plugins/hifiSixense/src/plugin.json
index 0967ef424b..9e6e15a354 100644
--- a/plugins/hifiSixense/src/plugin.json
+++ b/plugins/hifiSixense/src/plugin.json
@@ -1 +1 @@
-{}
+{"name":"Sixense"}
diff --git a/plugins/hifiSpacemouse/src/plugin.json b/plugins/hifiSpacemouse/src/plugin.json
index 0967ef424b..294f436039 100644
--- a/plugins/hifiSpacemouse/src/plugin.json
+++ b/plugins/hifiSpacemouse/src/plugin.json
@@ -1 +1 @@
-{}
+{"name":"Spacemouse"}
diff --git a/plugins/oculus/src/oculus.json b/plugins/oculus/src/oculus.json
index 0967ef424b..86546c8dd5 100644
--- a/plugins/oculus/src/oculus.json
+++ b/plugins/oculus/src/oculus.json
@@ -1 +1 @@
-{}
+{"name":"Oculus Rift"}
diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
index f89e71b829..8e044fbc16 100644
--- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
@@ -31,7 +31,7 @@
using namespace oglplus;
-const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift (0.5) (Legacy)");
+const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift");
OculusLegacyDisplayPlugin::OculusLegacyDisplayPlugin() {
}
diff --git a/plugins/oculusLegacy/src/oculus.json b/plugins/oculusLegacy/src/oculus.json
index 0967ef424b..86546c8dd5 100644
--- a/plugins/oculusLegacy/src/oculus.json
+++ b/plugins/oculusLegacy/src/oculus.json
@@ -1 +1 @@
-{}
+{"name":"Oculus Rift"}
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
index fe406cc29a..fbade9fd68 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
@@ -36,12 +36,14 @@ vec3 _trackedDeviceLinearVelocities[vr::k_unMaxTrackedDeviceCount];
vec3 _trackedDeviceAngularVelocities[vr::k_unMaxTrackedDeviceCount];
static mat4 _sensorResetMat;
static std::array VR_EYES { { vr::Eye_Left, vr::Eye_Right } };
+bool _openVrDisplayActive { false };
bool OpenVrDisplayPlugin::isSupported() const {
return openVrSupported();
}
bool OpenVrDisplayPlugin::internalActivate() {
+ _openVrDisplayActive = true;
_container->setIsOptionChecked(StandingHMDSensorMode, true);
if (!_system) {
@@ -94,6 +96,7 @@ bool OpenVrDisplayPlugin::internalActivate() {
void OpenVrDisplayPlugin::internalDeactivate() {
Parent::internalDeactivate();
+ _openVrDisplayActive = false;
_container->setIsOptionChecked(StandingHMDSensorMode, false);
if (_system) {
// Invalidate poses. It's fine if someone else sets these shared values, but we're about to stop updating them, and
diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp
index 155bc9f079..1ff1c65ef8 100644
--- a/plugins/openvr/src/OpenVrHelpers.cpp
+++ b/plugins/openvr/src/OpenVrHelpers.cpp
@@ -14,9 +14,13 @@
#include
#include
#include
+#include
+#include
#include
+#include
+
Q_DECLARE_LOGGING_CATEGORY(displayplugins)
Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display")
@@ -90,6 +94,121 @@ void releaseOpenVrSystem() {
}
}
+static char textArray[8192];
+
+static QMetaObject::Connection _focusConnection, _focusTextConnection;
+extern bool _openVrDisplayActive;
+static vr::IVROverlay* _overlay { nullptr };
+static QObject* _keyboardFocusObject { nullptr };
+static QString _existingText;
+static Qt::InputMethodHints _currentHints;
+extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
+static bool _keyboardShown { false };
+static const uint32_t SHOW_KEYBOARD_DELAY_MS = 100;
+
+void showOpenVrKeyboard(bool show = true) {
+ if (!_overlay) {
+ return;
+ }
+
+ if (show) {
+ // To avoid flickering the keyboard when a text element is only briefly selected,
+ // show the keyboard asynchrnously after a very short delay, but only after we check
+ // that the current focus object is still one that is text enabled
+ QTimer::singleShot(SHOW_KEYBOARD_DELAY_MS, [] {
+ auto offscreenUi = DependencyManager::get();
+ auto currentFocus = offscreenUi->getWindow()->focusObject();
+ QInputMethodQueryEvent query(Qt::ImEnabled | Qt::ImQueryInput | Qt::ImHints);
+ qApp->sendEvent(currentFocus, &query);
+ // Current focus isn't text enabled, bail early.
+ if (!query.value(Qt::ImEnabled).toBool()) {
+ return;
+ }
+ // We're going to show the keyboard now...
+ _keyboardFocusObject = currentFocus;
+ _currentHints = Qt::InputMethodHints(query.value(Qt::ImHints).toUInt());
+ vr::EGamepadTextInputMode inputMode = vr::k_EGamepadTextInputModeNormal;
+ if (_currentHints & Qt::ImhHiddenText) {
+ inputMode = vr::k_EGamepadTextInputModePassword;
+ }
+ vr::EGamepadTextInputLineMode lineMode = vr::k_EGamepadTextInputLineModeSingleLine;
+ if (_currentHints & Qt::ImhMultiLine) {
+ lineMode = vr::k_EGamepadTextInputLineModeMultipleLines;
+ }
+ _existingText = query.value(Qt::ImSurroundingText).toString();
+
+ auto showKeyboardResult = _overlay->ShowKeyboard(inputMode, lineMode, "Keyboard", 1024,
+ _existingText.toLocal8Bit().toStdString().c_str(), false, 0);
+
+ if (vr::VROverlayError_None == showKeyboardResult) {
+ _keyboardShown = true;
+ // Try to position the keyboard slightly below where the user is looking.
+ mat4 headPose = toGlm(_trackedDevicePose[0].mDeviceToAbsoluteTracking);
+ mat4 keyboardTransform = glm::translate(headPose, vec3(0, -0.5, -1));
+ keyboardTransform = keyboardTransform * glm::rotate(mat4(), 3.14159f / 4.0f, vec3(-1, 0, 0));
+ auto keyboardTransformVr = toOpenVr(keyboardTransform);
+ _overlay->SetKeyboardTransformAbsolute(vr::ETrackingUniverseOrigin::TrackingUniverseStanding, &keyboardTransformVr);
+ }
+ });
+ } else {
+ _keyboardFocusObject = nullptr;
+ if (_keyboardShown) {
+ _overlay->HideKeyboard();
+ _keyboardShown = false;
+ }
+ }
+}
+
+void finishOpenVrKeyboardInput() {
+ auto offscreenUi = DependencyManager::get();
+ auto chars = _overlay->GetKeyboardText(textArray, 8192);
+ auto newText = QString(QByteArray(textArray, chars));
+ // TODO modify the new text to match the possible input hints:
+ // ImhDigitsOnly ImhFormattedNumbersOnly ImhUppercaseOnly ImhLowercaseOnly
+ // ImhDialableCharactersOnly ImhEmailCharactersOnly ImhUrlCharactersOnly ImhLatinOnly
+ QInputMethodEvent event(_existingText, QList());
+ event.setCommitString(newText, 0, _existingText.size());
+ qApp->sendEvent(_keyboardFocusObject, &event);
+ // Simulate an enter press on the top level window to trigger the action
+ if (0 == (_currentHints & Qt::ImhMultiLine)) {
+ qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n")));
+ qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers()));
+ }
+}
+
+static const QString DEBUG_FLAG("HIFI_DISABLE_STEAM_VR_KEYBOARD");
+bool disableSteamVrKeyboard = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
+
+void enableOpenVrKeyboard() {
+ if (disableSteamVrKeyboard) {
+ return;
+ }
+ auto offscreenUi = DependencyManager::get();
+ _overlay = vr::VROverlay();
+
+ _focusConnection = QObject::connect(offscreenUi->getWindow(), &QQuickWindow::focusObjectChanged, [](QObject* object) {
+ if (object != _keyboardFocusObject) {
+ showOpenVrKeyboard(false);
+ }
+ });
+
+ _focusTextConnection = QObject::connect(offscreenUi.data(), &OffscreenUi::focusTextChanged, [](bool focusText) {
+ if (_openVrDisplayActive) {
+ showOpenVrKeyboard(focusText);
+ }
+ });
+}
+
+
+void disableOpenVrKeyboard() {
+ if (disableSteamVrKeyboard) {
+ return;
+ }
+ QObject::disconnect(_focusTextConnection);
+ QObject::disconnect(_focusConnection);
+}
+
+
void handleOpenVrEvents() {
if (!activeHmd) {
return;
@@ -107,6 +226,10 @@ void handleOpenVrEvents() {
activeHmd->AcknowledgeQuit_Exiting();
break;
+ case vr::VREvent_KeyboardDone:
+ finishOpenVrKeyboardInput();
+ break;
+
default:
break;
}
@@ -114,3 +237,4 @@ void handleOpenVrEvents() {
}
}
+
diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h
index 1e5914844c..426178cd65 100644
--- a/plugins/openvr/src/OpenVrHelpers.h
+++ b/plugins/openvr/src/OpenVrHelpers.h
@@ -18,6 +18,9 @@ vr::IVRSystem* acquireOpenVrSystem();
void releaseOpenVrSystem();
void handleOpenVrEvents();
bool openVrQuitRequested();
+void enableOpenVrKeyboard();
+void disableOpenVrKeyboard();
+
template
void openvr_for_each_eye(F f) {
@@ -41,3 +44,13 @@ inline mat4 toGlm(const vr::HmdMatrix34_t& m) {
m.m[0][3], m.m[1][3], m.m[2][3], 1.0f);
return result;
}
+
+inline vr::HmdMatrix34_t toOpenVr(const mat4& m) {
+ vr::HmdMatrix34_t result;
+ for (uint8_t i = 0; i < 3; ++i) {
+ for (uint8_t j = 0; j < 4; ++j) {
+ result.m[i][j] = m[j][i];
+ }
+ }
+ return result;
+}
diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp
index 739d3cde10..6d3ce46e82 100644
--- a/plugins/openvr/src/ViveControllerManager.cpp
+++ b/plugins/openvr/src/ViveControllerManager.cpp
@@ -11,8 +11,6 @@
#include "ViveControllerManager.h"
-#include
-
#include
#include
#include
@@ -22,6 +20,7 @@
#include
#include
#include
+#include
#include
@@ -68,6 +67,8 @@ bool ViveControllerManager::activate() {
}
Q_ASSERT(_system);
+ enableOpenVrKeyboard();
+
// OpenVR provides 3d mesh representations of the controllers
// Disabled controller rendering code
/*
@@ -132,6 +133,8 @@ bool ViveControllerManager::activate() {
void ViveControllerManager::deactivate() {
InputPlugin::deactivate();
+ disableOpenVrKeyboard();
+
_container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
_container->removeMenu(MENU_PATH);
diff --git a/plugins/openvr/src/plugin.json b/plugins/openvr/src/plugin.json
index 0967ef424b..d68c8e68d3 100644
--- a/plugins/openvr/src/plugin.json
+++ b/plugins/openvr/src/plugin.json
@@ -1 +1 @@
-{}
+{"name":"OpenVR (Vive)"}
diff --git a/scripts/system/assets/images/tools/hmd-switch-01.svg b/scripts/system/assets/images/tools/hmd-switch-01.svg
index 15ecb02b6b..31389d355c 100644
--- a/scripts/system/assets/images/tools/hmd-switch-01.svg
+++ b/scripts/system/assets/images/tools/hmd-switch-01.svg
@@ -4,99 +4,121 @@
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js
index be4bffe58c..8a96e9d80c 100644
--- a/scripts/system/controllers/handControllerGrab.js
+++ b/scripts/system/controllers/handControllerGrab.js
@@ -92,6 +92,7 @@ var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new posit
// other constants
//
+var HOTSPOT_DRAW_DISTANCE = 10;
var RIGHT_HAND = 1;
var LEFT_HAND = 0;
@@ -179,47 +180,85 @@ var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic";
var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC;
var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC;
-function stateToName(state) {
- switch (state) {
- case STATE_OFF:
- return "off";
- case STATE_SEARCHING:
- return "searching";
- case STATE_HOLD_SEARCHING:
- return "hold_searching";
- case STATE_DISTANCE_HOLDING:
- return "distance_holding";
- case STATE_CONTINUE_DISTANCE_HOLDING:
- return "continue_distance_holding";
- case STATE_NEAR_GRABBING:
- return "near_grabbing";
- case STATE_CONTINUE_NEAR_GRABBING:
- return "continue_near_grabbing";
- case STATE_NEAR_TRIGGER:
- return "near_trigger";
- case STATE_CONTINUE_NEAR_TRIGGER:
- return "continue_near_trigger";
- case STATE_FAR_TRIGGER:
- return "far_trigger";
- case STATE_CONTINUE_FAR_TRIGGER:
- return "continue_far_trigger";
- case STATE_RELEASE:
- return "release";
- case STATE_EQUIP:
- return "equip";
- case STATE_HOLD:
- return "hold";
- case STATE_CONTINUE_HOLD:
- return "continue_hold";
- case STATE_CONTINUE_EQUIP:
- return "continue_equip";
- case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE:
- return "waiting_for_equip_thumb_release";
- case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE:
- return "waiting_for_release_thumb_release";
- }
+var CONTROLLER_STATE_MACHINE = {};
- return "unknown";
+CONTROLLER_STATE_MACHINE[STATE_OFF] = {
+ name: "off",
+ updateMethod: "off"
+};
+CONTROLLER_STATE_MACHINE[STATE_SEARCHING] = {
+ name: "searching",
+ updateMethod: "search",
+ enterMethod: "searchEnter",
+ exitMethod: "searchExit"
+};
+CONTROLLER_STATE_MACHINE[STATE_HOLD_SEARCHING] = {
+ name: "hold_searching",
+ updateMethod: "search"
+};
+CONTROLLER_STATE_MACHINE[STATE_DISTANCE_HOLDING] = {
+ name: "distance_holding",
+ updateMethod: "distanceHolding"
+};
+CONTROLLER_STATE_MACHINE[STATE_CONTINUE_DISTANCE_HOLDING] = {
+ name: "continue_distance_holding",
+ updateMethod: "continueDistanceHolding"
+};
+CONTROLLER_STATE_MACHINE[STATE_NEAR_GRABBING] = {
+ name: "near_grabbing",
+ updateMethod: "nearGrabbing"
+};
+CONTROLLER_STATE_MACHINE[STATE_EQUIP] = {
+ name: "equip",
+ updateMethod: "nearGrabbing"
+};
+CONTROLLER_STATE_MACHINE[STATE_HOLD] = {
+ name: "hold",
+ updateMethod: "nearGrabbing"
+};
+CONTROLLER_STATE_MACHINE[STATE_CONTINUE_NEAR_GRABBING] = {
+ name: "continue_near_grabbing",
+ updateMethod: "continueNearGrabbing"
+};
+CONTROLLER_STATE_MACHINE[STATE_CONTINUE_HOLD] = {
+ name: "continue_hold",
+ updateMethod: "continueNearGrabbing"
+};
+CONTROLLER_STATE_MACHINE[STATE_CONTINUE_EQUIP] = {
+ name: "continue_equip",
+ updateMethod: "continueNearGrabbing"
+};
+CONTROLLER_STATE_MACHINE[STATE_NEAR_TRIGGER] = {
+ name: "near_trigger",
+ updateMethod: "nearTrigger"
+};
+CONTROLLER_STATE_MACHINE[STATE_CONTINUE_NEAR_TRIGGER] = {
+ name: "continue_near_trigger",
+ updateMethod: "continueNearTrigger"
+};
+CONTROLLER_STATE_MACHINE[STATE_FAR_TRIGGER] = {
+ name: "far_trigger",
+ updateMethod: "farTrigger"
+};
+CONTROLLER_STATE_MACHINE[STATE_CONTINUE_FAR_TRIGGER] = {
+ name: "continue_far_trigger",
+ updateMethod: "continueFarTrigger"
+};
+CONTROLLER_STATE_MACHINE[STATE_RELEASE] = {
+ name: "release",
+ updateMethod: "release"
+};
+CONTROLLER_STATE_MACHINE[STATE_WAITING_FOR_EQUIP_THUMB_RELEASE] = {
+ name: "waiting_for_equip_thumb_release",
+ updateMethod: "waitingForEquipThumbRelease"
+};
+CONTROLLER_STATE_MACHINE[STATE_WAITING_FOR_RELEASE_THUMB_RELEASE] = {
+ name: "waiting_for_release_thumb_release",
+ updateMethod: "waitingForReleaseThumbRelease"
+};
+
+function stateToName(state) {
+ return CONTROLLER_STATE_MACHINE[state] ? CONTROLLER_STATE_MACHINE[state].name : "???";
}
function getTag() {
@@ -249,6 +288,14 @@ function entityIsGrabbedByOther(entityID) {
return false;
}
+function propsArePhysical(props) {
+ if (!props.dynamic) {
+ return false;
+ }
+ var isPhysical = (props.shapeType && props.shapeType != 'none');
+ return isPhysical;
+}
+
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
@@ -314,55 +361,22 @@ function MyController(hand) {
this.update = function() {
this.updateSmoothedTrigger();
+
if (isIn2DMode()) {
_this.turnOffVisualizations();
return;
}
- switch (this.state) {
- case STATE_OFF:
- this.off();
- break;
- case STATE_SEARCHING:
- case STATE_HOLD_SEARCHING:
- this.search();
- break;
- case STATE_DISTANCE_HOLDING:
- this.distanceHolding();
- break;
- case STATE_CONTINUE_DISTANCE_HOLDING:
- this.continueDistanceHolding();
- break;
- case STATE_NEAR_GRABBING:
- case STATE_EQUIP:
- case STATE_HOLD:
- this.nearGrabbing();
- break;
- case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE:
- this.waitingForEquipThumbRelease();
- break;
- case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE:
- this.waitingForReleaseThumbRelease();
- break;
- case STATE_CONTINUE_NEAR_GRABBING:
- case STATE_CONTINUE_HOLD:
- case STATE_CONTINUE_EQUIP:
- this.continueNearGrabbing();
- break;
- case STATE_NEAR_TRIGGER:
- this.nearTrigger();
- break;
- case STATE_CONTINUE_NEAR_TRIGGER:
- this.continueNearTrigger();
- break;
- case STATE_FAR_TRIGGER:
- this.farTrigger();
- break;
- case STATE_CONTINUE_FAR_TRIGGER:
- this.continueFarTrigger();
- break;
- case STATE_RELEASE:
- this.release();
- break;
+
+ if (CONTROLLER_STATE_MACHINE[this.state]) {
+ var updateMethodName = CONTROLLER_STATE_MACHINE[this.state].updateMethod;
+ var updateMethod = this[updateMethodName];
+ if (updateMethod) {
+ updateMethod.call(this);
+ } else {
+ print("WARNING: could not find updateMethod for state " + stateToName(this.state));
+ }
+ } else {
+ print("WARNING: could not find state " + this.state + " in state machine");
}
};
@@ -374,9 +388,33 @@ function MyController(hand) {
this.setState = function(newState) {
this.grabSphereOff();
if (WANT_DEBUG || WANT_DEBUG_STATE) {
- print("STATE (" + this.hand + "): " + stateToName(this.state) + " --> " +
- stateToName(newState) + ", hand: " + this.hand);
+ var oldStateName = stateToName(this.state);
+ var newStateName = stateToName(newState);
+ print("STATE (" + this.hand + "): " + newStateName + " <-- " + oldStateName);
}
+
+ // exit the old state
+ if (CONTROLLER_STATE_MACHINE[this.state]) {
+ var exitMethodName = CONTROLLER_STATE_MACHINE[this.state].exitMethod;
+ var exitMethod = this[exitMethodName];
+ if (exitMethod) {
+ exitMethod.call(this);
+ }
+ } else {
+ print("WARNING: could not find state " + this.state + " in state machine");
+ }
+
+ // enter the new state
+ if (CONTROLLER_STATE_MACHINE[newState]) {
+ var enterMethodName = CONTROLLER_STATE_MACHINE[newState].enterMethod;
+ var enterMethod = this[enterMethodName];
+ if (enterMethod) {
+ enterMethod.call(this);
+ }
+ } else {
+ print("WARNING: could not find newState " + newState + " in state machine");
+ }
+
this.state = newState;
};
@@ -759,14 +797,6 @@ function MyController(hand) {
}
};
- this.propsArePhysical = function(props) {
- if (!props.dynamic) {
- return false;
- }
- var isPhysical = (props.shapeType && props.shapeType != 'none');
- return isPhysical;
- }
-
this.turnOffVisualizations = function() {
if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) {
this.lineOff();
@@ -852,6 +882,56 @@ function MyController(hand) {
}
};
+ this.searchEnter = function() {
+ this.equipHotspotOverlays = [];
+
+ // find entities near the avatar that might be equipable.
+ var entities = Entities.findEntities(MyAvatar.position, HOTSPOT_DRAW_DISTANCE);
+ var i, l = entities.length;
+ for (i = 0; i < l; i++) {
+
+ // is this entity equipable?
+ var grabData = getEntityCustomData(GRABBABLE_DATA_KEY, entities[i], undefined);
+ var grabProps = Entities.getEntityProperties(entities[i], GRABBABLE_PROPERTIES);
+ if (grabData) {
+
+ var hotspotPos = grabProps.position;
+
+ // does this entity have an attach point?
+ var wearableData = getEntityCustomData("wearable", entities[i], undefined);
+ if (wearableData) {
+ var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
+ if (wearableData[handJointName]) {
+ // draw the hotspot around the attach point.
+ hotspotPos = wearableData[handJointName][0];
+ }
+ }
+
+ // draw a hotspot!
+ this.equipHotspotOverlays.push(Overlays.addOverlay("sphere", {
+ position: hotspotPos,
+ size: 0.2,
+ color: { red: 90, green: 255, blue: 90 },
+ alpha: 0.7,
+ solid: true,
+ visible: true,
+ ignoreRayIntersection: false,
+ drawInFront: false
+ }));
+ }
+ }
+ };
+
+ this.searchExit = function() {
+
+ // delete all equip hotspots
+ var i, l = this.equipHotspotOverlays.length;
+ for (i = 0; i < l; i++) {
+ Overlays.deleteOverlay(this.equipHotspotOverlays[i]);
+ }
+ this.equipHotspotOverlays = [];
+ };
+
this.search = function() {
this.grabbedEntity = null;
this.isInitialGrab = false;
@@ -863,6 +943,7 @@ function MyController(hand) {
this.setState(STATE_RELEASE);
return;
}
+
if (this.state == STATE_HOLD_SEARCHING && this.bumperReleased()) {
this.setState(STATE_RELEASE);
return;
@@ -951,7 +1032,7 @@ function MyController(hand) {
var propsForCandidate = Entities.getEntityProperties(candidateEntities[i], GRABBABLE_PROPERTIES);
var near = (nearPickedCandidateEntities.indexOf(candidateEntities[i]) >= 0);
- var isPhysical = this.propsArePhysical(propsForCandidate);
+ var isPhysical = propsArePhysical(propsForCandidate);
var grabbable;
if (isPhysical) {
// physical things default to grabbable
@@ -1030,7 +1111,7 @@ function MyController(hand) {
if ((this.grabbedEntity !== null) && (this.triggerSmoothedGrab() || this.bumperSqueezed())) {
// We are squeezing enough to grab, and we've found an entity that we'll try to do something with.
var near = (nearPickedCandidateEntities.indexOf(this.grabbedEntity) >= 0) || minDistance <= NEAR_PICK_MAX_DISTANCE;
- var isPhysical = this.propsArePhysical(props);
+ var isPhysical = propsArePhysical(props);
// near or far trigger
if (grabbableData.wantsTrigger) {
@@ -1462,7 +1543,7 @@ function MyController(hand) {
}
}
- var isPhysical = this.propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity);
+ var isPhysical = propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity);
if (isPhysical && this.state == STATE_NEAR_GRABBING) {
// grab entity via action
if (!this.setupHoldAction()) {
@@ -1879,7 +1960,7 @@ function MyController(hand) {
var forceVelocity = false;
var doSetVelocity = false;
- if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && this.propsArePhysical(props)) {
+ if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && propsArePhysical(props)) {
// TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up
// props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that
// is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab
diff --git a/scripts/system/edit.js b/scripts/system/edit.js
index afbc679ec4..38d596f83e 100644
--- a/scripts/system/edit.js
+++ b/scripts/system/edit.js
@@ -181,7 +181,7 @@ var toolBar = (function() {
function initialize() {
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.edit.toolbar", function(windowDimensions, toolbar) {
return {
- x: windowDimensions.x / 2,
+ x: (windowDimensions.x / 2) + (Tool.IMAGE_WIDTH * 2),
y: windowDimensions.y
};
}, {
diff --git a/scripts/system/examples.js b/scripts/system/examples.js
index 9d33e473af..6f4268182c 100644
--- a/scripts/system/examples.js
+++ b/scripts/system/examples.js
@@ -60,7 +60,7 @@ var toolBar = (function() {
function initialize() {
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.examples.toolbar", function(windowDimensions, toolbar) {
return {
- x: windowDimensions.x / 2,
+ x: (windowDimensions.x / 2) + (Tool.IMAGE_WIDTH * 2),
y: windowDimensions.y
};
}, {
@@ -135,4 +135,4 @@ var toolBar = (function() {
}());
Controller.mousePressEvent.connect(toolBar.mousePressEvent)
-Script.scriptEnding.connect(toolBar.cleanup);
\ No newline at end of file
+Script.scriptEnding.connect(toolBar.cleanup);
diff --git a/scripts/system/goto.js b/scripts/system/goto.js
index 75d9829905..00b5e912c0 100644
--- a/scripts/system/goto.js
+++ b/scripts/system/goto.js
@@ -13,7 +13,7 @@ Script.include("libraries/toolBars.js");
function initialPosition(windowDimensions, toolbar) {
return {
- x: windowDimensions.x / 2 - Tool.IMAGE_WIDTH,
+ x: (windowDimensions.x / 2) - (Tool.IMAGE_WIDTH * 1),
y: windowDimensions.y
};
}
diff --git a/scripts/system/hmd.js b/scripts/system/hmd.js
index 277af68315..8b91e45676 100644
--- a/scripts/system/hmd.js
+++ b/scripts/system/hmd.js
@@ -22,7 +22,7 @@ var desktopMenuItemName = "Desktop";
function initialPosition(windowDimensions, toolbar) {
return {
- x: windowDimensions.x / 2 + (2 * Tool.IMAGE_WIDTH),
+ x: (windowDimensions.x / 2) - (Tool.IMAGE_WIDTH * 2.5),
y: windowDimensions.y
};
}
diff --git a/tests/ui/qml/main.qml b/tests/ui/qml/main.qml
index d752734de4..33408fb821 100644
--- a/tests/ui/qml/main.qml
+++ b/tests/ui/qml/main.qml
@@ -51,7 +51,7 @@ ApplicationWindow {
Button {
text: "toggle desktop"
- onClicked: desktop.toggleVisible()
+ onClicked: desktop.togglePinned()
}
// Error alerts