From c80193635bc694a7628b42a9c9d02ca96cacfa6d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 28 Jan 2016 21:19:21 -0800 Subject: [PATCH] Update input dialog to support choice selection --- interface/resources/qml/desktop/Desktop.qml | 6 +- .../resources/qml/dialogs/QueryDialog.qml | 25 ++++- libraries/ui/src/OffscreenUi.cpp | 102 +++++++++++++----- libraries/ui/src/OffscreenUi.h | 22 ++-- 4 files changed, 115 insertions(+), 40 deletions(-) diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index b610dbf73c..5bef1cb516 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -252,9 +252,9 @@ FocusScope { return messageDialogBuilder.createObject(desktop, properties); } - Component { id: queryDialogBuilder; QueryDialog { } } - function queryBox(properties) { - return queryDialogBuilder.createObject(desktop, properties); + Component { id: inputDialogBuilder; QueryDialog { } } + function inputDialog(properties) { + return inputDialogBuilder.createObject(desktop, properties); } Component { id: fileDialogBuilder; FileDialog { } } diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index 52fde34271..159bb95b5d 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -16,9 +16,17 @@ ModalWindow { signal selected(var result); signal canceled(); - property alias result: textResult.text + property var items; + property alias label: mainTextContainer.text + property var result; + // FIXME not current honored + property var current; + + // For text boxes property alias placeholderText: textResult.placeholderText - property alias text: mainTextContainer.text + + // For combo boxes + property bool editable: true; Rectangle { clip: true @@ -55,10 +63,20 @@ ModalWindow { anchors { top: mainTextContainer.bottom; bottom: buttons.top; left: parent.left; right: parent.right; margins: d.spacing } // FIXME make a text field type that can be bound to a history for autocompletion TextField { - focus: true id: textResult + focus: items ? false : true + visible: items ? false : true anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter } } + + VrControls.ComboBox { + id: comboBox + focus: items ? true : false + visible: items ? true : false + anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter } + model: items ? items : [] + } + } Flow { @@ -86,6 +104,7 @@ ModalWindow { text: qsTr("OK") shortcut: Qt.Key_Return onTriggered: { + root.result = items ? comboBox.currentText : textResult.text root.selected(root.result); root.destroy(); } diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index f399cd95a1..8e52507243 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -199,19 +199,7 @@ private slots: } }; -QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { - if (QThread::currentThread() != thread()) { - QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton; - QMetaObject::invokeMethod(this, "messageBox", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QMessageBox::StandardButton, result), - Q_ARG(QMessageBox::Icon, icon), - Q_ARG(QString, title), - Q_ARG(QString, text), - Q_ARG(QMessageBox::StandardButtons, buttons), - Q_ARG(QMessageBox::StandardButton, defaultButton)); - return result; - } - +QQuickItem* OffscreenUi::createMessageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { QVariantMap map; map.insert("title", title); map.insert("text", text); @@ -225,12 +213,34 @@ QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, cons if (!invokeResult) { qWarning() << "Failed to create message box"; - return QMessageBox::StandardButton::NoButton; + return nullptr; + } + return qvariant_cast(result); +} + +QMessageBox::StandardButton OffscreenUi::waitForMessageBoxResult(QQuickItem* messageBox) { + if (!messageBox) { + return QMessageBox::NoButton; } - QMessageBox::StandardButton resultButton = MessageBoxListener(qvariant_cast(result)).waitForButtonResult(); - qDebug() << "Message box got a result of " << resultButton; - return resultButton; + return MessageBoxListener(messageBox).waitForButtonResult(); +} + + +QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { + if (QThread::currentThread() != thread()) { + QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton; + QMetaObject::invokeMethod(this, "messageBox", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QMessageBox::StandardButton, result), + Q_ARG(QMessageBox::Icon, icon), + Q_ARG(QString, title), + Q_ARG(QString, text), + Q_ARG(QMessageBox::StandardButtons, buttons), + Q_ARG(QMessageBox::StandardButton, defaultButton)); + return result; + } + + return waitForMessageBoxResult(createMessageBox(icon, title, text, buttons, defaultButton)); } QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QString& text, @@ -273,6 +283,7 @@ private slots: // FIXME many input parameters currently ignored QString OffscreenUi::getText(void* ignored, const QString & title, const QString & label, QLineEdit::EchoMode mode, const QString & text, bool * ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints) { + if (ok) { *ok = false; } QVariant result = DependencyManager::get()->inputDialog(title, label, text).toString(); if (ok && result.isValid()) { *ok = true; @@ -280,35 +291,70 @@ QString OffscreenUi::getText(void* ignored, const QString & title, const QString return result.toString(); } +// FIXME many input parameters currently ignored +QString OffscreenUi::getItem(void *ignored, const QString & title, const QString & label, const QStringList & items, int current, bool editable, bool * ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints) { + if (ok) { + *ok = false; + } -QVariant OffscreenUi::inputDialog(const QString& query, const QString& placeholderText, const QString& currentValue) { + auto offscreenUi = DependencyManager::get(); + auto inputDialog = offscreenUi->createInputDialog(title, label, current); + if (!inputDialog) { + return QString(); + } + inputDialog->setProperty("items", items); + inputDialog->setProperty("editable", editable); + + QVariant result = offscreenUi->waitForInputDialogResult(inputDialog); + if (!result.isValid()) { + return QString(); + } + + if (ok) { + *ok = true; + } + return result.toString(); +} + +QVariant OffscreenUi::inputDialog(const QString& title, const QString& label, const QVariant& current) { if (QThread::currentThread() != thread()) { QVariant result; - QMetaObject::invokeMethod(this, "queryBox", Qt::BlockingQueuedConnection, + QMetaObject::invokeMethod(this, "inputDialog", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariant, result), - Q_ARG(QString, query), - Q_ARG(QString, placeholderText), - Q_ARG(QString, currentValue)); + Q_ARG(QString, title), + Q_ARG(QString, label), + Q_ARG(QVariant, current)); return result; } + return waitForInputDialogResult(createInputDialog(title, label, current)); +} + + +QQuickItem* OffscreenUi::createInputDialog(const QString& title, const QString& label, const QVariant& current) { QVariantMap map; - map.insert("text", query); - map.insert("placeholderText", placeholderText); - map.insert("result", currentValue); + map.insert("title", title); + map.insert("label", label); + map.insert("current", current); QVariant result; - bool invokeResult = QMetaObject::invokeMethod(_desktop, "queryBox", + bool invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, QVariant::fromValue(map))); if (!invokeResult) { qWarning() << "Failed to create message box"; - return QVariant(); + return nullptr; } - return InputDialogListener(qvariant_cast(result)).waitForResult(); + return qvariant_cast(result); } +QVariant OffscreenUi::waitForInputDialogResult(QQuickItem* inputDialog) { + if (!inputDialog) { + return QVariant(); + } + return InputDialogListener(inputDialog).waitForResult(); +} bool OffscreenUi::navigationFocused() { return offscreenFlags->isNavigationFocused(); diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 8ad6641e06..ec5ba433cc 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -42,6 +42,13 @@ public: QQuickItem* getToolWindow(); + // Message box compatibility + Q_INVOKABLE QMessageBox::StandardButton messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton); + // Must be called from the main thread + QQuickItem* createMessageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton); + // Must be called from the main thread + QMessageBox::StandardButton waitForMessageBoxResult(QQuickItem* messageBox); + /// Same design as QMessageBox::critical(), will block, returns result static QMessageBox::StandardButton critical(void* ignored, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, @@ -80,18 +87,21 @@ public: QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); - Q_INVOKABLE QMessageBox::StandardButton messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton); - Q_INVOKABLE QVariant inputDialog(const QString& query, const QString& placeholderText = QString(), const QString& currentValue = QString()); + // file dialog compatibility Q_INVOKABLE QString fileOpenDialog(const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); - - // FIXME implement - static QVariant query(const QString& query, const QString& placeholderText = QString(), const QString& currentValue = QString()); - // Compatibility with QFileDialog::getOpenFileName static QString getOpenFileName(void* ignored, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); + + // input dialog compatibility + Q_INVOKABLE QVariant inputDialog(const QString& title, const QString& label = QString(), const QVariant& current = QVariant()); + QQuickItem* createInputDialog(const QString& title, const QString& label, const QVariant& current); + QVariant waitForInputDialogResult(QQuickItem* inputDialog); + // Compatibility with QInputDialog::getText static QString getText(void* ignored, const QString & title, const QString & label, QLineEdit::EchoMode mode = QLineEdit::Normal, const QString & text = QString(), bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone); + // Compatibility with QInputDialog::getItem + static QString getItem(void *ignored, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone); private: QQuickItem* _desktop { nullptr };