Merge branch 'master' of github.com:highfidelity/hifi into assignment-client-exits

This commit is contained in:
Seth Alves 2015-04-29 08:23:27 -07:00
commit b2e99b754f
65 changed files with 1714 additions and 1084 deletions

View file

@ -29,12 +29,12 @@ NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit
* [Download the online installer](http://qt-project.org/downloads)
* When it asks you to select components, ONLY select the following:
* Qt > Qt 5.3.2 > **msvc2013 32-bit OpenGL**
* Qt > Qt 5.4.1 > **msvc2013 32-bit OpenGL**
* [Download the offline installer](http://download.qt-project.org/official_releases/qt/5.3/5.3.2/qt-opensource-windows-x86-msvc2013_opengl-5.3.2.exe)
* [Download the offline installer](http://download.qt.io/official_releases/qt/5.4/5.4.1/qt-opensource-windows-x86-msvc2013_opengl-5.4.1.exe)
Once Qt is installed, you need to manually configure the following:
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.3.2\msvc2013_opengl\lib\cmake` directory.
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.4.1\msvc2013_opengl\lib\cmake` directory.
* You can set an environment variable from Control Panel > System > Advanced System Settings > Environment Variables > New
###External Libraries

View file

@ -13,6 +13,7 @@
var createdRenderMenu = false;
var createdGeneratedAudioMenu = false;
var createdStereoInputMenuItem = false;
var DEVELOPER_MENU = "Developer";
@ -28,6 +29,7 @@ var AUDIO_SOURCE_INJECT = "Generated Audio";
var AUDIO_SOURCE_MENU = AUDIO_MENU + " > Generated Audio Source";
var AUDIO_SOURCE_PINK_NOISE = "Pink Noise";
var AUDIO_SOURCE_SINE_440 = "Sine 440hz";
var AUDIO_STEREO_INPUT = "Stereo Input";
function setupMenus() {
@ -78,6 +80,10 @@ function setupMenus() {
Audio.selectPinkNoise();
createdGeneratedAudioMenu = true;
}
if (!Menu.menuItemExists(AUDIO_MENU, AUDIO_STEREO_INPUT)) {
Menu.addMenuItem({ menuName: AUDIO_MENU, menuItemName: AUDIO_STEREO_INPUT, isCheckable: true, isChecked: false });
createdStereoInputMenuItem = true;
}
}
Menu.menuItemEvent.connect(function (menuItem) {
@ -99,6 +105,8 @@ Menu.menuItemEvent.connect(function (menuItem) {
} else if (menuItem == AUDIO_SOURCE_SINE_440 && !createdGeneratedAudioMenu) {
Audio.selectSine440();
Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, false);
} else if (menuItem == AUDIO_STEREO_INPUT) {
Audio.setStereoInput(Menu.isOptionChecked(AUDIO_STEREO_INPUT))
}
});
@ -125,6 +133,10 @@ function scriptEnding() {
Menu.removeMenuItem(AUDIO_MENU, AUDIO_SOURCE_INJECT);
Menu.removeMenu(AUDIO_SOURCE_MENU);
}
if (createdStereoInputMenuItem) {
Menu.removeMenuItem(AUDIO_MENU, AUDIO_STEREO_INPUT);
}
}
setupMenus();

View file

@ -4,12 +4,16 @@ import "controls"
import "styles"
Dialog {
id: root
HifiConstants { id: hifi }
title: "Go to..."
objectName: "AddressBarDialog"
height: 128
width: 512
contentImplicitWidth: addressBarDialog.implicitWidth
contentImplicitHeight: addressBarDialog.implicitHeight
destroyOnCloseButton: false
onVisibleChanged: {
if (!visible) {
reset();
@ -21,6 +25,11 @@ Dialog {
addressLine.forceActiveFocus();
}
}
onParentChanged: {
if (enabled && visible) {
addressLine.forceActiveFocus();
}
}
function reset() {
addressLine.text = ""
@ -29,26 +38,28 @@ Dialog {
AddressBarDialog {
id: addressBarDialog
// The client area
anchors.fill: parent
anchors.margins: parent.margins
anchors.topMargin: parent.topMargin
x: root.clientX
y: root.clientY
implicitWidth: 512
implicitHeight: border.height + hifi.layout.spacing * 4
Border {
id: border
height: 64
anchors.left: parent.left
anchors.leftMargin: 0
anchors.leftMargin: hifi.layout.spacing * 2
anchors.right: goButton.left
anchors.rightMargin: 8
anchors.rightMargin: hifi.layout.spacing
anchors.verticalCenter: parent.verticalCenter
TextInput {
id: addressLine
anchors.fill: parent
helperText: "domain, location, @user, /x,y,z"
anchors.margins: 8
anchors.margins: hifi.layout.spacing
onAccepted: {
event.accepted
event.accepted
addressBarDialog.loadAddress(addressLine.text)
}
}
@ -59,7 +70,7 @@ Dialog {
width: 32
height: 32
anchors.right: parent.right
anchors.rightMargin: 8
anchors.rightMargin: hifi.layout.spacing * 2
source: "../images/address-bar-submit.svg"
anchors.verticalCenter: parent.verticalCenter

View file

@ -1,20 +0,0 @@
import QtQuick 2.4
import QtQuick.Controls 1.3
Action {
property string name
objectName: name + "HifiAction"
text: qsTr(name)
signal triggeredByName(string name);
signal toggledByName(string name);
onTriggered: {
triggeredByName(name);
}
onToggled: {
toggledByName(name, checked);
}
}

View file

@ -1,272 +0,0 @@
import Hifi 1.0 as Hifi
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
import "controls"
import "styles"
Hifi.HifiMenu {
id: root
anchors.fill: parent
objectName: "HifiMenu"
enabled: false
opacity: 0.0
property int animationDuration: 200
HifiPalette { id: hifiPalette }
z: 10000
onEnabledChanged: {
if (enabled && columns.length == 0) {
pushColumn(rootMenu.items);
}
opacity = enabled ? 1.0 : 0.0
if (enabled) {
forceActiveFocus()
}
}
// The actual animator
Behavior on opacity {
NumberAnimation {
duration: root.animationDuration
easing.type: Easing.InOutBounce
}
}
onOpacityChanged: {
visible = (opacity != 0.0);
}
onVisibleChanged: {
if (!visible) reset();
}
property var menu: Menu {}
property var models: []
property var columns: []
property var itemBuilder: Component {
Text {
SystemPalette { id: sp; colorGroup: SystemPalette.Active }
id: thisText
x: 32
property var source
property var root
property var listViewIndex
property var listView
text: typedText()
height: implicitHeight
width: implicitWidth
color: source.enabled ? "black" : "gray"
onImplicitWidthChanged: {
if (listView) {
listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64);
listView.recalculateSize();
}
}
FontAwesome {
visible: source.type == 1 && source.checkable
x: -32
text: (source.type == 1 && source.checked) ? "\uF05D" : "\uF10C"
}
FontAwesome {
visible: source.type == 2
x: listView.width - 64
text: "\uF0DA"
}
function typedText() {
switch(source.type) {
case 2:
return source.title;
case 1:
return source.text;
case 0:
return "-----"
}
}
MouseArea {
id: mouseArea
acceptedButtons: Qt.LeftButton
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
width: listView.width
onClicked: {
listView.currentIndex = listViewIndex
parent.root.selectItem(parent.source);
}
}
}
}
property var menuBuilder: Component {
Border {
SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active }
x: root.models.length == 1 ?
(root.width / 2 - width / 2) :
root.columns[root.models.length - 2].x + 60;
anchors.verticalCenter: parent.verticalCenter
border.color: hifiPalette.hifiBlue
color: sysPalette.window
ListView {
spacing: 6
property int outerMargin: 8
property real minWidth: 0
anchors.fill: parent
anchors.margins: outerMargin
id: listView
height: root.height
currentIndex: -1
onCountChanged: {
recalculateSize()
}
function recalculateSize() {
var newHeight = 0
var newWidth = minWidth;
for (var i = 0; i < children.length; ++i) {
var item = children[i];
newHeight += item.height
}
parent.height = newHeight + outerMargin * 2;
parent.width = newWidth + outerMargin * 2
}
highlight: Rectangle {
width: listView.minWidth; height: 32
color: sysPalette.highlight
y: (listView.currentItem) ? listView.currentItem.y : 0;
x: 32
Behavior on y {
NumberAnimation {
duration: 100
easing.type: Easing.InOutQuint
}
}
}
property int columnIndex: root.models.length - 1
model: root.models[columnIndex]
delegate: Loader {
id: loader
sourceComponent: root.itemBuilder
Binding {
target: loader.item
property: "root"
value: root
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "source"
value: modelData
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "listViewIndex"
value: index
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "listView"
value: listView
when: loader.status == Loader.Ready
}
}
}
}
}
function lastColumn() {
return columns[root.columns.length - 1];
}
function pushColumn(items) {
models.push(items)
if (columns.length) {
var oldColumn = lastColumn();
oldColumn.enabled = false;
oldColumn.opacity = 0.5;
}
var newColumn = menuBuilder.createObject(root);
columns.push(newColumn);
newColumn.forceActiveFocus();
}
function popColumn() {
if (columns.length > 0) {
var curColumn = columns.pop();
console.log(curColumn);
curColumn.visible = false;
curColumn.destroy();
models.pop();
}
if (columns.length == 0) {
enabled = false;
return;
}
curColumn = lastColumn();
curColumn.enabled = true;
curColumn.opacity = 1.0;
curColumn.forceActiveFocus();
}
function selectItem(source) {
switch (source.type) {
case 2:
pushColumn(source.items)
break;
case 1:
source.trigger()
enabled = false
break;
case 0:
break;
}
}
function reset() {
while (columns.length > 0) {
popColumn();
}
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Escape:
root.popColumn()
event.accepted = true;
}
}
MouseArea {
anchors.fill: parent
id: mouseArea
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button == Qt.RightButton) {
root.popColumn();
} else {
root.enabled = false;
}
}
}
}

View file

@ -5,9 +5,8 @@ import "controls"
import "styles"
Dialog {
HifiConstants { id: hifi }
title: "Login"
HifiPalette { id: hifiPalette }
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
objectName: "LoginDialog"
height: 512
width: 384
@ -61,9 +60,6 @@ Dialog {
anchors.margins: 8
KeyNavigation.tab: password
KeyNavigation.backtab: password
onAccepted: {
password.forceActiveFocus()
}
}
}
@ -79,13 +75,6 @@ Dialog {
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()
@ -117,7 +106,7 @@ Dialog {
width: 192
height: 64
anchors.horizontalCenter: parent.horizontalCenter
color: hifiPalette.hifiBlue
color: hifi.colors.hifiBlue
border.width: 0
radius: 10
@ -160,7 +149,7 @@ Dialog {
text:"Create Account"
font.pointSize: 12
font.bold: true
color: hifiPalette.hifiBlue
color: hifi.colors.hifiBlue
MouseArea {
anchors.fill: parent
@ -177,7 +166,7 @@ Dialog {
verticalAlignment: Text.AlignVCenter
font.pointSize: 12
text: "Recover Password"
color: hifiPalette.hifiBlue
color: hifi.colors.hifiBlue
MouseArea {
anchors.fill: parent
@ -188,4 +177,22 @@ Dialog {
}
}
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
if (username.activeFocus) {
event.accepted = true
password.forceActiveFocus()
} else if (password.activeFocus) {
event.accepted = true
if (username.text == "") {
username.forceActiveFocus()
} else {
loginDialog.login(username.text, password.text)
}
}
break;
}
}
}

View file

@ -3,56 +3,37 @@ import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import "controls"
import "styles"
Dialog {
id: root
property real spacing: 8
property real outerSpacing: 16
HifiConstants { id: hifi }
property real spacing: hifi.layout.spacing
property real outerSpacing: hifi.layout.spacing * 2
destroyOnCloseButton: true
destroyOnInvisible: true
implicitHeight: content.implicitHeight + outerSpacing * 2 + 48
implicitWidth: Math.min(200, Math.max(mainText.implicitWidth, content.buttonsRowImplicitWidth) + outerSpacing * 2);
onImplicitHeightChanged: root.height = implicitHeight
onImplicitWidthChanged: root.width = implicitWidth
SystemPalette { id: palette }
function calculateImplicitWidth() {
if (buttons.visibleChildren.length < 2)
return;
var calcWidth = 0;
for (var i = 0; i < buttons.visibleChildren.length; ++i) {
calcWidth += Math.max(100, buttons.visibleChildren[i].implicitWidth) + root.spacing
}
content.buttonsRowImplicitWidth = outerSpacing + calcWidth + 48
}
contentImplicitWidth: content.implicitWidth
contentImplicitHeight: content.implicitHeight
Component.onCompleted: {
enabled = true
}
onEnabledChanged: {
if (enabled) {
root.forceActiveFocus();
onParentChanged: {
if (visible && enabled) {
forceActiveFocus();
}
}
Hifi.MessageDialog {
id: content
clip: true
anchors.fill: parent
anchors.topMargin: parent.topMargin + root.outerSpacing
anchors.leftMargin: parent.margins + root.outerSpacing
anchors.rightMargin: parent.margins + root.outerSpacing
anchors.bottomMargin: parent.margins + root.outerSpacing
implicitHeight: contentColumn.implicitHeight + outerSpacing * 2
implicitWidth: Math.max(mainText.implicitWidth, buttonsRowImplicitWidth);
property real buttonsRowImplicitWidth: Screen.pixelDensity * 50
onImplicitWidthChanged: root.width = implicitWidth
x: root.clientX
y: root.clientY
implicitHeight: contentColumn.implicitHeight + outerSpacing * 2
implicitWidth: mainText.implicitWidth + outerSpacing * 2
Component.onCompleted: {
root.title = title
@ -63,13 +44,10 @@ Dialog {
}
Column {
anchors.fill: parent
anchors.margins: 8
id: contentColumn
spacing: root.outerSpacing
anchors {
top: parent.top
left: parent.left
right: parent.right
}
Item {
width: parent.width
@ -264,7 +242,6 @@ Dialog {
onClicked: content.click(StandardButton.Help)
visible: content.standardButtons & StandardButton.Help
}
onVisibleChildrenChanged: root.calculateImplicitWidth()
}
}
@ -321,6 +298,7 @@ Dialog {
]
}
Keys.onPressed: {
if (event.modifiers === Qt.ControlModifier)
switch (event.key) {
@ -335,7 +313,7 @@ Dialog {
case Qt.Key_Period:
if (Qt.platform.os === "osx") {
event.accepted = true
content.reject()
content.reject()
}
break
} else switch (event.key) {
@ -347,7 +325,6 @@ Dialog {
case Qt.Key_Enter:
case Qt.Key_Return:
console.log("Accepting");
event.accepted = true
content.accept()
break

View file

@ -8,7 +8,7 @@ Root {
anchors.fill: parent
onParentChanged: {
forceActiveFocus();
forceActiveFocus();
}
}

View file

@ -0,0 +1,115 @@
import QtQuick 2.4
import QtQuick.Controls 1.3
import Hifi 1.0
// Currently for testing a pure QML replacement menu
Item {
Item {
objectName: "AllActions"
Action {
id: aboutApp
objectName: "HifiAction_" + MenuConstants.AboutApp
text: qsTr("About Interface")
}
//
// File Menu
//
Action {
id: login
objectName: "HifiAction_" + MenuConstants.Login
text: qsTr("Login")
}
Action {
id: quit
objectName: "HifiAction_" + MenuConstants.Quit
text: qsTr("Quit")
//shortcut: StandardKey.Quit
shortcut: "Ctrl+Q"
}
//
// Edit menu
//
Action {
id: undo
text: "Undo"
shortcut: StandardKey.Undo
}
Action {
id: redo
text: "Redo"
shortcut: StandardKey.Redo
}
Action {
id: animations
objectName: "HifiAction_" + MenuConstants.Animations
text: qsTr("Animations...")
}
Action {
id: attachments
text: qsTr("Attachments...")
}
Action {
id: explode
text: qsTr("Explode on quit")
checkable: true
checked: true
}
Action {
id: freeze
text: qsTr("Freeze on quit")
checkable: true
checked: false
}
ExclusiveGroup {
Action {
id: visibleToEveryone
objectName: "HifiAction_" + MenuConstants.VisibleToEveryone
text: qsTr("Everyone")
checkable: true
checked: true
}
Action {
id: visibleToFriends
objectName: "HifiAction_" + MenuConstants.VisibleToFriends
text: qsTr("Friends")
checkable: true
}
Action {
id: visibleToNoOne
objectName: "HifiAction_" + MenuConstants.VisibleToNoOne
text: qsTr("No one")
checkable: true
}
}
}
Menu {
objectName: "rootMenu";
Menu {
title: "File"
MenuItem { action: login }
MenuItem { action: explode }
MenuItem { action: freeze }
MenuItem { action: quit }
}
Menu {
title: "Tools"
Menu {
title: "I Am Visible To"
MenuItem { action: visibleToEveryone }
MenuItem { action: visibleToFriends }
MenuItem { action: visibleToNoOne }
}
MenuItem { action: animations }
}
Menu {
title: "Help"
MenuItem { action: aboutApp }
}
}
}

View file

@ -6,10 +6,10 @@ import QtQuick.Controls 1.3
import "controls"
Root {
id: root
id: root
anchors.fill: parent
onParentChanged: {
forceActiveFocus();
forceActiveFocus();
}
Button {
id: messageBox
@ -37,7 +37,7 @@ Root {
}
Keys.onPressed: {
console.log("Key press root")
}
console.log("Key press root")
}
}

View file

@ -0,0 +1,326 @@
import Hifi 1.0 as Hifi
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
import "controls"
import "styles"
Hifi.VrMenu {
id: root
HifiConstants { id: hifi }
anchors.fill: parent
objectName: "VrMenu"
enabled: false
opacity: 0.0
property int animationDuration: 200
property var models: []
property var columns: []
z: 10000
onEnabledChanged: {
if (enabled && columns.length == 0) {
pushColumn(rootMenu.items);
}
opacity = enabled ? 1.0 : 0.0
if (enabled) {
forceActiveFocus()
}
}
// The actual animator
Behavior on opacity {
NumberAnimation {
duration: root.animationDuration
easing.type: Easing.InOutBounce
}
}
onOpacityChanged: {
visible = (opacity != 0.0);
}
onVisibleChanged: {
if (!visible) reset();
}
property var menuBuilder: Component {
Border {
HifiConstants { id: hifi }
Component.onCompleted: {
menuDepth = root.models.length - 1
if (menuDepth == 0) {
x = lastMousePosition.x - 20
y = lastMousePosition.y - 20
} else {
var lastColumn = root.columns[menuDepth - 1]
x = lastColumn.x + 64;
y = lastMousePosition.y - height / 2;
}
}
border.color: hifi.colors.hifiBlue
color: hifi.colors.window
property int menuDepth
implicitHeight: listView.implicitHeight + 16
implicitWidth: listView.implicitWidth + 16
Column {
id: listView
property real minWidth: 0
anchors {
top: parent.top
topMargin: 8
left: parent.left
leftMargin: 8
right: parent.right
rightMargin: 8
}
Repeater {
model: root.models[menuDepth]
delegate: Loader {
id: loader
sourceComponent: root.itemBuilder
Binding {
target: loader.item
property: "root"
value: root
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "source"
value: modelData
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "border"
value: listView.parent
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "listView"
value: listView
when: loader.status == Loader.Ready
}
}
}
}
}
}
property var itemBuilder: Component {
Item {
property var source
property var root
property var listView
property var border
implicitHeight: row.implicitHeight + 4
implicitWidth: row.implicitWidth + label.height
// FIXME uncommenting this line results in menus that have blank spots
// rather than having the correct size
// visible: source.visible
Row {
id: row
spacing: 2
anchors {
top: parent.top
topMargin: 2
}
Spacer { size: 4 }
FontAwesome {
id: check
verticalAlignment: Text.AlignVCenter
y: 2
size: label.height
text: checkText()
color: label.color
function checkText() {
if (!source || source.type != 1 || !source.checkable) {
return "";
}
// FIXME this works for native QML menus but I don't think it will
// for proxied QML menus
if (source.exclusiveGroup) {
return source.checked ? "\uF05D" : "\uF10C"
}
return source.checked ? "\uF046" : "\uF096"
}
}
Text {
id: label
text: typedText()
color: source.enabled ? hifi.colors.text : hifi.colors.disabledText
enabled: source.enabled && source.visible
function typedText() {
if (source) {
switch(source.type) {
case 2:
return source.title;
case 1:
return source.text;
case 0:
return "-----"
}
}
return ""
}
}
} // row
FontAwesome {
anchors {
top: row.top
}
id: tag
size: label.height
width: implicitWidth
visible: source.type == 2
x: listView.width - width - 4
text: "\uF0DA"
color: label.color
}
MouseArea {
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
right: tag.right
rightMargin: -4
}
acceptedButtons: Qt.LeftButton
hoverEnabled: true
Rectangle {
id: highlight
visible: false
anchors.fill: parent
color: "#7f0e7077"
}
Timer {
id: timer
interval: 1000
onTriggered: parent.select();
}
onEntered: {
/*
* Uncomment below to have menus auto-popup
*
* FIXME if we enabled timer based menu popup, either the timer has
* to be very very short or after auto popup there has to be a small
* amount of time, or a test if the mouse has moved before a click
* will be accepted, otherwise it's too easy to accidently click on
* something immediately after the auto-popup appears underneath your
* cursor
*
*/
//if (source.type == 2 && enabled) {
// timer.start()
//}
highlight.visible = source.enabled
}
onExited: {
timer.stop()
highlight.visible = false
}
onClicked: {
select();
}
function select() {
//timer.stop();
var popped = false;
while (columns.length - 1 > listView.parent.menuDepth) {
popColumn();
popped = true;
}
if (!popped || source.type != 1) {
parent.root.selectItem(parent.source);
}
}
}
}
}
function lastColumn() {
return columns[root.columns.length - 1];
}
function pushColumn(items) {
models.push(items)
if (columns.length) {
var oldColumn = lastColumn();
//oldColumn.enabled = false
}
var newColumn = menuBuilder.createObject(root);
columns.push(newColumn);
newColumn.forceActiveFocus();
}
function popColumn() {
if (columns.length > 0) {
var curColumn = columns.pop();
curColumn.visible = false;
curColumn.destroy();
models.pop();
}
if (columns.length == 0) {
enabled = false;
return;
}
curColumn = lastColumn();
curColumn.enabled = true;
curColumn.opacity = 1.0;
curColumn.forceActiveFocus();
}
function selectItem(source) {
switch (source.type) {
case 2:
pushColumn(source.items)
break;
case 1:
source.trigger()
enabled = false
break;
case 0:
break;
}
}
function reset() {
while (columns.length > 0) {
popColumn();
}
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Escape:
root.popColumn()
event.accepted = true;
}
}
MouseArea {
anchors.fill: parent
id: mouseArea
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button == Qt.RightButton) {
root.popColumn();
} else {
root.enabled = false;
}
}
}
}

View file

@ -5,6 +5,5 @@ import "."
import "../styles"
Original.Button {
style: ButtonStyle {
}
style: ButtonStyle { }
}

View file

@ -0,0 +1,16 @@
import QtQuick.Controls 1.3 as Original
import QtQuick.Controls.Styles 1.3
import "../styles"
import "."
Original.CheckBox {
text: "Check Box"
style: CheckBoxStyle {
indicator: FontAwesome {
text: control.checked ? "\uf046" : "\uf096"
}
label: Text {
text: control.text
}
}
}

View file

@ -11,28 +11,21 @@ import "../styles"
* Examine the QML ApplicationWindow.qml source for how it does this
*
*/
Item {
DialogBase {
id: root
HifiPalette { id: hifiPalette }
SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active }
HifiConstants { id: hifi }
// FIXME better placement via a window manager
x: parent ? parent.width / 2 - width / 2 : 0
y: parent ? parent.height / 2 - height / 2 : 0
property int animationDuration: 400
property bool destroyOnInvisible: false
property bool destroyOnCloseButton: true
property bool resizable: false
property int animationDuration: hifi.effects.fadeInDuration
property int minX: 256
property int minY: 256
property int topMargin: root.height - clientBorder.height + 8
property int margins: 8
property string title
property int titleSize: titleBorder.height + 12
property string frameColor: hifiPalette.hifiBlue
property string backgroundColor: sysPalette.window
property string headerBackgroundColor: sysPalette.dark
clip: true
readonly property int topMargin: root.height - clientBorder.height + hifi.layout.spacing
/*
* Support for animating the dialog in and out.
@ -44,7 +37,8 @@ Item {
// visibility, so that we can do animations in both directions. Because
// visibility and enabled are boolean flags, they cannot be animated. So when
// enabled is change, we modify a property that can be animated, like scale or
// opacity.
// opacity, and then when the target animation value is reached, we can
// modify the visibility
onEnabledChanged: {
scale = enabled ? 1.0 : 0.0
}
@ -57,13 +51,13 @@ Item {
}
}
// We remove any load the dialog might have on the QML by toggling it's
// visibility based on the state of the animated property
// Once we're scaled to 0, disable the dialog's visibility
onScaleChanged: {
visible = (scale != 0.0);
}
// Some dialogs should be destroyed when they become invisible, so handle that
// Some dialogs should be destroyed when they become invisible,
// so handle that
onVisibleChanged: {
if (!visible && destroyOnInvisible) {
destroy();
@ -91,19 +85,21 @@ Item {
MouseArea {
id: sizeDrag
enabled: root.resizable
property int startX
property int startY
anchors.right: parent.right
anchors.bottom: parent.bottom
width: 16
height: 16
z: 1000
hoverEnabled: true
onPressed: {
startX = mouseX
startY = mouseY
}
onPositionChanged: {
if (pressed && root.resizable) {
if (pressed) {
root.deltaSize((mouseX - startX), (mouseY - startY))
startX = mouseX
startY = mouseY
@ -111,83 +107,52 @@ Item {
}
}
/*
* Window decorations, with a title bar and frames
*/
Border {
id: windowBorder
anchors.fill: parent
border.color: root.frameColor
color: root.backgroundColor
MouseArea {
id: titleDrag
x: root.titleX
y: root.titleY
width: root.titleWidth
height: root.titleHeight
Border {
id: titleBorder
height: 48
drag {
target: root
minimumX: 0
minimumY: 0
maximumX: root.parent ? root.parent.width - root.width : 0
maximumY: root.parent ? root.parent.height - root.height : 0
}
Row {
id: windowControls
anchors.bottom: parent.bottom
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
border.color: root.frameColor
color: root.headerBackgroundColor
Text {
id: titleText
// FIXME move all constant colors to our own palette class HifiPalette
color: "white"
text: root.title
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
MouseArea {
id: titleDrag
anchors.right: closeButton.left
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.top: parent.top
anchors.rightMargin: 4
drag {
target: root
minimumX: 0
minimumY: 0
maximumX: root.parent ? root.parent.width - root.width : 0
maximumY: root.parent ? root.parent.height - root.height : 0
}
}
Image {
id: closeButton
x: 360
height: 16
anchors.rightMargin: hifi.layout.spacing
FontAwesome {
id: icon
anchors.verticalCenter: parent.verticalCenter
width: 16
anchors.right: parent.right
anchors.rightMargin: 12
source: "../../styles/close.svg"
size: root.titleHeight - hifi.layout.spacing * 2
color: "red"
text: "\uf00d"
MouseArea {
anchors.margins: hifi.layout.spacing / 2
anchors.fill: parent
onClicked: {
root.close();
}
}
}
} // header border
Border {
id: clientBorder
border.color: root.frameColor
// FIXME move all constant colors to our own palette class HifiPalette
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
clip: true
} // client border
} // window border
}
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_W:
if (event.modifiers == Qt.ControlModifier) {
event.accepted = true
enabled = false
}
break;
}
}
}

View file

@ -0,0 +1,98 @@
import QtQuick 2.3
import QtQuick.Controls 1.2
import "."
import "../styles"
Item {
id: root
HifiConstants { id: hifi }
implicitHeight: contentImplicitHeight + titleBorder.height + hifi.styles.borderWidth
implicitWidth: contentImplicitWidth + hifi.styles.borderWidth * 2
property string title
property int titleSize: titleBorder.height + 12
property string frameColor: hifi.colors.hifiBlue
property string backgroundColor: hifi.colors.dialogBackground
property bool active: false
property real contentImplicitWidth: 800
property real contentImplicitHeight: 800
property alias titleBorder: titleBorder
readonly property alias titleX: titleBorder.x
readonly property alias titleY: titleBorder.y
readonly property alias titleWidth: titleBorder.width
readonly property alias titleHeight: titleBorder.height
// readonly property real borderWidth: hifi.styles.borderWidth
readonly property real borderWidth: 0
property alias clientBorder: clientBorder
readonly property real clientX: clientBorder.x + borderWidth
readonly property real clientY: clientBorder.y + borderWidth
readonly property real clientWidth: clientBorder.width - borderWidth * 2
readonly property real clientHeight: clientBorder.height - borderWidth * 2
/*
* Window decorations, with a title bar and frames
*/
Border {
id: windowBorder
anchors.fill: parent
border.color: root.frameColor
border.width: 0
color: "#00000000"
Border {
id: titleBorder
height: hifi.layout.windowTitleHeight
anchors.right: parent.right
anchors.left: parent.left
border.color: root.frameColor
border.width: 0
clip: true
color: root.active ?
hifi.colors.activeWindow.headerBackground :
hifi.colors.inactiveWindow.headerBackground
Text {
id: titleText
color: root.active ?
hifi.colors.activeWindow.headerText :
hifi.colors.inactiveWindow.headerText
text: root.title
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
} // header border
// These two rectangles hide the curves between the title area
// and the client area
Rectangle {
y: titleBorder.height - titleBorder.radius
height: titleBorder.radius
width: titleBorder.width
color: titleBorder.color
visible: borderWidth == 0
}
Rectangle {
y: titleBorder.height
width: clientBorder.width
height: clientBorder.radius
color: clientBorder.color
}
Border {
id: clientBorder
border.width: 0
border.color: root.frameColor
color: root.backgroundColor
anchors.bottom: parent.bottom
anchors.top: titleBorder.bottom
anchors.topMargin: -titleBorder.border.width
anchors.right: parent.right
anchors.left: parent.left
} // client border
} // window border
}

View file

@ -8,9 +8,9 @@ Text {
property int size: 32
width: size
height: size
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
horizontalAlignment: Text.AlignLeft
font.family: iconFont.name
font.pointSize: 18
}

View file

@ -1,24 +0,0 @@
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"
}
}
}

View file

@ -1,5 +0,0 @@
import QtQuick 2.3
import QtQuick.Controls 1.3 as Original
import "../styles"
import "../controls"

View file

@ -0,0 +1,8 @@
import QtQuick.Controls 1.3 as Original
import QtQuick.Controls.Styles 1.3
import "../styles"
import "."
Original.Slider {
}

View file

@ -0,0 +1,11 @@
import QtQuick 2.4
import "../styles"
Item {
id: root
HifiConstants { id: hifi }
property real size: hifi.layout.spacing
property real multiplier: 1.0
height: size * multiplier
width: size * multiplier
}

View file

@ -0,0 +1,15 @@
import QtQuick.Controls 1.3 as Original
import QtQuick.Controls.Styles 1.3
import "../styles"
import "."
Original.SpinBox {
style: SpinBoxStyle {
HifiConstants { id: hifi }
font.family: hifi.fonts.fontFamily
font.pointSize: hifi.fonts.fontSize
}
}

View file

@ -1,7 +1,9 @@
import QtQuick 2.3 as Original
import "../styles"
Original.Text {
font.family: "Helvetica"
font.pointSize: 18
HifiConstants { id: hifi }
font.family: hifi.fonts.fontFamily
font.pointSize: hifi.fonts.fontSize
}

View file

@ -0,0 +1,24 @@
import QtQuick 2.3 as Original
import "../styles"
import "."
Original.Item {
property alias text: label.text
property alias value: slider.value
Text {
id: label
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
verticalAlignment: Original.Text.AlignVCenter
}
Slider {
id: slider
width: 120
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
}
}

View file

@ -0,0 +1,26 @@
import QtQuick 2.3 as Original
import "../styles"
import "."
Original.Item {
property alias text: label.text
property alias value: spinBox.value
Text {
id: label
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
verticalAlignment: Original.Text.AlignVCenter
text: "Minimum HMD FPS"
}
SpinBox {
id: spinBox
width: 120
maximumValue: 240
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
}
}

View file

@ -1,7 +1,9 @@
import QtQuick 2.3 as Original
import QtQuick.Controls 2.3 as Original
import "../styles"
Original.TextArea {
font.family: "Helvetica"
font.pointSize: 18
HifiConstants { id: hifi }
font.family: hifi.fonts.fontFamily
font.pointSize: hifi.fonts.fontSize
}

View file

@ -1,7 +1,9 @@
import QtQuick 2.3 as Original
import "../styles"
Original.TextEdit {
font.family: "Helvetica"
font.pointSize: 18
HifiConstants { id: hifi }
font.family: hifi.fonts.fontFamily
font.pointSize: hifi.fonts.fontSize
}

View file

@ -0,0 +1,9 @@
import "."
import "../styles"
Text {
HifiConstants { id: hifi }
color: hifi.colors.hifiBlue
font.pointSize: hifi.fonts.headerPointSize
font.bold: true
}

View file

@ -1,34 +1,36 @@
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick 2.3 as Original
import "../styles"
import "."
TextInput {
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
Original.TextInput {
id: root
HifiConstants { id: hifi }
property string helperText
font.family: "Helvetica"
font.pointSize: 18
width: 256
height: 64
color: myPalette.text
height: hifi.layout.rowHeight
clip: true
verticalAlignment: TextInput.AlignVCenter
color: hifi.colors.text
verticalAlignment: Original.TextInput.AlignVCenter
font.family: hifi.fonts.fontFamily
font.pointSize: hifi.fonts.fontSize
onTextChanged: {
if (text == "") {
helperText.visible = true;
} else {
helperText.visible = false;
}
/*
Original.Rectangle {
// Render the rectangle as background
z: -1
anchors.fill: parent
color: hifi.colors.inputBackground
}
*/
Text {
id: helperText
anchors.fill: parent
font.pointSize: parent.font.pointSize
font.family: parent.font.family
verticalAlignment: TextInput.AlignVCenter
text: parent.helperText
color: myPalette.dark
clip: true
verticalAlignment: parent.verticalAlignment
horizontalAlignment: parent.horizontalAlignment
text: root.helperText
color: hifi.colors.hintText
visible: !root.text
}
}

View file

@ -0,0 +1,40 @@
import QtQuick 2.3 as Original
import "../styles"
import "."
Original.Item {
id: root
HifiConstants { id: hifi }
height: hifi.layout.rowHeight
property string text
property string helperText
property string buttonText
property int buttonWidth: 0
property alias input: input
property alias button: button
signal clicked()
TextInput {
id: input
text: root.text
helperText: root.helperText
anchors.left: parent.left
anchors.right: button.left
anchors.rightMargin: 8
anchors.bottom: parent.bottom
anchors.top: parent.top
}
Button {
id: button
clip: true
width: root.buttonWidth ? root.buttonWidth : implicitWidth
text: root.buttonText
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.top: parent.top
onClicked: root.clicked()
}
}

View file

@ -1,11 +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
HifiConstants { id: hifi }
implicitHeight: 64
implicitWidth: 64
color: hifi.colors.window
border.color: hifi.colors.hifiBlue
border.width: hifi.styles.borderWidth
radius: hifi.styles.borderRadius
}

View file

@ -4,7 +4,7 @@ import "."
import "../controls"
OriginalStyles.ButtonStyle {
Original.SystemPalette { id: myPalette; colorGroup: Original.SystemPalette.Active }
HifiConstants { id: hifi }
padding {
top: 8
left: 12
@ -15,10 +15,9 @@ OriginalStyles.ButtonStyle {
anchors.fill: parent
}
label: Text {
renderType: Original.Text.NativeRendering
verticalAlignment: Original.Text.AlignVCenter
horizontalAlignment: Original.Text.AlignHCenter
text: control.text
color: control.enabled ? myPalette.text : myPalette.dark
color: control.enabled ? hifi.colors.text : hifi.colors.disabledText
}
}

View file

@ -0,0 +1,61 @@
import QtQuick 2.4
Item {
SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active }
readonly property alias colors: colors
readonly property alias layout: layout
readonly property alias fonts: fonts
readonly property alias styles: styles
readonly property alias effects: effects
Item {
id: colors
readonly property color hifiBlue: "#0e7077"
readonly property color window: sysPalette.window
readonly property color dialogBackground: sysPalette.window
//readonly property color dialogBackground: "#00000000"
readonly property color inputBackground: "white"
readonly property color background: sysPalette.dark
readonly property color text: sysPalette.text
readonly property color disabledText: "gray"
readonly property color hintText: sysPalette.dark
readonly property color light: sysPalette.light
readonly property alias activeWindow: activeWindow
readonly property alias inactiveWindow: inactiveWindow
QtObject {
id: activeWindow
readonly property color headerBackground: "white"
readonly property color headerText: "black"
}
QtObject {
id: inactiveWindow
readonly property color headerBackground: "gray"
readonly property color headerText: "black"
}
}
QtObject {
id: fonts
readonly property real headerPointSize: 24
readonly property string fontFamily: "Helvetica"
readonly property real fontSize: 18
}
QtObject {
id: layout
property int spacing: 8
property int rowHeight: 40
property int windowTitleHeight: 48
}
QtObject {
id: styles
readonly property int borderWidth: 5
readonly property int borderRadius: borderWidth * 2
}
QtObject {
id: effects
readonly property int fadeInDuration: 400
}
}

View file

@ -1,5 +1,11 @@
import QtQuick 2.4
QtObject {
Item {
property string hifiBlue: "#0e7077"
property alias colors: colorsObj
Item {
id: colorsObj
property string hifiRed: "red"
}
}

View file

@ -1,15 +1,10 @@
ButtonStyle {
background: Item { anchors.fill: parent }
label: Text {
label: FontAwesome {
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"; }
property alias unicode: text
text: control.text
color: control.enabled ? "white" : "dimgray"
color: control.enabled ? hifi.colors.text : hifi.colors.disabledText
}
}

View file

@ -1,22 +0,0 @@
import QtQuick 2.4
import QtQuick.Controls.Styles 1.3
import "../controls"
import "."
ButtonStyle {
HifiPalette { id: hifiPalette }
padding {
top: 2
left: 4
right: 4
bottom: 2
}
background: Item {}
label: Text {
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: control.text
color: control.enabled ? "yellow" : "brown"
}
}

View file

@ -63,6 +63,7 @@
#include <GlowEffect.h>
#include <HFActionEvent.h>
#include <HFBackEvent.h>
#include <VrMenu.h>
#include <LogHandler.h>
#include <MainWindow.h>
#include <ModelEntityItem.h>
@ -356,9 +357,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_bookmarks = new Bookmarks(); // Before setting up the menu
// call Menu getInstance static method to set up the menu
_window->setMenuBar(Menu::getInstance());
_runningScriptsWidget = new RunningScriptsWidget(_window);
// start the nodeThread so its event loop is running
@ -731,6 +729,10 @@ void Application::initializeGL() {
qCDebug(interfaceapp, "Initialized Offscreen UI.");
_glWidget->makeCurrent();
// call Menu getInstance static method to set up the menu
// Needs to happen AFTER the QML UI initialization
_window->setMenuBar(Menu::getInstance());
init();
qCDebug(interfaceapp, "init() complete.");
@ -766,6 +768,7 @@ void Application::initializeUi() {
AddressBarDialog::registerType();
LoginDialog::registerType();
MessageDialog::registerType();
VrMenu::registerType();
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_glWidget->context()->contextHandle());
@ -774,6 +777,8 @@ void Application::initializeUi() {
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
offscreenUi->load("Root.qml");
offscreenUi->load("RootMenu.qml");
VrMenu::load();
VrMenu::executeQueuedLambdas();
offscreenUi->setMouseTranslator([this](const QPointF& p){
if (OculusManager::isConnected()) {
glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));
@ -1068,8 +1073,10 @@ bool Application::eventFilter(QObject* object, QEvent* event) {
return false;
}
void Application::keyPressEvent(QKeyEvent* event) {
static bool _altPressed{ false };
void Application::keyPressEvent(QKeyEvent* event) {
_altPressed = event->key() == Qt::Key_Alt;
_keysPressed.insert(event->key());
_controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts
@ -1317,7 +1324,19 @@ void Application::keyPressEvent(QKeyEvent* event) {
}
}
//#define VR_MENU_ONLY_IN_HMD
void Application::keyReleaseEvent(QKeyEvent* event) {
if (event->key() == Qt::Key_Alt && _altPressed && _window->isActiveWindow()) {
#ifdef VR_MENU_ONLY_IN_HMD
if (OculusManager::isConnected()) {
#endif
VrMenu::toggle();
#ifdef VR_MENU_ONLY_IN_HMD
}
#endif
}
_keysPressed.remove(event->key());
@ -1328,6 +1347,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
return;
}
switch (event->key()) {
case Qt::Key_E:
case Qt::Key_PageUp:
@ -4447,3 +4467,7 @@ void Application::friendsWindowClosed() {
delete _friendsWindow;
_friendsWindow = NULL;
}
void Application::postLambdaEvent(std::function<void()> f) {
QCoreApplication::postEvent(this, new LambdaEvent(f));
}

View file

@ -84,7 +84,7 @@ void Bookmarks::persistToFile() {
saveFile.write(data);
}
void Bookmarks::setupMenus(Menu* menubar, QMenu* menu) {
void Bookmarks::setupMenus(Menu* menubar, MenuWrapper* menu) {
// Add menus/actions
menubar->addActionToQMenuAndActionHash(menu, MenuOption::BookmarkLocation, 0,
this, SLOT(bookmarkLocation()));
@ -192,7 +192,7 @@ void Bookmarks::enableMenuItems(bool enabled) {
}
void Bookmarks::addLocationToMenu(Menu* menubar, QString& name, QString& address) {
QAction* teleportAction = new QAction(_bookmarksMenu);
QAction* teleportAction = _bookmarksMenu->newAction();
teleportAction->setData(address);
connect(teleportAction, SIGNAL(triggered()), this, SLOT(teleportToBookmark()));

View file

@ -19,6 +19,7 @@
class QAction;
class QMenu;
class Menu;
class MenuWrapper;
class Bookmarks: public QObject {
Q_OBJECT
@ -26,7 +27,7 @@ class Bookmarks: public QObject {
public:
Bookmarks();
void setupMenus(Menu* menubar, QMenu* menu);
void setupMenus(Menu* menubar, MenuWrapper* menu);
private slots:
void bookmarkLocation();
@ -36,7 +37,7 @@ private slots:
private:
QVariantMap _bookmarks; // { name: address, ... }
QPointer<QMenu> _bookmarksMenu;
QPointer<MenuWrapper> _bookmarksMenu;
QPointer<QAction> _deleteBookmarksAction;
const QString BOOKMARKS_FILENAME = "bookmarks.json";

View file

@ -55,7 +55,6 @@ Camera::Camera() :
_farClip(DEFAULT_FAR_CLIP), // default
_hmdPosition(),
_hmdRotation(),
_scale(1.0f),
_isKeepLookingAt(false),
_lookingAt(0.0f, 0.0f, 0.0f)
{
@ -94,8 +93,8 @@ void Camera::setHmdRotation(const glm::quat& hmdRotation) {
}
float Camera::getFarClip() const {
return (_scale * _farClip < std::numeric_limits<int16_t>::max())
? _scale * _farClip
return (_farClip < std::numeric_limits<int16_t>::max())
? _farClip
: std::numeric_limits<int16_t>::max() - 1;
}

View file

@ -54,7 +54,6 @@ public:
void setFarClip(float f);
void setEyeOffsetPosition(const glm::vec3& p) { _eyeOffsetPosition = p; }
void setEyeOffsetOrientation(const glm::quat& o) { _eyeOffsetOrientation = o; }
void setScale(const float s) { _scale = s; }
glm::quat getRotation() const { return _rotation * _hmdRotation; }
const glm::vec3& getHmdPosition() const { return _hmdPosition; }
@ -63,11 +62,10 @@ public:
CameraMode getMode() const { return _mode; }
float getFieldOfView() const { return _fieldOfView; }
float getAspectRatio() const { return _aspectRatio; }
float getNearClip() const { return _scale * _nearClip; }
float getNearClip() const { return _nearClip; }
float getFarClip() const;
const glm::vec3& getEyeOffsetPosition() const { return _eyeOffsetPosition; }
const glm::quat& getEyeOffsetOrientation() const { return _eyeOffsetOrientation; }
float getScale() const { return _scale; }
public slots:
QString getModeString() const;
void setModeString(const QString& mode);
@ -107,7 +105,6 @@ private:
glm::quat _rotation;
glm::vec3 _hmdPosition;
glm::quat _hmdRotation;
float _scale;
bool _isKeepLookingAt;
glm::vec3 _lookingAt;
};

View file

@ -20,6 +20,7 @@
#include <PathUtils.h>
#include <SettingHandle.h>
#include <UserActivityLogger.h>
#include <VrMenu.h>
#include "Application.h"
#include "AccountManager.h"
@ -52,7 +53,6 @@ Menu* Menu::getInstance() {
if (!_instance) {
qCDebug(interfaceapp, "First call to Menu::getInstance() - initing menu.");
_instance = new Menu();
}
@ -62,8 +62,7 @@ Menu* Menu::getInstance() {
}
Menu::Menu() {
QMenu* fileMenu = addMenu("File");
MenuWrapper * fileMenu = addMenu("File");
#ifdef Q_OS_MAC
addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole);
#endif
@ -113,7 +112,7 @@ Menu::Menu() {
QAction::QuitRole);
QMenu* editMenu = addMenu("Edit");
MenuWrapper* editMenu = addMenu("Edit");
QUndoStack* undoStack = qApp->getUndoStack();
QAction* undoAction = undoStack->createUndoAction(editMenu);
@ -136,7 +135,7 @@ Menu::Menu() {
addActionToQMenuAndActionHash(editMenu, MenuOption::Animations, 0,
dialogsManager.data(), SLOT(editAnimations()));
QMenu* toolsMenu = addMenu("Tools");
MenuWrapper* toolsMenu = addMenu("Tools");
addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S,
dialogsManager.data(), SLOT(showScriptEditor()));
@ -156,7 +155,7 @@ Menu::Menu() {
addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0,
qApp, SLOT(showFriendsWindow()));
QMenu* visibilityMenu = toolsMenu->addMenu("I Am Visible To");
MenuWrapper* visibilityMenu = toolsMenu->addMenu("I Am Visible To");
{
QActionGroup* visibilityGroup = new QActionGroup(toolsMenu);
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
@ -201,10 +200,10 @@ Menu::Menu() {
addActionToQMenuAndActionHash(toolsMenu, MenuOption::PackageModel, 0,
qApp, SLOT(packageModel()));
QMenu* avatarMenu = addMenu("Avatar");
MenuWrapper* avatarMenu = addMenu("Avatar");
QObject* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
QMenu* avatarSizeMenu = avatarMenu->addMenu("Size");
MenuWrapper* avatarSizeMenu = avatarMenu->addMenu("Size");
addActionToQMenuAndActionHash(avatarSizeMenu,
MenuOption::IncreaseAvatarSize,
0, // QML Qt::Key_Plus,
@ -233,7 +232,7 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false,
avatar, SLOT(updateMotionBehavior()));
QMenu* viewMenu = addMenu("View");
MenuWrapper* viewMenu = addMenu("View");
addCheckableActionToQMenuAndActionHash(viewMenu,
MenuOption::Fullscreen,
@ -277,7 +276,7 @@ Menu::Menu() {
SLOT(setEnable3DTVMode(bool)));
QMenu* nodeBordersMenu = viewMenu->addMenu("Server Borders");
MenuWrapper* nodeBordersMenu = viewMenu->addMenu("Server Borders");
NodeBounds& nodeBounds = qApp->getNodeBoundsDisplay();
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes,
Qt::CTRL | Qt::SHIFT | Qt::Key_1, false,
@ -299,16 +298,16 @@ Menu::Menu() {
dialogsManager.data(), SLOT(octreeStatsDetails()));
QMenu* developerMenu = addMenu("Developer");
MenuWrapper* developerMenu = addMenu("Developer");
QMenu* renderOptionsMenu = developerMenu->addMenu("Render");
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere,
0, // QML Qt::SHIFT | Qt::Key_A,
true);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
QMenu* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight);
MenuWrapper* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight);
QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu);
ambientLightGroup->setExclusive(true);
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLightGlobal, 0, true));
@ -323,14 +322,14 @@ Menu::Menu() {
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false));
QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows");
MenuWrapper* shadowMenu = renderOptionsMenu->addMenu("Shadows");
QActionGroup* shadowGroup = new QActionGroup(shadowMenu);
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true));
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
{
QMenu* framerateMenu = renderOptionsMenu->addMenu(MenuOption::RenderTargetFramerate);
MenuWrapper* framerateMenu = renderOptionsMenu->addMenu(MenuOption::RenderTargetFramerate);
QActionGroup* framerateGroup = new QActionGroup(framerateMenu);
framerateGroup->setExclusive(true);
framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerateUnlimited, 0, true));
@ -347,7 +346,7 @@ Menu::Menu() {
}
QMenu* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution);
MenuWrapper* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution);
QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu);
resolutionGroup->setExclusive(true);
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionOne, 0, true));
@ -367,9 +366,9 @@ Menu::Menu() {
0, // QML Qt::SHIFT | Qt::Key_L,
dialogsManager.data(), SLOT(lodTools()));
QMenu* avatarDebugMenu = developerMenu->addMenu("Avatar");
MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar");
QMenu* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking");
MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking");
{
QActionGroup* faceTrackerGroup = new QActionGroup(avatarDebugMenu);
@ -405,14 +404,14 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false);
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false);
QMenu* handOptionsMenu = developerMenu->addMenu("Hands");
MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false);
QMenu* sixenseOptionsMenu = handOptionsMenu->addMenu("Sixense");
MenuWrapper* sixenseOptionsMenu = handOptionsMenu->addMenu("Sixense");
#ifdef __APPLE__
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu,
MenuOption::SixenseEnabled,
@ -435,7 +434,7 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true);
addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseLasers, 0, false);
QMenu* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion");
MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion");
addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false);
#ifdef HAVE_RSSDK
@ -444,7 +443,7 @@ Menu::Menu() {
RealSense::getInstance(), SLOT(loadRSSDKFile()));
#endif
QMenu* networkMenu = developerMenu->addMenu("Network");
MenuWrapper* networkMenu = developerMenu->addMenu("Network");
addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false);
addCheckableActionToQMenuAndActionHash(networkMenu,
MenuOption::DisableActivityLogger,
@ -457,8 +456,8 @@ Menu::Menu() {
addActionToQMenuAndActionHash(networkMenu, MenuOption::DiskCacheEditor, 0,
dialogsManager.data(), SLOT(toggleDiskCacheEditor()));
QMenu* timingMenu = developerMenu->addMenu("Timing and Stats");
QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer");
MenuWrapper* timingMenu = developerMenu->addMenu("Timing and Stats");
MenuWrapper* perfTimerMenu = timingMenu->addMenu("Performance Timer");
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
@ -474,7 +473,7 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings);
auto audioIO = DependencyManager::get<AudioClient>();
QMenu* audioDebugMenu = developerMenu->addMenu("Audio");
MenuWrapper* audioDebugMenu = developerMenu->addMenu("Audio");
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction,
0,
true,
@ -485,8 +484,6 @@ Menu::Menu() {
audioIO.data(), SLOT(toggleServerEcho()));
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio, 0, false,
audioIO.data(), SLOT(toggleLocalEcho()));
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false,
audioIO.data(), SLOT(toggleStereoInput()));
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteAudio,
Qt::CTRL | Qt::Key_M,
false,
@ -500,7 +497,7 @@ Menu::Menu() {
auto scope = DependencyManager::get<AudioScope>();
QMenu* audioScopeMenu = audioDebugMenu->addMenu("Audio Scope");
MenuWrapper* audioScopeMenu = audioDebugMenu->addMenu("Audio Scope");
addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScope,
Qt::CTRL | Qt::Key_P, false,
scope.data(),
@ -550,11 +547,11 @@ Menu::Menu() {
SLOT(toggleShowInjectedStreams()));
QMenu* physicsOptionsMenu = developerMenu->addMenu("Physics");
MenuWrapper* physicsOptionsMenu = developerMenu->addMenu("Physics");
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned);
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls);
QMenu* helpMenu = addMenu("Help");
MenuWrapper* helpMenu = addMenu("Help");
addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp()));
#ifndef Q_OS_MAC
@ -600,7 +597,7 @@ void Menu::scanMenu(QMenu& menu, settingsAction modifySetting, Settings& setting
settings.endGroup();
}
void Menu::addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& actionName, int menuItemLocation) {
void Menu::addDisabledActionAndSeparator(MenuWrapper* destinationMenu, const QString& actionName, int menuItemLocation) {
QAction* actionBefore = NULL;
if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) {
actionBefore = destinationMenu->actions()[menuItemLocation];
@ -620,7 +617,7 @@ void Menu::addDisabledActionAndSeparator(QMenu* destinationMenu, const QString&
}
}
QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu,
QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu,
const QString& actionName,
const QKeySequence& shortcut,
const QObject* receiver,
@ -657,7 +654,7 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu,
return action;
}
QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu,
QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu,
QAction* action,
const QString& actionName,
const QKeySequence& shortcut,
@ -692,7 +689,7 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu,
return action;
}
QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
QAction* Menu::addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMenu,
const QString& actionName,
const QKeySequence& shortcut,
const bool checked,
@ -708,7 +705,7 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
return action;
}
void Menu::removeAction(QMenu* menu, const QString& actionName) {
void Menu::removeAction(MenuWrapper* menu, const QString& actionName) {
menu->removeAction(_actionHash.value(actionName));
_actionHash.remove(actionName);
}
@ -747,7 +744,7 @@ QAction* Menu::getActionForOption(const QString& menuOption) {
return _actionHash.value(menuOption);
}
QAction* Menu::getActionFromName(const QString& menuName, QMenu* menu) {
QAction* Menu::getActionFromName(const QString& menuName, MenuWrapper* menu) {
QList<QAction*> menuActions;
if (menu) {
menuActions = menu->actions();
@ -756,6 +753,7 @@ QAction* Menu::getActionFromName(const QString& menuName, QMenu* menu) {
}
foreach (QAction* menuAction, menuActions) {
QString actionText = menuAction->text();
if (menuName == menuAction->text()) {
return menuAction;
}
@ -763,18 +761,18 @@ QAction* Menu::getActionFromName(const QString& menuName, QMenu* menu) {
return NULL;
}
QMenu* Menu::getSubMenuFromName(const QString& menuName, QMenu* menu) {
MenuWrapper* Menu::getSubMenuFromName(const QString& menuName, MenuWrapper* menu) {
QAction* action = getActionFromName(menuName, menu);
if (action) {
return action->menu();
return MenuWrapper::fromMenu(action->menu());
}
return NULL;
}
QMenu* Menu::getMenuParent(const QString& menuName, QString& finalMenuPart) {
MenuWrapper* Menu::getMenuParent(const QString& menuName, QString& finalMenuPart) {
QStringList menuTree = menuName.split(">");
QMenu* parent = NULL;
QMenu* menu = NULL;
MenuWrapper* parent = NULL;
MenuWrapper* menu = NULL;
foreach (QString menuTreePart, menuTree) {
parent = menu;
finalMenuPart = menuTreePart.trimmed();
@ -786,10 +784,10 @@ QMenu* Menu::getMenuParent(const QString& menuName, QString& finalMenuPart) {
return parent;
}
QMenu* Menu::getMenu(const QString& menuName) {
MenuWrapper* Menu::getMenu(const QString& menuName) {
QStringList menuTree = menuName.split(">");
QMenu* parent = NULL;
QMenu* menu = NULL;
MenuWrapper* parent = NULL;
MenuWrapper* menu = NULL;
int item = 0;
foreach (QString menuTreePart, menuTree) {
menu = getSubMenuFromName(menuTreePart.trimmed(), parent);
@ -804,19 +802,19 @@ QMenu* Menu::getMenu(const QString& menuName) {
QAction* Menu::getMenuAction(const QString& menuName) {
QStringList menuTree = menuName.split(">");
QMenu* parent = NULL;
MenuWrapper* parent = NULL;
QAction* action = NULL;
foreach (QString menuTreePart, menuTree) {
action = getActionFromName(menuTreePart.trimmed(), parent);
if (!action) {
break;
}
parent = action->menu();
parent = MenuWrapper::fromMenu(action->menu());
}
return action;
}
int Menu::findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem) {
int Menu::findPositionOfMenuItem(MenuWrapper* menu, const QString& searchMenuItem) {
int position = 0;
foreach(QAction* action, menu->actions()) {
if (action->text() == searchMenuItem) {
@ -827,7 +825,7 @@ int Menu::findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem) {
return UNSPECIFIED_POSITION; // not found
}
int Menu::positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition) {
int Menu::positionBeforeSeparatorIfNeeded(MenuWrapper* menu, int requestedPosition) {
QList<QAction*> menuActions = menu->actions();
if (requestedPosition > 1 && requestedPosition < menuActions.size()) {
QAction* beforeRequested = menuActions[requestedPosition - 1];
@ -839,15 +837,15 @@ int Menu::positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition) {
}
QMenu* Menu::addMenu(const QString& menuName) {
MenuWrapper* Menu::addMenu(const QString& menuName) {
QStringList menuTree = menuName.split(">");
QMenu* addTo = NULL;
QMenu* menu = NULL;
MenuWrapper* addTo = NULL;
MenuWrapper* menu = NULL;
foreach (QString menuTreePart, menuTree) {
menu = getSubMenuFromName(menuTreePart.trimmed(), addTo);
if (!menu) {
if (!addTo) {
menu = QMenuBar::addMenu(menuTreePart.trimmed());
menu = new MenuWrapper(QMenuBar::addMenu(menuTreePart.trimmed()));
} else {
menu = addTo->addMenu(menuTreePart.trimmed());
}
@ -865,7 +863,7 @@ void Menu::removeMenu(const QString& menuName) {
// only proceed if the menu actually exists
if (action) {
QString finalMenuPart;
QMenu* parent = getMenuParent(menuName, finalMenuPart);
MenuWrapper* parent = getMenuParent(menuName, finalMenuPart);
if (parent) {
parent->removeAction(action);
} else {
@ -887,14 +885,14 @@ bool Menu::menuExists(const QString& menuName) {
}
void Menu::addSeparator(const QString& menuName, const QString& separatorName) {
QMenu* menuObj = getMenu(menuName);
MenuWrapper* menuObj = getMenu(menuName);
if (menuObj) {
addDisabledActionAndSeparator(menuObj, separatorName);
}
}
void Menu::removeSeparator(const QString& menuName, const QString& separatorName) {
QMenu* menu = getMenu(menuName);
MenuWrapper* menu = getMenu(menuName);
bool separatorRemoved = false;
if (menu) {
int textAt = findPositionOfMenuItem(menu, separatorName);
@ -917,7 +915,7 @@ void Menu::removeSeparator(const QString& menuName, const QString& separatorName
}
void Menu::addMenuItem(const MenuItemProperties& properties) {
QMenu* menuObj = getMenu(properties.menuName);
MenuWrapper* menuObj = getMenu(properties.menuName);
if (menuObj) {
QShortcut* shortcut = NULL;
if (!properties.shortcutKeySequence.isEmpty()) {
@ -958,7 +956,7 @@ void Menu::addMenuItem(const MenuItemProperties& properties) {
}
void Menu::removeMenuItem(const QString& menu, const QString& menuitem) {
QMenu* menuObj = getMenu(menu);
MenuWrapper* menuObj = getMenu(menu);
if (menuObj) {
removeAction(menuObj, menuitem);
QMenuBar::repaint();
@ -972,3 +970,63 @@ bool Menu::menuItemExists(const QString& menu, const QString& menuitem) {
}
return false;
};
MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) {
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addMenu(menu);
});
_backMap[menu] = this;
}
QList<QAction*> MenuWrapper::actions() {
return _realMenu->actions();
}
MenuWrapper* MenuWrapper::addMenu(const QString& menuName) {
return new MenuWrapper(_realMenu->addMenu(menuName));
}
void MenuWrapper::setEnabled(bool enabled) {
_realMenu->setEnabled(enabled);
}
void MenuWrapper::addSeparator() {
_realMenu->addSeparator();
}
void MenuWrapper::addAction(QAction* action) {
_realMenu->addAction(action);
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addAction(_realMenu, action);
});
}
QAction* MenuWrapper::addAction(const QString& menuName) {
QAction* action = _realMenu->addAction(menuName);
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addAction(_realMenu, action);
});
return action;
}
QAction* MenuWrapper::addAction(const QString& menuName, const QObject* receiver, const char* member, const QKeySequence& shortcut) {
QAction* action = _realMenu->addAction(menuName, receiver, member, shortcut);
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addAction(_realMenu, action);
});
return action;
}
void MenuWrapper::removeAction(QAction* action) {
_realMenu->removeAction(action);
}
void MenuWrapper::insertAction(QAction* before, QAction* action) {
_realMenu->insertAction(before, action);
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->insertAction(before, action);
});
}
QHash<QMenu*, MenuWrapper*> MenuWrapper::_backMap;

View file

@ -25,6 +25,35 @@
class Settings;
class MenuWrapper : public QObject {
public:
QList<QAction*> actions();
MenuWrapper* addMenu(const QString& menuName);
void setEnabled(bool enabled = true);
void addSeparator();
void addAction(QAction* action);
QAction* addAction(const QString& menuName);
void insertAction(QAction* before, QAction* menuName);
QAction* addAction(const QString& menuName, const QObject* receiver, const char* member, const QKeySequence& shortcut = 0);
void removeAction(QAction* action);
QAction* newAction() {
return new QAction(_realMenu);
}
private:
MenuWrapper(QMenu* menu);
static MenuWrapper* fromMenu(QMenu* menu) {
return _backMap[menu];
}
QMenu* const _realMenu;
static QHash<QMenu*, MenuWrapper*> _backMap;
friend class Menu;
};
class Menu : public QMenuBar {
Q_OBJECT
public:
@ -33,29 +62,29 @@ public:
void loadSettings();
void saveSettings();
QMenu* getMenu(const QString& menuName);
MenuWrapper* getMenu(const QString& menuName);
void triggerOption(const QString& menuOption);
QAction* getActionForOption(const QString& menuOption);
QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
QAction* addActionToQMenuAndActionHash(MenuWrapper* destinationMenu,
const QString& actionName,
const QKeySequence& shortcut = 0,
const QObject* receiver = NULL,
const char* member = NULL,
QAction::MenuRole role = QAction::NoRole,
int menuItemLocation = UNSPECIFIED_POSITION);
QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
QAction* addActionToQMenuAndActionHash(MenuWrapper* destinationMenu,
QAction* action,
const QString& actionName = QString(),
const QKeySequence& shortcut = 0,
QAction::MenuRole role = QAction::NoRole,
int menuItemLocation = UNSPECIFIED_POSITION);
void removeAction(QMenu* menu, const QString& actionName);
void removeAction(MenuWrapper* menu, const QString& actionName);
public slots:
QMenu* addMenu(const QString& menuName);
MenuWrapper* addMenu(const QString& menuName);
void removeMenu(const QString& menuName);
bool menuExists(const QString& menuName);
void addSeparator(const QString& menuName, const QString& separatorName);
@ -77,10 +106,10 @@ private:
void scanMenu(QMenu& menu, settingsAction modifySetting, Settings& settings);
/// helper method to have separators with labels that are also compatible with OS X
void addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& actionName,
void addDisabledActionAndSeparator(MenuWrapper* destinationMenu, const QString& actionName,
int menuItemLocation = UNSPECIFIED_POSITION);
QAction* addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
QAction* addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMenu,
const QString& actionName,
const QKeySequence& shortcut = 0,
const bool checked = false,
@ -88,13 +117,13 @@ private:
const char* member = NULL,
int menuItemLocation = UNSPECIFIED_POSITION);
QAction* getActionFromName(const QString& menuName, QMenu* menu);
QMenu* getSubMenuFromName(const QString& menuName, QMenu* menu);
QMenu* getMenuParent(const QString& menuName, QString& finalMenuPart);
QAction* getActionFromName(const QString& menuName, MenuWrapper* menu);
MenuWrapper* getSubMenuFromName(const QString& menuName, MenuWrapper* menu);
MenuWrapper* getMenuParent(const QString& menuName, QString& finalMenuPart);
QAction* getMenuAction(const QString& menuName);
int findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem);
int positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition);
int findPositionOfMenuItem(MenuWrapper* menu, const QString& searchMenuItem);
int positionBeforeSeparatorIfNeeded(MenuWrapper* menu, int requestedPosition);
QHash<QString, QAction*> _actionHash;
};
@ -238,7 +267,6 @@ namespace MenuOption {
const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations";
const QString Stars = "Stars";
const QString Stats = "Stats";
const QString StereoAudio = "Stereo Audio (disables spatial sound)";
const QString StopAllScripts = "Stop All Scripts";
const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
const QString TestPing = "Test Ping";

View file

@ -166,7 +166,6 @@ void MyAvatar::simulate(float deltaTime) {
if (_scale != _targetScale) {
float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale;
setScale(scale);
Application::getInstance()->getCamera()->setScale(scale);
}
{
@ -673,8 +672,6 @@ void MyAvatar::loadData() {
_leanScale = loadSetting(settings, "leanScale", 0.05f);
_targetScale = loadSetting(settings, "scale", 1.0f);
setScale(_scale);
Application::getInstance()->getCamera()->setScale(_scale);
// The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls
// for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If

View file

@ -45,13 +45,19 @@ QScriptValue WindowScriptingInterface::hasFocus() {
}
void WindowScriptingInterface::setFocus() {
auto window = Application::getInstance()->getWindow();
window->activateWindow();
window->setFocus();
// It's forbidden to call focus() from another thread.
Application::getInstance()->postLambdaEvent([] {
auto window = Application::getInstance()->getWindow();
window->activateWindow();
window->setFocus();
});
}
void WindowScriptingInterface::raiseMainWindow() {
Application::getInstance()->getWindow()->raise();
// It's forbidden to call raise() from another thread.
Application::getInstance()->postLambdaEvent([] {
Application::getInstance()->getWindow()->raise();
});
}
void WindowScriptingInterface::setCursorVisible(bool visible) {

View file

@ -0,0 +1,29 @@
//
// MarketplaceDialog.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 "Application.h"
#include "MarketplaceDialog.h"
#include "DependencyManager.h"
HIFI_QML_DEF(MarketplaceDialog)
MarketplaceDialog::MarketplaceDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) {
}
bool MarketplaceDialog::navigationRequested(const QString& url) {
qDebug() << url;
if (Application::getInstance()->canAcceptURL(url)) {
if (Application::getInstance()->acceptURL(url)) {
return false; // we handled it, so QWebPage doesn't need to handle it
}
}
return true;
}

View file

@ -0,0 +1,29 @@
//
// MarketplaceDialog.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_MarketplaceDialog_h
#define hifi_MarketplaceDialog_h
#include <OffscreenQmlDialog.h>
class MarketplaceDialog : public OffscreenQmlDialog
{
Q_OBJECT
HIFI_QML_DECL
public:
MarketplaceDialog(QQuickItem* parent = nullptr);
Q_INVOKABLE bool navigationRequested(const QString& url);
};
#endif

View file

@ -44,8 +44,9 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) :
connect(&_scriptsModelFilter, &QSortFilterProxyModel::modelReset,
this, &RunningScriptsWidget::selectFirstInList);
QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText);
ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts.");
// FIXME: menu isn't prepared at this point.
//QString shortcutText = Menu::getInstance()->getActionForOption(MenuOption::ReloadAllScripts)->shortcut().toString(QKeySequence::NativeText);
//ui->tipLabel->setText("Tip: Use " + shortcutText + " to reload all scripts.");
_scriptsModelFilter.setSourceModel(&_scriptsModel);
_scriptsModelFilter.sort(0, Qt::AscendingOrder);

View file

@ -108,8 +108,6 @@ public:
bool isMuted() { return _muted; }
void setIsStereoInput(bool isStereoInput);
const AudioIOStats& getStats() const { return _stats; }
float getInputRingBufferMsecsAvailable() const;
@ -147,13 +145,13 @@ public slots:
virtual void selectAudioSourcePinkNoise();
virtual void selectAudioSourceSine440();
virtual void setIsStereoInput(bool stereo);
void toggleAudioNoiseReduction() { _isNoiseGateEnabled = !_isNoiseGateEnabled; }
void toggleLocalEcho() { _shouldEchoLocally = !_shouldEchoLocally; }
void toggleServerEcho() { _shouldEchoToServer = !_shouldEchoToServer; }
void toggleStereoInput() { setIsStereoInput(!_isStereoInput); }
void processReceivedSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer);
void sendMuteEnvironmentPacket();

View file

@ -31,6 +31,8 @@ public slots:
virtual void enableAudioSourceInject(bool enable) = 0;
virtual void selectAudioSourcePinkNoise() = 0;
virtual void selectAudioSourceSine440() = 0;
virtual void setIsStereoInput(bool stereo) = 0;
};
Q_DECLARE_METATYPE(AbstractAudioInterface*)

View file

@ -55,6 +55,17 @@ bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) {
return !avatarWithDisplayName(displayName).isNull();
}
bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range) {
foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) {
glm::vec3 avatarPosition = sharedAvatar->getPosition();
float distance = glm::distance(avatarPosition, position);
if (distance < range) {
return true;
}
}
return false;
}
AvatarWeakPointer AvatarHashMap::avatarWithDisplayName(const QString& displayName) {
foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) {
if (sharedAvatar->getDisplayName() == displayName) {

View file

@ -20,6 +20,7 @@
#include <Node.h>
#include "AvatarData.h"
#include <glm/glm.hpp>
typedef QSharedPointer<AvatarData> AvatarSharedPointer;
typedef QWeakPointer<AvatarData> AvatarWeakPointer;
@ -36,6 +37,7 @@ public:
public slots:
void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer);
bool containsAvatarWithDisplayName(const QString& displayName);
bool isAvatarInRange(const glm::vec3 & position, const float range);
AvatarWeakPointer avatarWithDisplayName(const QString& displayname);
private slots:

View file

@ -285,6 +285,7 @@ void OctreePersistThread::restoreFromMostRecentBackup() {
qCDebug(octree) << "DONE restoring backup file " << mostRecentBackupFileName << "to" << _filename << "...";
} else {
qCDebug(octree) << "ERROR while restoring backup file " << mostRecentBackupFileName << "to" << _filename << "...";
perror("ERROR while restoring backup file");
}
} else {
qCDebug(octree) << "NO BEST backup file found.";
@ -366,6 +367,7 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
qCDebug(octree) << "DONE rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
} else {
qCDebug(octree) << "ERROR in rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "...";
perror("ERROR in rolling backup file");
}
}
}
@ -425,6 +427,7 @@ void OctreePersistThread::backup() {
rule.lastBackup = now; // only record successful backup in this case.
} else {
qCDebug(octree) << "ERROR in backing up persist file...";
perror("ERROR in backing up persist file");
}
} else {
qCDebug(octree) << "persist file " << _filename << " does not exist. " <<

View file

@ -41,8 +41,8 @@ protected:
DynamicCharacterController::DynamicCharacterController(AvatarData* avatarData) {
_halfHeight = 1.0f;
_shape = NULL;
_rigidBody = NULL;
_shape = nullptr;
_rigidBody = nullptr;
assert(avatarData);
_avatarData = avatarData;
@ -262,7 +262,7 @@ void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) {
_dynamicsWorld->removeRigidBody(_rigidBody);
_dynamicsWorld->removeAction(this);
}
_dynamicsWorld = NULL;
_dynamicsWorld = nullptr;
}
if (world && _rigidBody) {
_dynamicsWorld = world;
@ -292,9 +292,9 @@ void DynamicCharacterController::updateShapeIfNecessary() {
_pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE;
// delete shape and RigidBody
delete _rigidBody;
_rigidBody = NULL;
_rigidBody = nullptr;
delete _shape;
_shape = NULL;
_shape = nullptr;
// compute new dimensions from avatar's bounding box
float x = _boxScale.x;
@ -314,7 +314,7 @@ void DynamicCharacterController::updateShapeIfNecessary() {
// create new body
float mass = 1.0f;
btVector3 inertia(1.0f, 1.0f, 1.0f);
_rigidBody = new btRigidBody(mass, NULL, _shape, inertia);
_rigidBody = new btRigidBody(mass, nullptr, _shape, inertia);
_rigidBody->setSleepingThresholds(0.0f, 0.0f);
_rigidBody->setAngularFactor(0.0f);
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),

View file

@ -30,7 +30,7 @@ protected:
glm::vec3 _shapeLocalOffset;
glm::vec3 _boxScale; // used to compute capsule shape
AvatarData* _avatarData = NULL;
AvatarData* _avatarData = nullptr;
bool _enabled;
bool _isOnGround;
@ -41,7 +41,7 @@ protected:
quint64 _jumpToHoverStart;
uint32_t _pendingFlags;
btDynamicsWorld* _dynamicsWorld = NULL;
btDynamicsWorld* _dynamicsWorld = nullptr;
btScalar _jumpSpeed;
@ -78,7 +78,8 @@ public:
bool needsRemoval() const;
bool needsAddition() const;
void setEnabled(bool enabled);
bool isEnabled() const { return _enabled; }
bool isEnabled() const { return _enabled && _dynamicsWorld; }
void setDynamicsWorld(btDynamicsWorld* world);
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);

View file

@ -89,4 +89,8 @@ void AudioScriptingInterface::selectSine440() {
}
}
void AudioScriptingInterface::setStereoInput(bool stereo) {
if (_localAudioInterface) {
_localAudioInterface->setIsStereoInput(stereo);
}
}

View file

@ -33,6 +33,8 @@ protected:
Q_INVOKABLE void selectPinkNoise();
Q_INVOKABLE void selectSine440();
Q_INVOKABLE void setStereoInput(bool stereo);
signals:
void mutedByMixer();
void environmentMuted();

View file

@ -13,8 +13,12 @@
#include "ScriptAudioInjector.h"
QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in) {
// when the script goes down we want to cleanup the injector
// The AudioScriptingInterface::playSound method can return null, so we need to account for that.
if (!in) {
return QScriptValue(QScriptValue::NullValue);
}
// when the script goes down we want to cleanup the injector
QObject::connect(engine, &QScriptEngine::destroyed, in, &ScriptAudioInjector::stopInjectorImmediately,
Qt::DirectConnection);

View file

@ -1,289 +0,0 @@
//
// HifiMenu.cpp
//
// Created by Bradley Austin Davis on 2015/04/21
// 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 "HifiMenu.h"
#include <QtQml>
// FIXME can this be made a class member?
static const QString MENU_SUFFIX{ "__Menu" };
HIFI_QML_DEF_LAMBDA(HifiMenu, [=](QQmlContext* context, QObject* newItem) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
QObject * rootMenu = offscreenUi->getRootItem()->findChild<QObject*>("rootMenu");
Q_ASSERT(rootMenu);
static_cast<HifiMenu*>(newItem)->setRootMenu(rootMenu);
context->setContextProperty("rootMenu", rootMenu);
});
HifiMenu::HifiMenu(QQuickItem* parent) : QQuickItem(parent), _triggerMapper(this), _toggleMapper(this) {
this->setEnabled(false);
connect(&_triggerMapper, SIGNAL(mapped(QString)), this, SLOT(onTriggeredByName(const QString &)));
connect(&_toggleMapper, SIGNAL(mapped(QString)), this, SLOT(onToggledByName(const QString &)));
}
void HifiMenu::onTriggeredByName(const QString & name) {
qDebug() << name << " triggered";
if (_triggerActions.count(name)) {
_triggerActions[name]();
}
}
void HifiMenu::onToggledByName(const QString & name) {
qDebug() << name << " toggled";
if (_toggleActions.count(name)) {
QObject* menu = findMenuObject(name);
bool checked = menu->property("checked").toBool();
_toggleActions[name](checked);
}
}
void HifiMenu::setToggleAction(const QString & name, std::function<void(bool)> f) {
_toggleActions[name] = f;
}
void HifiMenu::setTriggerAction(const QString & name, std::function<void()> f) {
_triggerActions[name] = f;
}
QObject* addMenu(QObject* parent, const QString & text) {
// FIXME add more checking here to ensure no name conflicts
QVariant returnedValue;
QMetaObject::invokeMethod(parent, "addMenu", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, text));
QObject* result = returnedValue.value<QObject*>();
if (result) {
result->setObjectName(text + MENU_SUFFIX);
}
return result;
}
class QQuickMenuItem;
QObject* addItem(QObject* parent, const QString& text) {
// FIXME add more checking here to ensure no name conflicts
QQuickMenuItem* returnedValue{ nullptr };
bool invokeResult = QMetaObject::invokeMethod(parent, "addItem", Qt::DirectConnection,
Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
Q_ARG(QString, text));
Q_ASSERT(invokeResult);
QObject* result = reinterpret_cast<QObject*>(returnedValue);
return result;
}
const QObject* HifiMenu::findMenuObject(const QString & menuOption) const {
if (menuOption.isEmpty()) {
return _rootMenu;
}
const QObject* result = _rootMenu->findChild<QObject*>(menuOption + MENU_SUFFIX);
return result;
}
QObject* HifiMenu::findMenuObject(const QString & menuOption) {
if (menuOption.isEmpty()) {
return _rootMenu;
}
QObject* result = _rootMenu->findChild<QObject*>(menuOption + MENU_SUFFIX);
return result;
}
void HifiMenu::addMenu(const QString & parentMenu, const QString & menuOption) {
QObject* parent = findMenuObject(parentMenu);
QObject* result = ::addMenu(parent, menuOption);
Q_ASSERT(result);
result->setObjectName(menuOption + MENU_SUFFIX);
Q_ASSERT(findMenuObject(menuOption));
}
void HifiMenu::removeMenu(const QString& menuName) {
QObject* menu = findMenuObject(menuName);
Q_ASSERT(menu);
Q_ASSERT(menu != _rootMenu);
QMetaObject::invokeMethod(menu->parent(), "removeItem",
Q_ARG(QVariant, QVariant::fromValue(menu)));
}
bool HifiMenu::menuExists(const QString& menuName) const {
return findMenuObject(menuName);
}
void HifiMenu::addSeparator(const QString& parentMenu, const QString& separatorName) {
QObject * parent = findMenuObject(parentMenu);
bool invokeResult = QMetaObject::invokeMethod(parent, "addSeparator", Qt::DirectConnection);
Q_ASSERT(invokeResult);
addItem(parentMenu, separatorName);
enableItem(separatorName, false);
}
void HifiMenu::removeSeparator(const QString& parentMenu, const QString& separatorName) {
}
void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption) {
QObject* parent = findMenuObject(parentMenu);
Q_ASSERT(parent);
QObject* result = ::addItem(parent, menuOption);
Q_ASSERT(result);
result->setObjectName(menuOption + MENU_SUFFIX);
Q_ASSERT(findMenuObject(menuOption));
_triggerMapper.setMapping(result, menuOption);
connect(result, SIGNAL(triggered()), &_triggerMapper, SLOT(map()));
_toggleMapper.setMapping(result, menuOption);
connect(result, SIGNAL(toggled(bool)), &_toggleMapper, SLOT(map()));
}
void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption, std::function<void()> f) {
setTriggerAction(menuOption, f);
addItem(parentMenu, menuOption);
}
void HifiMenu::addItem(const QString & parentMenu, const QString & menuOption, QObject* receiver, const char* slot) {
addItem(parentMenu, menuOption);
connectItem(menuOption, receiver, slot);
}
void HifiMenu::removeItem(const QString& menuOption) {
removeMenu(menuOption);
}
bool HifiMenu::itemExists(const QString& menuName, const QString& menuitem) const {
return findMenuObject(menuName);
}
void HifiMenu::triggerItem(const QString& menuOption) {
QObject* menuItem = findMenuObject(menuOption);
Q_ASSERT(menuItem);
Q_ASSERT(menuItem != _rootMenu);
QMetaObject::invokeMethod(menuItem, "trigger");
}
QHash<QString, QString> warned;
void warn(const QString & menuOption) {
if (!warned.contains(menuOption)) {
warned[menuOption] = menuOption;
qWarning() << "No menu item: " << menuOption;
}
}
bool HifiMenu::isChecked(const QString& menuOption) const {
const QObject* menuItem = findMenuObject(menuOption);
if (!menuItem) {
warn(menuOption);
return false;
}
return menuItem->property("checked").toBool();
}
void HifiMenu::setChecked(const QString& menuOption, bool isChecked) {
QObject* menuItem = findMenuObject(menuOption);
if (!menuItem) {
warn(menuOption);
return;
}
if (menuItem->property("checked").toBool() != isChecked) {
menuItem->setProperty("checked", QVariant::fromValue(isChecked));
Q_ASSERT(menuItem->property("checked").toBool() == isChecked);
}
}
void HifiMenu::setCheckable(const QString& menuOption, bool checkable) {
QObject* menuItem = findMenuObject(menuOption);
if (!menuItem) {
warn(menuOption);
return;
}
menuItem->setProperty("checkable", QVariant::fromValue(checkable));
Q_ASSERT(menuItem->property("checkable").toBool() == checkable);
}
void HifiMenu::setItemText(const QString& menuOption, const QString& text) {
QObject* menuItem = findMenuObject(menuOption);
if (!menuItem) {
warn(menuOption);
return;
}
if (menuItem->property("type").toInt() == 2) {
menuItem->setProperty("title", QVariant::fromValue(text));
} else {
menuItem->setProperty("text", QVariant::fromValue(text));
}
}
void HifiMenu::setRootMenu(QObject* rootMenu) {
_rootMenu = rootMenu;
}
void HifiMenu::enableItem(const QString & menuOption, bool enabled) {
QObject* menuItem = findMenuObject(menuOption);
if (!menuItem) {
warn(menuOption);
return;
}
menuItem->setProperty("enabled", QVariant::fromValue(enabled));
}
void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked) {
addItem(parentMenu, menuOption);
setCheckable(menuOption);
if (checked) {
setChecked(menuOption, checked);
}
}
void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function<void(bool)> f) {
setToggleAction(menuOption, f);
addCheckableItem(parentMenu, menuOption, checked);
}
void HifiMenu::setItemVisible(const QString& menuOption, bool visible) {
QObject* result = findMenuObject(menuOption);
if (result) {
result->setProperty("visible", visible);
}
}
bool HifiMenu::isItemVisible(const QString& menuOption) {
QObject* result = findMenuObject(menuOption);
if (result) {
return result->property("visible").toBool();
}
return false;
}
void HifiMenu::setItemShortcut(const QString& menuOption, const QString& shortcut) {
QObject* result = findMenuObject(menuOption);
if (result) {
result->setProperty("shortcut", shortcut);
}
}
QString HifiMenu::getItemShortcut(const QString& menuOption) {
QObject* result = findMenuObject(menuOption);
if (result) {
return result->property("shortcut").toString();
}
return QString();
}
void HifiMenu::addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, QObject* receiver, const char* slot) {
addCheckableItem(parentMenu, menuOption, checked);
connectItem(menuOption, receiver, slot);
}
void HifiMenu::connectCheckable(const QString& menuOption, QObject* receiver, const char* slot) {
QObject* result = findMenuObject(menuOption);
connect(result, SIGNAL(toggled(bool)), receiver, slot);
}
void HifiMenu::connectItem(const QString& menuOption, QObject* receiver, const char* slot) {
QObject* result = findMenuObject(menuOption);
connect(result, SIGNAL(triggered()), receiver, slot);
}

View file

@ -1,79 +0,0 @@
//
// HifiMenu.h
//
// Created by Bradley Austin Davis on 2015/04/21
// 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_HifiMenu_h
#define hifi_HifiMenu_h
#include <QQuickItem>
#include <QHash>
#include <QList>
#include <QSignalMapper>
#include "OffscreenUi.h"
class HifiMenu : public QQuickItem {
Q_OBJECT
HIFI_QML_DECL_LAMBDA
public:
HifiMenu(QQuickItem* parent = nullptr);
void setToggleAction(const QString& name, std::function<void(bool)> f);
void setTriggerAction(const QString& name, std::function<void()> f);
void addMenu(const QString& parentMenu, const QString& menuOption);
void removeMenu(const QString& menuName);
bool menuExists(const QString& menuName) const;
void addSeparator(const QString& menuName, const QString& separatorName);
void removeSeparator(const QString& menuName, const QString& separatorName);
void addItem(const QString& parentMenu, const QString& menuOption);
void addItem(const QString& parentMenu, const QString& menuOption, std::function<void()> f);
void addItem(const QString& parentMenu, const QString& menuOption, QObject* receiver, const char* slot);
void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked = false);
void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function<void(bool)> f);
void addCheckableItem(const QString& parentMenu, const QString& menuOption, bool checked, QObject* receiver, const char* slot);
void connectCheckable(const QString& menuOption, QObject* receiver, const char* slot);
void connectItem(const QString& menuOption, QObject* receiver, const char* slot);
void removeItem(const QString& menuitem);
bool itemExists(const QString& menuName, const QString& menuitem) const;
void triggerItem(const QString& menuOption);
void enableItem(const QString& menuOption, bool enabled = true);
bool isChecked(const QString& menuOption) const;
void setChecked(const QString& menuOption, bool checked = true);
void setCheckable(const QString& menuOption, bool checkable = true);
void setExclusiveGroup(const QString& menuOption, const QString& groupName);
void setItemText(const QString& menuOption, const QString& text);
void setItemVisible(const QString& menuOption, bool visible = true);
bool isItemVisible(const QString& menuOption);
void setItemShortcut(const QString& menuOption, const QString& shortcut);
QString getItemShortcut(const QString& menuOption);
void setRootMenu(QObject* rootMenu);
private slots:
void onTriggeredByName(const QString& name);
void onToggledByName(const QString& name);
protected:
QHash<QString, std::function<void()>> _triggerActions;
QHash<QString, std::function<void(bool)>> _toggleActions;
QObject* findMenuObject(const QString& name);
const QObject* findMenuObject(const QString& name) const;
QObject* _rootMenu{ nullptr };
QSignalMapper _triggerMapper;
QSignalMapper _toggleMapper;
};
#endif // hifi_HifiMenu_h

