diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index cf61a2ae4a..69411edce5 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -177,7 +177,7 @@ ScrollingWindow { SHAPE_TYPE_STATIC_MESH ], checkStateOnDisable: false, - warningOnDisable: "Models with automatic collisions set to 'Exact' cannot be dynamic" + warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic" } }); diff --git a/interface/resources/qml/dialogs/CustomQueryDialog.qml b/interface/resources/qml/dialogs/CustomQueryDialog.qml index 97f55d087b..4d6fe74bca 100644 --- a/interface/resources/qml/dialogs/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/CustomQueryDialog.qml @@ -107,10 +107,10 @@ ModalWindow { QtObject { id: d; - readonly property int minWidth: 480; - readonly property int maxWdith: 1280; - readonly property int minHeight: 120; - readonly property int maxHeight: 720; + readonly property int minWidth: 480 + readonly property int maxWdith: 1280 + readonly property int minHeight: 120 + readonly property int maxHeight: 720 function resize() { var targetWidth = Math.max(titleWidth, pane.width); @@ -259,6 +259,7 @@ ModalWindow { visible: Boolean(root.warning); text: hifi.glyphs.alert; size: hifi.dimensions.controlLineHeight; + width: 20 // Line up with checkbox. } } diff --git a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml index 3f6e07da4f..7965006b8b 100644 --- a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs -import "../controls-uit" as ControlsUIT +import "../controls-uit" import "../styles-uit" import "../windows" @@ -20,7 +20,9 @@ TabletModalWindow { id: root; HifiConstants { id: hifi; } - y: hifi.dimensions.tabletMenuHeader + anchors.fill: parent + width: parent.width + height: parent.height title: "" visible: true; @@ -108,18 +110,24 @@ TabletModalWindow { TabletModalFrame { id: modalWindowItem - width: parent.width - 12 + width: parent.width - 6 height: 240 anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } + MouseArea { + // Clicking dialog background defocuses active control. + anchors.fill: parent + onClicked: parent.forceActiveFocus(); + } + QtObject { id: d; readonly property int minWidth: 470 readonly property int maxWidth: 470 - readonly property int minHeight: 240 + readonly property int minHeight: 120 readonly property int maxHeight: 720 function resize() { @@ -130,8 +138,8 @@ TabletModalWindow { ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + hifi.dimensions.contentSpacing.y) : 0); root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth); - root.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? - d.maxHeight : targetHeight); + modalWindowItem.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? + d.maxHeight : targetHeight); if (checkBoxField.visible && comboBoxField.visible) { checkBoxField.width = extraInputs.width / 2; comboBoxField.width = extraInputs.width / 2; @@ -140,141 +148,149 @@ TabletModalWindow { } } } -// Item { -// anchors { -// // top: parent.top; -// // bottom: extraInputs.visible ? extraInputs.top : buttons.top; -// left: parent.left; -// right: parent.right; -// topMargin: 20 -// } + + Item { + anchors { + top: parent.top; + bottom: extraInputs.visible ? extraInputs.top : buttons.top; + left: parent.left; + right: parent.right; + leftMargin: 12 + rightMargin: 12 + } // FIXME make a text field type that can be bound to a history for autocompletion - ControlsUIT.TextField { + TextField { id: textField; label: root.textInput.label; focus: root.textInput ? true : false; visible: root.textInput ? true : false; anchors { - top: parent.top left: parent.left; right: parent.right; - leftMargin: 5; rightMargin: 5; - topMargin: textField.controlHeight - textField.height + 5 + bottom: keyboard.top; + bottomMargin: hifi.dimensions.contentSpacing.y; } } - ControlsUIT.Keyboard { + property alias keyboardOverride: root.keyboardOverride + property alias keyboardRaised: root.keyboardRaised + property alias punctuationMode: root.punctuationMode + Keyboard { id: keyboard raised: keyboardEnabled && keyboardRaised numeric: punctuationMode anchors { left: parent.left right: parent.right - leftMargin: 5; rightMargin: 5; - top: textField.bottom - topMargin: raised ? hifi.dimensions.contentSpacing.y : 0 + bottom: parent.bottom + bottomMargin: raised ? hifi.dimensions.contentSpacing.y : 0 } } - // } + } - Row { - id: extraInputs; - visible: Boolean(root.checkBox || root.comboBox); + Item { + id: extraInputs; + visible: Boolean(root.checkBox || root.comboBox); + anchors { + left: parent.left; + right: parent.right; + bottom: buttons.top; + bottomMargin: hifi.dimensions.contentSpacing.y; + leftMargin: 12 + rightMargin: 12 + } + height: comboBoxField.controlHeight; + onHeightChanged: d.resize(); + onWidthChanged: d.resize(); + z: 20 + + CheckBox { + id: checkBoxField; + text: root.checkBox.label; + focus: Boolean(root.checkBox); + visible: Boolean(root.checkBox); anchors { left: parent.left; - right: parent.right; - leftMargin: 5; rightMargin: 5; - top: keyboard.bottom; - topMargin: hifi.dimensions.contentSpacing.y + 20; - } - height: comboBoxField.controlHeight; - onHeightChanged: d.resize(); - onWidthChanged: d.resize(); - - ControlsUIT.CheckBox { - id: checkBoxField; - text: root.checkBox.label; - focus: Boolean(root.checkBox); - visible: Boolean(root.checkBox); - // anchors { - // left: parent.left; - // bottom: parent.bottom; - // leftMargin: 6; // Magic number to align with warning icon - // bottomMargin: 6; - // } - } - - ControlsUIT.ComboBox { - id: comboBoxField; - label: root.comboBox.label; - focus: Boolean(root.comboBox); - visible: Boolean(root.comboBox); - // anchors { - // right: parent.right; - // bottom: parent.bottom; - // } - model: root.comboBox ? root.comboBox.items : []; - onAccepted: { - updateCheckbox(); - focus = true; - } - } - } - - Row { - id: buttons; - focus: true; - spacing: hifi.dimensions.contentSpacing.x; - layoutDirection: Qt.RightToLeft; - onHeightChanged: d.resize(); - onWidthChanged: { - d.resize(); - resizeWarningText(); - } - - anchors { bottom: parent.bottom; - left: parent.left; - right: parent.right; - bottomMargin: hifi.dimensions.contentSpacing.y; - leftMargin: 5; rightMargin: 5; - } - - function resizeWarningText() { - var rowWidth = buttons.width; - var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2; - var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x; - warningText.width = rowWidth - buttonsWidth - warningIconWidth; - } - - ControlsUIT.Button { - id: cancelButton; - action: cancelAction; - } - - ControlsUIT.Button { - id: acceptButton; - action: acceptAction; - } - - Text { - id: warningText; - visible: Boolean(root.warning); - text: root.warning; - wrapMode: Text.WordWrap; - font.italic: true; - maximumLineCount: 2; - } - - HiFiGlyphs { - id: warningIcon; - visible: Boolean(root.warning); - text: hifi.glyphs.alert; - size: hifi.dimensions.controlLineHeight; + leftMargin: 6; // Magic number to align with warning icon + bottomMargin: 6; } } -// }//column + + ComboBox { + id: comboBoxField; + label: root.comboBox.label; + focus: Boolean(root.comboBox); + visible: Boolean(root.comboBox); + anchors { + right: parent.right; + bottom: parent.bottom; + } + model: root.comboBox ? root.comboBox.items : []; + onAccepted: { + updateCheckbox(); + focus = true; + } + } + } + + Row { + id: buttons; + focus: true; + spacing: hifi.dimensions.contentSpacing.x; + layoutDirection: Qt.RightToLeft; + onHeightChanged: d.resize(); + onWidthChanged: { + d.resize(); + resizeWarningText(); + } + z: 10 + + anchors { + bottom: parent.bottom; + left: parent.left; + right: parent.right; + bottomMargin: hifi.dimensions.contentSpacing.y; + leftMargin: 12 + rightMargin: 12 + } + + function resizeWarningText() { + var rowWidth = buttons.width; + var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2; + var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x; + warningText.width = rowWidth - buttonsWidth - warningIconWidth; + } + + Button { + id: cancelButton; + action: cancelAction; + } + + Button { + id: acceptButton; + action: acceptAction; + } + + Text { + id: warningText; + visible: Boolean(root.warning); + text: root.warning; + wrapMode: Text.WordWrap; + font.italic: true; + maximumLineCount: 2; + } + + HiFiGlyphs { + id: warningIcon; + visible: Boolean(root.warning); + text: hifi.glyphs.alert; + size: hifi.dimensions.controlLineHeight; + width: 20 // Line up with checkbox. + } + } + Action { id: cancelAction; text: qsTr("Cancel"); diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index 93e18c7aba..2460fc39d5 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -176,7 +176,7 @@ Rectangle { SHAPE_TYPE_STATIC_MESH ], checkStateOnDisable: false, - warningOnDisable: "Models with automatic collisions set to 'Exact' cannot be dynamic" + warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic" } }); diff --git a/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml new file mode 100644 index 0000000000..b33b957e15 --- /dev/null +++ b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml @@ -0,0 +1,160 @@ +// +// TabletDCDialog.qml +// +// Created by Vlad Stelmahovsky on 3/15/17 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import Qt.labs.settings 1.0 + +import "../../styles-uit" +import "../../controls-uit" as HifiControls +import "../../windows" + +Rectangle { + id: root + objectName: "DCConectionTiming" + + property var eventBridge; + signal sendToScript(var message); + property bool isHMD: false + + color: hifi.colors.baseGray + + property int colorScheme: hifi.colorSchemes.dark + + HifiConstants { id: hifi } + + Component.onCompleted: DCModel.refresh() + + Row { + id: header + anchors.top: parent.top + anchors.topMargin: hifi.dimensions.tabletMenuHeader + anchors.leftMargin: 5 + anchors.rightMargin: 5 + anchors.left: parent.left + anchors.right: parent.right + + HifiControls.Label { + id: nameButton + text: qsTr("Name") + size: 15 + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + height: 40 + width: 175 + } + HifiControls.Label { + id: tsButton + text: qsTr("Timestamp\n(ms)") + size: 15 + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + height: 40 + width: 125 + } + HifiControls.Label { + id: deltaButton + text: qsTr("Delta\n(ms)") + size: 15 + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + height: 40 + width: 80 + } + HifiControls.Label { + id: elapseButton + text: qsTr("Time elapsed\n(ms)") + size: 15 + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + height: 40 + width: 80 + } + } + + ListView { + anchors.leftMargin: 5 + anchors.rightMargin: 5 + anchors.left: parent.left + anchors.right: parent.right + anchors.top: header.bottom + anchors.topMargin: 5 + anchors.bottom: refreshButton.top + anchors.bottomMargin: 10 + clip: true + snapMode: ListView.SnapToItem + + model: DCModel + + delegate: Rectangle { + anchors.left: parent.left + anchors.right: parent.right + height: 30 + color: index % 2 === 0 ? hifi.colors.baseGray : hifi.colors.lightGray + Row { + anchors.fill: parent + spacing: 5 + HifiControls.Label { + size: 15 + text: name + color: "white" + anchors.verticalCenter: parent.verticalCenter + colorScheme: root.colorScheme + width: nameButton.width + } + HifiControls.Label { + size: 15 + text: timestamp + color: "white" + anchors.verticalCenter: parent.verticalCenter + colorScheme: root.colorScheme + horizontalAlignment: Text.AlignHCenter + width: tsButton.width + } + HifiControls.Label { + size: 15 + text: delta + color: "white" + anchors.verticalCenter: parent.verticalCenter + colorScheme: root.colorScheme + horizontalAlignment: Text.AlignHCenter + width: deltaButton.width + } + HifiControls.Label { + size: 15 + text: timeelapsed + color: "white" + anchors.verticalCenter: parent.verticalCenter + colorScheme: root.colorScheme + horizontalAlignment: Text.AlignHCenter + width: elapseButton.width + } + } + } + } + + HifiControls.Button { + id: refreshButton + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + text: qsTr("Refresh") + color: hifi.buttons.blue + colorScheme: root.colorScheme + height: 30 + onClicked: { + DCModel.refresh() + } + } +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 040ee46bb8..d78fc295a7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -171,6 +171,7 @@ #include "ui/Stats.h" #include "ui/UpdateDialog.h" #include "ui/overlays/Overlays.h" +#include "ui/DomainConnectionModel.h" #include "Util.h" #include "InterfaceParentFinder.h" #include "ui/OctreeStatsProvider.h" @@ -501,6 +502,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); #if defined(Q_OS_MAC) || defined(Q_OS_WIN) DependencyManager::set(); @@ -6412,8 +6414,19 @@ void Application::loadEntityStatisticsDialog() { } else { tablet->pushOntoStack("../../hifi/dialogs/TabletEntityStatistics.qml"); } - } + +void Application::loadDomainConnectionDialog() { + auto tabletScriptingInterface = DependencyManager::get(); + auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); + if (tablet->getToolbarMode() || (!tablet->getTabletRoot() && !isHMDMode())) { + auto dialogsManager = DependencyManager::get(); + dialogsManager->showDomainConnectionDialog(); + } else { + tablet->pushOntoStack("../../hifi/dialogs/TabletDCDialog.qml"); + } +} + void Application::toggleLogDialog() { if (! _logDialog) { _logDialog = new LogDialog(nullptr, getLogger()); diff --git a/interface/src/Application.h b/interface/src/Application.h index 2ed54a05d8..653b724364 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -405,6 +405,7 @@ public slots: Q_INVOKABLE void toggleMuteAudio(); void loadLODToolsDialog(); void loadEntityStatisticsDialog(); + void loadDomainConnectionDialog(); private slots: void showDesktop(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2ae66af14b..b95b4d28b9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -572,7 +572,7 @@ Menu::Menu() { addActionToQMenuAndActionHash(networkMenu, MenuOption::DiskCacheEditor, 0, dialogsManager.data(), SLOT(toggleDiskCacheEditor())); addActionToQMenuAndActionHash(networkMenu, MenuOption::ShowDSConnectTable, 0, - dialogsManager.data(), SLOT(showDomainConnectionDialog())); + qApp, SLOT(loadDomainConnectionDialog())); #if (PR_BUILD || DEV_BUILD) addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::SendWrongProtocolVersion, 0, false, diff --git a/interface/src/ui/DomainConnectionModel.cpp b/interface/src/ui/DomainConnectionModel.cpp new file mode 100644 index 0000000000..b9e4c1348e --- /dev/null +++ b/interface/src/ui/DomainConnectionModel.cpp @@ -0,0 +1,101 @@ +// +// DomainConnectionModel.cpp +// +// Created by Vlad Stelmahovsky +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "DomainConnectionModel.h" +#include + +#include +#include + +Q_LOGGING_CATEGORY(dcmodel, "hifi.dcmodel") + +DomainConnectionModel::DomainConnectionModel(QAbstractItemModel* parent) : + QAbstractItemModel(parent) +{} + +DomainConnectionModel::~DomainConnectionModel() { +} + +QVariant DomainConnectionModel::data(const QModelIndex& index, int role) const { + //sanity + const QMap × = + DependencyManager::get()->getLastConnectionTimes(); + + if (!index.isValid() || index.row() >= times.size()) + return QVariant(); + + // setup our data with the values from the NodeList + quint64 firstStepTime = times.firstKey() / USECS_PER_MSEC; + quint64 timestamp = times.keys().at(index.row()); + + quint64 stepTime = timestamp / USECS_PER_MSEC; + quint64 delta = 0;//(stepTime - lastStepTime); + quint64 elapsed = 0;//stepTime - firstStepTime; + + if (index.row() > 0) { + quint64 prevstepTime = times.keys().at(index.row() - 1) / USECS_PER_MSEC; + delta = (stepTime - prevstepTime); + elapsed = stepTime - firstStepTime; + } + + if (role == Qt::DisplayRole || role == DisplayNameRole) { + const QMetaObject &nodeListMeta = NodeList::staticMetaObject; + QMetaEnum stepEnum = nodeListMeta.enumerator(nodeListMeta.indexOfEnumerator("ConnectionStep")); + int stepIndex = (int) times.value(timestamp); + return stepEnum.valueToKey(stepIndex); + } else if (role == DeltaRole) { + return delta; + } else if (role == TimestampRole) { + return stepTime; + } else if (role == TimeElapsedRole) { + return elapsed; + } + return QVariant(); +} + +int DomainConnectionModel::rowCount(const QModelIndex& parent) const { + Q_UNUSED(parent) + const QMap × = + DependencyManager::get()->getLastConnectionTimes(); + return times.size(); +} + +QHash DomainConnectionModel::roleNames() const { + QHash roles; + roles.insert(DisplayNameRole, "name"); + roles.insert(TimestampRole, "timestamp"); + roles.insert(DeltaRole, "delta"); + roles.insert(TimeElapsedRole, "timeelapsed"); + return roles; +} + +QModelIndex DomainConnectionModel::index(int row, int column, const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return createIndex(row, column); +} + +QModelIndex DomainConnectionModel::parent(const QModelIndex &child) const +{ + Q_UNUSED(child) + return QModelIndex(); +} + +int DomainConnectionModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return 1; +} + +void DomainConnectionModel::refresh() { + //inform view that we want refresh data + beginResetModel(); + endResetModel(); +} \ No newline at end of file diff --git a/interface/src/ui/DomainConnectionModel.h b/interface/src/ui/DomainConnectionModel.h new file mode 100644 index 0000000000..11ecb23bd2 --- /dev/null +++ b/interface/src/ui/DomainConnectionModel.h @@ -0,0 +1,47 @@ +// +// DomainConnectionModel.h +// +// Created by Vlad Stelmahovsky +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#ifndef hifi_DomainConnectionModel_h +#define hifi_DomainConnectionModel_h + +#include +#include + +class DomainConnectionModel : public QAbstractItemModel, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY +public: + DomainConnectionModel(QAbstractItemModel* parent = nullptr); + ~DomainConnectionModel(); + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QHash roleNames() const override; + + QModelIndex index(int row, int column, const QModelIndex& parent) const override; + QModelIndex parent(const QModelIndex& child) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + + enum Roles { + DisplayNameRole = Qt::UserRole, + TimestampRole, + DeltaRole, + TimeElapsedRole + }; + +public slots: + void refresh(); + +protected: + +private: +}; + +#endif // hifi_DomainConnectionModel_h diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index e239a5e456..fa815421c7 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -45,6 +45,7 @@ #include "AudioClient.h" #include "LODManager.h" #include "ui/OctreeStatsProvider.h" +#include "ui/DomainConnectionModel.h" static const float DPI = 30.47f; static const float INCHES_TO_METERS = 1.0f / 39.3701f; @@ -187,6 +188,7 @@ void Web3DOverlay::loadSourceURL() { _webSurface->getRootContext()->setContextProperty("Assets", DependencyManager::get().data()); _webSurface->getRootContext()->setContextProperty("LODManager", DependencyManager::get().data()); _webSurface->getRootContext()->setContextProperty("OctreeStats", DependencyManager::get().data()); + _webSurface->getRootContext()->setContextProperty("DCModel", DependencyManager::get().data()); _webSurface->getRootContext()->setContextProperty("pathToFonts", "../../"); tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data());