mirror of
https://github.com/lubosz/overte.git
synced 2025-04-14 14:46:55 +02:00
Adding OffscreenUI API for QInputDialog functionality
This commit is contained in:
parent
27fdb523cb
commit
858bbbf987
12 changed files with 283 additions and 66 deletions
|
@ -2,7 +2,7 @@ set(TARGET_NAME interface)
|
|||
project(${TARGET_NAME})
|
||||
|
||||
# set a default root dir for each of our optional externals if it was not passed
|
||||
set(OPTIONAL_EXTERNALS "LeapMotion")
|
||||
#set(OPTIONAL_EXTERNALS "LeapMotion")
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND OPTIONAL_EXTERNALS "3DConnexionClient")
|
||||
|
|
|
@ -18,8 +18,6 @@ FocusScope {
|
|||
// The VR version of the primary menu
|
||||
property var rootMenu: Menu { objectName: "rootMenu" }
|
||||
|
||||
Component { id: messageDialogBuilder; MessageDialog { } }
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int zBasisNormal: 0
|
||||
|
@ -158,16 +156,22 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
|
||||
MenuMouseHandler { id: menuPopperUpper }
|
||||
|
||||
function raise(item) {
|
||||
d.raiseWindow(item);
|
||||
}
|
||||
|
||||
|
||||
Component { id: messageDialogBuilder; MessageDialog { } }
|
||||
function messageBox(properties) {
|
||||
return messageDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
Component { id: queryDialogBuilder; QueryDialog { } }
|
||||
function queryBox(properties) {
|
||||
return queryDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
MenuMouseHandler { id: menuPopperUpper }
|
||||
function popupMenu(point) {
|
||||
menuPopperUpper.popup(desktop, rootMenu.items, point);
|
||||
}
|
||||
|
@ -213,7 +217,7 @@ FocusScope {
|
|||
function onWindowFocusChanged() {
|
||||
console.log("Focus item is " + offscreenWindow.activeFocusItem);
|
||||
var focusedItem = offscreenWindow.activeFocusItem ;
|
||||
if (DebugQML && focusedItem) {
|
||||
if (DebugQML && focusedItem && false) {
|
||||
var rect = desktop.mapFromItem(focusedItem, 0, 0, focusedItem.width, focusedItem.height);
|
||||
focusDebugger.visible = true
|
||||
focusDebugger.x = rect.x;
|
||||
|
|
|
@ -19,7 +19,6 @@ ModalWindow {
|
|||
signal selected(int button);
|
||||
|
||||
function click(button) {
|
||||
console.log("User clicked " + button)
|
||||
clickedButton = button;
|
||||
selected(button);
|
||||
destroy();
|
||||
|
|
114
interface/resources/qml/dialogs/QueryDialog.qml
Normal file
114
interface/resources/qml/dialogs/QueryDialog.qml
Normal file
|
@ -0,0 +1,114 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
|
||||
import "../controls" as VrControls
|
||||
import "../styles"
|
||||
import "../windows"
|
||||
|
||||
ModalWindow {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
implicitWidth: 640
|
||||
implicitHeight: 320
|
||||
visible: true
|
||||
|
||||
signal selected(var result);
|
||||
signal canceled();
|
||||
|
||||
property alias result: textResult.text
|
||||
property alias placeholderText: textResult.placeholderText
|
||||
property alias text: mainTextContainer.text
|
||||
|
||||
Rectangle {
|
||||
clip: true
|
||||
anchors.fill: parent
|
||||
radius: 4
|
||||
color: "white"
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property real spacing: hifi.layout.spacing
|
||||
readonly property real outerSpacing: hifi.layout.spacing * 2
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWdith: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = mainTextContainer.width + d.spacing * 6
|
||||
var targetHeight = mainTextContainer.implicitHeight + textResult.height + d.spacing + buttons.height
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth)
|
||||
root.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: mainTextContainer
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
wrapMode: Text.WordWrap
|
||||
font { pointSize: 14; weight: Font.Bold }
|
||||
anchors { left: parent.left; top: parent.top; margins: d.spacing }
|
||||
}
|
||||
|
||||
Item {
|
||||
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
|
||||
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: buttons
|
||||
focus: true
|
||||
spacing: d.spacing
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
layoutDirection: Qt.RightToLeft
|
||||
anchors { bottom: parent.bottom; right: parent.right; margins: d.spacing; }
|
||||
Button { action: acceptAction }
|
||||
Button { action: cancelAction }
|
||||
}
|
||||
|
||||
Action {
|
||||
id: cancelAction
|
||||
text: qsTr("Cancel")
|
||||
shortcut: Qt.Key_Escape
|
||||
onTriggered: {
|
||||
root.canceled();
|
||||
root.destroy();
|
||||
}
|
||||
}
|
||||
Action {
|
||||
id: acceptAction
|
||||
text: qsTr("OK")
|
||||
shortcut: Qt.Key_Return
|
||||
onTriggered: {
|
||||
root.selected(root.result);
|
||||
root.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
cancelAction.trigger()
|
||||
event.accepted = true;
|
||||
break;
|
||||
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Enter:
|
||||
acceptAction.trigger()
|
||||
event.accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ Frame {
|
|||
|
||||
// FIXME needed?
|
||||
Rectangle {
|
||||
anchors { margins: -iconSize; topMargin: -iconSize * (window.closable ? 2 : 1); }
|
||||
anchors { margins: -iconSize; topMargin: -iconSize * ((window && window.closable) ? 2 : 1); }
|
||||
anchors.fill: parent;
|
||||
color: "#7f7f7f7f";
|
||||
radius: 3;
|
||||
|
@ -46,7 +46,7 @@ Frame {
|
|||
}
|
||||
}
|
||||
FontAwesome {
|
||||
visible: window.closable
|
||||
visible: window ? window.closable : false
|
||||
text: closeClickArea.containsMouse ? "\uf057" : "\uf05c"
|
||||
style: Text.Outline;
|
||||
styleColor: "white"
|
||||
|
|
|
@ -20,7 +20,7 @@ Item {
|
|||
Text {
|
||||
id: debugZ
|
||||
visible: DebugQML
|
||||
text: "Z: " + window.z
|
||||
text: window ? "Z: " + window.z : ""
|
||||
y: -height
|
||||
}
|
||||
|
||||
|
@ -41,21 +41,21 @@ Item {
|
|||
|
||||
Rectangle {
|
||||
id: sizeOutline
|
||||
width: window.width
|
||||
height: window.height
|
||||
width: window ? window.width : 0
|
||||
height: window ? window.height : 0
|
||||
color: "#00000000"
|
||||
border.width: 4
|
||||
radius: 10
|
||||
visible: !window.content.visible
|
||||
visible: window ? !window.content.visible : false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: sizeDrag
|
||||
width: iconSize
|
||||
height: iconSize
|
||||
enabled: window.resizable
|
||||
x: window.width
|
||||
y: window.height
|
||||
enabled: window ? window.resizable : false
|
||||
x: window ? window.width : 0
|
||||
y: window ? window.height : 0
|
||||
property vector2d pressOrigin
|
||||
property vector2d sizeOrigin
|
||||
property bool hid: false
|
||||
|
|
|
@ -6,6 +6,8 @@ Window {
|
|||
id: root
|
||||
anchors.centerIn: parent
|
||||
modality: Qt.ApplicationModal
|
||||
destroyOnCloseButton: true
|
||||
destroyOnInvisible: true
|
||||
frame: ModalFrame{}
|
||||
}
|
||||
|
||||
|
|
|
@ -4554,22 +4554,8 @@ void Application::loadDialog() {
|
|||
}
|
||||
|
||||
void Application::loadScriptURLDialog() {
|
||||
// To be migratd to QML
|
||||
QInputDialog scriptURLDialog(getWindow());
|
||||
scriptURLDialog.setWindowTitle("Open and Run Script URL");
|
||||
scriptURLDialog.setLabelText("Script:");
|
||||
scriptURLDialog.setWindowFlags(Qt::Sheet);
|
||||
const float DIALOG_RATIO_OF_WINDOW = 0.30f;
|
||||
scriptURLDialog.resize(scriptURLDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW,
|
||||
scriptURLDialog.size().height());
|
||||
|
||||
int dialogReturn = scriptURLDialog.exec();
|
||||
QString newScript;
|
||||
if (dialogReturn == QDialog::Accepted) {
|
||||
if (scriptURLDialog.textValue().size() > 0) {
|
||||
// the user input a new hostname, use that
|
||||
newScript = scriptURLDialog.textValue();
|
||||
}
|
||||
auto newScript = OffscreenUi::getText(nullptr, "Open and Run Script", "Script URL");
|
||||
if (!newScript.isEmpty()) {
|
||||
DependencyManager::get<ScriptEngines>()->loadScript(newScript);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
//
|
||||
#include "OffscreenUi.h"
|
||||
|
||||
#include <QtQml/QtQml>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
#include <QtQml/QtQml>
|
||||
|
||||
#include <AbstractUriHandler.h>
|
||||
#include <AccountManager.h>
|
||||
|
@ -132,47 +133,64 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<voi
|
|||
}
|
||||
}
|
||||
|
||||
class MessageBoxListener : public QObject {
|
||||
class ModalDialogListener : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
friend class OffscreenUi;
|
||||
|
||||
MessageBoxListener(QQuickItem* messageBox) : _messageBox(messageBox) {
|
||||
if (!_messageBox) {
|
||||
protected:
|
||||
ModalDialogListener(QQuickItem* dialog) : _dialog(dialog) {
|
||||
if (!dialog) {
|
||||
_finished = true;
|
||||
return;
|
||||
}
|
||||
connect(_messageBox, SIGNAL(selected(int)), this, SLOT(onSelected(int)));
|
||||
connect(_messageBox, SIGNAL(destroyed()), this, SLOT(onDestroyed()));
|
||||
}
|
||||
connect(_dialog, SIGNAL(destroyed()), this, SLOT(onDestroyed()));
|
||||
}
|
||||
|
||||
~MessageBoxListener() {
|
||||
disconnect(_messageBox);
|
||||
~ModalDialogListener() {
|
||||
disconnect(_dialog);
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton waitForResult() {
|
||||
virtual QVariant waitForResult() {
|
||||
while (!_finished) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void onSelected(int button) {
|
||||
_result = static_cast<QMessageBox::StandardButton>(button);
|
||||
_finished = true;
|
||||
disconnect(_messageBox);
|
||||
}
|
||||
|
||||
protected slots:
|
||||
void onDestroyed() {
|
||||
_finished = true;
|
||||
disconnect(_messageBox);
|
||||
disconnect(_dialog);
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
QQuickItem* const _dialog;
|
||||
bool _finished { false };
|
||||
QMessageBox::StandardButton _result { QMessageBox::StandardButton::NoButton };
|
||||
QQuickItem* const _messageBox;
|
||||
QVariant _result;
|
||||
};
|
||||
|
||||
class MessageBoxListener : public ModalDialogListener {
|
||||
Q_OBJECT
|
||||
|
||||
friend class OffscreenUi;
|
||||
MessageBoxListener(QQuickItem* messageBox) : ModalDialogListener(messageBox) {
|
||||
if (_finished) {
|
||||
return;
|
||||
}
|
||||
connect(_dialog, SIGNAL(selected(int)), this, SLOT(onSelected(int)));
|
||||
}
|
||||
|
||||
virtual QMessageBox::StandardButton waitForButtonResult() {
|
||||
ModalDialogListener::waitForResult();
|
||||
return static_cast<QMessageBox::StandardButton>(_result.toInt());
|
||||
}
|
||||
|
||||
private slots:
|
||||
void onSelected(int button) {
|
||||
_result = button;
|
||||
_finished = true;
|
||||
disconnect(_dialog);
|
||||
}
|
||||
};
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
|
@ -204,7 +222,7 @@ QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, cons
|
|||
return QMessageBox::StandardButton::NoButton;
|
||||
}
|
||||
|
||||
auto resultButton = MessageBoxListener(qvariant_cast<QQuickItem*>(result)).waitForResult();
|
||||
QMessageBox::StandardButton resultButton = MessageBoxListener(qvariant_cast<QQuickItem*>(result)).waitForButtonResult();
|
||||
qDebug() << "Message box got a result of " << resultButton;
|
||||
return resultButton;
|
||||
}
|
||||
|
@ -226,6 +244,66 @@ QMessageBox::StandardButton OffscreenUi::warning(const QString& title, const QSt
|
|||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class InputDialogListener : public ModalDialogListener {
|
||||
Q_OBJECT
|
||||
|
||||
friend class OffscreenUi;
|
||||
InputDialogListener(QQuickItem* queryBox) : ModalDialogListener(queryBox) {
|
||||
if (_finished) {
|
||||
return;
|
||||
}
|
||||
connect(_dialog, SIGNAL(selected(QVariant)), this, SLOT(onSelected(const QVariant&)));
|
||||
}
|
||||
|
||||
private slots:
|
||||
void onSelected(const QVariant& result) {
|
||||
_result = result;
|
||||
_finished = true;
|
||||
disconnect(_dialog);
|
||||
}
|
||||
};
|
||||
|
||||
// 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) {
|
||||
QVariant result = DependencyManager::get<OffscreenUi>()->inputDialog(title, label, text).toString();
|
||||
if (ok && result.isValid()) {
|
||||
*ok = true;
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
QVariant OffscreenUi::inputDialog(const QString& query, const QString& placeholderText, const QString& currentValue) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QVariant result;
|
||||
QMetaObject::invokeMethod(this, "queryBox", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariant, result),
|
||||
Q_ARG(QString, query),
|
||||
Q_ARG(QString, placeholderText),
|
||||
Q_ARG(QString, currentValue));
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariantMap map;
|
||||
map.insert("text", query);
|
||||
map.insert("placeholderText", placeholderText);
|
||||
map.insert("result", currentValue);
|
||||
QVariant result;
|
||||
bool invokeResult = QMetaObject::invokeMethod(_desktop, "queryBox",
|
||||
Q_RETURN_ARG(QVariant, result),
|
||||
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||
|
||||
if (!invokeResult) {
|
||||
qWarning() << "Failed to create message box";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
return InputDialogListener(qvariant_cast<QQuickItem*>(result)).waitForResult();
|
||||
}
|
||||
|
||||
|
||||
bool OffscreenUi::navigationFocused() {
|
||||
return offscreenFlags->isNavigationFocused();
|
||||
}
|
||||
|
|
|
@ -13,9 +13,11 @@
|
|||
#define hifi_OffscreenUi_h
|
||||
|
||||
#include <QtCore/QVariant>
|
||||
#include <gl/OffscreenQmlSurface.h>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <gl/OffscreenQmlSurface.h>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "OffscreenQmlElement.h"
|
||||
|
@ -78,7 +80,18 @@ public:
|
|||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
|
||||
QMessageBox::StandardButton messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
|
||||
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());
|
||||
|
||||
// FIXME implement
|
||||
static QVariant query(const QString& query, const QString& placeholderText = QString(), const QString& currentValue = QString());
|
||||
|
||||
// FIXME implement
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
private:
|
||||
QQuickItem* _desktop { nullptr };
|
||||
|
|
|
@ -72,10 +72,30 @@ ApplicationWindow {
|
|||
Button {
|
||||
text: "Show Error"
|
||||
onClicked: {
|
||||
desktop.messageBox({
|
||||
text: "Diagnostic cycle will be complete in 30 seconds",
|
||||
icon: OriginalDialogs.StandardIcon.Critical,
|
||||
});
|
||||
var messageBox = desktop.messageBox({
|
||||
text: "Diagnostic cycle will be complete in 30 seconds",
|
||||
icon: OriginalDialogs.StandardIcon.Critical,
|
||||
});
|
||||
messageBox.selected.connect(function(button) {
|
||||
console.log("You clicked " + button)
|
||||
})
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: "Show Query"
|
||||
onClicked: {
|
||||
var queryBox = desktop.queryBox({
|
||||
text: "Have you stopped beating your wife?",
|
||||
placeholderText: "Are you sure?",
|
||||
// icon: OriginalDialogs.StandardIcon.Critical,
|
||||
});
|
||||
queryBox.selected.connect(function(result) {
|
||||
console.log("User responded with " + result);
|
||||
});
|
||||
|
||||
queryBox.canceled.connect(function() {
|
||||
console.log("User cancelled query box ");
|
||||
})
|
||||
}
|
||||
}
|
||||
Button {
|
||||
|
@ -118,7 +138,7 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
Window {
|
||||
id: blue
|
||||
closable: true
|
||||
|
@ -143,7 +163,7 @@ ApplicationWindow {
|
|||
Component.onDestruction: console.log("Blue destroyed")
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Window {
|
||||
id: green
|
||||
alwaysOnTop: true
|
||||
|
|
|
@ -100,7 +100,8 @@ DISTFILES += \
|
|||
../../interface/resources/qml/hifi/dialogs/preferences/CheckBox.qml \
|
||||
../../interface/resources/qml/dialogs/fileDialog/FileTableView.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/Avatar.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/AvatarBrowser.qml
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/AvatarBrowser.qml \
|
||||
../../interface/resources/qml/dialogs/QueryDialog.qml
|
||||
|
||||
HEADERS += \
|
||||
../../libraries/ui/src/FileDialogHelper.h
|
||||
|
|
Loading…
Reference in a new issue