View file

@ -124,9 +124,9 @@ void OffscreenUi::resize(const QSize& newSize) {
if (_quickWindow) {
_quickWindow->setGeometry(QRect(QPoint(), newSize));
_quickWindow->contentItem()->setSize(newSize);
}
_quickWindow->contentItem()->setSize(newSize);
// Update our members
if (_rootItem) {
@ -145,13 +145,12 @@ void OffscreenUi::setBaseUrl(const QUrl& baseUrl) {
}
QObject* OffscreenUi::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
qDebug() << "Loading QML from URL " << qmlSource;
_qmlComponent->loadUrl(qmlSource);
if (_qmlComponent->isLoading()) {
connect(_qmlComponent, &QQmlComponent::statusChanged, this,
[this, f](QQmlComponent::Status){
finishQmlLoad(f);
});
[this, f](QQmlComponent::Status){
finishQmlLoad(f);
});
return nullptr;
}
@ -360,10 +359,14 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
QPointF originalPos = mouseEvent->localPos();
QPointF transformedPos = _mouseTranslator(originalPos);
transformedPos = mapWindowToUi(transformedPos, originalDestination);
QMouseEvent mappedEvent(mouseEvent->type(),
mapWindowToUi(transformedPos, originalDestination),
transformedPos,
mouseEvent->screenPos(), mouseEvent->button(),
mouseEvent->buttons(), mouseEvent->modifiers());
if (event->type() == QEvent::MouseMove) {
_qmlEngine->rootContext()->setContextProperty("lastMousePosition", transformedPos);
}
mappedEvent.ignore();
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
return mappedEvent.isAccepted();

View file

@ -169,11 +169,11 @@ public:
ButtonCallback callback = NO_OP_CALLBACK,
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
protected:
private:
QObject* finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f);
private slots:
void updateQuick();
QObject* finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f);
public slots:
void requestUpdate();

