From d14d5f3d2952fd1be1043cdefcdc52db2bf46100 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 14 Apr 2015 15:55:42 -0700 Subject: [PATCH 01/20] Working on new-UI implementations of address bar and login --- CMakeLists.txt | 9 + interface/CMakeLists.txt | 2 +- interface/resources/qml/AddressBarDialog.qml | 84 +++++ interface/resources/qml/CustomBorder.qml | 12 + interface/resources/qml/CustomButton.qml | 23 ++ interface/resources/qml/CustomDialog.qml | 98 ++++++ interface/resources/qml/CustomText.qml | 7 + interface/resources/qml/CustomTextArea.qml | 10 + interface/resources/qml/CustomTextEdit.qml | 7 + interface/resources/qml/CustomTextInput.qml | 34 ++ interface/resources/qml/Icon.qml | 8 + interface/resources/qml/IconControl.qml | 24 ++ interface/resources/qml/LoginDialog.qml | 191 ++++++++++ interface/resources/qml/Root.qml | 14 + interface/resources/qml/componentCreation.js | 27 ++ interface/resources/qml/hifiConstants.js | 4 + interface/src/Application.cpp | 112 +++++- interface/src/Application.h | 3 + interface/src/GLCanvas.cpp | 71 ++-- interface/src/GLCanvas.h | 15 - interface/src/Menu.cpp | 50 ++- interface/src/devices/OculusManager.cpp | 15 +- interface/src/devices/OculusManager.h | 1 + interface/src/devices/TV3DManager.cpp | 2 +- interface/src/main.cpp | 1 + interface/src/ui/AddressBarDialog.cpp | 142 ++------ interface/src/ui/AddressBarDialog.h | 42 +-- interface/src/ui/ApplicationOverlay.cpp | 118 ++++--- interface/src/ui/ApplicationOverlay.h | 8 +- interface/src/ui/DialogsManager.cpp | 16 +- interface/src/ui/FramelessDialog.cpp | 166 --------- interface/src/ui/FramelessDialog.h | 50 --- interface/src/ui/LoginDialog.cpp | 148 +++----- interface/src/ui/LoginDialog.h | 49 +-- libraries/render-utils/CMakeLists.txt | 2 +- libraries/render-utils/src/FboCache.cpp | 98 ++++++ libraries/render-utils/src/FboCache.h | 50 +++ .../render-utils/src/OffscreenGlCanvas.cpp | 43 +++ .../render-utils/src/OffscreenGlCanvas.h | 31 ++ libraries/render-utils/src/OffscreenUi.cpp | 325 ++++++++++++++++++ libraries/render-utils/src/OffscreenUi.h | 136 ++++++++ libraries/render-utils/src/RenderUtil.h | 50 +++ libraries/shared/src/GLMHelpers.h | 11 + libraries/shared/src/ThreadHelpers.h | 13 + tests/render-utils/src/main.cpp | 250 +++++++++----- 45 files changed, 1844 insertions(+), 728 deletions(-) create mode 100644 interface/resources/qml/AddressBarDialog.qml create mode 100644 interface/resources/qml/CustomBorder.qml create mode 100644 interface/resources/qml/CustomButton.qml create mode 100644 interface/resources/qml/CustomDialog.qml create mode 100644 interface/resources/qml/CustomText.qml create mode 100644 interface/resources/qml/CustomTextArea.qml create mode 100644 interface/resources/qml/CustomTextEdit.qml create mode 100644 interface/resources/qml/CustomTextInput.qml create mode 100644 interface/resources/qml/Icon.qml create mode 100644 interface/resources/qml/IconControl.qml create mode 100644 interface/resources/qml/LoginDialog.qml create mode 100644 interface/resources/qml/Root.qml create mode 100644 interface/resources/qml/componentCreation.js create mode 100644 interface/resources/qml/hifiConstants.js delete mode 100644 interface/src/ui/FramelessDialog.cpp delete mode 100644 interface/src/ui/FramelessDialog.h create mode 100644 libraries/render-utils/src/FboCache.cpp create mode 100644 libraries/render-utils/src/FboCache.h create mode 100644 libraries/render-utils/src/OffscreenGlCanvas.cpp create mode 100644 libraries/render-utils/src/OffscreenGlCanvas.h create mode 100644 libraries/render-utils/src/OffscreenUi.cpp create mode 100644 libraries/render-utils/src/OffscreenUi.h create mode 100644 libraries/shared/src/ThreadHelpers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 81d532fbe2..d27774e169 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,8 +92,17 @@ else () if (NOT QT_CMAKE_PREFIX_PATH) set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) endif () + if (NOT QT_CMAKE_PREFIX_PATH) + get_filename_component(QT_CMAKE_PREFIX_PATH "${Qt5_DIR}/.." REALPATH) + endif () endif () +if (WIN32) + if (NOT EXISTS ${QT_CMAKE_PREFIX_PATH}) + message(FATAL_ERROR "Could not determine QT_CMAKE_PREFIX_PATH.") + endif () +endif() + # figure out where the qt dir is get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index f4f390607b..5d2fe5ae38 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -54,7 +54,7 @@ else () list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP}) endif () -find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Script Svg WebKitWidgets) +find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg WebKitWidgets) # grab the ui files in resources/ui file (GLOB_RECURSE QT_UI_FILES ui/*.ui) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml new file mode 100644 index 0000000000..df06fabbe6 --- /dev/null +++ b/interface/resources/qml/AddressBarDialog.qml @@ -0,0 +1,84 @@ +import Hifi 1.0 +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Controls.Styles 1.3 + +AddressBarDialog { + id: addressBarDialog + objectName: "AddressBarDialog" + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + height: 128 + width: 512 + + onVisibleChanged: { + if (!visible) { + reset(); + } else { + addressLine.focus = true + addressLine.forceActiveFocus() + } + } + + Component.onCompleted: { + addressLine.focus = true + addressLine.forceActiveFocus() + } + + function reset() { + addressLine.text = "" + goButton.source = "../images/address-bar-submit.svg" + } + + CustomDialog { + id: dialog + anchors.fill: parent + title: "Go to..." + + // The client area + Item { + id: item1 + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + + CustomBorder { + height: 64 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: goButton.left + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter + CustomTextInput { + id: addressLine + anchors.fill: parent + helperText: "domain, location, @user, /x,y,z" + anchors.margins: 8 + onAccepted: { + addressBarDialog.loadAddress(addressLine.text) + } + } + } + + Image { + id: goButton + width: 32 + height: 32 + anchors.right: parent.right + anchors.rightMargin: 8 + source: "../images/address-bar-submit.svg" + anchors.verticalCenter: parent.verticalCenter + + MouseArea { + anchors.fill: parent + onClicked: { + parent.source = "../images/address-bar-submit-active.svg" + addressBarDialog.loadAddress(addressLine.text) + } + } + } + + } + } +} + diff --git a/interface/resources/qml/CustomBorder.qml b/interface/resources/qml/CustomBorder.qml new file mode 100644 index 0000000000..1bb30d1ebc --- /dev/null +++ b/interface/resources/qml/CustomBorder.qml @@ -0,0 +1,12 @@ +import QtQuick 2.3 + + +Rectangle { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + property int margin: 5 + color: myPalette.window + border.color: myPalette.dark + border.width: 5 + radius: border.width * 2 +} + diff --git a/interface/resources/qml/CustomButton.qml b/interface/resources/qml/CustomButton.qml new file mode 100644 index 0000000000..ce57d7ce5e --- /dev/null +++ b/interface/resources/qml/CustomButton.qml @@ -0,0 +1,23 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 +import QtQuick.Window 2.2 +import QtQuick.Controls.Styles 1.3 + +Button { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + text: "Text" + width: 128 + height: 64 + style: ButtonStyle { + background: CustomBorder { + anchors.fill: parent + } + label: CustomText { + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.text + color: control.enabled ? myPalette.text : myPalette.dark + } + } +} diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml new file mode 100644 index 0000000000..71f36b4108 --- /dev/null +++ b/interface/resources/qml/CustomDialog.qml @@ -0,0 +1,98 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 +import "hifiConstants.js" as HifiConstants + +Item { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + + id: dialog + width: 256 + height: 256 + property rect clientArea: clientBorder + property int topMargin: dialog.height - clientBorder.height + 8 + property int margins: 8 + property string title + property int titleSize: titleBorder.height + 12 + property string frameColor: HifiConstants.color + property string backgroundColor: myPalette.window + property string headerBackgroundColor: myPalette.dark + + CustomBorder { + id: windowBorder + anchors.fill: parent + border.color: dialog.frameColor + color: dialog.backgroundColor + + CustomBorder { + id: titleBorder + height: 48 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + border.color: dialog.frameColor + color: dialog.headerBackgroundColor + + CustomText { + id: titleText + color: "white" + text: dialog.title + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.fill: parent + } + + MouseArea { + id: titleDrag + property int startX + property int startY + anchors.right: closeButton.left + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.top: parent.top + anchors.rightMargin: 4 + drag { + target: dialog.parent + minimumX: 0 + minimumY: 0 + maximumX: dialog.parent.parent.width - dialog.parent.width + maximumY: dialog.parent.parent.height - dialog.parent.height + } + } + Image { + id: closeButton + x: 360 + height: 16 + anchors.verticalCenter: parent.verticalCenter + width: 16 + anchors.right: parent.right + anchors.rightMargin: 12 + source: "../styles/close.svg" + MouseArea { + anchors.fill: parent + onClicked: { + dialog.parent.destroy() + } + } + } + + } // header border + + CustomBorder { + id: clientBorder + border.color: dialog.frameColor + color: "#00000000" + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: titleBorder.bottom + anchors.topMargin: -titleBorder.border.width + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + } // client border + } // window border +} diff --git a/interface/resources/qml/CustomText.qml b/interface/resources/qml/CustomText.qml new file mode 100644 index 0000000000..83229b783e --- /dev/null +++ b/interface/resources/qml/CustomText.qml @@ -0,0 +1,7 @@ +import QtQuick 2.3 + +Text { + font.family: "Helvetica" + font.pointSize: 18 +} + diff --git a/interface/resources/qml/CustomTextArea.qml b/interface/resources/qml/CustomTextArea.qml new file mode 100644 index 0000000000..cf3308e2b7 --- /dev/null +++ b/interface/resources/qml/CustomTextArea.qml @@ -0,0 +1,10 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +TextArea { + font.family: "Helvetica" + font.pointSize: 18 + backgroundVisible: false + readOnly: true +} + diff --git a/interface/resources/qml/CustomTextEdit.qml b/interface/resources/qml/CustomTextEdit.qml new file mode 100644 index 0000000000..0602bbc150 --- /dev/null +++ b/interface/resources/qml/CustomTextEdit.qml @@ -0,0 +1,7 @@ +import QtQuick 2.3 + +TextEdit { + font.family: "Helvetica" + font.pointSize: 18 +} + diff --git a/interface/resources/qml/CustomTextInput.qml b/interface/resources/qml/CustomTextInput.qml new file mode 100644 index 0000000000..a706187376 --- /dev/null +++ b/interface/resources/qml/CustomTextInput.qml @@ -0,0 +1,34 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +TextInput { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + property string helperText: "" + font.family: "Helvetica" + font.pointSize: 18 + width: 256 + height: 64 + color: myPalette.text + clip: true + verticalAlignment: TextInput.AlignVCenter + + onTextChanged: { + if (text == "") { + helperText.visible = true; + } else { + helperText.visible = false; + } + } + + Text { + id: helperText + anchors.fill: parent + font.pointSize: parent.font.pointSize + font.family: "Helvetica" + verticalAlignment: TextInput.AlignVCenter + text: parent.helperText + color: myPalette.dark + clip: true + } +} + diff --git a/interface/resources/qml/Icon.qml b/interface/resources/qml/Icon.qml new file mode 100644 index 0000000000..0d60afb2b7 --- /dev/null +++ b/interface/resources/qml/Icon.qml @@ -0,0 +1,8 @@ +import QtQuick 1.0 + +Image { +id: icon +width: 64 +height: 64 +source: "file.svg" +} \ No newline at end of file diff --git a/interface/resources/qml/IconControl.qml b/interface/resources/qml/IconControl.qml new file mode 100644 index 0000000000..346865aacb --- /dev/null +++ b/interface/resources/qml/IconControl.qml @@ -0,0 +1,24 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.3 +import QtQuick.Window 2.2 +import QtQuick.Controls.Styles 1.3 + +Button { + text: "Text" + style: ButtonStyle { + background: Item { anchors.fill: parent } + label: Text { + id: icon + width: height + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + font.family: iconFont.name + font.pointSize: 18 + property alias unicode: icon.text + FontLoader { id: iconFont; source: "/fonts/fontawesome-webfont.ttf"; } + text: control.text + color: control.enabled ? "white" : "dimgray" + } + } +} + diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml new file mode 100644 index 0000000000..c306f4ed7e --- /dev/null +++ b/interface/resources/qml/LoginDialog.qml @@ -0,0 +1,191 @@ +import Hifi 1.0 +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Controls.Styles 1.3 +import "hifiConstants.js" as HifiConstants + +LoginDialog { + SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } + id: loginDialog + objectName: "LoginDialog" + height: 512 + width: 384 + + onVisibleChanged: { + if (!visible) { + reset() + } else { + username.forceActiveFocus() + } + } + + function reset() { + username.text = "" + password.text = "" + loginDialog.statusText = "" + } + + CustomDialog { + anchors.fill: parent + title: "Login" + Item { + id: item1 + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + Column { + anchors.topMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.top: parent.top + spacing: 8 + + Image { + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + width: 64 + source: "../images/hifi-logo.svg" + } + + CustomBorder { + width: 304 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + CustomTextInput { + id: username + anchors.fill: parent + helperText: "Username or Email" + anchors.margins: 8 + KeyNavigation.tab: password + KeyNavigation.backtab: password + onAccepted: { + password.forceActiveFocus() + } + } + } + + CustomBorder { + width: 304 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + CustomTextInput { + id: password + anchors.fill: parent + echoMode: TextInput.Password + helperText: "Password" + anchors.margins: 8 + KeyNavigation.tab: username + KeyNavigation.backtab: username + onAccepted: { + if (username.text == "") { + username.forceActiveFocus() + } else { + loginDialog.login(username.text, password.text) + } + } + onFocusChanged: { + if (password.focus) { + password.selectAll() + } + } + } + } + + CustomText { + anchors.horizontalCenter: parent.horizontalCenter + textFormat: Text.StyledText + width: parent.width + height: 96 + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: loginDialog.statusText + } + } + + Column { + anchors.bottomMargin: 5 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.bottom: parent.bottom + + Rectangle { + width: 192 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + color: HifiConstants.color + border.width: 0 + radius: 10 + + MouseArea { + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + onClicked: { + loginDialog.login(username.text, password.text) + } + } + + Row { + anchors.centerIn: parent + anchors.verticalCenter: parent.verticalCenter + spacing: 8 + Image { + id: loginIcon + height: 32 + width: 32 + source: "../images/login.svg" + } + CustomText { + text: "Login" + color: "white" + width: 64 + height: parent.height + } + } + + } + + CustomText { + width: parent.width + height: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text:"Create Account" + font.pointSize: 12 + font.bold: true + color: HifiConstants.color + + MouseArea { + anchors.fill: parent + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/signup") + } + } + } + + CustomText { + width: parent.width + height: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.pointSize: 12 + text: "Recover Password" + color: HifiConstants.color + + MouseArea { + anchors.fill: parent + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new") + } + } + } + } + } + } +} diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml new file mode 100644 index 0000000000..f290a8b5ca --- /dev/null +++ b/interface/resources/qml/Root.qml @@ -0,0 +1,14 @@ +import QtQuick 2.3 +import "componentCreation.js" as Creator + + +Item { + id: root + width: 1280 + height: 720 + + function loadChild(url) { + Creator.createObject(root, url) + } +} + diff --git a/interface/resources/qml/componentCreation.js b/interface/resources/qml/componentCreation.js new file mode 100644 index 0000000000..6e6469adfb --- /dev/null +++ b/interface/resources/qml/componentCreation.js @@ -0,0 +1,27 @@ +var component; +var instance; +var parent; + +function createObject(parentObject, url) { + parent = parentObject; + component = Qt.createComponent(url); + if (component.status == Component.Ready) + finishCreation(); + else + component.statusChanged.connect(finishCreation); +} + +function finishCreation() { + if (component.status == Component.Ready) { + instance = component.createObject(parent, {"x": 100, "y": 100}); + if (instance == null) { + // Error Handling + console.log("Error creating object"); + } else { + instance.focus = true; + } + } else if (component.status == Component.Error) { + // Error Handling + console.log("Error loading component:", component.errorString()); + } +} \ No newline at end of file diff --git a/interface/resources/qml/hifiConstants.js b/interface/resources/qml/hifiConstants.js new file mode 100644 index 0000000000..860226c963 --- /dev/null +++ b/interface/resources/qml/hifiConstants.js @@ -0,0 +1,4 @@ +var color = "#0e7077" +var Colors = { + hifiBlue: "#0e7077" +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 82447257fb..0766d45ff3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -137,6 +137,7 @@ #include "ui/Snapshot.h" #include "ui/StandAloneJSConsole.h" #include "ui/Stats.h" +#include "ui/AddressBarDialog.h" // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU #if defined(Q_OS_WIN) @@ -209,8 +210,12 @@ public: void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); - + if (!logMessage.isEmpty()) { +#ifdef Q_OS_WIN + OutputDebugStringA(logMessage.toLocal8Bit().constData()); + OutputDebugStringA("\n"); +#endif Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage + "\n")); } } @@ -260,6 +265,7 @@ bool setupEssentials(int& argc, char** argv) { #endif auto discoverabilityManager = DependencyManager::set(); auto sceneScriptingInterface = DependencyManager::set(); + auto offscreenUi = DependencyManager::set(); return true; } @@ -316,8 +322,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : #ifdef Q_OS_WIN installNativeEventFilter(&MyNativeEventFilter::getInstance()); #endif + _logger = new FileLogger(this); // After setting organization name in order to get correct directory + qInstallMessageHandler(messageHandler); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf"); @@ -562,8 +570,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : #endif this->installEventFilter(this); + // The offscreen UI needs to intercept the mouse and keyboard + // events coming from the onscreen window + _glWidget->installEventFilter( + DependencyManager::get().data()); } + void Application::aboutToQuit() { emit beforeAboutToQuit(); @@ -720,10 +733,35 @@ void Application::initializeGL() { // update before the first render update(1.0f / _fps); + + // The UI can't be created until the primary OpenGL + // context is created, because it needs to share + // texture resources + initializeUi(); InfoView::showFirstTime(INFO_HELP_PATH); } +void Application::initializeUi() { + AddressBarDialog::registerType(); + LoginDialog::registerType(); + + auto offscreenUi = DependencyManager::get(); + offscreenUi->create(_glWidget->context()->contextHandle()); + offscreenUi->resize(_glWidget->size()); + offscreenUi->setProxyWindow(_window->windowHandle()); + auto rootQml = PathUtils::resourcesPath() + "qml/Root.qml"; + offscreenUi->loadQml(QUrl::fromLocalFile(rootQml)); + offscreenUi->setMouseTranslator([this](const QPointF& p){ + if (OculusManager::isConnected()) { + glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); + return QPointF(pos.x, pos.y); + } + return QPointF(p); + }); + offscreenUi->resume(); +} + void Application::paintGL() { PROFILE_RANGE(__FUNCTION__); PerformanceTimer perfTimer("paintGL"); @@ -818,7 +856,7 @@ void Application::paintGL() { { PerformanceTimer perfTimer("renderOverlay"); - _applicationOverlay.renderOverlay(true); + _applicationOverlay.renderOverlay(); _applicationOverlay.displayOverlayTexture(); } } @@ -863,6 +901,9 @@ void Application::resizeGL(int width, int height) { updateProjectionMatrix(); glLoadIdentity(); + auto offscreenUi = DependencyManager::get(); + offscreenUi->resize(QSize(width, height)); + // update Stats width // let's set horizontal offset to give stats some margin to mirror int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; @@ -911,6 +952,44 @@ bool Application::importSVOFromURL(const QString& urlString) { } bool Application::event(QEvent* event) { + switch (event->type()) { + case QEvent::MouseMove: + mouseMoveEvent((QMouseEvent*)event); + return true; + case QEvent::MouseButtonPress: + mousePressEvent((QMouseEvent*)event); + return true; + case QEvent::MouseButtonRelease: + mouseReleaseEvent((QMouseEvent*)event); + return true; + case QEvent::KeyPress: + keyPressEvent((QKeyEvent*)event); + return true; + case QEvent::KeyRelease: + keyReleaseEvent((QKeyEvent*)event); + return true; + case QEvent::FocusOut: + focusOutEvent((QFocusEvent*)event); + return true; + case QEvent::TouchBegin: + touchBeginEvent(static_cast(event)); + event->accept(); + return true; + case QEvent::TouchEnd: + touchEndEvent(static_cast(event)); + return true; + case QEvent::TouchUpdate: + touchUpdateEvent(static_cast(event)); + return true; + case QEvent::Wheel: + wheelEvent(static_cast(event)); + return true; + case QEvent::Drop: + dropEvent(static_cast(event)); + return true; + default: + break; + } // handle custom URL if (event->type() == QEvent::FileOpen) { @@ -931,7 +1010,7 @@ bool Application::event(QEvent* event) { if (HFActionEvent::types().contains(event->type())) { _controllerScriptingInterface.handleMetaEvent(static_cast(event)); } - + return QApplication::event(event); } @@ -963,14 +1042,17 @@ void Application::keyPressEvent(QKeyEvent* event) { bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); bool isOption = event->modifiers().testFlag(Qt::AltModifier); + bool isKeypad = event->modifiers().testFlag(Qt::KeypadModifier); switch (event->key()) { break; case Qt::Key_L: - if (isShifted) { - Menu::getInstance()->triggerOption(MenuOption::LodTools); - } else if (isMeta) { + if (isShifted && isMeta) { Menu::getInstance()->triggerOption(MenuOption::Log); - } + } else if (isMeta) { + Menu::getInstance()->triggerOption(MenuOption::AddressBar); + } else if (isShifted) { + Menu::getInstance()->triggerOption(MenuOption::LodTools); + } break; case Qt::Key_E: @@ -1030,11 +1112,6 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; - case Qt::Key_Return: - case Qt::Key_Enter: - Menu::getInstance()->triggerOption(MenuOption::AddressBar); - break; - case Qt::Key_Backslash: Menu::getInstance()->triggerOption(MenuOption::Chat); break; @@ -1494,6 +1571,17 @@ void Application::dropEvent(QDropEvent *event) { } } +void Application::dragEnterEvent(QDragEnterEvent* event) { + const QMimeData* mimeData = event->mimeData(); + foreach(QUrl url, mimeData->urls()) { + auto urlString = url.toString(); + if (canAcceptURL(urlString)) { + event->acceptProposedAction(); + break; + } + } +} + bool Application::acceptSnapshot(const QString& urlString) { QUrl url(urlString); QString snapshotPath = url.toLocalFile(); diff --git a/interface/src/Application.h b/interface/src/Application.h index cf047f02d4..57c6530ad4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -151,6 +152,7 @@ public: void setPreviousScriptLocation(const QString& previousScriptLocation); void clearScriptsBeforeRunning(); void initializeGL(); + void initializeUi(); void paintGL(); void resizeGL(int width, int height); @@ -170,6 +172,7 @@ public: void wheelEvent(QWheelEvent* event); void dropEvent(QDropEvent *event); + void dragEnterEvent(QDragEnterEvent *event); bool event(QEvent* event); bool eventFilter(QObject* object, QEvent* event); diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 12a10681ce..d0c0cb6713 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -82,30 +82,6 @@ void GLCanvas::resizeGL(int width, int height) { Application::getInstance()->resizeGL(width, height); } -void GLCanvas::keyPressEvent(QKeyEvent* event) { - Application::getInstance()->keyPressEvent(event); -} - -void GLCanvas::keyReleaseEvent(QKeyEvent* event) { - Application::getInstance()->keyReleaseEvent(event); -} - -void GLCanvas::focusOutEvent(QFocusEvent* event) { - Application::getInstance()->focusOutEvent(event); -} - -void GLCanvas::mouseMoveEvent(QMouseEvent* event) { - Application::getInstance()->mouseMoveEvent(event); -} - -void GLCanvas::mousePressEvent(QMouseEvent* event) { - Application::getInstance()->mousePressEvent(event); -} - -void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { - Application::getInstance()->mouseReleaseEvent(event); -} - void GLCanvas::activeChanged(Qt::ApplicationState state) { switch (state) { case Qt::ApplicationActive: @@ -151,40 +127,37 @@ void GLCanvas::throttleRender() { int updateTime = 0; bool GLCanvas::event(QEvent* event) { switch (event->type()) { + case QEvent::MouseMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::FocusIn: + case QEvent::FocusOut: + case QEvent::Resize: case QEvent::TouchBegin: - Application::getInstance()->touchBeginEvent(static_cast(event)); - event->accept(); - return true; case QEvent::TouchEnd: - Application::getInstance()->touchEndEvent(static_cast(event)); - return true; case QEvent::TouchUpdate: - Application::getInstance()->touchUpdateEvent(static_cast(event)); - return true; + case QEvent::Wheel: + case QEvent::DragEnter: + case QEvent::Drop: + if (QCoreApplication::sendEvent(QCoreApplication::instance(), event)) { + return true; + } + break; + case QEvent::Paint: + // Ignore paint events that occur after we've decided to quit + if (Application::getInstance()->isAboutToQuit()) { + return true; + } + break; + default: break; } return QGLWidget::event(event); } -void GLCanvas::wheelEvent(QWheelEvent* event) { - Application::getInstance()->wheelEvent(event); -} - -void GLCanvas::dragEnterEvent(QDragEnterEvent* event) { - const QMimeData* mimeData = event->mimeData(); - foreach (QUrl url, mimeData->urls()) { - auto urlString = url.toString(); - if (Application::getInstance()->canAcceptURL(urlString)) { - event->acceptProposedAction(); - break; - } - } -} - -void GLCanvas::dropEvent(QDropEvent* event) { - Application::getInstance()->dropEvent(event); -} // Pressing Alt (and Meta) key alone activates the menubar because its style inherits the // SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 7b86f983e9..6c53a17e04 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -40,23 +40,8 @@ protected: virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL(int width, int height); - - virtual void keyPressEvent(QKeyEvent* event); - virtual void keyReleaseEvent(QKeyEvent* event); - - virtual void focusOutEvent(QFocusEvent* event); - - virtual void mouseMoveEvent(QMouseEvent* event); - virtual void mousePressEvent(QMouseEvent* event); - virtual void mouseReleaseEvent(QMouseEvent* event); - virtual bool event(QEvent* event); - virtual void wheelEvent(QWheelEvent* event); - - virtual void dragEnterEvent(QDragEnterEvent *event); - virtual void dropEvent(QDropEvent* event); - private slots: void activeChanged(Qt::ApplicationState state); void throttleRender(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 1cce0b1f56..64e5accb1b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -97,7 +97,7 @@ Menu::Menu() { addActionToQMenuAndActionHash(fileMenu, MenuOption::AddressBar, - Qt::Key_Enter, + Qt::CTRL | Qt::Key_L, dialogsManager.data(), SLOT(toggleAddressBar())); auto addressManager = DependencyManager::get(); @@ -151,7 +151,8 @@ Menu::Menu() { connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool))); #endif - addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, Qt::Key_Backslash, + addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, + 0, // QML Qt::Key_Backslash, dialogsManager.data(), SLOT(showIRCLink())); addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0, qApp, SLOT(showFriendsWindow())); @@ -194,7 +195,7 @@ Menu::Menu() { addActionToQMenuAndActionHash(toolsMenu, MenuOption::ResetSensors, - Qt::Key_Apostrophe, + 0, // QML Qt::Key_Apostrophe, qApp, SLOT(resetSensors())); @@ -207,17 +208,17 @@ Menu::Menu() { QMenu* avatarSizeMenu = avatarMenu->addMenu("Size"); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::IncreaseAvatarSize, - Qt::Key_Plus, + 0, // QML Qt::Key_Plus, avatar, SLOT(increaseSize())); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::DecreaseAvatarSize, - Qt::Key_Minus, + 0, // QML Qt::Key_Minus, avatar, SLOT(decreaseSize())); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::ResetAvatarSize, - Qt::Key_Equal, + 0, // QML Qt::Key_Equal, avatar, SLOT(resetSize())); @@ -250,13 +251,17 @@ Menu::Menu() { qApp, SLOT(setFullscreen(bool))); #endif - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true, - qApp,SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, - qApp, SLOT(cameraMenuChanged())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, + 0, // QML Qt::Key_P, + true, qApp, SLOT(cameraMenuChanged())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, + 0, //QML Qt::SHIFT | Qt::Key_H, + true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, + 0, // QML Qt::Key_H, + false, qApp, SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H, + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::CTRL | Qt::SHIFT | Qt::Key_H, false, dialogsManager.data(), SLOT(hmdTools(bool))); @@ -283,8 +288,12 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash); - addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, qApp, SLOT(toggleLogDialog())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, + 0); // QML Qt::Key_Slash); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats); + addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, + Qt::CTRL | Qt::SHIFT | Qt::Key_L, + qApp, SLOT(toggleLogDialog())); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, dialogsManager.data(), SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, @@ -294,7 +303,9 @@ Menu::Menu() { QMenu* developerMenu = addMenu("Developer"); QMenu* renderOptionsMenu = developerMenu->addMenu("Render"); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, + 0, // QML Qt::SHIFT | Qt::Key_A, + true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges); @@ -346,13 +357,16 @@ Menu::Menu() { resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false)); resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false)); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, + 0, // QML Qt::Key_Asterisk, + true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true, DependencyManager::get().data(), SLOT(toggleGlowEffect(bool))); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Wireframe, Qt::ALT | Qt::Key_W, false); - addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, - dialogsManager.data(), SLOT(lodTools())); + addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, + 0, // QML Qt::SHIFT | Qt::Key_L, + dialogsManager.data(), SLOT(lodTools())); QMenu* avatarDebugMenu = developerMenu->addMenu("Avatar"); diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index d56ece12fb..a309831c14 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -114,8 +114,11 @@ void OculusManager::initSdk() { } void OculusManager::shutdownSdk() { - ovrHmd_Destroy(_ovrHmd); - ovr_Shutdown(); + if (_ovrHmd) { + ovrHmd_Destroy(_ovrHmd); + _ovrHmd = nullptr; + ovr_Shutdown(); + } } void OculusManager::init() { @@ -124,6 +127,12 @@ void OculusManager::init() { #endif } +void OculusManager::deinit() { +#ifdef OVR_DIRECT_MODE + shutdownSdk(); +#endif +} + void OculusManager::connect() { #ifndef OVR_DIRECT_MODE initSdk(); @@ -515,7 +524,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() - applicationOverlay.renderOverlay(true); + applicationOverlay.renderOverlay(); //Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index fe2da31231..4b1bc98fb2 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -51,6 +51,7 @@ class Text3DOverlay; class OculusManager { public: static void init(); + static void deinit(); static void connect(); static void disconnect(); static bool isConnected(); diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index f082c6de47..4f6e566d8c 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -103,7 +103,7 @@ void TV3DManager::display(Camera& whichCamera) { // We only need to render the overlays to a texture once, then we just render the texture as a quad // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() - applicationOverlay.renderOverlay(true); + applicationOverlay.renderOverlay(); DependencyManager::get()->prepare(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index b4486ceb2b..7d80b077b8 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -112,6 +112,7 @@ int main(int argc, const char* argv[]) { exitCode = app.exec(); } + OculusManager::deinit(); #ifdef Q_OS_WIN ReleaseMutex(mutex); #endif diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index b414f95240..49158265ba 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -1,148 +1,50 @@ // // AddressBarDialog.cpp -// interface/src/ui // -// Created by Stojce Slavkovski on 9/22/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AddressBarDialog.h" + #include -#include - -#include "AddressBarDialog.h" +#include "DependencyManager.h" #include "AddressManager.h" -#include "Application.h" -#include "MainWindow.h" -const QString ADDRESSBAR_GO_BUTTON_ICON = "images/address-bar-submit.svg"; -const QString ADDRESSBAR_GO_BUTTON_ACTIVE_ICON = "images/address-bar-submit-active.svg"; +QML_DIALOG_DEF(AddressBarDialog) -AddressBarDialog::AddressBarDialog(QWidget* parent) : - FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP) -{ - setAttribute(Qt::WA_DeleteOnClose, false); - setupUI(); - +AddressBarDialog::AddressBarDialog(QQuickItem *parent) : QQuickItem(parent) { auto addressManager = DependencyManager::get(); - connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); + connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide); } -void AddressBarDialog::setupUI() { - - const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;"; - const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, location, @user, /x,y,z"; - const QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;"; - - const int ADDRESSBAR_MIN_WIDTH = 200; - const int ADDRESSBAR_MAX_WIDTH = 615; - const int ADDRESSBAR_HEIGHT = 42; - const int ADDRESSBAR_STRETCH = 60; - - const int BUTTON_SPACER_SIZE = 5; - const int DEFAULT_SPACER_SIZE = 20; - const int ADDRESS_LAYOUT_RIGHT_MARGIN = 10; - - const int GO_BUTTON_SIZE = 42; - const int CLOSE_BUTTON_SIZE = 16; - const QString CLOSE_BUTTON_ICON = "styles/close.svg"; - - const int DIALOG_HEIGHT = 62; - const int DIALOG_INITIAL_WIDTH = 560; - - QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - setSizePolicy(sizePolicy); - setMinimumSize(QSize(DIALOG_INITIAL_WIDTH, DIALOG_HEIGHT)); - setMaximumHeight(DIALOG_HEIGHT); - setStyleSheet(DIALOG_STYLESHEET); - _verticalLayout = new QVBoxLayout(this); - _verticalLayout->setContentsMargins(0, 0, 0, 0); - - _addressLayout = new QHBoxLayout(); - _addressLayout->setContentsMargins(0, 0, ADDRESS_LAYOUT_RIGHT_MARGIN, 0); - - _leftSpacer = new QSpacerItem(DEFAULT_SPACER_SIZE, - DEFAULT_SPACER_SIZE, - QSizePolicy::MinimumExpanding, - QSizePolicy::Minimum); - - _addressLayout->addItem(_leftSpacer); - - _addressLineEdit = new QLineEdit(this); - _addressLineEdit->setAttribute(Qt::WA_MacShowFocusRect, 0); - _addressLineEdit->setPlaceholderText(ADDRESSBAR_PLACEHOLDER); - QSizePolicy sizePolicyLineEdit(QSizePolicy::Preferred, QSizePolicy::Fixed); - sizePolicyLineEdit.setHorizontalStretch(ADDRESSBAR_STRETCH); - _addressLineEdit->setSizePolicy(sizePolicyLineEdit); - _addressLineEdit->setMinimumSize(QSize(ADDRESSBAR_MIN_WIDTH, ADDRESSBAR_HEIGHT)); - _addressLineEdit->setMaximumSize(QSize(ADDRESSBAR_MAX_WIDTH, ADDRESSBAR_HEIGHT)); - _addressLineEdit->setStyleSheet(ADDRESSBAR_STYLESHEET); - _addressLayout->addWidget(_addressLineEdit); - - _buttonSpacer = new QSpacerItem(BUTTON_SPACER_SIZE, BUTTON_SPACER_SIZE, QSizePolicy::Fixed, QSizePolicy::Minimum); - _addressLayout->addItem(_buttonSpacer); - - _goButton = new QPushButton(this); - _goButton->setSizePolicy(sizePolicy); - _goButton->setMinimumSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE)); - _goButton->setMaximumSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE)); - _goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ICON)); - _goButton->setIconSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE)); - _goButton->setDefault(true); - _goButton->setFlat(true); - _addressLayout->addWidget(_goButton); - - _rightSpacer = new QSpacerItem(DEFAULT_SPACER_SIZE, - DEFAULT_SPACER_SIZE, - QSizePolicy::MinimumExpanding, - QSizePolicy::Minimum); - - _addressLayout->addItem(_rightSpacer); - - _closeButton = new QPushButton(this); - _closeButton->setSizePolicy(sizePolicy); - _closeButton->setMinimumSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE)); - _closeButton->setMaximumSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE)); - QIcon icon(PathUtils::resourcesPath() + CLOSE_BUTTON_ICON); - _closeButton->setIcon(icon); - _closeButton->setIconSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE)); - _closeButton->setFlat(true); - _addressLayout->addWidget(_closeButton, 0, Qt::AlignRight); - - _verticalLayout->addLayout(_addressLayout); - - connect(_goButton, &QPushButton::clicked, this, &AddressBarDialog::accept); - connect(_closeButton, &QPushButton::clicked, this, &QDialog::close); +void AddressBarDialog::hide() { + setEnabled(false); + setVisible(false); } -void AddressBarDialog::showEvent(QShowEvent* event) { - _goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ICON)); - _addressLineEdit->setText(QString()); - _addressLineEdit->setFocus(); - FramelessDialog::showEvent(event); -} - -void AddressBarDialog::accept() { - if (!_addressLineEdit->text().isEmpty()) { - _goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ACTIVE_ICON)); - auto addressManager = DependencyManager::get(); - connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &QDialog::hide); - addressManager->handleLookupString(_addressLineEdit->text()); +void AddressBarDialog::loadAddress(const QString & address) { + qDebug() << "Called LoadAddress with address " << address; + if (!address.isEmpty()) { + DependencyManager::get()->handleLookupString(address); } } +// TODO port to a QML based message box void AddressBarDialog::displayAddressOfflineMessage() { - QMessageBox::information(Application::getInstance()->getWindow(), "Address offline", - "That user or place is currently offline."); + QMessageBox::information(nullptr, "Address offline", + "That user or place is currently offline."); } +// TODO port to a QML based message box void AddressBarDialog::displayAddressNotFoundMessage() { - QMessageBox::information(Application::getInstance()->getWindow(), "Address not found", - "There is no address information for that user or place."); -} \ No newline at end of file + QMessageBox::information(nullptr, "Address not found", + "There is no address information for that user or place."); +} diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index dda807d6e2..00e55ceb10 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -1,9 +1,8 @@ // // AddressBarDialog.h -// interface/src/ui // -// Created by Stojce Slavkovski on 9/22/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -12,36 +11,25 @@ #ifndef hifi_AddressBarDialog_h #define hifi_AddressBarDialog_h -#include "FramelessDialog.h" +#pragma once +#include -#include -#include -#include -#include +#include "OffscreenUi.h" -class AddressBarDialog : public FramelessDialog { +class AddressBarDialog : public QQuickItem +{ Q_OBJECT + QML_DIALOG_DECL public: - AddressBarDialog(QWidget* parent); - -private: - void setupUI(); - void showEvent(QShowEvent* event); - - QVBoxLayout *_verticalLayout; - QHBoxLayout *_addressLayout; - QSpacerItem *_leftSpacer; - QSpacerItem *_rightSpacer; - QSpacerItem *_buttonSpacer; - QPushButton *_goButton; - QPushButton *_closeButton; - QLineEdit *_addressLineEdit; - -private slots: - void accept(); + AddressBarDialog(QQuickItem *parent = 0); + +protected: void displayAddressOfflineMessage(); void displayAddressNotFoundMessage(); + void hide(); + + Q_INVOKABLE void loadAddress(const QString & address); }; -#endif // hifi_AddressBarDialog_h +#endif diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index f08df229cc..5583790b13 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "AudioClient.h" #include "audio/AudioIOStatsRenderer.h" @@ -161,13 +162,27 @@ ApplicationOverlay::ApplicationOverlay() : _domainStatusBorder = geometryCache->allocateID(); _magnifierBorder = geometryCache->allocateID(); + // Once we move UI rendering and screen rendering to different + // threads, we need to use a sync object to deteremine when + // the current UI texture is no longer being read from, and only + // then release it back to the UI for re-use + auto offscreenUi = DependencyManager::get(); + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) { + auto offscreenUi = DependencyManager::get(); + offscreenUi->lockTexture(textureId); + assert(!glGetError()); + std::swap(_newUiTexture, textureId); + if (textureId) { + offscreenUi->releaseTexture(textureId); + } + }); } ApplicationOverlay::~ApplicationOverlay() { } // Renders the overlays either to a texture or to the screen -void ApplicationOverlay::renderOverlay(bool renderToTexture) { +void ApplicationOverlay::renderOverlay() { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); Overlays& overlays = qApp->getOverlays(); auto glCanvas = Application::getInstance()->getGLWidget(); @@ -183,11 +198,9 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (renderToTexture) { - _overlays.buildFramebufferObject(); - _overlays.bind(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } + _overlays.buildFramebufferObject(); + _overlays.bind(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); { const float NEAR_CLIP = -10000; @@ -218,9 +231,25 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { glEnable(GL_LIGHTING); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - if (renderToTexture) { - _overlays.release(); + _overlays.release(); +} + +// A quick and dirty solution for compositing the old overlay +// texture with the new one +template +void with_each_texture(GLuint a, GLuint b, F f) { + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + if (a) { + glBindTexture(GL_TEXTURE_2D, a); + f(); } + if (b) { + glBindTexture(GL_TEXTURE_2D, b); + f(); + } + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); } // Draws the FBO texture for the screen @@ -229,30 +258,24 @@ void ApplicationOverlay::displayOverlayTexture() { return; } auto glCanvas = Application::getInstance()->getGLWidget(); - - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - _overlays.bindTexture(); - glMatrixMode(GL_PROJECTION); glPushMatrix(); { glLoadIdentity(); - glOrtho(0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight(), 0, -1.0, 1.0); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); - glEnable(GL_BLEND); - - glm::vec2 topLeft(0.0f, 0.0f); - glm::vec2 bottomRight(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); - glm::vec2 texCoordTopLeft(0.0f, 1.0f); - glm::vec2 texCoordBottomRight(1.0f, 0.0f); + if (_alpha < 1.0) { + glEnable(GL_BLEND); + } - DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, - glm::vec4(1.0f, 1.0f, 1.0f, _alpha)); - + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + static const glm::vec2 topLeft(-1, 1); + static const glm::vec2 bottomRight(1, -1); + static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); + static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); + DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, + glm::vec4(1.0f, 1.0f, 1.0f, _alpha)); + }); } glPopMatrix(); - - glDisable(GL_TEXTURE_2D); } // Draws the FBO texture for Oculus rift. @@ -260,10 +283,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { if (_alpha == 0.0f) { return; } - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - _overlays.bindTexture(); - + glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glEnable(GL_DEPTH_TEST); @@ -271,8 +291,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glDisable(GL_LIGHTING); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.01f); - - + + //Update and draw the magnifiers MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); const glm::quat& orientation = myAvatar->getOrientation(); @@ -303,8 +323,9 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { //Render magnifier, but dont show border for mouse magnifier glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(), _reticlePosition[MOUSE].y())); - - renderMagnifier(projection, _magSizeMult[i], i != MOUSE); + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + renderMagnifier(projection, _magSizeMult[i], i != MOUSE); + }); } } @@ -319,12 +340,15 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); } - _overlays.render(); + + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + _overlays.render(); + }); + if (!Application::getInstance()->isMouseHidden()) { renderPointersOculus(myAvatar->getDefaultEyePosition()); } glDepthMask(GL_TRUE); - _overlays.releaseTexture(); glDisable(GL_TEXTURE_2D); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); @@ -341,14 +365,10 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); const glm::vec3& viewMatrixTranslation = qApp->getViewMatrixTranslation(); - glActiveTexture(GL_TEXTURE0); - glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - _overlays.bindTexture(); glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); - glEnable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); @@ -382,13 +402,15 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as GLfloat y = -halfQuadHeight; glDisable(GL_DEPTH_TEST); - DependencyManager::get()->renderQuad(glm::vec3(x, y + quadHeight, -distance), + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { + DependencyManager::get()->renderQuad(glm::vec3(x, y + quadHeight, -distance), glm::vec3(x + quadWidth, y + quadHeight, -distance), glm::vec3(x + quadWidth, y, -distance), glm::vec3(x, y, -distance), glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f), glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f), overlayColor); + }); auto glCanvas = Application::getInstance()->getGLWidget(); if (_crosshairTexture == 0) { @@ -993,14 +1015,6 @@ void ApplicationOverlay::TexturedHemisphere::release() { _framebufferObject->release(); } -void ApplicationOverlay::TexturedHemisphere::bindTexture() { - glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture()); -} - -void ApplicationOverlay::TexturedHemisphere::releaseTexture() { - glBindTexture(GL_TEXTURE_2D, 0); -} - void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, const float aspectRatio, const int slices, @@ -1099,14 +1113,14 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { } _framebufferObject = new QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::Depth); - bindTexture(); + glBindTexture(GL_TEXTURE_2D, getTexture()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - releaseTexture(); + glBindTexture(GL_TEXTURE_2D, 0); } //Renders a hemisphere with texture coordinates. @@ -1137,6 +1151,10 @@ void ApplicationOverlay::TexturedHemisphere::render() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } +GLuint ApplicationOverlay::TexturedHemisphere::getTexture() { + return _framebufferObject->texture(); +} + glm::vec2 ApplicationOverlay::directionToSpherical(glm::vec3 direction) const { glm::vec2 result; // Compute yaw diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index cc424d0c8f..cc4188e8ef 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -28,7 +28,7 @@ public: ApplicationOverlay(); ~ApplicationOverlay(); - void renderOverlay(bool renderToTexture = false); + void renderOverlay(); void displayOverlayTexture(); void displayOverlayTextureOculus(Camera& whichCamera); void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov); @@ -75,8 +75,7 @@ private: void bind(); void release(); - void bindTexture(); - void releaseTexture(); + GLuint getTexture(); void buildFramebufferObject(); void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks); @@ -122,6 +121,9 @@ private: float _trailingAudioLoudness; GLuint _crosshairTexture; + // TODO, move divide up the rendering, displaying and input handling + // facilities of this class + GLuint _newUiTexture{ 0 }; int _reticleQuad; int _magnifierQuad; diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 701ceb0189..3c54c26379 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DialogsManager.h" + #include #include @@ -28,14 +30,9 @@ #include "PreferencesDialog.h" #include "ScriptEditorWindow.h" -#include "DialogsManager.h" void DialogsManager::toggleAddressBar() { - maybeCreateDialog(_addressBarDialog); - - if (!_addressBarDialog->isVisible()) { - _addressBarDialog->show(); - } + AddressBarDialog::toggle(); } void DialogsManager::toggleDiskCacheEditor() { @@ -44,13 +41,11 @@ void DialogsManager::toggleDiskCacheEditor() { } void DialogsManager::toggleLoginDialog() { - maybeCreateDialog(_loginDialog); - _loginDialog->toggleQAction(); + LoginDialog::toggleAction(); } void DialogsManager::showLoginDialog() { - maybeCreateDialog(_loginDialog); - _loginDialog->showLoginForCurrentDomain(); + LoginDialog::show(); } void DialogsManager::octreeStatsDetails() { @@ -170,3 +165,4 @@ void DialogsManager::showIRCLink() { _ircInfoBox->raise(); } + diff --git a/interface/src/ui/FramelessDialog.cpp b/interface/src/ui/FramelessDialog.cpp deleted file mode 100644 index bae6217083..0000000000 --- a/interface/src/ui/FramelessDialog.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// -// FramelessDialog.cpp -// interface/src/ui -// -// Created by Stojce Slavkovski on 2/20/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include - -#include - -#include "Application.h" -#include "FramelessDialog.h" -#include "Menu.h" - -const int RESIZE_HANDLE_WIDTH = 7; - -FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags, Position position) : - QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint), - _allowResize(true), - _isResizing(false), - _resizeInitialWidth(0), - _selfHidden(false), - _position(position), - _hideOnBlur(true) { - - setAttribute(Qt::WA_DeleteOnClose); - - // handle rezize and move events - parentWidget()->installEventFilter(this); - - // handle minimize, restore and focus events - Application::getInstance()->installEventFilter(this); -} - -bool FramelessDialog::eventFilter(QObject* sender, QEvent* event) { - switch (event->type()) { - case QEvent::Move: - if (sender == parentWidget()) { - resizeAndPosition(false); - } - break; - case QEvent::Resize: - if (sender == parentWidget()) { - resizeAndPosition(false); - } - break; - case QEvent::WindowStateChange: - if (_hideOnBlur && parentWidget()->isMinimized()) { - if (isVisible()) { - _selfHidden = true; - setHidden(true); - } - } else if (_selfHidden) { - _selfHidden = false; - setHidden(false); - } - break; - case QEvent::ApplicationDeactivate: - // hide on minimize and focus lost - if (_hideOnBlur && isVisible()) { - _selfHidden = true; - setHidden(true); - } - break; - case QEvent::ApplicationActivate: - if (_selfHidden) { - _selfHidden = false; - setHidden(false); - } - break; - default: - break; - } - - return false; -} - -void FramelessDialog::setStyleSheetFile(const QString& fileName) { - QFile globalStyleSheet(PathUtils::resourcesPath() + "styles/global.qss"); - QFile styleSheet(PathUtils::resourcesPath() + fileName); - if (styleSheet.open(QIODevice::ReadOnly) && globalStyleSheet.open(QIODevice::ReadOnly) ) { - QDir::setCurrent(PathUtils::resourcesPath()); - setStyleSheet(globalStyleSheet.readAll() + styleSheet.readAll()); - } -} - -void FramelessDialog::showEvent(QShowEvent* event) { - resizeAndPosition(); - QDialog::showEvent(event); -} - -void FramelessDialog::resizeAndPosition(bool resizeParent) { - QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry(); - QSize parentSize = parentGeometry.size(); - - // keep full app height or width depending on position - if (_position == POSITION_LEFT || _position == POSITION_RIGHT) { - setFixedHeight(parentSize.height()); - } else { - setFixedWidth(parentSize.width()); - } - - // resize parrent if width is smaller than this dialog - if (resizeParent && parentSize.width() < size().width()) { - parentWidget()->resize(size().width(), parentSize.height()); - } - - if (_position == POSITION_LEFT || _position == POSITION_TOP) { - // move to upper left corner - move(parentGeometry.topLeft()); - } else if (_position == POSITION_RIGHT) { - // move to upper right corner - QPoint pos = parentGeometry.topRight(); - pos.setX(pos.x() - size().width()); - move(pos); - } - repaint(); -} - -void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) { - if (_allowResize && mouseEvent->button() == Qt::LeftButton) { - if (_position == POSITION_LEFT || _position == POSITION_RIGHT) { - bool hitLeft = (_position == POSITION_LEFT) && (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH); - bool hitRight = (_position == POSITION_RIGHT) && (mouseEvent->pos().x() < RESIZE_HANDLE_WIDTH); - if (hitLeft || hitRight) { - _isResizing = true; - _resizeInitialWidth = size().width(); - setCursor(Qt::SizeHorCursor); - } - } else { - bool hitTop = (_position == POSITION_TOP) && (abs(mouseEvent->pos().y() - size().height()) < RESIZE_HANDLE_WIDTH); - if (hitTop) { - _isResizing = true; - _resizeInitialWidth = size().height(); - setCursor(Qt::SizeHorCursor); - } - } - } -} - -void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) { - unsetCursor(); - _isResizing = false; -} - -void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) { - if (_isResizing) { - if (_position == POSITION_LEFT) { - resize(mouseEvent->pos().x(), size().height()); - } else if (_position == POSITION_RIGHT) { - setUpdatesEnabled(false); - resize(_resizeInitialWidth - mouseEvent->pos().x(), size().height()); - resizeAndPosition(); - _resizeInitialWidth = size().width(); - setUpdatesEnabled(true); - } else if (_position == POSITION_TOP) { - resize(size().width(), mouseEvent->pos().y()); - } - } -} diff --git a/interface/src/ui/FramelessDialog.h b/interface/src/ui/FramelessDialog.h deleted file mode 100644 index 32451f746d..0000000000 --- a/interface/src/ui/FramelessDialog.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// FramelessDialog.h -// interface/src/ui -// -// Created by Stojce Slavkovski on 2/20/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - - -#ifndef hifi_FramelessDialog_h -#define hifi_FramelessDialog_h - -#include - -class FramelessDialog : public QDialog { - Q_OBJECT - -public: - enum Position { POSITION_LEFT, POSITION_RIGHT, POSITION_TOP }; - - FramelessDialog(QWidget* parent, Qt::WindowFlags flags = 0, Position position = POSITION_LEFT); - void setStyleSheetFile(const QString& fileName); - void setAllowResize(bool allowResize) { _allowResize = allowResize; } - bool getAllowResize() { return _allowResize; } - void setHideOnBlur(bool hideOnBlur) { _hideOnBlur = hideOnBlur; } - bool getHideOnBlur() { return _hideOnBlur; } - void resizeAndPosition(bool resizeParent = true); - -protected: - virtual void mouseMoveEvent(QMouseEvent* mouseEvent); - virtual void mousePressEvent(QMouseEvent* mouseEvent); - virtual void mouseReleaseEvent(QMouseEvent* mouseEvent); - virtual void showEvent(QShowEvent* event); - - bool eventFilter(QObject* sender, QEvent* event); - -private: - bool _allowResize; - bool _isResizing; - int _resizeInitialWidth; - bool _selfHidden; ///< true when the dialog itself because of a window event (deactivation or minimization) - Position _position; - bool _hideOnBlur; - -}; - -#endif // hifi_FramelessDialog_h diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index b134f7f230..3b164041fa 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -1,120 +1,35 @@ // +// // LoginDialog.cpp -// interface/src/ui // -// Created by Ryan Huffman on 4/23/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - - -#include -#include -#include - -#include -#include - -#include "Application.h" -#include "Menu.h" -#include "AccountManager.h" -#include "ui_loginDialog.h" #include "LoginDialog.h" -#include "UIUtil.h" -const QString CREATE_ACCOUNT_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/signup"; -const QString FORGOT_PASSWORD_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/users/password/new"; +#include "DependencyManager.h" +#include "AccountManager.h" +#include "Menu.h" +#include -LoginDialog::LoginDialog(QWidget* parent) : - FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP), - _ui(new Ui::LoginDialog) { - - _ui->setupUi(this); - reset(); - - setAttribute(Qt::WA_DeleteOnClose, false); +QML_DIALOG_DEF(LoginDialog) +LoginDialog::LoginDialog(QQuickItem *parent) : QQuickItem(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) { connect(&AccountManager::getInstance(), &AccountManager::loginComplete, - this, &LoginDialog::handleLoginCompleted); + this, &LoginDialog::handleLoginCompleted); connect(&AccountManager::getInstance(), &AccountManager::loginFailed, - this, &LoginDialog::handleLoginFailed); - connect(_ui->loginButton, &QPushButton::clicked, - this, &LoginDialog::handleLoginClicked); - connect(_ui->closeButton, &QPushButton::clicked, - this, &LoginDialog::close); - - UIUtil::scaleWidgetFontSizes(this); - _ui->accountLabel->setText(_ui->accountLabel->text().arg(CREATE_ACCOUNT_URL, FORGOT_PASSWORD_URL)); - - // Initialize toggle connection - toggleQAction(); -}; - -LoginDialog::~LoginDialog() { - delete _ui; -}; - -void LoginDialog::reset() { - _ui->errorLabel->hide(); - _ui->emailLineEdit->setFocus(); - _ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg")); - _ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg")); - _ui->closeButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/close.svg")); - _ui->infoLabel->setVisible(false); - _ui->errorLabel->setVisible(false); - - _ui->emailLineEdit->setText(""); - _ui->passwordLineEdit->setText(""); - _ui->loginArea->setDisabled(false); + this, &LoginDialog::handleLoginFailed); } -void LoginDialog::handleLoginCompleted(const QUrl& authURL) { - reset(); - close(); -}; - -void LoginDialog::handleLoginFailed() { - _ui->infoLabel->setVisible(false); - _ui->errorLabel->setVisible(true); - - _ui->errorLabel->show(); - _ui->loginArea->setDisabled(false); - - // Move focus to password and select the entire line - _ui->passwordLineEdit->setFocus(); - _ui->passwordLineEdit->setSelection(0, _ui->emailLineEdit->maxLength()); -}; - -void LoginDialog::handleLoginClicked() { - // If the email or password inputs are empty, move focus to them, otherwise attempt to login. - if (_ui->emailLineEdit->text().isEmpty()) { - _ui->emailLineEdit->setFocus(); - } else if (_ui->passwordLineEdit->text().isEmpty()) { - _ui->passwordLineEdit->setFocus(); - } else { - _ui->infoLabel->setVisible(true); - _ui->errorLabel->setVisible(false); - - _ui->loginArea->setDisabled(true); - AccountManager::getInstance().requestAccessToken(_ui->emailLineEdit->text(), _ui->passwordLineEdit->text()); - } -}; - -void LoginDialog::moveEvent(QMoveEvent* event) { - // Modal dialogs seemed to get repositioned automatically. Combat this by moving the window if needed. - resizeAndPosition(); -}; - - -void LoginDialog::toggleQAction() { +void LoginDialog::toggleAction() { AccountManager& accountManager = AccountManager::getInstance(); QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login); Q_CHECK_PTR(loginAction); - disconnect(loginAction, 0, 0, 0); - + if (accountManager.isLoggedIn()) { // change the menu item to logout loginAction->setText("Logout " + accountManager.getAccountInfo().getUsername()); @@ -122,11 +37,40 @@ void LoginDialog::toggleQAction() { } else { // change the menu item to login loginAction->setText("Login"); - connect(loginAction, &QAction::triggered, this, &LoginDialog::showLoginForCurrentDomain); + connect(loginAction, &QAction::triggered, &LoginDialog::show); } } -void LoginDialog::showLoginForCurrentDomain() { - show(); - resizeAndPosition(false); +void LoginDialog::handleLoginCompleted(const QUrl& authURL) { + setEnabled(false); + setVisible(false); +} + +void LoginDialog::handleLoginFailed() { + setStatusText("Invalid username or password.< / font>"); +} + +void LoginDialog::setStatusText(const QString &a) { + if (a != _statusText) { + _statusText = a; + emit statusTextChanged(); + } +} + +QString LoginDialog::statusText() const { + return _statusText; +} + +QString LoginDialog::rootUrl() const { + return _rootUrl; +} + +void LoginDialog::login(const QString & username, const QString & password) { + qDebug() << "Attempting to login " << username; + setStatusText("Authenticating..."); + AccountManager::getInstance().requestAccessToken(username, password); +} + +void LoginDialog::openUrl(const QString & url) { + qDebug() << url; } diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index d5384c4625..3c9a98a9a4 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -1,9 +1,8 @@ // // LoginDialog.h -// interface/src/ui // -// Created by Ryan Huffman on 4/23/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -12,35 +11,41 @@ #ifndef hifi_LoginDialog_h #define hifi_LoginDialog_h -#include -#include "FramelessDialog.h" +#pragma once +#include -namespace Ui { - class LoginDialog; -} +#include "OffscreenUi.h" -class LoginDialog : public FramelessDialog { +class LoginDialog : public QQuickItem +{ Q_OBJECT + QML_DIALOG_DECL + + Q_PROPERTY(QString statusText READ statusText WRITE setStatusText NOTIFY statusTextChanged) + Q_PROPERTY(QString rootUrl READ rootUrl) public: - LoginDialog(QWidget* parent); - ~LoginDialog(); + static void toggleAction(); -public slots: - void toggleQAction(); - void showLoginForCurrentDomain(); - -protected slots: - void reset(); - void handleLoginClicked(); + LoginDialog(QQuickItem *parent = 0); + + void setStatusText(const QString & a); + QString statusText() const; + + QString rootUrl() const; + +signals: + void statusTextChanged(); + +protected: void handleLoginCompleted(const QUrl& authURL); void handleLoginFailed(); -protected: - void moveEvent(QMoveEvent* event); - + Q_INVOKABLE void login(const QString & username, const QString & password); + Q_INVOKABLE void openUrl(const QString & url); private: - Ui::LoginDialog* _ui = nullptr; + QString _statusText; + const QString _rootUrl; }; #endif // hifi_LoginDialog_h diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index caabff44cf..fd4d447b25 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -6,7 +6,7 @@ AUTOSCRIBE_SHADER_LIB(gpu model) qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") # use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(Widgets OpenGL Network Script) +setup_hifi_library(Widgets OpenGL Network Qml Quick Script) add_dependency_external_projects(glm) find_package(GLM REQUIRED) diff --git a/libraries/render-utils/src/FboCache.cpp b/libraries/render-utils/src/FboCache.cpp new file mode 100644 index 0000000000..fdd29d20d8 --- /dev/null +++ b/libraries/render-utils/src/FboCache.cpp @@ -0,0 +1,98 @@ +// +// OffscreenGlCanvas.cpp +// interface/src/renderer +// +// Created by Bradley Austin Davis on 2014/04/09. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#include "FboCache.h" + +#include +#include +#include "ThreadHelpers.h" + +FboCache::FboCache() { + // Why do we even HAVE that lever? +} + +void FboCache::lockTexture(int texture) { + withLock(_lock, [&] { + Q_ASSERT(_fboMap.count(texture)); + if (!_fboLocks.count(texture)) { + Q_ASSERT(_readyFboQueue.front()->texture() == texture); + _readyFboQueue.pop_front(); + _fboLocks[texture] = 1; + } else { + _fboLocks[texture]++; + } + }); +} + +void FboCache::releaseTexture(int texture) { + withLock(_lock, [&] { + Q_ASSERT(_fboMap.count(texture)); + Q_ASSERT(_fboLocks.count(texture)); + int newLockCount = --_fboLocks[texture]; + if (!newLockCount) { + auto fbo = _fboMap[texture].data(); + if (fbo->size() != _size) { + // Move the old FBO to the destruction queue. + // We can't destroy the FBO here because we might + // not be on the right thread or have the context active + _destroyFboQueue.push_back(_fboMap[texture]); + _fboMap.remove(texture); + } else { + _readyFboQueue.push_back(fbo); + } + _fboLocks.remove(texture); + } + }); +} + +QOpenGLFramebufferObject* FboCache::getReadyFbo() { + QOpenGLFramebufferObject* result = nullptr; + withLock(_lock, [&] { + // Delete any FBOs queued for deletion + _destroyFboQueue.clear(); + + if (_readyFboQueue.empty()) { + qDebug() << "Building new offscreen FBO number " << _fboMap.size() + 1; + result = new QOpenGLFramebufferObject(_size, QOpenGLFramebufferObject::CombinedDepthStencil); + _fboMap[result->texture()] = QSharedPointer(result); + _readyFboQueue.push_back(result); + } else { + result = _readyFboQueue.front(); + } + }); + return result; +} + +void FboCache::setSize(const QSize & newSize) { + if (_size == newSize) { + return; + } + _size = newSize; + withLock(_lock, [&] { + // Clear out any fbos with the old id + _readyFboQueue.clear(); + + QSet outdatedFbos; + // FBOs that are locked will be removed as they are unlocked + foreach(int texture, _fboMap.keys()) { + if (!_fboLocks.count(texture)) { + outdatedFbos.insert(texture); + } + } + // Implicitly deletes the FBO via the shared pointer destruction mechanism + foreach(int texture, outdatedFbos) { + _fboMap.remove(texture); + } + }); +} + + diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h new file mode 100644 index 0000000000..bbbb4a943e --- /dev/null +++ b/libraries/render-utils/src/FboCache.h @@ -0,0 +1,50 @@ +// +// OffscreenGlCanvas.h +// interface/src/renderer +// +// Created by Bradley Austin Davis on 2014/04/09. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once +#ifndef hifi_FboCache_h +#define hifi_FboCache_h + +#include +#include +#include +#include +#include + +class QOpenGLFramebufferObject; + +class FboCache : public QObject { +public: + FboCache(); + + // setSize() and getReadyFbo() must consitently be called from only a single + // thread. Additionally, it is the caller's responsibility to ensure that + // the appropriate OpenGL context is active when doing so. + + // Important.... textures are sharable resources, but FBOs ARE NOT. + void setSize(const QSize & newSize); + QOpenGLFramebufferObject* getReadyFbo(); + + // These operations are thread safe and require no OpenGL context. They manipulate the + // internal locks and pointers but execute no OpenGL opreations. + void lockTexture(int texture); + void releaseTexture(int texture); + +protected: + QMap> _fboMap; + QMap _fboLocks; + QQueue _readyFboQueue; + QQueue> _destroyFboQueue; + QMutex _lock; + QSize _size; + +}; + +#endif // hifi_FboCache_h diff --git a/libraries/render-utils/src/OffscreenGlCanvas.cpp b/libraries/render-utils/src/OffscreenGlCanvas.cpp new file mode 100644 index 0000000000..694fa68a5a --- /dev/null +++ b/libraries/render-utils/src/OffscreenGlCanvas.cpp @@ -0,0 +1,43 @@ +// +// OffscreenGlCanvas.cpp +// interface/src/renderer +// +// Created by Bradley Austin Davis on 2014/04/09. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#include "OffscreenGlCanvas.h" + +OffscreenGlCanvas::OffscreenGlCanvas() { +} + +void OffscreenGlCanvas::create(QOpenGLContext * sharedContext) { + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + format.setMajorVersion(4); + format.setMinorVersion(1); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + + _context.setFormat(format); + if (nullptr != sharedContext) { + _context.setShareContext(sharedContext); + } + _context.create(); + + _offscreenSurface.setFormat(_context.format()); + _offscreenSurface.create(); +} + +bool OffscreenGlCanvas::makeCurrent() { + return _context.makeCurrent(&_offscreenSurface); +} + +void OffscreenGlCanvas::doneCurrent() { + _context.doneCurrent(); +} + diff --git a/libraries/render-utils/src/OffscreenGlCanvas.h b/libraries/render-utils/src/OffscreenGlCanvas.h new file mode 100644 index 0000000000..1b2f15f690 --- /dev/null +++ b/libraries/render-utils/src/OffscreenGlCanvas.h @@ -0,0 +1,31 @@ +// +// OffscreenGlCanvas.h +// interface/src/renderer +// +// Created by Bradley Austin Davis on 2014/04/09. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once +#ifndef hifi_OffscreenGlCanvas_h +#define hifi_OffscreenGlCanvas_h + +#include +#include + +class OffscreenGlCanvas : public QObject { +public: + OffscreenGlCanvas(); + void create(QOpenGLContext * sharedContext = nullptr); + bool makeCurrent(); + void doneCurrent(); + +protected: + QOpenGLContext _context; + QOffscreenSurface _offscreenSurface; + +}; + +#endif // hifi_OffscreenGlCanvas_h diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp new file mode 100644 index 0000000000..cb57d86412 --- /dev/null +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -0,0 +1,325 @@ +#include "OffscreenUi.h" +#include +#include +#include + +OffscreenUi::OffscreenUi() { +} + +OffscreenUi::~OffscreenUi() { + // Make sure the context is current while doing cleanup. Note that we use the + // offscreen surface here because passing 'this' at this point is not safe: the + // underlying platform window may already be destroyed. To avoid all the trouble, use + // another surface that is valid for sure. + makeCurrent(); + + // Delete the render control first since it will free the scenegraph resources. + // Destroy the QQuickWindow only afterwards. + delete _renderControl; + + delete _qmlComponent; + delete _quickWindow; + delete _qmlEngine; + + doneCurrent(); +} + +void OffscreenUi::create(QOpenGLContext * shareContext) { + OffscreenGlCanvas::create(shareContext); + + makeCurrent(); + + // Create a QQuickWindow that is associated with out render control. Note that this + // window never gets created or shown, meaning that it will never get an underlying + // native (platform) window. + QQuickWindow::setDefaultAlphaBuffer(true); + _quickWindow = new QQuickWindow(_renderControl); + _quickWindow->setColor(QColor(255, 255, 255, 0)); + _quickWindow->setFlags(_quickWindow->flags() | static_cast(Qt::WA_TranslucentBackground)); + // Create a QML engine. + _qmlEngine = new QQmlEngine; + if (!_qmlEngine->incubationController()) + _qmlEngine->setIncubationController(_quickWindow->incubationController()); + + // When Quick says there is a need to render, we will not render immediately. Instead, + // a timer with a small interval is used to get better performance. + _updateTimer.setSingleShot(true); + _updateTimer.setInterval(5); + connect(&_updateTimer, &QTimer::timeout, this, &OffscreenUi::updateQuick); + + // Now hook up the signals. For simplicy we don't differentiate between + // renderRequested (only render is needed, no sync) and sceneChanged (polish and sync + // is needed too). + connect(_renderControl, &QQuickRenderControl::renderRequested, this, &OffscreenUi::requestRender); + connect(_renderControl, &QQuickRenderControl::sceneChanged, this, &OffscreenUi::requestUpdate); + connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, [this](QObject *object){ + OffscreenUi * p = this; + qDebug() << "Focus changed to " << object; + }); + _quickWindow->focusObject(); + + _qmlComponent = new QQmlComponent(_qmlEngine); + + // Initialize the render control and our OpenGL resources. + makeCurrent(); + _renderControl->initialize(&_context); +} + +void OffscreenUi::resize(const QSize & newSize) { + makeCurrent(); + + // Clear out any fbos with the old size + _fboCache.setSize(newSize); + + // Update our members + if (_rootItem) { + _rootItem->setSize(newSize); + } + + if (_quickWindow) { + _quickWindow->setGeometry(QRect(QPoint(), newSize)); + } + + doneCurrent(); +} + +QQmlContext * OffscreenUi::qmlContext() { + if (nullptr == _rootItem) { + return _qmlComponent->creationContext(); + } + return QQmlEngine::contextForObject(_rootItem); +} + +void OffscreenUi::loadQml(const QUrl & qmlSource, std::function f) { + _qmlComponent->loadUrl(qmlSource); + if (_qmlComponent->isLoading()) + connect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad); + else + finishQmlLoad(); +} + +void OffscreenUi::requestUpdate() { + _polish = true; + if (!_updateTimer.isActive()) + _updateTimer.start(); +} + +void OffscreenUi::requestRender() { + if (!_updateTimer.isActive()) + _updateTimer.start(); +} + +void OffscreenUi::finishQmlLoad() { + disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad); + if (_qmlComponent->isError()) { + QList errorList = _qmlComponent->errors(); + foreach(const QQmlError &error, errorList) { + qWarning() << error.url() << error.line() << error; + } + return; + } + + QObject *rootObject = _qmlComponent->create(); + if (_qmlComponent->isError()) { + QList errorList = _qmlComponent->errors(); + foreach(const QQmlError &error, errorList) + qWarning() << error.url() << error.line() << error; + qFatal("Unable to finish loading QML"); + return; + } + + _rootItem = qobject_cast(rootObject); + if (!_rootItem) { + qWarning("run: Not a QQuickItem"); + delete rootObject; + qFatal("Unable to find root QQuickItem"); + return; + } + + // Make sure we can assign focus to the root item (critical for + // supporting keyboard shortcuts) + _rootItem->setFlag(QQuickItem::ItemIsFocusScope, true); + // The root item is ready. Associate it with the window. + _rootItem->setParentItem(_quickWindow->contentItem()); + _rootItem->setSize(_quickWindow->renderTargetSize()); + qDebug() << "Finished setting up QML provider"; +} + + +void OffscreenUi::updateQuick() { + if (_paused) { + return; + } + if (!makeCurrent()) + return; + + // Polish, synchronize and render the next frame (into our fbo). In this example + // everything happens on the same thread and therefore all three steps are performed + // in succession from here. In a threaded setup the render() call would happen on a + // separate thread. + if (_polish) { + _renderControl->polishItems(); + _renderControl->sync(); + _polish = false; + } + + QOpenGLFramebufferObject* fbo = _fboCache.getReadyFbo(); + + _quickWindow->setRenderTarget(fbo); + fbo->bind(); + + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + _renderControl->render(); + + Q_ASSERT(!glGetError()); + + _quickWindow->resetOpenGLState(); + + QOpenGLFramebufferObject::bindDefault(); + // Force completion of all the operations before we emit the texture as being ready for use + glFinish(); + + emit textureUpdated(fbo->texture()); +} + +QPointF OffscreenUi::mapWindowToUi(const QPointF & p, QObject * dest) { + vec2 sourceSize; + if (dynamic_cast(dest)) { + sourceSize = toGlm(((QWidget*)dest)->size()); + } else if (dynamic_cast(dest)) { + sourceSize = toGlm(((QWindow*)dest)->size()); + } + vec2 pos = toGlm(p); + pos /= sourceSize; + pos *= vec2(toGlm(_quickWindow->renderTargetSize())); + return QPointF(pos.x, pos.y); +} + +/////////////////////////////////////////////////////// +// +// Event handling customization +// + +bool OffscreenUi::eventFilter(QObject * dest, QEvent * e) { + // Only intercept events while we're in an active state + if (_paused) { + return false; + } + + // Don't intercept our own events, or we enter an infinite recursion + if (dest == _quickWindow) { + return false; + } + + switch (e->type()) { + case QEvent::Resize: + { + QResizeEvent * re = (QResizeEvent *)e; + QGLWidget * widget = dynamic_cast(dest); + if (widget) { + this->resize(re->size()); + } + return false; + } + + case QEvent::KeyPress: + case QEvent::KeyRelease: + { + e->ignore(); + if (QApplication::sendEvent(_quickWindow, e)) { + return e->isAccepted(); + } + } + break; + + case QEvent::Wheel: + { + QWheelEvent * we = (QWheelEvent*)e; + QWheelEvent mappedEvent(mapWindowToUi(we->pos(), dest), we->delta(), we->buttons(), we->modifiers(), we->orientation()); + QCoreApplication::sendEvent(_quickWindow, &mappedEvent); + return true; + } + break; + + // Fall through + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + { + QMouseEvent * me = (QMouseEvent *)e; + QPointF originalPos = me->localPos(); + QPointF transformedPos = _mouseTranslator(originalPos); + QMouseEvent mappedEvent(e->type(), mapWindowToUi(transformedPos, dest), me->screenPos(), me->button(), me->buttons(), me->modifiers()); + QCoreApplication::sendEvent(_quickWindow, &mappedEvent); + return QObject::event(e); + } + + default: break; + } + + return false; +} + +void OffscreenUi::lockTexture(int texture) { + _fboCache.lockTexture(texture); +} + +void OffscreenUi::releaseTexture(int texture) { + _fboCache.releaseTexture(texture); +} + +void OffscreenUi::pause() { + _paused = true; +} + +void OffscreenUi::resume() { + _paused = false; + requestRender(); +} + +bool OffscreenUi::isPaused() const { + return _paused; +} + +void OffscreenUi::setProxyWindow(QWindow * window) { + _renderControl->_renderWindow = window; +} + +void OffscreenUi::show(const QUrl & url, const QString & name) { + QQuickItem * item = _rootItem->findChild(name); + if (nullptr != item) { + item->setEnabled(true); + item->setVisible(true); + } else { + load(url); + } +} + +void OffscreenUi::toggle(const QUrl & url, const QString & name) { + QQuickItem * item = _rootItem->findChild(name); + // First load? + if (nullptr == item) { + load(url); + return; + } + + // Toggle the visibity AND the enabled flag (otherwise invisible + // dialogs can still swallow keyboard input) + bool newFlag = !item->isVisible(); + item->setVisible(newFlag); + item->setEnabled(newFlag); +} + + +void OffscreenUi::load(const QUrl & url) { + QVariant returnedValue; + QVariant msg = url; + QMetaObject::invokeMethod(_rootItem, "loadChild", + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, msg)); + qDebug() << "QML function returned:" << returnedValue.toString(); +} + diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h new file mode 100644 index 0000000000..2e8206f466 --- /dev/null +++ b/libraries/render-utils/src/OffscreenUi.h @@ -0,0 +1,136 @@ +// +// OffscreenUi.h +// interface/src/entities +// +// Created by Bradley Austin Davis on 2015-04-04 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once +#ifndef hifi_OffscreenUi_h +#define hifi_OffscreenUi_h + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FboCache.h" +#include "OffscreenGlCanvas.h" + +#define QML_DIALOG_DECL \ +private: \ + static const QString NAME; \ + static const QUrl QML; \ +public: \ + static void registerType(); \ + static void show(); \ + static void toggle(); \ +private: + +#define QML_DIALOG_DEF(x) \ + const QUrl x::QML = #x ".qml"; \ + const QString x::NAME = #x; \ + \ + void x::registerType() { \ + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ + } \ + \ + void x::show() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->show(QML, NAME); \ + } \ + \ + void x::toggle() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->toggle(QML, NAME); \ + } + + +class OffscreenUi : public OffscreenGlCanvas, public Dependency { + Q_OBJECT + + class QMyQuickRenderControl : public QQuickRenderControl { + protected: + QWindow * renderWindow(QPoint * offset) Q_DECL_OVERRIDE{ + if (nullptr == _renderWindow) { + return QQuickRenderControl::renderWindow(offset); + } + if (nullptr != offset) { + offset->rx() = offset->ry() = 0; + } + return _renderWindow; + } + + private: + QWindow * _renderWindow{ nullptr }; + friend class OffscreenUi; + }; + +public: + using MouseTranslator = std::function < QPointF(const QPointF &) > ; + OffscreenUi(); + virtual ~OffscreenUi(); + void create(QOpenGLContext * context); + void resize(const QSize & size); + void loadQml(const QUrl & qmlSource, std::function f = [](QQmlContext*) {}); + void load(const QUrl & url); + void show(const QUrl & url, const QString & name); + void toggle(const QUrl & url, const QString & name); + + QQmlContext * qmlContext(); + + void pause(); + void resume(); + bool isPaused() const; + void setProxyWindow(QWindow * window); + QPointF mapWindowToUi(const QPointF & p, QObject * dest); + virtual bool eventFilter(QObject * dest, QEvent * e); + void setMouseTranslator(MouseTranslator mt) { + _mouseTranslator = mt; + } + +protected: + +private slots: + void updateQuick(); + void finishQmlLoad(); + +public slots: + void requestUpdate(); + void requestRender(); + void lockTexture(int texture); + void releaseTexture(int texture); + +signals: + void textureUpdated(GLuint texture); + +private: + QMyQuickRenderControl *_renderControl{ new QMyQuickRenderControl }; + QQuickWindow *_quickWindow{ nullptr }; + QQmlEngine *_qmlEngine{ nullptr }; + QQmlComponent *_qmlComponent{ nullptr }; + QQuickItem * _rootItem{ nullptr }; + QTimer _updateTimer; + FboCache _fboCache; + bool _polish{ true }; + bool _paused{ true }; + MouseTranslator _mouseTranslator{ [](const QPointF & p) { return p; } }; +}; + +#endif \ No newline at end of file diff --git a/libraries/render-utils/src/RenderUtil.h b/libraries/render-utils/src/RenderUtil.h index b2f244733a..74d6c23791 100644 --- a/libraries/render-utils/src/RenderUtil.h +++ b/libraries/render-utils/src/RenderUtil.h @@ -15,4 +15,54 @@ /// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, tMin) to (sMax, tMax). void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f, float tMin = 0.0f, float tMax = 1.0f); +template +void withMatrixPush(F f) { + glMatrixMode(matrix); + glPushMatrix(); + f(); + glPopMatrix(); +} + +template +void withProjectionPush(F f) { + withMatrixPush(f); +} + +template +void withProjectionIdentity(F f) { + withProjectionPush([&] { + glLoadIdentity(); + f(); + }); +} + +template +void withProjectionMatrix(GLfloat * matrix, F f) { + withProjectionPush([&] { + glLoadMatrixf(matrix); + f(); + }); +} + +template +void withModelviewPush(F f) { + withMatrixPush(f); +} + +template +void withModelviewIdentity(F f) { + withModelviewPush([&] { + glLoadIdentity(); + f(); + }); +} + +template +void withModelviewMatrix(GLfloat * matrix, F f) { + withModelviewPush([&] { + glLoadMatrixf(matrix); + f(); + }); +} + #endif // hifi_RenderUtil_h diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 50393b7f5f..e5d22d67dc 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -17,6 +17,17 @@ #include #include +// Bring the most commonly used GLM types into the default namespace +using glm::ivec3; +using glm::ivec2; +using glm::uvec2; +using glm::mat3; +using glm::mat4; +using glm::vec2; +using glm::vec3; +using glm::vec4; +using glm::quat; + #include #include #include diff --git a/libraries/shared/src/ThreadHelpers.h b/libraries/shared/src/ThreadHelpers.h new file mode 100644 index 0000000000..862f7bf673 --- /dev/null +++ b/libraries/shared/src/ThreadHelpers.h @@ -0,0 +1,13 @@ +#pragma once +#include + +template +void withLock(L lock, F function) { + throw std::exception(); +} + +template +void withLock(QMutex & lock, F function) { + QMutexLocker locker(&lock); + function(); +} diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index b62ab68c22..304d6f1a07 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -10,6 +10,7 @@ #include "TextRenderer.h" #include "MatrixStack.h" +#include "OffscreenUi.h" #include #include @@ -21,9 +22,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -66,99 +69,143 @@ public: }; // Create a simple OpenGL window that renders text in various ways -class QTestWindow: public QWindow { +class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext * _context; + + QOpenGLContext * _context{ nullptr }; QSize _size; TextRenderer* _textRenderer[4]; RateCounter fps; + OffscreenUi _offscreenUi; + int testQmlTexture{ 0 }; + //ProgramPtr _planeProgam; + //ShapeWrapperPtr _planeShape; protected: - void resizeEvent(QResizeEvent * ev) override { - QWindow::resizeEvent(ev); - _size = ev->size(); - resizeGl(); - } - void resizeGl() { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, _size.width(), _size.height(), 0, 1, -1); - glMatrixMode(GL_MODELVIEW); - glViewport(0, 0, _size.width(), _size.height()); + void renderText(); + void renderQml(); + +private: + void resizeWindow(const QSize & size) { + _size = size; + _offscreenUi.resize(_size); } public: - QTestWindow(); - virtual ~QTestWindow() { + QTestWindow() { + setSurfaceType(QSurface::OpenGLSurface); + QSurfaceFormat format; + // Qt Quick may need a depth and stencil buffer. Always make sure these are available. + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + format.setVersion(4, 5); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + format.setOption(QSurfaceFormat::DebugContext); + + setFormat(format); + + _context = new QOpenGLContext; + _context->setFormat(format); + _context->create(); + + show(); + makeCurrent(); + + { + QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + logger->initialize(); // initializes in the current context, i.e. ctx + logger->enableMessages(); + connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { + qDebug() << debugMessage; + }); + // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); + } + qDebug() << (const char*)glGetString(GL_VERSION); + +#ifdef WIN32 + glewExperimental = true; + GLenum err = glewInit(); + if (GLEW_OK != err) { + /* Problem: glewInit failed, something is seriously wrong. */ + const GLubyte * errStr = glewGetErrorString(err); + qDebug("Error: %s\n", errStr); + } + qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); + + if (wglewGetExtension("WGL_EXT_swap_control")) { + int swapInterval = wglGetSwapIntervalEXT(); + qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); + } + glGetError(); +#endif + + _textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); + _textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, + TextRenderer::SHADOW_EFFECT); + _textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1, + false, TextRenderer::OUTLINE_EFFECT); + _textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClearColor(0.2f, 0.2f, 0.2f, 1); + glDisable(GL_DEPTH_TEST); + + _offscreenUi.create(_context); + // FIXME, need to switch to a QWindow for mouse and keyboard input to work + _offscreenUi.setProxyWindow(this); + // "#0e7077" + setFramePosition(QPoint(-1000, 0)); + resize(QSize(800, 600)); + + static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/Root.qml"); + _offscreenUi.loadQml(QUrl::fromLocalFile(f)); + connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) { + _offscreenUi.lockTexture(textureId); + assert(!glGetError()); + GLuint oldTexture = testQmlTexture; + testQmlTexture = textureId; + if (oldTexture) { + _offscreenUi.releaseTexture(oldTexture); + } + }); + installEventFilter(&_offscreenUi); + _offscreenUi.resume(); } + + virtual ~QTestWindow() { + } + + void draw(); void makeCurrent() { _context->makeCurrent(this); } - void draw(); +protected: + + void resizeEvent(QResizeEvent * ev) override { + resizeWindow(ev->size()); + } + + + void keyPressEvent(QKeyEvent *event) { + switch (event->key()) { + case Qt::Key_Slash: + qDebug() << "Foo"; + _offscreenUi.load(QString("Login.qml")); + break; + } + QWindow::keyPressEvent(event); + } + }; #ifndef SERIF_FONT_FAMILY #define SERIF_FONT_FAMILY "Times New Roman" #endif -QTestWindow::QTestWindow() { - setSurfaceType(QSurface::OpenGLSurface); - - QSurfaceFormat format; - // Qt Quick may need a depth and stencil buffer. Always make sure these are available. - format.setDepthBufferSize(16); - format.setStencilBufferSize(8); - format.setVersion(3, 2); - format.setProfile( - QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); - setFormat(format); - - _context = new QOpenGLContext; - _context->setFormat(format); - _context->create(); - - show(); - makeCurrent(); - qDebug() << (const char*) glGetString(GL_VERSION); - -#ifdef WIN32 - glewExperimental = true; - GLenum err = glewInit(); - if (GLEW_OK != err) { - /* Problem: glewInit failed, something is seriously wrong. */ - const GLubyte * errStr = glewGetErrorString(err); - qDebug("Error: %s\n", errStr); - } - qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); - - if (wglewGetExtension("WGL_EXT_swap_control")) { - int swapInterval = wglGetSwapIntervalEXT(); - qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); - } - glGetError(); -#endif - - setFramePosition(QPoint(100, -900)); - resize(QSize(800, 600)); - _size = QSize(800, 600); - - _textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); - _textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, - TextRenderer::SHADOW_EFFECT); - _textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1, - false, TextRenderer::OUTLINE_EFFECT); - _textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glClearColor(0.2f, 0.2f, 0.2f, 1); - glDisable(GL_DEPTH_TEST); - resizeGl(); -} - static const wchar_t * EXAMPLE_TEXT = L"Hello"; //static const wchar_t * EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y"; static const glm::uvec2 QUAD_OFFSET(10, 10); @@ -166,14 +213,21 @@ static const glm::uvec2 QUAD_OFFSET(10, 10); static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, { 1.0, 0.5, 0.5 }, { 0.5, 0.5, 1.0 } }; -void QTestWindow::draw() { - makeCurrent(); - glClear(GL_COLOR_BUFFER_BIT); +void QTestWindow::renderText() { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, _size.width(), _size.height(), 0, 1, -1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); const glm::uvec2 size = glm::uvec2(_size.width() / 2, _size.height() / 2); - const glm::uvec2 offsets[4] = { { QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x - + QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x + QUAD_OFFSET.x, size.y - + QUAD_OFFSET.y }, { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, }; + + const glm::uvec2 offsets[4] = { + { QUAD_OFFSET.x, QUAD_OFFSET.y }, + { size.x + QUAD_OFFSET.x, QUAD_OFFSET.y }, + { size.x + QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, + { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, + }; QString str = QString::fromWCharArray(EXAMPLE_TEXT); for (int i = 0; i < 4; ++i) { @@ -200,17 +254,57 @@ void QTestWindow::draw() { glm::vec4(COLORS[i], 1.0f)); } } +} + +void QTestWindow::renderQml() { + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if (testQmlTexture > 0) { + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, testQmlTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + glBegin(GL_QUADS); + { + + glTexCoord2f(0, 0); + glVertex2f(-1, -1); + glTexCoord2f(0, 1); + glVertex2f(-1, 1); + glTexCoord2f(1, 1); + glVertex2f(1, 1); + glTexCoord2f(1, 0); + glVertex2f(1, -1); + } + glEnd(); +} + +void QTestWindow::draw() { + makeCurrent(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, _size.width(), _size.height()); + + renderText(); + //renderQml(); + _context->swapBuffers(this); glFinish(); + fps.increment(); if (fps.elapsed() >= 2.0f) { - qDebug() << "FPS: " << fps.rate(); + //qDebug() << "FPS: " << fps.rate(); fps.reset(); } } int main(int argc, char** argv) { QApplication app(argc, argv); + //QLoggingCategory::setFilterRules("qt.quick.mouse.debug = true"); QTestWindow window; QTimer timer; timer.setInterval(1); From aba2b395a6769bd91df352506e63fd47391e240c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 15 Apr 2015 12:35:30 -0700 Subject: [PATCH 02/20] Working on testing the QML ui --- interface/resources/qml/Palettes.qml | 236 +++++++++++++++++++++ interface/resources/qml/TestDialog.qml | 112 ++++++++++ interface/resources/qml/TestRoot.qml | 26 +++ interface/src/ui/ApplicationOverlay.h | 3 +- libraries/render-utils/src/OffscreenUi.cpp | 5 +- tests/render-utils/src/main.cpp | 11 +- 6 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 interface/resources/qml/Palettes.qml create mode 100644 interface/resources/qml/TestDialog.qml create mode 100644 interface/resources/qml/TestRoot.qml diff --git a/interface/resources/qml/Palettes.qml b/interface/resources/qml/Palettes.qml new file mode 100644 index 0000000000..c4b0953df7 --- /dev/null +++ b/interface/resources/qml/Palettes.qml @@ -0,0 +1,236 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 + +Rectangle { + color: "teal" + height: 512 + width: 192 + SystemPalette { id: sp; colorGroup: SystemPalette.Active } + SystemPalette { id: spi; colorGroup: SystemPalette.Inactive } + SystemPalette { id: spd; colorGroup: SystemPalette.Disabled } + + Column { + anchors.margins: 8 + anchors.fill: parent + spacing: 8 + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "base" } + Rectangle { height: parent.height; width: 16; color: sp.base } + Rectangle { height: parent.height; width: 16; color: spi.base } + Rectangle { height: parent.height; width: 16; color: spd.base } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "alternateBase" } + Rectangle { height: parent.height; width: 16; color: sp.alternateBase } + Rectangle { height: parent.height; width: 16; color: spi.alternateBase } + Rectangle { height: parent.height; width: 16; color: spd.alternateBase } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "dark" } + Rectangle { height: parent.height; width: 16; color: sp.dark } + Rectangle { height: parent.height; width: 16; color: spi.dark } + Rectangle { height: parent.height; width: 16; color: spd.dark } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "mid" } + Rectangle { height: parent.height; width: 16; color: sp.mid } + Rectangle { height: parent.height; width: 16; color: spi.mid } + Rectangle { height: parent.height; width: 16; color: spd.mid } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "mid light" } + Rectangle { height: parent.height; width: 16; color: sp.midlight } + Rectangle { height: parent.height; width: 16; color: spi.midlight } + Rectangle { height: parent.height; width: 16; color: spd.midlight } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "light" } + Rectangle { height: parent.height; width: 16; color: sp.light} + Rectangle { height: parent.height; width: 16; color: spi.light} + Rectangle { height: parent.height; width: 16; color: spd.light} + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "shadow" } + Rectangle { height: parent.height; width: 16; color: sp.shadow} + Rectangle { height: parent.height; width: 16; color: spi.shadow} + Rectangle { height: parent.height; width: 16; color: spd.shadow} + } + Item { + height: 16 + width:parent.width + } + + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "text" } + Rectangle { height: parent.height; width: 16; color: sp.text } + Rectangle { height: parent.height; width: 16; color: spi.text } + Rectangle { height: parent.height; width: 16; color: spd.text } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "window" } + Rectangle { height: parent.height; width: 16; color: sp.window } + Rectangle { height: parent.height; width: 16; color: spi.window } + Rectangle { height: parent.height; width: 16; color: spd.window } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "window text" } + Rectangle { height: parent.height; width: 16; color: sp.windowText } + Rectangle { height: parent.height; width: 16; color: spi.windowText } + Rectangle { height: parent.height; width: 16; color: spd.windowText } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "button" } + Rectangle { height: parent.height; width: 16; color: sp.button } + Rectangle { height: parent.height; width: 16; color: spi.button } + Rectangle { height: parent.height; width: 16; color: spd.button } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "buttonText" } + Rectangle { height: parent.height; width: 16; color: sp.buttonText } + Rectangle { height: parent.height; width: 16; color: spi.buttonText } + Rectangle { height: parent.height; width: 16; color: spd.buttonText } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "highlight" } + Rectangle { height: parent.height; width: 16; color: sp.highlight } + Rectangle { height: parent.height; width: 16; color: spi.highlight } + Rectangle { height: parent.height; width: 16; color: spd.highlight } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "highlighted text" } + Rectangle { height: parent.height; width: 16; color: sp.highlightedText} + Rectangle { height: parent.height; width: 16; color: spi.highlightedText} + Rectangle { height: parent.height; width: 16; color: spd.highlightedText} + } + } + + +/* + CustomDialog { + title: "Test Dlg" + anchors.fill: parent + + Rectangle { + property int d: 100 + id: square + objectName: "testRect" + width: d + height: d + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + + + CustomTextEdit { + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + clip: true + text: "test edit" + anchors.top: parent.top + anchors.topMargin: parent.titleSize + 12 + } + + CustomButton { + x: 128 + y: 192 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + onClicked: { + console.log("Click"); + if (square.visible) { + square.visible = false + } else { + square.visible = true + } + } + } + + CustomButton { + id: customButton2 + y: 192 + text: "Close" + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + onClicked: { + onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0 + } + } + + Keys.onPressed: { + console.log("Key " + event.key); + switch (event.key) { + case Qt.Key_Q: + if (Qt.ControlModifier == event.modifiers) { + event.accepted = true; + break; + } + } + } + } +*/ + +} + + +/* + +// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property + +MouseArea { + anchors.fill: parent +} +*/ diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml new file mode 100644 index 0000000000..9c8bcccd75 --- /dev/null +++ b/interface/resources/qml/TestDialog.qml @@ -0,0 +1,112 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 + +Item { + objectName: "TestDialog" + id: testDialog + width: 384 + height: 384 + scale: 0.0 + + onEnabledChanged: { + scale = enabled ? 1.0 : 0.0 + } + onScaleChanged: { + visible = (scale != 0.0); + } + Component.onCompleted: { + scale = 1.0 + } + Behavior on scale { + NumberAnimation { + //This specifies how long the animation takes + duration: 400 + //This selects an easing curve to interpolate with, the default is Easing.Linear + easing.type: Easing.InOutBounce + } + } + + CustomDialog { + title: "Test Dlg" + anchors.fill: parent + + Rectangle { + property int d: 100 + id: square + objectName: "testRect" + width: d + height: d + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + + + CustomTextEdit { + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + clip: true + text: "test edit" + anchors.top: parent.top + anchors.topMargin: parent.titleSize + 12 + } + + CustomButton { + x: 128 + y: 192 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + onClicked: { + console.log("Click"); + if (square.visible) { + square.visible = false + } else { + square.visible = true + } + } + } + + CustomButton { + id: customButton2 + y: 192 + text: "Close" + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + onClicked: { + onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0 + } + } + + Keys.onPressed: { + console.log("Key " + event.key); + switch (event.key) { + case Qt.Key_Q: + if (Qt.ControlModifier == event.modifiers) { + event.accepted = true; + break; + } + } + } + } + + +} + + +/* + +// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property + +MouseArea { + anchors.fill: parent +} +*/ diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml new file mode 100644 index 0000000000..a3ef5f8fe9 --- /dev/null +++ b/interface/resources/qml/TestRoot.qml @@ -0,0 +1,26 @@ +import QtQuick 2.3 +import "componentCreation.js" as Creator + + +Item { + id: root + width: 1280 + height: 720 + + function loadChild(url) { + Creator.createObject(root, url) + } + + + CustomButton { + anchors.right: parent.right + anchors.rightMargin: 24 + anchors.bottom: parent.bottom + anchors.bottomMargin: 24 + text: "Test" + onClicked: { + loadChild("TestDialog.qml"); + } + } +} + diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index cc4188e8ef..e6c7526c5d 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -23,7 +23,8 @@ const float MAGNIFY_MULT = 2.0f; const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; // Handles the drawing of the overlays to the screen -class ApplicationOverlay { +class ApplicationOverlay : public QObject { + Q_OBJECT public: ApplicationOverlay(); ~ApplicationOverlay(); diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index cb57d86412..718a70f4e1 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -308,9 +308,10 @@ void OffscreenUi::toggle(const QUrl & url, const QString & name) { // Toggle the visibity AND the enabled flag (otherwise invisible // dialogs can still swallow keyboard input) - bool newFlag = !item->isVisible(); - item->setVisible(newFlag); + bool newFlag = !item->isEnabled(); item->setEnabled(newFlag); + // item->setVisible(newFlag); + } diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 304d6f1a07..dd413a9f57 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -160,7 +160,7 @@ public: setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); - static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/Root.qml"); + static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/TestRoot.qml"); _offscreenUi.loadQml(QUrl::fromLocalFile(f)); connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) { _offscreenUi.lockTexture(textureId); @@ -193,8 +193,7 @@ protected: void keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Slash: - qDebug() << "Foo"; - _offscreenUi.load(QString("Login.qml")); + _offscreenUi.toggle(QString("TestDialog.qml"), "TestDialog"); break; } QWindow::keyPressEvent(event); @@ -289,15 +288,15 @@ void QTestWindow::draw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, _size.width(), _size.height()); - renderText(); - //renderQml(); + //renderText(); + renderQml(); _context->swapBuffers(this); glFinish(); fps.increment(); if (fps.elapsed() >= 2.0f) { - //qDebug() << "FPS: " << fps.rate(); + qDebug() << "FPS: " << fps.rate(); fps.reset(); } } From f700607a65c7cfe9087e360cef921964092d9078 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 15 Apr 2015 23:00:10 -0700 Subject: [PATCH 03/20] Working on OSX functionality --- interface/resources/qml/CustomDialog.qml | 1 - interface/src/Application.cpp | 1 + libraries/render-utils/src/FboCache.h | 1 + .../render-utils/src/OffscreenGlCanvas.cpp | 18 ++++++++++-------- libraries/render-utils/src/OffscreenUi.h | 2 +- tests/render-utils/src/main.cpp | 9 +++++++-- 6 files changed, 20 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml index 71f36b4108..828cd80231 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/CustomDialog.qml @@ -11,7 +11,6 @@ Item { id: dialog width: 256 height: 256 - property rect clientArea: clientBorder property int topMargin: dialog.height - clientBorder.height + 8 property int margins: 8 property string title diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0f75de9696..36b4eaec91 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -650,6 +650,7 @@ Application::~Application() { // stop the glWidget frame timer so it doesn't call paintGL _glWidget->stopFrameTimer(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h index bbbb4a943e..975d602278 100644 --- a/libraries/render-utils/src/FboCache.h +++ b/libraries/render-utils/src/FboCache.h @@ -17,6 +17,7 @@ #include #include #include +#include class QOpenGLFramebufferObject; diff --git a/libraries/render-utils/src/OffscreenGlCanvas.cpp b/libraries/render-utils/src/OffscreenGlCanvas.cpp index 694fa68a5a..d6b268d4e9 100644 --- a/libraries/render-utils/src/OffscreenGlCanvas.cpp +++ b/libraries/render-utils/src/OffscreenGlCanvas.cpp @@ -16,16 +16,18 @@ OffscreenGlCanvas::OffscreenGlCanvas() { } void OffscreenGlCanvas::create(QOpenGLContext * sharedContext) { - QSurfaceFormat format; - format.setDepthBufferSize(16); - format.setStencilBufferSize(8); - format.setMajorVersion(4); - format.setMinorVersion(1); - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); - - _context.setFormat(format); if (nullptr != sharedContext) { + sharedContext->doneCurrent(); + _context.setFormat(sharedContext->format()); _context.setShareContext(sharedContext); + } else { + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + format.setMajorVersion(4); + format.setMinorVersion(1); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + _context.setFormat(format); } _context.create(); diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index 2e8206f466..60302d9860 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -44,7 +44,7 @@ public: \ private: #define QML_DIALOG_DEF(x) \ - const QUrl x::QML = #x ".qml"; \ + const QUrl x::QML = QUrl(#x ".qml"); \ const QString x::NAME = #x; \ \ void x::registerType() { \ diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index dd413a9f57..62c1fcf1c5 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -31,6 +31,7 @@ #include #include #include +#include class RateCounter { std::vector times; @@ -159,8 +160,12 @@ public: // "#0e7077" setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); - - static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/TestRoot.qml"); + + QApplication::applicationDirPath(); + QDir path(__FILE__); + path.cdUp(); + static const QString f(path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/TestRoot.qml"))); + _offscreenUi.loadQml(QUrl::fromLocalFile(f)); connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) { _offscreenUi.lockTexture(textureId); From 36ca9132cc97ed13f4af50b2401b58104a3361ea Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 16 Apr 2015 01:02:13 -0700 Subject: [PATCH 04/20] More build failure fixes --- libraries/render-utils/src/OffscreenUi.cpp | 10 ++++++++++ libraries/shared/src/ThreadHelpers.h | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 718a70f4e1..d0e54b08a9 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -1,3 +1,13 @@ +// +// OffscreenUi.cpp +// interface/src/render-utils +// +// Created by Bradley Austin Davis on 2015-04-04 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// #include "OffscreenUi.h" #include #include diff --git a/libraries/shared/src/ThreadHelpers.h b/libraries/shared/src/ThreadHelpers.h index 862f7bf673..8a64691da7 100644 --- a/libraries/shared/src/ThreadHelpers.h +++ b/libraries/shared/src/ThreadHelpers.h @@ -1,5 +1,19 @@ +// +// ThreadHelpers.h +// +// Created by Bradley Austin Davis on 2015-04-04 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// #pragma once +#ifndef hifi_ThreadHelpers_h +#define hifi_ThreadHelpers_h + #include +#include +#include template void withLock(L lock, F function) { @@ -11,3 +25,5 @@ void withLock(QMutex & lock, F function) { QMutexLocker locker(&lock); function(); } + +#endif \ No newline at end of file From a624ff43c4c891b179be56e6b159b3d3a2f421f7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 16 Apr 2015 14:10:29 -0700 Subject: [PATCH 05/20] Nothing to see here, move along --- interface/src/Menu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index aa24c8ca2c..5d02cf9094 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -251,7 +251,6 @@ Menu::Menu() { qApp, SLOT(setFullscreen(bool))); #endif -<<<<<<< HEAD addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, 0, // QML Qt::Key_P, true, qApp, SLOT(cameraMenuChanged())); From 759acfa17539865d6b34ebc517951637af39c7d7 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 16 Apr 2015 19:07:21 -0700 Subject: [PATCH 06/20] Working on getting the offscreen UI working on retina --- interface/src/Application.cpp | 12 +++++++++++- libraries/render-utils/src/OffscreenUi.cpp | 18 ++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 930e244136..d0ae13ce21 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -764,6 +764,16 @@ void Application::initializeUi() { return QPointF(p); }); offscreenUi->resume(); + connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect & r){ + static qreal oldDevicePixelRatio = 0; + qreal devicePixelRatio = _glWidget->devicePixelRatio(); + if (devicePixelRatio != oldDevicePixelRatio) { + oldDevicePixelRatio = devicePixelRatio; + qDebug() << "Device pixel ratio changed, triggering GL resize"; + resizeGL(_glWidget->width(), + _glWidget->height()); + } + }); } void Application::paintGL() { @@ -906,7 +916,7 @@ void Application::resizeGL(int width, int height) { glLoadIdentity(); auto offscreenUi = DependencyManager::get(); - offscreenUi->resize(QSize(width, height)); + offscreenUi->resize(_glWidget->size()); // update Stats width // let's set horizontal offset to give stats some margin to mirror diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d0e54b08a9..d2d314bf96 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -79,7 +79,8 @@ void OffscreenUi::resize(const QSize & newSize) { makeCurrent(); // Clear out any fbos with the old size - _fboCache.setSize(newSize); + qreal pixelRatio = _renderControl->_renderWindow ? _renderControl->_renderWindow->devicePixelRatio() : 1.0; + _fboCache.setSize(newSize * pixelRatio); // Update our members if (_rootItem) { @@ -203,7 +204,7 @@ QPointF OffscreenUi::mapWindowToUi(const QPointF & p, QObject * dest) { } vec2 pos = toGlm(p); pos /= sourceSize; - pos *= vec2(toGlm(_quickWindow->renderTargetSize())); + pos *= vec2(toGlm(_quickWindow->size())); return QPointF(pos.x, pos.y); } @@ -300,11 +301,13 @@ void OffscreenUi::setProxyWindow(QWindow * window) { void OffscreenUi::show(const QUrl & url, const QString & name) { QQuickItem * item = _rootItem->findChild(name); + if (nullptr == item) { + load(url); + item = _rootItem->findChild(name); + } + if (nullptr != item) { item->setEnabled(true); - item->setVisible(true); - } else { - load(url); } } @@ -312,7 +315,7 @@ void OffscreenUi::toggle(const QUrl & url, const QString & name) { QQuickItem * item = _rootItem->findChild(name); // First load? if (nullptr == item) { - load(url); + show(url, name); return; } @@ -320,12 +323,11 @@ void OffscreenUi::toggle(const QUrl & url, const QString & name) { // dialogs can still swallow keyboard input) bool newFlag = !item->isEnabled(); item->setEnabled(newFlag); - // item->setVisible(newFlag); - } void OffscreenUi::load(const QUrl & url) { + qDebug() << "Loading from url: " << url; QVariant returnedValue; QVariant msg = url; QMetaObject::invokeMethod(_rootItem, "loadChild", From fd0c130dc2ea6d302d8eeea7c93f1ab9a6286f77 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 16 Apr 2015 22:20:49 -0700 Subject: [PATCH 07/20] Working on simplifying new dialog creation --- interface/resources/qml/AddressBarDialog.qml | 85 +++--- interface/resources/qml/CustomDialog.qml | 35 ++- interface/resources/qml/LoginDialog.qml | 286 +++++++++--------- interface/src/ui/AddressBarDialog.cpp | 6 +- interface/src/ui/AddressBarDialog.h | 8 +- interface/src/ui/LoginDialog.cpp | 5 +- interface/src/ui/LoginDialog.h | 8 +- .../render-utils/src/OffscreenQmlDialog.cpp | 18 ++ .../render-utils/src/OffscreenQmlDialog.h | 56 ++++ libraries/render-utils/src/OffscreenUi.h | 30 +- 10 files changed, 290 insertions(+), 247 deletions(-) create mode 100644 libraries/render-utils/src/OffscreenQmlDialog.cpp create mode 100644 libraries/render-utils/src/OffscreenQmlDialog.h diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index df06fabbe6..9508481309 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -4,8 +4,9 @@ import QtQuick.Controls 1.2 import QtQuick.Window 2.2 import QtQuick.Controls.Styles 1.3 -AddressBarDialog { - id: addressBarDialog +CustomDialog { + id: dialog + title: "Go to..." objectName: "AddressBarDialog" SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } height: 128 @@ -14,70 +15,56 @@ AddressBarDialog { onVisibleChanged: { if (!visible) { reset(); - } else { - addressLine.focus = true - addressLine.forceActiveFocus() } } - Component.onCompleted: { - addressLine.focus = true - addressLine.forceActiveFocus() - } - function reset() { addressLine.text = "" goButton.source = "../images/address-bar-submit.svg" } - CustomDialog { - id: dialog - anchors.fill: parent - title: "Go to..." + AddressBarDialog { + id: addressBarDialog // The client area - Item { - id: item1 - anchors.fill: parent - anchors.margins: parent.margins - anchors.topMargin: parent.topMargin + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin - CustomBorder { - height: 64 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.right: goButton.left - anchors.rightMargin: 8 - anchors.verticalCenter: parent.verticalCenter - CustomTextInput { - id: addressLine - anchors.fill: parent - helperText: "domain, location, @user, /x,y,z" - anchors.margins: 8 - onAccepted: { - addressBarDialog.loadAddress(addressLine.text) - } + CustomBorder { + height: 64 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: goButton.left + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter + CustomTextInput { + id: addressLine + anchors.fill: parent + helperText: "domain, location, @user, /x,y,z" + anchors.margins: 8 + onAccepted: { + addressBarDialog.loadAddress(addressLine.text) } } + } - Image { - id: goButton - width: 32 - height: 32 - anchors.right: parent.right - anchors.rightMargin: 8 - source: "../images/address-bar-submit.svg" - anchors.verticalCenter: parent.verticalCenter + Image { + id: goButton + width: 32 + height: 32 + anchors.right: parent.right + anchors.rightMargin: 8 + source: "../images/address-bar-submit.svg" + anchors.verticalCenter: parent.verticalCenter - MouseArea { - anchors.fill: parent - onClicked: { - parent.source = "../images/address-bar-submit-active.svg" - addressBarDialog.loadAddress(addressLine.text) - } + MouseArea { + anchors.fill: parent + onClicked: { + parent.source = "../images/address-bar-submit-active.svg" + addressBarDialog.loadAddress(addressLine.text) } } - } } } diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml index 828cd80231..a681612f2c 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/CustomDialog.qml @@ -7,10 +7,34 @@ import "hifiConstants.js" as HifiConstants Item { SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - id: dialog width: 256 height: 256 + scale: 0.0 + enabled: false + visible: false + + onEnabledChanged: { + scale = enabled ? 1.0 : 0.0 + } + + onScaleChanged: { + visible = (scale != 0.0); + } + + Component.onCompleted: { + scale = 1.0 + } + + Behavior on scale { + NumberAnimation { + //This specifies how long the animation takes + duration: 400 + //This selects an easing curve to interpolate with, the default is Easing.Linear + easing.type: Easing.InOutBounce + } + } + property int topMargin: dialog.height - clientBorder.height + 8 property int margins: 8 property string title @@ -54,11 +78,11 @@ Item { anchors.top: parent.top anchors.rightMargin: 4 drag { - target: dialog.parent + target: dialog minimumX: 0 minimumY: 0 - maximumX: dialog.parent.parent.width - dialog.parent.width - maximumY: dialog.parent.parent.height - dialog.parent.height + maximumX: dialog.parent.width - dialog.width + maximumY: dialog.parent.height - dialog.height } } Image { @@ -73,11 +97,10 @@ Item { MouseArea { anchors.fill: parent onClicked: { - dialog.parent.destroy() + dialog.destroy() } } } - } // header border CustomBorder { diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index c306f4ed7e..e96309f625 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -5,9 +5,9 @@ import QtQuick.Window 2.2 import QtQuick.Controls.Styles 1.3 import "hifiConstants.js" as HifiConstants -LoginDialog { +CustomDialog { + title: "Login" SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } - id: loginDialog objectName: "LoginDialog" height: 512 width: 384 @@ -15,8 +15,6 @@ LoginDialog { onVisibleChanged: { if (!visible) { reset() - } else { - username.forceActiveFocus() } } @@ -26,163 +24,159 @@ LoginDialog { loginDialog.statusText = "" } - CustomDialog { + LoginDialog { + id: loginDialog anchors.fill: parent - title: "Login" - Item { - id: item1 - anchors.fill: parent - anchors.margins: parent.margins - anchors.topMargin: parent.topMargin - Column { - anchors.topMargin: 8 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.top: parent.top - spacing: 8 + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + Column { + anchors.topMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.top: parent.top + spacing: 8 - Image { - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - width: 64 - source: "../images/hifi-logo.svg" - } + Image { + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + width: 64 + source: "../images/hifi-logo.svg" + } - CustomBorder { - width: 304 - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - CustomTextInput { - id: username - anchors.fill: parent - helperText: "Username or Email" - anchors.margins: 8 - KeyNavigation.tab: password - KeyNavigation.backtab: password - onAccepted: { - password.forceActiveFocus() - } + CustomBorder { + width: 304 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + CustomTextInput { + id: username + anchors.fill: parent + helperText: "Username or Email" + anchors.margins: 8 + KeyNavigation.tab: password + KeyNavigation.backtab: password + onAccepted: { + password.forceActiveFocus() } } - - CustomBorder { - width: 304 - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - CustomTextInput { - id: password - anchors.fill: parent - echoMode: TextInput.Password - helperText: "Password" - anchors.margins: 8 - KeyNavigation.tab: username - KeyNavigation.backtab: username - onAccepted: { - if (username.text == "") { - username.forceActiveFocus() - } else { - loginDialog.login(username.text, password.text) - } - } - onFocusChanged: { - if (password.focus) { - password.selectAll() - } - } - } - } - - CustomText { - anchors.horizontalCenter: parent.horizontalCenter - textFormat: Text.StyledText - width: parent.width - height: 96 - wrapMode: Text.WordWrap - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: loginDialog.statusText - } } - Column { - anchors.bottomMargin: 5 - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.bottom: parent.bottom - - Rectangle { - width: 192 - height: 64 - anchors.horizontalCenter: parent.horizontalCenter - color: HifiConstants.color - border.width: 0 - radius: 10 - - MouseArea { - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: parent.top - anchors.right: parent.right - anchors.left: parent.left - onClicked: { + CustomBorder { + width: 304 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + CustomTextInput { + id: password + anchors.fill: parent + echoMode: TextInput.Password + helperText: "Password" + anchors.margins: 8 + KeyNavigation.tab: username + KeyNavigation.backtab: username + onAccepted: { + if (username.text == "") { + username.forceActiveFocus() + } else { loginDialog.login(username.text, password.text) } } - - Row { - anchors.centerIn: parent - anchors.verticalCenter: parent.verticalCenter - spacing: 8 - Image { - id: loginIcon - height: 32 - width: 32 - source: "../images/login.svg" - } - CustomText { - text: "Login" - color: "white" - width: 64 - height: parent.height - } - } - - } - - CustomText { - width: parent.width - height: 24 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - text:"Create Account" - font.pointSize: 12 - font.bold: true - color: HifiConstants.color - - MouseArea { - anchors.fill: parent - onClicked: { - loginDialog.openUrl(loginDialog.rootUrl + "/signup") + onFocusChanged: { + if (password.focus) { + password.selectAll() } } } + } - CustomText { - width: parent.width - height: 24 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.pointSize: 12 - text: "Recover Password" - color: HifiConstants.color + CustomText { + anchors.horizontalCenter: parent.horizontalCenter + textFormat: Text.StyledText + width: parent.width + height: 96 + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: loginDialog.statusText + } + } - MouseArea { - anchors.fill: parent - onClicked: { - loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new") - } + Column { + anchors.bottomMargin: 5 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.bottom: parent.bottom + + Rectangle { + width: 192 + height: 64 + anchors.horizontalCenter: parent.horizontalCenter + color: HifiConstants.color + border.width: 0 + radius: 10 + + MouseArea { + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + onClicked: { + loginDialog.login(username.text, password.text) + } + } + + Row { + anchors.centerIn: parent + anchors.verticalCenter: parent.verticalCenter + spacing: 8 + Image { + id: loginIcon + height: 32 + width: 32 + source: "../images/login.svg" + } + CustomText { + text: "Login" + color: "white" + width: 64 + height: parent.height + } + } + + } + + CustomText { + width: parent.width + height: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text:"Create Account" + font.pointSize: 12 + font.bold: true + color: HifiConstants.color + + MouseArea { + anchors.fill: parent + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/signup") + } + } + } + + CustomText { + width: parent.width + height: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.pointSize: 12 + text: "Recover Password" + color: HifiConstants.color + + MouseArea { + anchors.fill: parent + onClicked: { + loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new") } } } diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 49158265ba..befeb40cce 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -17,17 +17,15 @@ QML_DIALOG_DEF(AddressBarDialog) -AddressBarDialog::AddressBarDialog(QQuickItem *parent) : QQuickItem(parent) { +AddressBarDialog::AddressBarDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { auto addressManager = DependencyManager::get(); connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide); } - void AddressBarDialog::hide() { - setEnabled(false); - setVisible(false); + ((QQuickItem *)parent())->setEnabled(false); } void AddressBarDialog::loadAddress(const QString & address) { diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index 00e55ceb10..b4f4c44e0f 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -8,15 +8,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#pragma once #ifndef hifi_AddressBarDialog_h #define hifi_AddressBarDialog_h -#pragma once -#include +#include -#include "OffscreenUi.h" - -class AddressBarDialog : public QQuickItem +class AddressBarDialog : public OffscreenQmlDialog { Q_OBJECT QML_DIALOG_DECL diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 3b164041fa..3637d824fb 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -17,7 +17,7 @@ QML_DIALOG_DEF(LoginDialog) -LoginDialog::LoginDialog(QQuickItem *parent) : QQuickItem(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) { +LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) { connect(&AccountManager::getInstance(), &AccountManager::loginComplete, this, &LoginDialog::handleLoginCompleted); connect(&AccountManager::getInstance(), &AccountManager::loginFailed, @@ -42,8 +42,7 @@ void LoginDialog::toggleAction() { } void LoginDialog::handleLoginCompleted(const QUrl& authURL) { - setEnabled(false); - setVisible(false); + hide(); } void LoginDialog::handleLoginFailed() { diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index 3c9a98a9a4..d3f54981a5 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -8,15 +8,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#pragma once #ifndef hifi_LoginDialog_h #define hifi_LoginDialog_h -#pragma once -#include +#include -#include "OffscreenUi.h" - -class LoginDialog : public QQuickItem +class LoginDialog : public OffscreenQmlDialog { Q_OBJECT QML_DIALOG_DECL diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/render-utils/src/OffscreenQmlDialog.cpp new file mode 100644 index 0000000000..d6cfc9951b --- /dev/null +++ b/libraries/render-utils/src/OffscreenQmlDialog.cpp @@ -0,0 +1,18 @@ +// +// OffscreenQmlDialog.cpp +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "OffscreenQmlDialog.h" + +OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem *parent) + : QQuickItem(parent) { } + +void OffscreenQmlDialog::hide() { + ((QQuickItem *)parent())->setEnabled(false); +} diff --git a/libraries/render-utils/src/OffscreenQmlDialog.h b/libraries/render-utils/src/OffscreenQmlDialog.h new file mode 100644 index 0000000000..6e94587fd2 --- /dev/null +++ b/libraries/render-utils/src/OffscreenQmlDialog.h @@ -0,0 +1,56 @@ +// +// OffscreenQmlDialog.h +// +// Created by Bradley Austin Davis on 2015/04/14 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_OffscreenQmlDialog_h +#define hifi_OffscreenQmlDialog_h + +#include +#include "OffscreenUi.h" + +#define QML_DIALOG_DECL \ +private: \ + static const QString NAME; \ + static const QUrl QML; \ +public: \ + static void registerType(); \ + static void show(); \ + static void toggle(); \ +private: + +#define QML_DIALOG_DEF(x) \ + const QUrl x::QML = QUrl(#x ".qml"); \ + const QString x::NAME = #x; \ + \ + void x::registerType() { \ + qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ + } \ + \ + void x::show() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->show(QML, NAME); \ + } \ + \ + void x::toggle() { \ + auto offscreenUi = DependencyManager::get(); \ + offscreenUi->toggle(QML, NAME); \ + } + +class OffscreenQmlDialog : public QQuickItem +{ + Q_OBJECT +public: + OffscreenQmlDialog(QQuickItem *parent = 0); + +protected: + void hide(); +}; + +#endif diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index 60302d9860..b9cf5d2226 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -33,34 +33,6 @@ #include "FboCache.h" #include "OffscreenGlCanvas.h" -#define QML_DIALOG_DECL \ -private: \ - static const QString NAME; \ - static const QUrl QML; \ -public: \ - static void registerType(); \ - static void show(); \ - static void toggle(); \ -private: - -#define QML_DIALOG_DEF(x) \ - const QUrl x::QML = QUrl(#x ".qml"); \ - const QString x::NAME = #x; \ - \ - void x::registerType() { \ - qmlRegisterType("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \ - } \ - \ - void x::show() { \ - auto offscreenUi = DependencyManager::get(); \ - offscreenUi->show(QML, NAME); \ - } \ - \ - void x::toggle() { \ - auto offscreenUi = DependencyManager::get(); \ - offscreenUi->toggle(QML, NAME); \ - } - class OffscreenUi : public OffscreenGlCanvas, public Dependency { Q_OBJECT @@ -133,4 +105,4 @@ private: MouseTranslator _mouseTranslator{ [](const QPointF & p) { return p; } }; }; -#endif \ No newline at end of file +#endif From 781abdd0473048c007be81e6cab4c2c92e7eafab Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Apr 2015 09:53:40 -0700 Subject: [PATCH 08/20] Tweaking test dialog and adding browser test --- interface/resources/qml/Browser.qml | 45 ++++++++++++++++++++++++++ interface/resources/qml/TestDialog.qml | 40 ++++++++--------------- 2 files changed, 59 insertions(+), 26 deletions(-) create mode 100644 interface/resources/qml/Browser.qml diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml new file mode 100644 index 0000000000..d7e08fbd97 --- /dev/null +++ b/interface/resources/qml/Browser.qml @@ -0,0 +1,45 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.3 +import QtWebKit 3.0 + +CustomDialog { + title: "Test Dlg" + id: testDialog + objectName: "Browser" + width: 1280 + height: 720 + + Item { + id: clientArea + // The client area + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + + + ScrollView { + anchors.fill: parent + WebView { + id: webview + url: "http://slashdot.org" + anchors.fill: parent + } + } + + } + + +} + + +/* + +// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property + +MouseArea { + anchors.fill: parent +} +*/ diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml index 9c8bcccd75..8ce68413b6 100644 --- a/interface/resources/qml/TestDialog.qml +++ b/interface/resources/qml/TestDialog.qml @@ -4,34 +4,20 @@ import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 import QtQuick.Controls.Styles 1.3 -Item { - objectName: "TestDialog" +CustomDialog { + title: "Test Dlg" id: testDialog - width: 384 - height: 384 + objectName: "TestDialog" + width: 512 + height: 512 scale: 0.0 - onEnabledChanged: { - scale = enabled ? 1.0 : 0.0 - } - onScaleChanged: { - visible = (scale != 0.0); - } - Component.onCompleted: { - scale = 1.0 - } - Behavior on scale { - NumberAnimation { - //This specifies how long the animation takes - duration: 400 - //This selects an easing curve to interpolate with, the default is Easing.Linear - easing.type: Easing.InOutBounce - } - } - - CustomDialog { - title: "Test Dlg" + Item { + id: clientArea + // The client area anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin Rectangle { property int d: 100 @@ -55,16 +41,18 @@ Item { anchors.top: parent.top anchors.topMargin: parent.titleSize + 12 } - + CustomButton { x: 128 y: 192 + text: "Test" anchors.bottom: parent.bottom anchors.bottomMargin: 12 anchors.right: parent.right anchors.rightMargin: 12 onClicked: { console.log("Click"); + if (square.visible) { square.visible = false } else { @@ -76,7 +64,7 @@ Item { CustomButton { id: customButton2 y: 192 - text: "Close" + text: "Move" anchors.left: parent.left anchors.leftMargin: 12 anchors.bottom: parent.bottom From ad585f75595f323507d1314d4ea13dccf4f47d24 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Apr 2015 10:05:54 -0700 Subject: [PATCH 09/20] Fixing NaN reference in test dialog --- interface/resources/qml/TestDialog.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml index 8ce68413b6..69aad4cdc8 100644 --- a/interface/resources/qml/TestDialog.qml +++ b/interface/resources/qml/TestDialog.qml @@ -10,7 +10,6 @@ CustomDialog { objectName: "TestDialog" width: 512 height: 512 - scale: 0.0 Item { id: clientArea @@ -39,7 +38,7 @@ CustomDialog { clip: true text: "test edit" anchors.top: parent.top - anchors.topMargin: parent.titleSize + 12 + anchors.topMargin: 12 } CustomButton { @@ -86,7 +85,6 @@ CustomDialog { } } - } From 4b73481604890e76f0df7ee57618839b995ed8c8 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Fri, 17 Apr 2015 10:19:31 -0700 Subject: [PATCH 10/20] Respond to changes in the device pixel ratio in the test window --- libraries/render-utils/src/OffscreenUi.cpp | 1 + tests/render-utils/src/main.cpp | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d2d314bf96..68bb3eeacd 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -80,6 +80,7 @@ void OffscreenUi::resize(const QSize & newSize) { // Clear out any fbos with the old size qreal pixelRatio = _renderControl->_renderWindow ? _renderControl->_renderWindow->devicePixelRatio() : 1.0; + qDebug() << "Offscreen UI resizing to " << newSize.width() << "x" << newSize.height() << " with pixel ratio " << pixelRatio; _fboCache.setSize(newSize * pixelRatio); // Update our members diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 62c1fcf1c5..556fef0561 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -203,7 +203,16 @@ protected: } QWindow::keyPressEvent(event); } - + + void moveEvent(QMoveEvent *event) { + static qreal oldPixelRatio = 0.0; + if (devicePixelRatio() != oldPixelRatio) { + oldPixelRatio = devicePixelRatio(); + resizeWindow(size()); + } + + QWindow::moveEvent(event); + } }; #ifndef SERIF_FONT_FAMILY @@ -291,7 +300,7 @@ void QTestWindow::renderQml() { void QTestWindow::draw() { makeCurrent(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, _size.width(), _size.height()); + glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); //renderText(); renderQml(); From 16efa2a46fc850772b1723e502421afa1924954a Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Apr 2015 16:58:29 -0700 Subject: [PATCH 11/20] Improving toggle visibility and loading behavior --- interface/resources/qml/AddressBarDialog.qml | 9 +- interface/resources/qml/CustomDialog.qml | 26 +++- interface/resources/qml/LoginDialog.qml | 6 + interface/resources/qml/Root.qml | 9 +- interface/resources/qml/TestDialog.qml | 10 +- interface/resources/qml/TestRoot.qml | 25 ++-- interface/resources/qml/componentCreation.js | 4 +- interface/src/Application.cpp | 4 +- interface/src/ui/AddressBarDialog.cpp | 7 +- libraries/render-utils/src/OffscreenUi.cpp | 133 +++++++++++++------ libraries/render-utils/src/OffscreenUi.h | 50 +++++-- tests/render-utils/src/main.cpp | 46 ++++--- 12 files changed, 231 insertions(+), 98 deletions(-) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 9508481309..ec1480928a 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -5,16 +5,21 @@ import QtQuick.Window 2.2 import QtQuick.Controls.Styles 1.3 CustomDialog { - id: dialog title: "Go to..." objectName: "AddressBarDialog" - SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } height: 128 width: 512 + destroyOnCloseButton: false onVisibleChanged: { if (!visible) { reset(); + } + } + + onEnabledChanged: { + if (enabled) { + addressLine.forceActiveFocus(); } } diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml index a681612f2c..dd051566e3 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/CustomDialog.qml @@ -12,7 +12,9 @@ Item { height: 256 scale: 0.0 enabled: false - visible: false + property int animationDuration: 400 + property bool destroyOnInvisible: false + property bool destroyOnCloseButton: true onEnabledChanged: { scale = enabled ? 1.0 : 0.0 @@ -22,14 +24,24 @@ Item { visible = (scale != 0.0); } - Component.onCompleted: { - scale = 1.0 + onVisibleChanged: { + if (!visible && destroyOnInvisible) { + console.log("Destroying closed component"); + destroy(); + } + } + + function close() { + if (destroyOnCloseButton) { + destroyOnInvisible = true + } + enabled = false; } Behavior on scale { NumberAnimation { //This specifies how long the animation takes - duration: 400 + duration: dialog.animationDuration //This selects an easing curve to interpolate with, the default is Easing.Linear easing.type: Easing.InOutBounce } @@ -81,8 +93,8 @@ Item { target: dialog minimumX: 0 minimumY: 0 - maximumX: dialog.parent.width - dialog.width - maximumY: dialog.parent.height - dialog.height + maximumX: dialog.parent ? dialog.parent.width - dialog.width : 0 + maximumY: dialog.parent ? dialog.parent.height - dialog.height : 0 } } Image { @@ -97,7 +109,7 @@ Item { MouseArea { anchors.fill: parent onClicked: { - dialog.destroy() + dialog.close(); } } } diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index e96309f625..be69b65ef7 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -18,6 +18,12 @@ CustomDialog { } } + onEnabledChanged: { + if (enabled) { + username.forceActiveFocus(); + } + } + function reset() { username.text = "" password.text = "" diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml index f290a8b5ca..9422ef123d 100644 --- a/interface/resources/qml/Root.qml +++ b/interface/resources/qml/Root.qml @@ -1,14 +1,9 @@ +import Hifi 1.0 import QtQuick 2.3 -import "componentCreation.js" as Creator - -Item { +Root { id: root width: 1280 height: 720 - - function loadChild(url) { - Creator.createObject(root, url) - } } diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml index 69aad4cdc8..1fe8676bc6 100644 --- a/interface/resources/qml/TestDialog.qml +++ b/interface/resources/qml/TestDialog.qml @@ -5,12 +5,19 @@ import QtQuick.Dialogs 1.2 import QtQuick.Controls.Styles 1.3 CustomDialog { - title: "Test Dlg" + title: "Test Dialog" id: testDialog objectName: "TestDialog" width: 512 height: 512 + animationDuration: 200 + onEnabledChanged: { + if (enabled) { + edit.forceActiveFocus(); + } + } + Item { id: clientArea // The client area @@ -31,6 +38,7 @@ CustomDialog { CustomTextEdit { + id: edit anchors.left: parent.left anchors.leftMargin: 12 anchors.right: parent.right diff --git a/interface/resources/qml/TestRoot.qml b/interface/resources/qml/TestRoot.qml index a3ef5f8fe9..158c0b7a54 100644 --- a/interface/resources/qml/TestRoot.qml +++ b/interface/resources/qml/TestRoot.qml @@ -1,25 +1,34 @@ +import Hifi 1.0 import QtQuick 2.3 -import "componentCreation.js" as Creator - -Item { +Root { id: root width: 1280 height: 720 - function loadChild(url) { - Creator.createObject(root, url) + CustomButton { + id: messageBox + anchors.right: createDialog.left + anchors.rightMargin: 24 + anchors.bottom: parent.bottom + anchors.bottomMargin: 24 + text: "Message" + onClicked: { + console.log("Foo") + root.information("a") + console.log("Bar") + } } - CustomButton { + id: createDialog anchors.right: parent.right anchors.rightMargin: 24 anchors.bottom: parent.bottom anchors.bottomMargin: 24 - text: "Test" + text: "Create" onClicked: { - loadChild("TestDialog.qml"); + root.loadChild("TestDialog.qml"); } } } diff --git a/interface/resources/qml/componentCreation.js b/interface/resources/qml/componentCreation.js index 6e6469adfb..15a828d6f8 100644 --- a/interface/resources/qml/componentCreation.js +++ b/interface/resources/qml/componentCreation.js @@ -18,10 +18,12 @@ function finishCreation() { // Error Handling console.log("Error creating object"); } else { - instance.focus = true; + instance.enabled = true } } else if (component.status == Component.Error) { // Error Handling console.log("Error loading component:", component.errorString()); + } else { + console.log("Unknown component status: " + component.status); } } \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d0ae13ce21..18a325080c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -754,8 +754,8 @@ void Application::initializeUi() { offscreenUi->create(_glWidget->context()->contextHandle()); offscreenUi->resize(_glWidget->size()); offscreenUi->setProxyWindow(_window->windowHandle()); - auto rootQml = PathUtils::resourcesPath() + "qml/Root.qml"; - offscreenUi->loadQml(QUrl::fromLocalFile(rootQml)); + offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); + offscreenUi->load("Root.qml"); offscreenUi->setMouseTranslator([this](const QPointF& p){ if (OculusManager::isConnected()) { glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p)); diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index befeb40cce..5ef9b930ac 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -35,14 +35,13 @@ void AddressBarDialog::loadAddress(const QString & address) { } } -// TODO port to a QML based message box void AddressBarDialog::displayAddressOfflineMessage() { - QMessageBox::information(nullptr, "Address offline", + OffscreenUi::information("Address offline", "That user or place is currently offline."); } -// TODO port to a QML based message box void AddressBarDialog::displayAddressNotFoundMessage() { - QMessageBox::information(nullptr, "Address not found", + OffscreenUi::information("Address not found", "There is no address information for that user or place."); } + diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 68bb3eeacd..d9dd030758 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -12,8 +12,29 @@ #include #include #include +#include + +class OffscreenUiRoot : public QQuickItem { + Q_OBJECT +public: + + OffscreenUiRoot(QQuickItem *parent = 0); + Q_INVOKABLE void information(const QString & title, const QString & text); + Q_INVOKABLE void loadChild(const QUrl & url) { + DependencyManager::get()->load(url); + } +}; + + +OffscreenUiRoot::OffscreenUiRoot(QQuickItem *parent) : QQuickItem(parent) { +} + +void OffscreenUiRoot::information(const QString & title, const QString & text = "foo") { + OffscreenUi::information(title, text); +} OffscreenUi::OffscreenUi() { + ::qmlRegisterType("Hifi", 1, 0, "Root"); } OffscreenUi::~OffscreenUi() { @@ -62,19 +83,18 @@ void OffscreenUi::create(QOpenGLContext * shareContext) { // is needed too). connect(_renderControl, &QQuickRenderControl::renderRequested, this, &OffscreenUi::requestRender); connect(_renderControl, &QQuickRenderControl::sceneChanged, this, &OffscreenUi::requestUpdate); - connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, [this](QObject *object){ - OffscreenUi * p = this; - qDebug() << "Focus changed to " << object; - }); _quickWindow->focusObject(); _qmlComponent = new QQmlComponent(_qmlEngine); - // Initialize the render control and our OpenGL resources. makeCurrent(); _renderControl->initialize(&_context); } +void OffscreenUi::addImportPath(const QString & path) { + _qmlEngine->addImportPath(path); +} + void OffscreenUi::resize(const QSize & newSize) { makeCurrent(); @@ -102,10 +122,15 @@ QQmlContext * OffscreenUi::qmlContext() { return QQmlEngine::contextForObject(_rootItem); } -void OffscreenUi::loadQml(const QUrl & qmlSource, std::function f) { +void OffscreenUi::setBaseUrl(const QUrl & baseUrl) { + _qmlEngine->setBaseUrl(baseUrl); +} + +void OffscreenUi::load(const QUrl & qmlSource, std::function f) { + qDebug() << "Loading QML from URL " << qmlSource; _qmlComponent->loadUrl(qmlSource); if (_qmlComponent->isLoading()) - connect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad); + connect(_qmlComponent, &QQmlComponent::statusChanged, this, [] {}); else finishQmlLoad(); } @@ -131,30 +156,43 @@ void OffscreenUi::finishQmlLoad() { return; } - QObject *rootObject = _qmlComponent->create(); + QObject *newObject = _qmlComponent->create(); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); foreach(const QQmlError &error, errorList) qWarning() << error.url() << error.line() << error; - qFatal("Unable to finish loading QML"); + if (!_rootItem) { + qFatal("Unable to finish loading QML root"); + } return; } - _rootItem = qobject_cast(rootObject); - if (!_rootItem) { + QQuickItem * newItem = qobject_cast(newObject); + if (!newItem) { qWarning("run: Not a QQuickItem"); - delete rootObject; - qFatal("Unable to find root QQuickItem"); + delete newObject; + if (!_rootItem) { + qFatal("Unable to find root QQuickItem"); + } return; } - // Make sure we can assign focus to the root item (critical for + // Make sure we make items focusable (critical for // supporting keyboard shortcuts) - _rootItem->setFlag(QQuickItem::ItemIsFocusScope, true); - // The root item is ready. Associate it with the window. - _rootItem->setParentItem(_quickWindow->contentItem()); - _rootItem->setSize(_quickWindow->renderTargetSize()); - qDebug() << "Finished setting up QML provider"; + newItem->setFlag(QQuickItem::ItemIsFocusScope, true); + + if (!_rootItem) { + // The root item is ready. Associate it with the window. + _rootItem = newItem; + _rootItem->setParentItem(_quickWindow->contentItem()); + _rootItem->setSize(_quickWindow->renderTargetSize()); + } else { + // Allow child windows to be destroyed from JS + QQmlEngine::setObjectOwnership(newItem, QQmlEngine::JavaScriptOwnership); + newItem->setParent(_rootItem); + newItem->setParentItem(_rootItem); + newItem->setEnabled(true); + } } @@ -240,7 +278,7 @@ bool OffscreenUi::eventFilter(QObject * dest, QEvent * e) { case QEvent::KeyRelease: { e->ignore(); - if (QApplication::sendEvent(_quickWindow, e)) { + if (QCoreApplication::sendEvent(_quickWindow, e)) { return e->isAccepted(); } } @@ -302,38 +340,55 @@ void OffscreenUi::setProxyWindow(QWindow * window) { void OffscreenUi::show(const QUrl & url, const QString & name) { QQuickItem * item = _rootItem->findChild(name); + // First load? if (nullptr == item) { load(url); - item = _rootItem->findChild(name); - } - - if (nullptr != item) { - item->setEnabled(true); + return; } + item->setEnabled(true); } void OffscreenUi::toggle(const QUrl & url, const QString & name) { QQuickItem * item = _rootItem->findChild(name); // First load? if (nullptr == item) { - show(url, name); + load(url); return; } + item->setEnabled(!item->isEnabled()); +} - // Toggle the visibity AND the enabled flag (otherwise invisible - // dialogs can still swallow keyboard input) - bool newFlag = !item->isEnabled(); - item->setEnabled(newFlag); +void OffscreenUi::messageBox(const QString &title, const QString &text, + QMessageBox::Icon icon, + QMessageBox::StandardButtons buttons, + ButtonCallback f) { +} + +void OffscreenUi::information(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons, + ButtonCallback callback) { + callback(QMessageBox::information(nullptr, title, text, buttons)); +} + +void OffscreenUi::question(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons, + ButtonCallback callback) { + callback(QMessageBox::question(nullptr, title, text, buttons)); +} + +void OffscreenUi::warning(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons, + ButtonCallback callback) { + callback(QMessageBox::warning(nullptr, title, text, buttons)); +} + +void OffscreenUi::critical(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons, + ButtonCallback callback) { + callback(QMessageBox::critical(nullptr, title, text, buttons)); } -void OffscreenUi::load(const QUrl & url) { - qDebug() << "Loading from url: " << url; - QVariant returnedValue; - QVariant msg = url; - QMetaObject::invokeMethod(_rootItem, "loadChild", - Q_RETURN_ARG(QVariant, returnedValue), - Q_ARG(QVariant, msg)); - qDebug() << "QML function returned:" << returnedValue.toString(); -} +OffscreenUi::ButtonCallback OffscreenUi::NO_OP_CALLBACK = [](QMessageBox::StandardButton) {}; +#include "OffscreenUi.moc" \ No newline at end of file diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index b9cf5d2226..73c022e4be 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -12,26 +12,25 @@ #ifndef hifi_OffscreenUi_h #define hifi_OffscreenUi_h - -#include -#include #include #include #include #include #include #include -#include -#include -#include #include -#include +#include + #include #include + +#include +#include #include -#include "FboCache.h" #include "OffscreenGlCanvas.h" +#include "FboCache.h" +#include class OffscreenUi : public OffscreenGlCanvas, public Dependency { @@ -60,11 +59,14 @@ public: virtual ~OffscreenUi(); void create(QOpenGLContext * context); void resize(const QSize & size); - void loadQml(const QUrl & qmlSource, std::function f = [](QQmlContext*) {}); - void load(const QUrl & url); + void load(const QUrl & qmlSource, std::function f = [](QQmlContext*) {}); + void load(const QString & qmlSourceFile, std::function f = [](QQmlContext*) {}) { + load(QUrl(qmlSourceFile), f); + } void show(const QUrl & url, const QString & name); void toggle(const QUrl & url, const QString & name); - + void setBaseUrl(const QUrl & baseUrl); + void addImportPath(const QString & path); QQmlContext * qmlContext(); void pause(); @@ -77,6 +79,32 @@ public: _mouseTranslator = mt; } + + // Messagebox replacement functions + using ButtonCallback = std::function < void(QMessageBox::StandardButton) >; + static ButtonCallback NO_OP_CALLBACK; + + static void messageBox(const QString &title, const QString &text, + QMessageBox::Icon icon, + QMessageBox::StandardButtons buttons, + ButtonCallback f); + + static void information(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + ButtonCallback callback = NO_OP_CALLBACK); + + static void question(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), + ButtonCallback callback = [](QMessageBox::StandardButton) {}); + + static void warning(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + ButtonCallback callback = [](QMessageBox::StandardButton) {}); + + static void critical(const QString &title, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + ButtonCallback callback = [](QMessageBox::StandardButton) {}); + protected: private slots: diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 556fef0561..eb61fd1f72 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -69,6 +69,17 @@ public: } }; + +const QString & getQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/")) + "/"; + qDebug() << "Qml Path: " << dir; + } + return dir; +} // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { Q_OBJECT @@ -77,7 +88,6 @@ class QTestWindow : public QWindow { QSize _size; TextRenderer* _textRenderer[4]; RateCounter fps; - OffscreenUi _offscreenUi; int testQmlTexture{ 0 }; //ProgramPtr _planeProgam; //ShapeWrapperPtr _planeShape; @@ -90,11 +100,12 @@ protected: private: void resizeWindow(const QSize & size) { _size = size; - _offscreenUi.resize(_size); + DependencyManager::get()->resize(_size); } public: QTestWindow() { + DependencyManager::set(); setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format; @@ -154,30 +165,30 @@ public: glClearColor(0.2f, 0.2f, 0.2f, 1); glDisable(GL_DEPTH_TEST); - _offscreenUi.create(_context); + auto offscreenUi = DependencyManager::get(); + offscreenUi->create(_context); // FIXME, need to switch to a QWindow for mouse and keyboard input to work - _offscreenUi.setProxyWindow(this); + offscreenUi->setProxyWindow(this); // "#0e7077" setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); - QApplication::applicationDirPath(); - QDir path(__FILE__); - path.cdUp(); - static const QString f(path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/TestRoot.qml"))); + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); + offscreenUi->load(QUrl("TestRoot.qml")); + offscreenUi->addImportPath(getQmlDir()); + offscreenUi->addImportPath("."); - _offscreenUi.loadQml(QUrl::fromLocalFile(f)); - connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) { - _offscreenUi.lockTexture(textureId); + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { + offscreenUi->lockTexture(textureId); assert(!glGetError()); GLuint oldTexture = testQmlTexture; testQmlTexture = textureId; if (oldTexture) { - _offscreenUi.releaseTexture(oldTexture); + offscreenUi->releaseTexture(oldTexture); } }); - installEventFilter(&_offscreenUi); - _offscreenUi.resume(); + installEventFilter(offscreenUi.data()); + offscreenUi->resume(); } virtual ~QTestWindow() { @@ -197,8 +208,10 @@ protected: void keyPressEvent(QKeyEvent *event) { switch (event->key()) { - case Qt::Key_Slash: - _offscreenUi.toggle(QString("TestDialog.qml"), "TestDialog"); + case Qt::Key_L: + if (event->modifiers() & Qt::CTRL) { + DependencyManager::get()->toggle(QString("TestDialog.qml"), "TestDialog"); + } break; } QWindow::keyPressEvent(event); @@ -319,6 +332,7 @@ int main(int argc, char** argv) { QApplication app(argc, argv); //QLoggingCategory::setFilterRules("qt.quick.mouse.debug = true"); QTestWindow window; + QTimer timer; timer.setInterval(1); app.connect(&timer, &QTimer::timeout, &app, [&] { From 8d23bf874f325cdcd375e5fe6e86d62a26f36858 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Apr 2015 17:43:54 -0700 Subject: [PATCH 12/20] Enable resizable dialogs --- interface/resources/qml/CustomDialog.qml | 34 ++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/CustomDialog.qml b/interface/resources/qml/CustomDialog.qml index dd051566e3..1e0351af4f 100644 --- a/interface/resources/qml/CustomDialog.qml +++ b/interface/resources/qml/CustomDialog.qml @@ -15,6 +15,10 @@ Item { property int animationDuration: 400 property bool destroyOnInvisible: false property bool destroyOnCloseButton: true + property bool resizable: false + property int minX: 256 + property int minY: 256 + clip: true onEnabledChanged: { scale = enabled ? 1.0 : 0.0 @@ -37,6 +41,11 @@ Item { } enabled = false; } + + function deltaSize(dx, dy) { + width = Math.max(width + dx, minX) + height = Math.max(height + dy, minY) + } Behavior on scale { NumberAnimation { @@ -82,8 +91,6 @@ Item { MouseArea { id: titleDrag - property int startX - property int startY anchors.right: closeButton.left anchors.bottom: parent.bottom anchors.left: parent.left @@ -127,6 +134,29 @@ Item { anchors.rightMargin: 0 anchors.left: parent.left anchors.leftMargin: 0 + clip: true } // client border } // window border + + MouseArea { + id: sizeDrag + property int startX + property int startY + anchors.right: parent.right + anchors.bottom: parent.bottom + width: 16 + height: 16 + hoverEnabled: true + onPressed: { + startX = mouseX + startY = mouseY + } + onPositionChanged: { + if (pressed && dialog.resizable) { + dialog.deltaSize((mouseX - startX), (mouseY - startY)) + startX = mouseX + startY = mouseY + } + } + } } From e68f149aac64f4197ef891ced260e33af66e4d11 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 21 Apr 2015 13:18:53 -0700 Subject: [PATCH 13/20] Fixing bad merge --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 84c810ac0d..259b71afc2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -245,7 +245,7 @@ Menu::Menu() { false, qApp, SLOT(setFullscreen(bool))); -#endif + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, 0, // QML Qt::Key_P, true, qApp, SLOT(cameraMenuChanged())); From 8d8c4babba722957683f9bca92f79d01ddb17369 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 19:05:57 -0700 Subject: [PATCH 14/20] Coding standard fixes --- interface/src/Application.cpp | 3 +- interface/src/ui/ApplicationOverlay.cpp | 10 +- interface/src/ui/LoginDialog.h | 6 +- .../render-utils/src/OffscreenGlCanvas.cpp | 2 +- .../render-utils/src/OffscreenGlCanvas.h | 2 +- .../render-utils/src/OffscreenQmlDialog.cpp | 2 +- .../render-utils/src/OffscreenQmlDialog.h | 2 +- libraries/render-utils/src/OffscreenUi.cpp | 139 +++++++++--------- libraries/render-utils/src/OffscreenUi.h | 50 +++---- 9 files changed, 107 insertions(+), 109 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e7f8096e33..5adc408d8c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -569,8 +569,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : this->installEventFilter(this); // The offscreen UI needs to intercept the mouse and keyboard // events coming from the onscreen window - _glWidget->installEventFilter( - DependencyManager::get().data()); + _glWidget->installEventFilter(DependencyManager::get().data()); } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 5583790b13..2a8f01aafc 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -237,15 +237,15 @@ void ApplicationOverlay::renderOverlay() { // A quick and dirty solution for compositing the old overlay // texture with the new one template -void with_each_texture(GLuint a, GLuint b, F f) { +void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) { glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); - if (a) { - glBindTexture(GL_TEXTURE_2D, a); + if (firstPassTexture) { + glBindTexture(GL_TEXTURE_2D, firstPassTexture); f(); } - if (b) { - glBindTexture(GL_TEXTURE_2D, b); + if (secondPassTexture) { + glBindTexture(GL_TEXTURE_2D, secondPassTexture); f(); } glBindTexture(GL_TEXTURE_2D, 0); diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index d3f54981a5..7fe44bf543 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -25,7 +25,7 @@ class LoginDialog : public OffscreenQmlDialog public: static void toggleAction(); - LoginDialog(QQuickItem *parent = 0); + LoginDialog(QQuickItem* parent = 0); void setStatusText(const QString & a); QString statusText() const; @@ -39,8 +39,8 @@ protected: void handleLoginCompleted(const QUrl& authURL); void handleLoginFailed(); - Q_INVOKABLE void login(const QString & username, const QString & password); - Q_INVOKABLE void openUrl(const QString & url); + Q_INVOKABLE void login(const QString& username, const QString& password); + Q_INVOKABLE void openUrl(const QString& url); private: QString _statusText; const QString _rootUrl; diff --git a/libraries/render-utils/src/OffscreenGlCanvas.cpp b/libraries/render-utils/src/OffscreenGlCanvas.cpp index d6b268d4e9..0e5d4928d8 100644 --- a/libraries/render-utils/src/OffscreenGlCanvas.cpp +++ b/libraries/render-utils/src/OffscreenGlCanvas.cpp @@ -15,7 +15,7 @@ OffscreenGlCanvas::OffscreenGlCanvas() { } -void OffscreenGlCanvas::create(QOpenGLContext * sharedContext) { +void OffscreenGlCanvas::create(QOpenGLContext* sharedContext) { if (nullptr != sharedContext) { sharedContext->doneCurrent(); _context.setFormat(sharedContext->format()); diff --git a/libraries/render-utils/src/OffscreenGlCanvas.h b/libraries/render-utils/src/OffscreenGlCanvas.h index 1b2f15f690..5a64a4cf10 100644 --- a/libraries/render-utils/src/OffscreenGlCanvas.h +++ b/libraries/render-utils/src/OffscreenGlCanvas.h @@ -18,7 +18,7 @@ class OffscreenGlCanvas : public QObject { public: OffscreenGlCanvas(); - void create(QOpenGLContext * sharedContext = nullptr); + void create(QOpenGLContext* sharedContext = nullptr); bool makeCurrent(); void doneCurrent(); diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/render-utils/src/OffscreenQmlDialog.cpp index d6cfc9951b..ae0525e17d 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.cpp +++ b/libraries/render-utils/src/OffscreenQmlDialog.cpp @@ -10,7 +10,7 @@ #include "OffscreenQmlDialog.h" -OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem *parent) +OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem* parent) : QQuickItem(parent) { } void OffscreenQmlDialog::hide() { diff --git a/libraries/render-utils/src/OffscreenQmlDialog.h b/libraries/render-utils/src/OffscreenQmlDialog.h index 6e94587fd2..bb69b4b63f 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.h +++ b/libraries/render-utils/src/OffscreenQmlDialog.h @@ -47,7 +47,7 @@ class OffscreenQmlDialog : public QQuickItem { Q_OBJECT public: - OffscreenQmlDialog(QQuickItem *parent = 0); + OffscreenQmlDialog(QQuickItem* parent = 0); protected: void hide(); diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d9dd030758..6849837da3 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -18,18 +18,18 @@ class OffscreenUiRoot : public QQuickItem { Q_OBJECT public: - OffscreenUiRoot(QQuickItem *parent = 0); - Q_INVOKABLE void information(const QString & title, const QString & text); - Q_INVOKABLE void loadChild(const QUrl & url) { + OffscreenUiRoot(QQuickItem* parent = 0); + Q_INVOKABLE void information(const QString& title, const QString& text); + Q_INVOKABLE void loadChild(const QUrl& url) { DependencyManager::get()->load(url); } }; -OffscreenUiRoot::OffscreenUiRoot(QQuickItem *parent) : QQuickItem(parent) { +OffscreenUiRoot::OffscreenUiRoot(QQuickItem* parent) : QQuickItem(parent) { } -void OffscreenUiRoot::information(const QString & title, const QString & text = "foo") { +void OffscreenUiRoot::information(const QString& title, const QString& text) { OffscreenUi::information(title, text); } @@ -55,7 +55,7 @@ OffscreenUi::~OffscreenUi() { doneCurrent(); } -void OffscreenUi::create(QOpenGLContext * shareContext) { +void OffscreenUi::create(QOpenGLContext* shareContext) { OffscreenGlCanvas::create(shareContext); makeCurrent(); @@ -69,8 +69,9 @@ void OffscreenUi::create(QOpenGLContext * shareContext) { _quickWindow->setFlags(_quickWindow->flags() | static_cast(Qt::WA_TranslucentBackground)); // Create a QML engine. _qmlEngine = new QQmlEngine; - if (!_qmlEngine->incubationController()) + if (!_qmlEngine->incubationController()) { _qmlEngine->setIncubationController(_quickWindow->incubationController()); + } // When Quick says there is a need to render, we will not render immediately. Instead, // a timer with a small interval is used to get better performance. @@ -91,11 +92,11 @@ void OffscreenUi::create(QOpenGLContext * shareContext) { _renderControl->initialize(&_context); } -void OffscreenUi::addImportPath(const QString & path) { +void OffscreenUi::addImportPath(const QString& path) { _qmlEngine->addImportPath(path); } -void OffscreenUi::resize(const QSize & newSize) { +void OffscreenUi::resize(const QSize& newSize) { makeCurrent(); // Clear out any fbos with the old size @@ -115,24 +116,25 @@ void OffscreenUi::resize(const QSize & newSize) { doneCurrent(); } -QQmlContext * OffscreenUi::qmlContext() { +QQmlContext* OffscreenUi::qmlContext() { if (nullptr == _rootItem) { return _qmlComponent->creationContext(); } return QQmlEngine::contextForObject(_rootItem); } -void OffscreenUi::setBaseUrl(const QUrl & baseUrl) { +void OffscreenUi::setBaseUrl(const QUrl& baseUrl) { _qmlEngine->setBaseUrl(baseUrl); } -void OffscreenUi::load(const QUrl & qmlSource, std::function f) { +void OffscreenUi::load(const QUrl& qmlSource, std::function f) { qDebug() << "Loading QML from URL " << qmlSource; _qmlComponent->loadUrl(qmlSource); - if (_qmlComponent->isLoading()) - connect(_qmlComponent, &QQmlComponent::statusChanged, this, [] {}); - else + if (_qmlComponent->isLoading()) { + connect(_qmlComponent, &QQmlComponent::statusChanged, this, []{}); + } else { finishQmlLoad(); + } } void OffscreenUi::requestUpdate() { @@ -156,7 +158,7 @@ void OffscreenUi::finishQmlLoad() { return; } - QObject *newObject = _qmlComponent->create(); + QObject* newObject = _qmlComponent->create(); if (_qmlComponent->isError()) { QList errorList = _qmlComponent->errors(); foreach(const QQmlError &error, errorList) @@ -167,7 +169,7 @@ void OffscreenUi::finishQmlLoad() { return; } - QQuickItem * newItem = qobject_cast(newObject); + QQuickItem* newItem = qobject_cast(newObject); if (!newItem) { qWarning("run: Not a QQuickItem"); delete newObject; @@ -200,8 +202,9 @@ void OffscreenUi::updateQuick() { if (_paused) { return; } - if (!makeCurrent()) + if (!makeCurrent()) { return; + } // Polish, synchronize and render the next frame (into our fbo). In this example // everything happens on the same thread and therefore all three steps are performed @@ -234,7 +237,7 @@ void OffscreenUi::updateQuick() { emit textureUpdated(fbo->texture()); } -QPointF OffscreenUi::mapWindowToUi(const QPointF & p, QObject * dest) { +QPointF OffscreenUi::mapWindowToUi(const QPointF& p, QObject* dest) { vec2 sourceSize; if (dynamic_cast(dest)) { sourceSize = toGlm(((QWidget*)dest)->size()); @@ -252,7 +255,7 @@ QPointF OffscreenUi::mapWindowToUi(const QPointF & p, QObject * dest) { // Event handling customization // -bool OffscreenUi::eventFilter(QObject * dest, QEvent * e) { +bool OffscreenUi::eventFilter(QObject* dest, QEvent* e) { // Only intercept events while we're in an active state if (_paused) { return false; @@ -264,50 +267,46 @@ bool OffscreenUi::eventFilter(QObject * dest, QEvent * e) { } switch (e->type()) { - case QEvent::Resize: - { - QResizeEvent * re = (QResizeEvent *)e; - QGLWidget * widget = dynamic_cast(dest); - if (widget) { - this->resize(re->size()); + case QEvent::Resize: { + QResizeEvent* re = (QResizeEvent*)e; + QGLWidget* widget = dynamic_cast(dest); + if (widget) { + this->resize(re->size()); + } + return false; } - return false; - } - case QEvent::KeyPress: - case QEvent::KeyRelease: - { - e->ignore(); - if (QCoreApplication::sendEvent(_quickWindow, e)) { - return e->isAccepted(); + case QEvent::KeyPress: + case QEvent::KeyRelease: { + e->ignore(); + if (QCoreApplication::sendEvent(_quickWindow, e)) { + return e->isAccepted(); + } + break; } - } - break; - case QEvent::Wheel: - { - QWheelEvent * we = (QWheelEvent*)e; - QWheelEvent mappedEvent(mapWindowToUi(we->pos(), dest), we->delta(), we->buttons(), we->modifiers(), we->orientation()); - QCoreApplication::sendEvent(_quickWindow, &mappedEvent); - return true; - } - break; + case QEvent::Wheel: { + QWheelEvent* we = (QWheelEvent*)e; + QWheelEvent mappedEvent(mapWindowToUi(we->pos(), dest), we->delta(), we->buttons(), we->modifiers(), we->orientation()); + QCoreApplication::sendEvent(_quickWindow, &mappedEvent); + return true; + } - // Fall through - case QEvent::MouseButtonDblClick: - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseMove: - { - QMouseEvent * me = (QMouseEvent *)e; - QPointF originalPos = me->localPos(); - QPointF transformedPos = _mouseTranslator(originalPos); - QMouseEvent mappedEvent(e->type(), mapWindowToUi(transformedPos, dest), me->screenPos(), me->button(), me->buttons(), me->modifiers()); - QCoreApplication::sendEvent(_quickWindow, &mappedEvent); - return QObject::event(e); - } + // Fall through + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: { + QMouseEvent* me = (QMouseEvent *)e; + QPointF originalPos = me->localPos(); + QPointF transformedPos = _mouseTranslator(originalPos); + QMouseEvent mappedEvent(e->type(), mapWindowToUi(transformedPos, dest), me->screenPos(), me->button(), me->buttons(), me->modifiers()); + QCoreApplication::sendEvent(_quickWindow, &mappedEvent); + return QObject::event(e); + } - default: break; + default: + break; } return false; @@ -334,22 +333,22 @@ bool OffscreenUi::isPaused() const { return _paused; } -void OffscreenUi::setProxyWindow(QWindow * window) { +void OffscreenUi::setProxyWindow(QWindow* window) { _renderControl->_renderWindow = window; } -void OffscreenUi::show(const QUrl & url, const QString & name) { - QQuickItem * item = _rootItem->findChild(name); +void OffscreenUi::show(const QUrl& url, const QString& name) { + QQuickItem* item = _rootItem->findChild(name); // First load? - if (nullptr == item) { + if (!item) { load(url); return; } item->setEnabled(true); } -void OffscreenUi::toggle(const QUrl & url, const QString & name) { - QQuickItem * item = _rootItem->findChild(name); +void OffscreenUi::toggle(const QUrl& url, const QString& name) { + QQuickItem* item = _rootItem->findChild(name); // First load? if (nullptr == item) { load(url); @@ -358,31 +357,31 @@ void OffscreenUi::toggle(const QUrl & url, const QString & name) { item->setEnabled(!item->isEnabled()); } -void OffscreenUi::messageBox(const QString &title, const QString &text, +void OffscreenUi::messageBox(const QString& title, const QString& text, QMessageBox::Icon icon, QMessageBox::StandardButtons buttons, ButtonCallback f) { } -void OffscreenUi::information(const QString &title, const QString &text, +void OffscreenUi::information(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, ButtonCallback callback) { callback(QMessageBox::information(nullptr, title, text, buttons)); } -void OffscreenUi::question(const QString &title, const QString &text, +void OffscreenUi::question(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, ButtonCallback callback) { callback(QMessageBox::question(nullptr, title, text, buttons)); } -void OffscreenUi::warning(const QString &title, const QString &text, +void OffscreenUi::warning(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, ButtonCallback callback) { callback(QMessageBox::warning(nullptr, title, text, buttons)); } -void OffscreenUi::critical(const QString &title, const QString &text, +void OffscreenUi::critical(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, ButtonCallback callback) { callback(QMessageBox::critical(nullptr, title, text, buttons)); @@ -391,4 +390,4 @@ void OffscreenUi::critical(const QString &title, const QString &text, OffscreenUi::ButtonCallback OffscreenUi::NO_OP_CALLBACK = [](QMessageBox::StandardButton) {}; -#include "OffscreenUi.moc" \ No newline at end of file +#include "OffscreenUi.moc" diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index 73c022e4be..16db24e5ae 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -38,7 +38,7 @@ class OffscreenUi : public OffscreenGlCanvas, public Dependency { class QMyQuickRenderControl : public QQuickRenderControl { protected: - QWindow * renderWindow(QPoint * offset) Q_DECL_OVERRIDE{ + QWindow* renderWindow(QPoint* offset) Q_DECL_OVERRIDE{ if (nullptr == _renderWindow) { return QQuickRenderControl::renderWindow(offset); } @@ -49,59 +49,59 @@ class OffscreenUi : public OffscreenGlCanvas, public Dependency { } private: - QWindow * _renderWindow{ nullptr }; + QWindow* _renderWindow{ nullptr }; friend class OffscreenUi; }; public: - using MouseTranslator = std::function < QPointF(const QPointF &) > ; + using MouseTranslator = std::function; OffscreenUi(); virtual ~OffscreenUi(); - void create(QOpenGLContext * context); - void resize(const QSize & size); - void load(const QUrl & qmlSource, std::function f = [](QQmlContext*) {}); - void load(const QString & qmlSourceFile, std::function f = [](QQmlContext*) {}) { + void create(QOpenGLContext* context); + void resize(const QSize& size); + void load(const QUrl& qmlSource, std::function f = [](QQmlContext*) {}); + void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*) {}) { load(QUrl(qmlSourceFile), f); } - void show(const QUrl & url, const QString & name); - void toggle(const QUrl & url, const QString & name); - void setBaseUrl(const QUrl & baseUrl); - void addImportPath(const QString & path); + void show(const QUrl& url, const QString& name); + void toggle(const QUrl& url, const QString& name); + void setBaseUrl(const QUrl& baseUrl); + void addImportPath(const QString& path); QQmlContext * qmlContext(); void pause(); void resume(); bool isPaused() const; - void setProxyWindow(QWindow * window); - QPointF mapWindowToUi(const QPointF & p, QObject * dest); - virtual bool eventFilter(QObject * dest, QEvent * e); + void setProxyWindow(QWindow* window); + QPointF mapWindowToUi(const QPointF& p, QObject* dest); + virtual bool eventFilter(QObject* dest, QEvent* e); void setMouseTranslator(MouseTranslator mt) { _mouseTranslator = mt; } // Messagebox replacement functions - using ButtonCallback = std::function < void(QMessageBox::StandardButton) >; + using ButtonCallback = std::function; static ButtonCallback NO_OP_CALLBACK; - static void messageBox(const QString &title, const QString &text, + static void messageBox(const QString& title, const QString& text, QMessageBox::Icon icon, QMessageBox::StandardButtons buttons, ButtonCallback f); - static void information(const QString &title, const QString &text, + static void information(const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, ButtonCallback callback = NO_OP_CALLBACK); - static void question(const QString &title, const QString &text, + static void question(const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), ButtonCallback callback = [](QMessageBox::StandardButton) {}); - static void warning(const QString &title, const QString &text, + static void warning(const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, ButtonCallback callback = [](QMessageBox::StandardButton) {}); - static void critical(const QString &title, const QString &text, + static void critical(const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, ButtonCallback callback = [](QMessageBox::StandardButton) {}); @@ -121,11 +121,11 @@ signals: void textureUpdated(GLuint texture); private: - QMyQuickRenderControl *_renderControl{ new QMyQuickRenderControl }; - QQuickWindow *_quickWindow{ nullptr }; - QQmlEngine *_qmlEngine{ nullptr }; - QQmlComponent *_qmlComponent{ nullptr }; - QQuickItem * _rootItem{ nullptr }; + QMyQuickRenderControl* _renderControl{ new QMyQuickRenderControl }; + QQuickWindow* _quickWindow{ nullptr }; + QQmlEngine* _qmlEngine{ nullptr }; + QQmlComponent* _qmlComponent{ nullptr }; + QQuickItem* _rootItem{ nullptr }; QTimer _updateTimer; FboCache _fboCache; bool _polish{ true }; From c4d2bd2cdaac29a237fa84398e923db9bb633115 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 19:18:09 -0700 Subject: [PATCH 15/20] More coding standard fixes --- interface/src/Application.h | 4 ++-- interface/src/GLCanvas.cpp | 2 +- interface/src/ui/AddressBarDialog.cpp | 6 +++--- interface/src/ui/AddressBarDialog.h | 4 ++-- interface/src/ui/LoginDialog.cpp | 10 +++++----- interface/src/ui/LoginDialog.h | 2 +- libraries/render-utils/src/FboCache.cpp | 2 +- libraries/render-utils/src/FboCache.h | 2 +- .../render-utils/src/OffscreenQmlDialog.cpp | 2 +- libraries/render-utils/src/OffscreenUi.cpp | 6 ++++-- libraries/shared/src/ThreadHelpers.h | 4 ++-- tests/render-utils/src/main.cpp | 18 ++++++++---------- 12 files changed, 31 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index cb54f7dc79..89de18dde5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -171,8 +171,8 @@ public: void touchUpdateEvent(QTouchEvent* event); void wheelEvent(QWheelEvent* event); - void dropEvent(QDropEvent *event); - void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent* event); + void dragEnterEvent(QDragEnterEvent* event); bool event(QEvent* event); bool eventFilter(QObject* object, QEvent* event); diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index d0c0cb6713..0e25f0f596 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -127,7 +127,7 @@ void GLCanvas::throttleRender() { int updateTime = 0; bool GLCanvas::event(QEvent* event) { switch (event->type()) { - case QEvent::MouseMove: + case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::KeyPress: diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 5ef9b930ac..6b5c92c194 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -17,7 +17,7 @@ QML_DIALOG_DEF(AddressBarDialog) -AddressBarDialog::AddressBarDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { +AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) { auto addressManager = DependencyManager::get(); connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage); connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage); @@ -25,10 +25,10 @@ AddressBarDialog::AddressBarDialog(QQuickItem *parent) : OffscreenQmlDialog(pare } void AddressBarDialog::hide() { - ((QQuickItem *)parent())->setEnabled(false); + ((QQuickItem*)parent())->setEnabled(false); } -void AddressBarDialog::loadAddress(const QString & address) { +void AddressBarDialog::loadAddress(const QString& address) { qDebug() << "Called LoadAddress with address " << address; if (!address.isEmpty()) { DependencyManager::get()->handleLookupString(address); diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index b4f4c44e0f..a9035cc915 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -20,14 +20,14 @@ class AddressBarDialog : public OffscreenQmlDialog QML_DIALOG_DECL public: - AddressBarDialog(QQuickItem *parent = 0); + AddressBarDialog(QQuickItem* parent = 0); protected: void displayAddressOfflineMessage(); void displayAddressNotFoundMessage(); void hide(); - Q_INVOKABLE void loadAddress(const QString & address); + Q_INVOKABLE void loadAddress(const QString& address); }; #endif diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 3637d824fb..10541415bf 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -41,7 +41,7 @@ void LoginDialog::toggleAction() { } } -void LoginDialog::handleLoginCompleted(const QUrl& authURL) { +void LoginDialog::handleLoginCompleted(const QUrl&) { hide(); } @@ -49,9 +49,9 @@ void LoginDialog::handleLoginFailed() { setStatusText("Invalid username or password.< / font>"); } -void LoginDialog::setStatusText(const QString &a) { +void LoginDialog::setStatusText(const QString& statusText) { if (a != _statusText) { - _statusText = a; + _statusText = statusText; emit statusTextChanged(); } } @@ -64,12 +64,12 @@ QString LoginDialog::rootUrl() const { return _rootUrl; } -void LoginDialog::login(const QString & username, const QString & password) { +void LoginDialog::login(const QString& username, const QString& password) { qDebug() << "Attempting to login " << username; setStatusText("Authenticating..."); AccountManager::getInstance().requestAccessToken(username, password); } -void LoginDialog::openUrl(const QString & url) { +void LoginDialog::openUrl(const QString& url) { qDebug() << url; } diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index 7fe44bf543..b4f83bb9ad 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -27,7 +27,7 @@ public: LoginDialog(QQuickItem* parent = 0); - void setStatusText(const QString & a); + void setStatusText(const QString& a); QString statusText() const; QString rootUrl() const; diff --git a/libraries/render-utils/src/FboCache.cpp b/libraries/render-utils/src/FboCache.cpp index fdd29d20d8..2ca3d47bdf 100644 --- a/libraries/render-utils/src/FboCache.cpp +++ b/libraries/render-utils/src/FboCache.cpp @@ -72,7 +72,7 @@ QOpenGLFramebufferObject* FboCache::getReadyFbo() { return result; } -void FboCache::setSize(const QSize & newSize) { +void FboCache::setSize(const QSize& newSize) { if (_size == newSize) { return; } diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h index 975d602278..30278470fd 100644 --- a/libraries/render-utils/src/FboCache.h +++ b/libraries/render-utils/src/FboCache.h @@ -30,7 +30,7 @@ public: // the appropriate OpenGL context is active when doing so. // Important.... textures are sharable resources, but FBOs ARE NOT. - void setSize(const QSize & newSize); + void setSize(const QSize& newSize); QOpenGLFramebufferObject* getReadyFbo(); // These operations are thread safe and require no OpenGL context. They manipulate the diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/render-utils/src/OffscreenQmlDialog.cpp index ae0525e17d..98dc68f94b 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.cpp +++ b/libraries/render-utils/src/OffscreenQmlDialog.cpp @@ -14,5 +14,5 @@ OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem* parent) : QQuickItem(parent) { } void OffscreenQmlDialog::hide() { - ((QQuickItem *)parent())->setEnabled(false); + ((QQuickItem*)parent())->setEnabled(false); } diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 6849837da3..5fb2773d31 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -139,13 +139,15 @@ void OffscreenUi::load(const QUrl& qmlSource, std::function void OffscreenUi::requestUpdate() { _polish = true; - if (!_updateTimer.isActive()) + if (!_updateTimer.isActive()) { _updateTimer.start(); + } } void OffscreenUi::requestRender() { - if (!_updateTimer.isActive()) + if (!_updateTimer.isActive()) { _updateTimer.start(); + } } void OffscreenUi::finishQmlLoad() { diff --git a/libraries/shared/src/ThreadHelpers.h b/libraries/shared/src/ThreadHelpers.h index 8a64691da7..cc0e1ee666 100644 --- a/libraries/shared/src/ThreadHelpers.h +++ b/libraries/shared/src/ThreadHelpers.h @@ -21,9 +21,9 @@ void withLock(L lock, F function) { } template -void withLock(QMutex & lock, F function) { +void withLock(QMutex& lock, F function) { QMutexLocker locker(&lock); function(); } -#endif \ No newline at end of file +#endif diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index eb61fd1f72..7adad34879 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -70,7 +70,7 @@ public: }; -const QString & getQmlDir() { +const QString& getQmlDir() { static QString dir; if (dir.isEmpty()) { QDir path(__FILE__); @@ -98,7 +98,7 @@ protected: void renderQml(); private: - void resizeWindow(const QSize & size) { + void resizeWindow(const QSize& size) { _size = size; DependencyManager::get()->resize(_size); } @@ -126,7 +126,7 @@ public: makeCurrent(); { - QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); logger->initialize(); // initializes in the current context, i.e. ctx logger->enableMessages(); connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { @@ -201,12 +201,12 @@ public: protected: - void resizeEvent(QResizeEvent * ev) override { + void resizeEvent(QResizeEvent* ev) override { resizeWindow(ev->size()); } - void keyPressEvent(QKeyEvent *event) { + void keyPressEvent(QKeyEvent* event) { switch (event->key()) { case Qt::Key_L: if (event->modifiers() & Qt::CTRL) { @@ -217,7 +217,7 @@ protected: QWindow::keyPressEvent(event); } - void moveEvent(QMoveEvent *event) { + void moveEvent(QMoveEvent* event) { static qreal oldPixelRatio = 0.0; if (devicePixelRatio() != oldPixelRatio) { oldPixelRatio = devicePixelRatio(); @@ -232,8 +232,8 @@ protected: #define SERIF_FONT_FAMILY "Times New Roman" #endif -static const wchar_t * EXAMPLE_TEXT = L"Hello"; -//static const wchar_t * EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y"; +static const wchar_t* EXAMPLE_TEXT = L"Hello"; +//static const wchar_t* EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y"; static const glm::uvec2 QUAD_OFFSET(10, 10); static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, { @@ -283,7 +283,6 @@ void QTestWindow::renderText() { } void QTestWindow::renderQml() { - glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); @@ -297,7 +296,6 @@ void QTestWindow::renderQml() { } glBegin(GL_QUADS); { - glTexCoord2f(0, 0); glVertex2f(-1, -1); glTexCoord2f(0, 1); From 930ec7a6d8ecb8d61566d85d91a7afd3295bb252 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 19:22:10 -0700 Subject: [PATCH 16/20] One more --- tests/render-utils/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 7adad34879..9d7363c241 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -84,7 +84,7 @@ const QString& getQmlDir() { class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext * _context{ nullptr }; + QOpenGLContext* _context{ nullptr }; QSize _size; TextRenderer* _textRenderer[4]; RateCounter fps; From 732e9723cd0294880776dfd74b371c9db824eecc Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 19:24:43 -0700 Subject: [PATCH 17/20] Messed up rename --- interface/src/ui/LoginDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 10541415bf..4df42c0f15 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -50,7 +50,7 @@ void LoginDialog::handleLoginFailed() { } void LoginDialog::setStatusText(const QString& statusText) { - if (a != _statusText) { + if (statusText != _statusText) { _statusText = statusText; emit statusTextChanged(); } From 44efcdf82ad48ee56a72674a377543699bc7b24d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 20:08:49 -0700 Subject: [PATCH 18/20] More coding standard --- libraries/render-utils/src/OffscreenUi.cpp | 56 ++++++++++++---------- libraries/render-utils/src/OffscreenUi.h | 12 ++--- libraries/render-utils/src/RenderUtil.h | 4 +- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index 5fb2773d31..d63f3330e9 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -239,17 +239,17 @@ void OffscreenUi::updateQuick() { emit textureUpdated(fbo->texture()); } -QPointF OffscreenUi::mapWindowToUi(const QPointF& p, QObject* dest) { +QPointF OffscreenUi::mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject) { vec2 sourceSize; - if (dynamic_cast(dest)) { - sourceSize = toGlm(((QWidget*)dest)->size()); - } else if (dynamic_cast(dest)) { - sourceSize = toGlm(((QWindow*)dest)->size()); + if (dynamic_cast(sourceObject)) { + sourceSize = toGlm(((QWidget*)sourceObject)->size()); + } else if (dynamic_cast(sourceObject)) { + sourceSize = toGlm(((QWindow*)sourceObject)->size()); } - vec2 pos = toGlm(p); - pos /= sourceSize; - pos *= vec2(toGlm(_quickWindow->size())); - return QPointF(pos.x, pos.y); + vec2 offscreenPosition = toGlm(sourcePosition); + offscreenPosition /= sourceSize; + offscreenPosition *= vec2(toGlm(_quickWindow->size())); + return QPointF(offscreenPosition.x, offscreenPosition.y); } /////////////////////////////////////////////////////// @@ -257,39 +257,42 @@ QPointF OffscreenUi::mapWindowToUi(const QPointF& p, QObject* dest) { // Event handling customization // -bool OffscreenUi::eventFilter(QObject* dest, QEvent* e) { +bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { // Only intercept events while we're in an active state if (_paused) { return false; } // Don't intercept our own events, or we enter an infinite recursion - if (dest == _quickWindow) { + if (originalDestination == _quickWindow) { return false; } - switch (e->type()) { + switch (event->type()) { case QEvent::Resize: { - QResizeEvent* re = (QResizeEvent*)e; - QGLWidget* widget = dynamic_cast(dest); + QResizeEvent* resizeEvent = (QResizeEvent*)event; + QGLWidget* widget = dynamic_cast(originalDestination); if (widget) { - this->resize(re->size()); + this->resize(resizeEvent->size()); } return false; } case QEvent::KeyPress: case QEvent::KeyRelease: { - e->ignore(); - if (QCoreApplication::sendEvent(_quickWindow, e)) { - return e->isAccepted(); + event->ignore(); + if (QCoreApplication::sendEvent(_quickWindow, event)) { + return event->isAccepted(); } break; } case QEvent::Wheel: { - QWheelEvent* we = (QWheelEvent*)e; - QWheelEvent mappedEvent(mapWindowToUi(we->pos(), dest), we->delta(), we->buttons(), we->modifiers(), we->orientation()); + QWheelEvent* wheelEvent = (QWheelEvent*)event; + QWheelEvent mappedEvent( + mapWindowToUi(wheelEvent->pos(), originalDestination), + wheelEvent->delta(), wheelEvent->buttons(), + wheelEvent->modifiers(), wheelEvent->orientation()); QCoreApplication::sendEvent(_quickWindow, &mappedEvent); return true; } @@ -299,12 +302,15 @@ bool OffscreenUi::eventFilter(QObject* dest, QEvent* e) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { - QMouseEvent* me = (QMouseEvent *)e; - QPointF originalPos = me->localPos(); + QMouseEvent* mouseEvent = (QMouseEvent *)event; + QPointF originalPos = mouseEvent->localPos(); QPointF transformedPos = _mouseTranslator(originalPos); - QMouseEvent mappedEvent(e->type(), mapWindowToUi(transformedPos, dest), me->screenPos(), me->button(), me->buttons(), me->modifiers()); + QMouseEvent mappedEvent(mouseEvent->type(), + mapWindowToUi(transformedPos, originalDestination), + mouseEvent->screenPos(), mouseEvent->button(), + mouseEvent->buttons(), mouseEvent->modifiers()); QCoreApplication::sendEvent(_quickWindow, &mappedEvent); - return QObject::event(e); + return QObject::event(event); } default: @@ -352,7 +358,7 @@ void OffscreenUi::show(const QUrl& url, const QString& name) { void OffscreenUi::toggle(const QUrl& url, const QString& name) { QQuickItem* item = _rootItem->findChild(name); // First load? - if (nullptr == item) { + if (!item) { load(url); return; } diff --git a/libraries/render-utils/src/OffscreenUi.h b/libraries/render-utils/src/OffscreenUi.h index 16db24e5ae..d86f99554e 100644 --- a/libraries/render-utils/src/OffscreenUi.h +++ b/libraries/render-utils/src/OffscreenUi.h @@ -67,16 +67,16 @@ public: void toggle(const QUrl& url, const QString& name); void setBaseUrl(const QUrl& baseUrl); void addImportPath(const QString& path); - QQmlContext * qmlContext(); + QQmlContext* qmlContext(); void pause(); void resume(); bool isPaused() const; void setProxyWindow(QWindow* window); - QPointF mapWindowToUi(const QPointF& p, QObject* dest); - virtual bool eventFilter(QObject* dest, QEvent* e); - void setMouseTranslator(MouseTranslator mt) { - _mouseTranslator = mt; + QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); + virtual bool eventFilter(QObject* originalDestination, QEvent* event); + void setMouseTranslator(MouseTranslator mouseTranslator) { + _mouseTranslator = mouseTranslator; } @@ -130,7 +130,7 @@ private: FboCache _fboCache; bool _polish{ true }; bool _paused{ true }; - MouseTranslator _mouseTranslator{ [](const QPointF & p) { return p; } }; + MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p; } }; }; #endif diff --git a/libraries/render-utils/src/RenderUtil.h b/libraries/render-utils/src/RenderUtil.h index 74d6c23791..8c1b1e12e7 100644 --- a/libraries/render-utils/src/RenderUtil.h +++ b/libraries/render-utils/src/RenderUtil.h @@ -37,7 +37,7 @@ void withProjectionIdentity(F f) { } template -void withProjectionMatrix(GLfloat * matrix, F f) { +void withProjectionMatrix(GLfloat* matrix, F f) { withProjectionPush([&] { glLoadMatrixf(matrix); f(); @@ -58,7 +58,7 @@ void withModelviewIdentity(F f) { } template -void withModelviewMatrix(GLfloat * matrix, F f) { +void withModelviewMatrix(GLfloat* matrix, F f) { withModelviewPush([&] { glLoadMatrixf(matrix); f(); From eab4ad9ea98343afeb4bd8a7a171a8aa2957ae91 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 20:16:41 -0700 Subject: [PATCH 19/20] More coding standard stuff --- interface/src/ui/AddressBarDialog.h | 2 +- interface/src/ui/LoginDialog.h | 4 ++-- libraries/render-utils/src/OffscreenQmlDialog.cpp | 2 +- libraries/render-utils/src/OffscreenQmlDialog.h | 2 +- libraries/render-utils/src/OffscreenUi.cpp | 7 ++++++- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index a9035cc915..28056edd30 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -20,7 +20,7 @@ class AddressBarDialog : public OffscreenQmlDialog QML_DIALOG_DECL public: - AddressBarDialog(QQuickItem* parent = 0); + AddressBarDialog(QQuickItem* parent = nullptr); protected: void displayAddressOfflineMessage(); diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index b4f83bb9ad..b6d505943e 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -25,9 +25,9 @@ class LoginDialog : public OffscreenQmlDialog public: static void toggleAction(); - LoginDialog(QQuickItem* parent = 0); + LoginDialog(QQuickItem* parent = nullptr); - void setStatusText(const QString& a); + void setStatusText(const QString& statusText); QString statusText() const; QString rootUrl() const; diff --git a/libraries/render-utils/src/OffscreenQmlDialog.cpp b/libraries/render-utils/src/OffscreenQmlDialog.cpp index 98dc68f94b..d1e060245d 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.cpp +++ b/libraries/render-utils/src/OffscreenQmlDialog.cpp @@ -14,5 +14,5 @@ OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem* parent) : QQuickItem(parent) { } void OffscreenQmlDialog::hide() { - ((QQuickItem*)parent())->setEnabled(false); + static_cast(parent())->setEnabled(false); } diff --git a/libraries/render-utils/src/OffscreenQmlDialog.h b/libraries/render-utils/src/OffscreenQmlDialog.h index bb69b4b63f..eca82261c0 100644 --- a/libraries/render-utils/src/OffscreenQmlDialog.h +++ b/libraries/render-utils/src/OffscreenQmlDialog.h @@ -47,7 +47,7 @@ class OffscreenQmlDialog : public QQuickItem { Q_OBJECT public: - OffscreenQmlDialog(QQuickItem* parent = 0); + OffscreenQmlDialog(QQuickItem* parent = nullptr); protected: void hide(); diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d63f3330e9..d4e1f15b22 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -14,6 +14,11 @@ #include #include +// Time between receiving a request to render the offscreen UI actually triggering +// the render. Could possibly be increased depending on the framerate we expect to +// achieve. +static const int SMALL_INTERVAL = 5; + class OffscreenUiRoot : public QQuickItem { Q_OBJECT public: @@ -76,7 +81,7 @@ void OffscreenUi::create(QOpenGLContext* shareContext) { // When Quick says there is a need to render, we will not render immediately. Instead, // a timer with a small interval is used to get better performance. _updateTimer.setSingleShot(true); - _updateTimer.setInterval(5); + _updateTimer.setInterval(SMALL_INTERVAL); connect(&_updateTimer, &QTimer::timeout, this, &OffscreenUi::updateQuick); // Now hook up the signals. For simplicy we don't differentiate between From de179256d3a15aad8a78b391047b47e52e0e2efa Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 22 Apr 2015 20:19:19 -0700 Subject: [PATCH 20/20] Kill all the whitespace --- libraries/render-utils/src/OffscreenUi.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/OffscreenUi.cpp b/libraries/render-utils/src/OffscreenUi.cpp index d4e1f15b22..db93a14b0d 100644 --- a/libraries/render-utils/src/OffscreenUi.cpp +++ b/libraries/render-utils/src/OffscreenUi.cpp @@ -275,7 +275,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { switch (event->type()) { case QEvent::Resize: { - QResizeEvent* resizeEvent = (QResizeEvent*)event; + QResizeEvent* resizeEvent = static_cast(event); QGLWidget* widget = dynamic_cast(originalDestination); if (widget) { this->resize(resizeEvent->size()); @@ -293,7 +293,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { } case QEvent::Wheel: { - QWheelEvent* wheelEvent = (QWheelEvent*)event; + QWheelEvent* wheelEvent = static_cast(event); QWheelEvent mappedEvent( mapWindowToUi(wheelEvent->pos(), originalDestination), wheelEvent->delta(), wheelEvent->buttons(), @@ -307,7 +307,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { - QMouseEvent* mouseEvent = (QMouseEvent *)event; + QMouseEvent* mouseEvent = static_cast(event); QPointF originalPos = mouseEvent->localPos(); QPointF transformedPos = _mouseTranslator(originalPos); QMouseEvent mappedEvent(mouseEvent->type(),