218
libraries/ui/src/VrMenu.cpp Normal file
View file

@ -0,0 +1,218 @@
//
// VrMenu.cpp
//
// Created by Bradley Austin Davis on 2015/04/21
// 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 "VrMenu.h"
#include <QtQml>
#include <QMenuBar>
// Binds together a Qt Action or Menu with the QML Menu or MenuItem
//
// TODO On reflection, it may be pointless to use the UUID. Perhaps
// simply creating the bidirectional link pointing to both the widget
// and qml object and inject the pointer into both objects
class MenuUserData : public QObjectUserData {
static const int USER_DATA_ID;
public:
MenuUserData(QAction* action, QObject* qmlObject) {
init(action, qmlObject);
}
MenuUserData(QMenu* menu, QObject* qmlObject) {
init(menu, qmlObject);
}
const QUuid uuid{ QUuid::createUuid() };
static MenuUserData* forObject(QObject* object) {
return static_cast<MenuUserData*>(object->userData(USER_DATA_ID));
}
private:
MenuUserData(const MenuUserData&);
void init(QObject* widgetObject, QObject* qmlObject) {
widgetObject->setUserData(USER_DATA_ID, this);
qmlObject->setUserData(USER_DATA_ID, this);
qmlObject->setObjectName(uuid.toString());
// Make sure we can find it again in the future
Q_ASSERT(VrMenu::_instance->findMenuObject(uuid.toString()));
}
};
const int MenuUserData::USER_DATA_ID = QObject::registerUserData();
HIFI_QML_DEF_LAMBDA(VrMenu, [&](QQmlContext* context, QObject* newItem) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
QObject* rootMenu = offscreenUi->getRootItem()->findChild<QObject*>("rootMenu");
Q_ASSERT(rootMenu);
static_cast<VrMenu*>(newItem)->setRootMenu(rootMenu);
context->setContextProperty("rootMenu", rootMenu);
});
VrMenu* VrMenu::_instance{ nullptr };
static QQueue<std::function<void(VrMenu*)>> queuedLambdas;
void VrMenu::executeOrQueue(std::function<void(VrMenu*)> f) {
if (_instance) {
foreach(std::function<void(VrMenu*)> priorLambda, queuedLambdas) {
priorLambda(_instance);
}
f(_instance);
} else {
queuedLambdas.push_back(f);
}
}
void VrMenu::executeQueuedLambdas() {
Q_ASSERT(_instance);
foreach(std::function<void(VrMenu*)> f, queuedLambdas) {
f(_instance);
}
queuedLambdas.clear();
}
VrMenu::VrMenu(QQuickItem* parent) : QQuickItem(parent) {
_instance = this;
this->setEnabled(false);
}
// QML helper functions
QObject* addMenu(QObject* parent, const QString& text) {
// FIXME add more checking here to ensure no name conflicts
QVariant returnedValue;
QMetaObject::invokeMethod(parent, "addMenu", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, text));
QObject* result = returnedValue.value<QObject*>();
if (result) {
result->setObjectName(text);
}
return result;
}
class QQuickMenuItem;
QObject* addItem(QObject* parent, const QString& text) {
// FIXME add more checking here to ensure no name conflicts
QQuickMenuItem* returnedValue{ nullptr };
bool invokeResult = QMetaObject::invokeMethod(parent, "addItem", Qt::DirectConnection,
Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
Q_ARG(QString, text));
Q_ASSERT(invokeResult);
QObject* result = reinterpret_cast<QObject*>(returnedValue);
return result;
}
const QObject* VrMenu::findMenuObject(const QString& menuOption) const {
if (menuOption.isEmpty()) {
return _rootMenu;
}
const QObject* result = _rootMenu->findChild<QObject*>(menuOption);
return result;
}
QObject* VrMenu::findMenuObject(const QString& menuOption) {
if (menuOption.isEmpty()) {
return _rootMenu;
}
QObject* result = _rootMenu->findChild<QObject*>(menuOption);
return result;
}
void VrMenu::setRootMenu(QObject* rootMenu) {
_rootMenu = rootMenu;
}
void VrMenu::addMenu(QMenu* menu) {
Q_ASSERT(!MenuUserData::forObject(menu));
QObject * parent = menu->parent();
QObject * qmlParent;
if (dynamic_cast<QMenu*>(parent)) {
MenuUserData* userData = MenuUserData::forObject(parent);
qmlParent = findMenuObject(userData->uuid.toString());
} else if (dynamic_cast<QMenuBar*>(parent)) {
qmlParent = _rootMenu;
} else {
Q_ASSERT(false);
}
QObject* result = ::addMenu(qmlParent, menu->title());
new MenuUserData(menu, result);
}
void updateQmlItemFromAction(QObject* target, QAction* source) {
target->setProperty("checkable", source->isCheckable());
target->setProperty("enabled", source->isEnabled());
target->setProperty("visible", source->isVisible());
target->setProperty("text", source->text());
target->setProperty("checked", source->isChecked());
}
void bindActionToQmlAction(QObject* qmlAction, QAction* action) {
new MenuUserData(action, qmlAction);
updateQmlItemFromAction(qmlAction, action);
QObject::connect(action, &QAction::changed, [=] {
updateQmlItemFromAction(qmlAction, action);
});
QObject::connect(action, &QAction::toggled, [=](bool checked) {
qmlAction->setProperty("checked", checked);
});
QObject::connect(qmlAction, SIGNAL(triggered()), action, SLOT(trigger()));
}
void VrMenu::addAction(QMenu* menu, QAction* action) {
Q_ASSERT(!MenuUserData::forObject(action));
Q_ASSERT(MenuUserData::forObject(menu));
MenuUserData* userData = MenuUserData::forObject(menu);
QObject* parent = findMenuObject(userData->uuid.toString());
Q_ASSERT(parent);
QObject* result = ::addItem(parent, action->text());
Q_ASSERT(result);
// Bind the QML and Widget together
bindActionToQmlAction(result, action);
}
void VrMenu::insertAction(QAction* before, QAction* action) {
QObject* beforeQml{ nullptr };
{
MenuUserData* beforeUserData = MenuUserData::forObject(before);
Q_ASSERT(beforeUserData);
beforeQml = findMenuObject(beforeUserData->uuid.toString());
}
QObject* menu = beforeQml->parent();
int index{ -1 };
QVariant itemsVar = menu->property("items");
QList<QVariant> items = itemsVar.toList();
// FIXME add more checking here to ensure no name conflicts
for (index = 0; index < items.length(); ++index) {
QObject* currentQmlItem = items.at(index).value<QObject*>();
if (currentQmlItem == beforeQml) {
break;
}
}
QObject* result{ nullptr };
if (index < 0 || index >= items.length()) {
result = ::addItem(menu, action->text());
} else {
QQuickMenuItem* returnedValue{ nullptr };
bool invokeResult = QMetaObject::invokeMethod(menu, "insertItem", Qt::DirectConnection,
Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
Q_ARG(int, index), Q_ARG(QString, action->text()));
Q_ASSERT(invokeResult);
result = reinterpret_cast<QObject*>(returnedValue);
}
Q_ASSERT(result);
bindActionToQmlAction(result, action);
}
void VrMenu::removeAction(QAction* action) {
// FIXME implement
}

49
libraries/ui/src/VrMenu.h Normal file
View file

@ -0,0 +1,49 @@
//
// VrMenu.h
//
// Created by Bradley Austin Davis on 2015/04/21
// 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_VrMenu_h
#define hifi_VrMenu_h
#include <QQuickItem>
#include <QHash>
#include <QList>
#include <QSignalMapper>
#include <QAction>
#include <QMenu>
#include "OffscreenUi.h"
// FIXME break up the rendering code (VrMenu) and the code for mirroring a Widget based menu in QML
class VrMenu : public QQuickItem {
Q_OBJECT
HIFI_QML_DECL_LAMBDA
public:
static void executeOrQueue(std::function<void(VrMenu*)> f);
static void executeQueuedLambdas();
VrMenu(QQuickItem* parent = nullptr);
void addMenu(QMenu* menu);
void addAction(QMenu* parent, QAction* action);
void insertAction(QAction* before, QAction* action);
void removeAction(QAction* action);
void setRootMenu(QObject* rootMenu);
protected:
QObject* _rootMenu{ nullptr };
QObject* findMenuObject(const QString& name);
const QObject* findMenuObject(const QString& name) const;
static VrMenu* _instance;
friend class MenuUserData;
};
#endif // hifi_VrMenu_h

View file

@ -35,7 +35,7 @@
#include <QDir>
#include "MessageDialog.h"
#include "HifiMenu.h"
#include "VrMenu.h"
class RateCounter {
std::vector<float> times;
@ -74,7 +74,172 @@ public:
};
const QString & getQmlDir() {
class MenuConstants : public QObject{
Q_OBJECT
Q_ENUMS(Item)
public:
enum Item {
AboutApp,
AddRemoveFriends,
AddressBar,
AlignForearmsWithWrists,
AlternateIK,
AmbientOcclusion,
Animations,
Atmosphere,
Attachments,
AudioNoiseReduction,
AudioScope,
AudioScopeFiftyFrames,
AudioScopeFiveFrames,
AudioScopeFrames,
AudioScopePause,
AudioScopeTwentyFrames,
AudioStats,
AudioStatsShowInjectedStreams,
BandwidthDetails,
BlueSpeechSphere,
BookmarkLocation,
Bookmarks,
CascadedShadows,
CachesSize,
Chat,
Collisions,
Console,
ControlWithSpeech,
CopyAddress,
CopyPath,
DecreaseAvatarSize,
DeleteBookmark,
DisableActivityLogger,
DisableLightEntities,
DisableNackPackets,
DiskCacheEditor,
DisplayHands,
DisplayHandTargets,
DisplayModelBounds,
DisplayModelTriangles,
DisplayModelElementChildProxies,
DisplayModelElementProxy,
DisplayDebugTimingDetails,
DontDoPrecisionPicking,
DontFadeOnOctreeServerChanges,
DontRenderEntitiesAsScene,
EchoLocalAudio,
EchoServerAudio,
EditEntitiesHelp,
Enable3DTVMode,
EnableCharacterController,
EnableGlowEffect,
EnableVRMode,
ExpandMyAvatarSimulateTiming,
ExpandMyAvatarTiming,
ExpandOtherAvatarTiming,
ExpandPaintGLTiming,
ExpandUpdateTiming,
Faceshift,
FilterSixense,
FirstPerson,
FrameTimer,
Fullscreen,
FullscreenMirror,
GlowWhenSpeaking,
NamesAboveHeads,
GoToUser,
HMDTools,
IncreaseAvatarSize,
KeyboardMotorControl,
LeapMotionOnHMD,
LoadScript,
LoadScriptURL,
LoadRSSDKFile,
LodTools,
Login,
Log,
LowVelocityFilter,
Mirror,
MuteAudio,
MuteEnvironment,
NoFaceTracking,
NoShadows,
OctreeStats,
OffAxisProjection,
OnlyDisplayTopTen,
PackageModel,
Pair,
PipelineWarnings,
Preferences,
Quit,
ReloadAllScripts,
RenderBoundingCollisionShapes,
RenderFocusIndicator,
RenderHeadCollisionShapes,
RenderLookAtVectors,
RenderSkeletonCollisionShapes,
RenderTargetFramerate,
RenderTargetFramerateUnlimited,
RenderTargetFramerate60,
RenderTargetFramerate50,
RenderTargetFramerate40,
RenderTargetFramerate30,
RenderTargetFramerateVSyncOn,
RenderResolution,
RenderResolutionOne,
RenderResolutionTwoThird,
RenderResolutionHalf,
RenderResolutionThird,
RenderResolutionQuarter,
RenderAmbientLight,
RenderAmbientLightGlobal,
RenderAmbientLight0,
RenderAmbientLight1,
RenderAmbientLight2,
RenderAmbientLight3,
RenderAmbientLight4,
RenderAmbientLight5,
RenderAmbientLight6,
RenderAmbientLight7,
RenderAmbientLight8,
RenderAmbientLight9,
ResetAvatarSize,
ResetSensors,
RunningScripts,
RunTimingTests,
ScriptEditor,
ScriptedMotorControl,
ShowBordersEntityNodes,
ShowIKConstraints,
SimpleShadows,
SixenseEnabled,
SixenseMouseInput,
SixenseLasers,
ShiftHipsForIdleAnimations,
Stars,
Stats,
StereoAudio,
StopAllScripts,
SuppressShortTimings,
TestPing,
ToolWindow,
TransmitterDrive,
TurnWithHead,
UseAudioForMouth,
UseCamera,
VelocityFilter,
VisibleToEveryone,
VisibleToFriends,
VisibleToNoOne,
Wireframe,
};
public:
MenuConstants(QObject* parent = nullptr) : QObject(parent) {
}
};
const QString& getQmlDir() {
static QString dir;
if (dir.isEmpty()) {
QDir path(__FILE__);
@ -85,7 +250,7 @@ const QString & getQmlDir() {
return dir;
}
const QString & getTestQmlDir() {
const QString& getTestQmlDir() {
static QString dir;
if (dir.isEmpty()) {
QDir path(__FILE__);
@ -100,7 +265,7 @@ const QString & getTestQmlDir() {
class QTestWindow : public QWindow, private QOpenGLFunctions {
Q_OBJECT
QOpenGLContext * _context{ nullptr };
QOpenGLContext* _context{ nullptr };
QSize _size;
bool _altPressed{ false };
RateCounter fps;
@ -108,7 +273,7 @@ class QTestWindow : public QWindow, private QOpenGLFunctions {
int testQmlTexture{ 0 };
public:
QObject * rootMenu;
QObject* rootMenu;
QTestWindow() {
_timer.setInterval(1);
@ -139,7 +304,7 @@ public:
initializeOpenGLFunctions();
{
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) {
@ -155,7 +320,9 @@ public:
glDisable(GL_DEPTH_TEST);
MessageDialog::registerType();
HifiMenu::registerType();
VrMenu::registerType();
qmlRegisterType<MenuConstants>("Hifi", 1, 0, "MenuConstants");
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_context);
@ -181,24 +348,9 @@ public:
#else
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir()));
offscreenUi->load(QUrl("TestRoot.qml"));
offscreenUi->load(QUrl("RootMenu.qml"));
HifiMenu::load();
QObject* menuObject = offscreenUi->getRootItem()->findChild<QObject*>("HifiMenu");
HifiMenu* menu = offscreenUi->getRootItem()->findChild<HifiMenu*>();
menu->addMenu("", "File");
menu->addItem("File", "Quit", []{
QApplication::quit();
});
menu->addCheckableItem("File", "Toggle", false, [](bool toggled) {
qDebug() << "Toggle is " << toggled;
});
menu->addMenu("", "Edit");
menu->addItem("Edit", "Undo");
menu->addItem("Edit", "Redo");
menu->addItem("Edit", "Copy");
menu->addItem("Edit", "Cut");
menu->addItem("Edit", "Paste");
menu->addMenu("", "Long Menu Name...");
offscreenUi->load(QUrl("TestMenu.qml"));
// Requires a root menu to have been loaded before it can load
VrMenu::load();
#endif
installEventFilter(offscreenUi.data());
offscreenUi->resume();
@ -244,20 +396,16 @@ private:
protected:
void resizeEvent(QResizeEvent * ev) override {
void resizeEvent(QResizeEvent* ev) override {
resizeWindow(ev->size());
}
void keyPressEvent(QKeyEvent *event) {
void keyPressEvent(QKeyEvent* event) {
_altPressed = Qt::Key_Alt == event->key();
switch (event->key()) {
case Qt::Key_L:
if (event->modifiers() & Qt::CTRL) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
HifiMenu * menu = offscreenUi->findChild<HifiMenu*>();
menu->addItem("", "Test 3");
menu->addItem("File", "Test 3");
}
break;
case Qt::Key_K:
@ -280,11 +428,11 @@ protected:
QQmlContext* menuContext{ nullptr };
void keyReleaseEvent(QKeyEvent *event) {
if (_altPressed && Qt::Key_Alt == event->key()) {
HifiMenu::toggle();
VrMenu::toggle();
}
}
void moveEvent(QMoveEvent *event) {
void moveEvent(QMoveEvent* event) {
static qreal oldPixelRatio = 0.0;
if (devicePixelRatio() != oldPixelRatio) {
oldPixelRatio = devicePixelRatio();
@ -322,7 +470,7 @@ void QTestWindow::renderQml() {
const char * LOG_FILTER_RULES = R"V0G0N(
*.debug=false
hifi.offscreen.focus.debug=false
qt.quick.mouse.debug=false
)V0G0N";
@ -334,11 +482,9 @@ qt.quick.mouse.debug=false
// return app.exec();
//}
int main(int argc, char** argv) {
QGuiApplication app(argc, argv);
// QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
QTestWindow window;
app.exec();
return 0;