mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 01:24:03 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into tablet-ui-edit-js
This commit is contained in:
commit
838d7f6f10
27 changed files with 2003 additions and 80 deletions
60
interface/resources/icons/tablet-icons/mic-mute.svg
Normal file
60
interface/resources/icons/tablet-icons/mic-mute.svg
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 40 40"
|
||||
style="enable-background:new 0 0 40 40;"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="mic-mute.svg"><metadata
|
||||
id="metadata6958"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6956" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1824"
|
||||
inkscape:window-height="1057"
|
||||
id="namedview6954"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.9"
|
||||
inkscape:cx="-40.338983"
|
||||
inkscape:cy="20"
|
||||
inkscape:window-x="88"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><style
|
||||
type="text/css"
|
||||
id="style6942">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style><ellipse
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path8048"
|
||||
cx="20.1"
|
||||
cy="20.5"
|
||||
rx="15.967586"
|
||||
ry="15.967585" /><rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#feffff;stroke-width:0;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect8065"
|
||||
width="30.1991"
|
||||
height="2.9999897"
|
||||
x="13.432917"
|
||||
y="-1.2235159"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" /></svg>
|
After Width: | Height: | Size: 2.2 KiB |
62
interface/resources/icons/tablet-icons/mic.svg
Normal file
62
interface/resources/icons/tablet-icons/mic.svg
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 40 40"
|
||||
style="enable-background:new 0 0 40 40;"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="tablet-mic.svg"><metadata
|
||||
id="metadata6958"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6956" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1824"
|
||||
inkscape:window-height="1057"
|
||||
id="namedview6954"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.9"
|
||||
inkscape:cx="20"
|
||||
inkscape:cy="20"
|
||||
inkscape:window-x="88"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><style
|
||||
type="text/css"
|
||||
id="style6942">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style><path
|
||||
class="st0"
|
||||
d="m 22.5,14.7 0,-3.1 C 22.5,10.1 21.3,9 19.9,9 l 0,0 c -1.5,0 -2.6,1.1 -2.6,2.6 l 0,3.1 5.2,0 z"
|
||||
id="path6948"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" /><path
|
||||
class="st0"
|
||||
d="m 17.3,17.4 0,3 c 0,1.5 1.2,2.6 2.7,2.6 l 0,0 c 1.5,0 2.6,-1.2 2.6,-2.6 l 0,-3 -5.3,0 z"
|
||||
id="path6950"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" /><path
|
||||
class="st0"
|
||||
d="m 27.9,20.9 c 0,0 0,-3.6 0,-3.8 0,-0.7 -0.6,-1.2 -1.3,-1.2 -0.7,0 -1.2,0.6 -1.2,1.3 0,0.2 0,3.4 0,3.7 0,2.6 -2.4,4.8 -5.3,4.8 -2.9,0 -5.3,-2.1 -5.3,-4.8 0,-0.3 0,-3.5 0,-3.8 0,-0.7 -0.5,-1.3 -1.2,-1.3 -0.7,0 -1.3,0.5 -1.3,1.2 0,0.2 0,3.9 0,3.9 0,3.6 2.9,6.6 6.6,7.2 l 0,2.4 -3.1,0 c -0.7,0 -1.3,0.6 -1.3,1.3 0,0.7 0.6,1.3 1.3,1.3 l 8.8,0 c 0.7,0 1.3,-0.6 1.3,-1.3 0,-0.7 -0.6,-1.3 -1.3,-1.3 l -3.2,0 0,-2.4 c 3.6,-0.5 6.5,-3.5 6.5,-7.2 z"
|
||||
id="path6952"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" /></svg>
|
After Width: | Height: | Size: 2.5 KiB |
211
interface/resources/qml/controls-uit/TabletComboBox.qml
Normal file
211
interface/resources/qml/controls-uit/TabletComboBox.qml
Normal file
|
@ -0,0 +1,211 @@
|
|||
//
|
||||
// ComboBox.qml
|
||||
//
|
||||
// Created by Dante Ruiz on 13 Feb 2017
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "../styles-uit"
|
||||
import "../controls-uit" as HifiControls
|
||||
import "." as VrControls
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
property alias model: comboBox.model;
|
||||
property alias comboBox: comboBox
|
||||
readonly property alias currentText: comboBox.currentText;
|
||||
property alias currentIndex: comboBox.currentIndex;
|
||||
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
|
||||
property string label: ""
|
||||
property real controlHeight: height + (comboBoxLabel.visible ? comboBoxLabel.height + comboBoxLabel.anchors.bottomMargin : 0)
|
||||
|
||||
readonly property ComboBox control: comboBox
|
||||
|
||||
signal accepted();
|
||||
|
||||
implicitHeight: comboBox.height;
|
||||
focus: true
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.2
|
||||
color: popup.visible
|
||||
? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark)
|
||||
: (isLightColorScheme ? hifi.colors.dropDownLightStart : hifi.colors.dropDownDarkStart)
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: popup.visible
|
||||
? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark)
|
||||
: (isLightColorScheme ? hifi.colors.dropDownLightFinish : hifi.colors.dropDownDarkFinish)
|
||||
}
|
||||
}
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
SystemPalette { id: palette }
|
||||
|
||||
ComboBox {
|
||||
id: comboBox
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
height: hifi.fontSizes.textFieldInput + 13 // Match height of TextField control.
|
||||
}
|
||||
|
||||
FiraSansSemiBold {
|
||||
id: textField
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: hifi.dimensions.textPadding
|
||||
right: dropIcon.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
size: hifi.fontSizes.textFieldInput
|
||||
text: comboBox.currentText
|
||||
elide: Text.ElideRight
|
||||
color: controlHover.containsMouse || popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText )
|
||||
}
|
||||
|
||||
Item {
|
||||
id: dropIcon
|
||||
anchors { right: parent.right; verticalCenter: parent.verticalCenter }
|
||||
height: background.height
|
||||
width: height
|
||||
Rectangle {
|
||||
width: 1
|
||||
height: parent.height
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
color: isLightColorScheme ? hifi.colors.faintGray : hifi.colors.baseGray
|
||||
}
|
||||
HiFiGlyphs {
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: -11
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
size: hifi.dimensions.spinnerSize
|
||||
text: hifi.glyphs.caratDn
|
||||
color: controlHover.containsMouse || popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText)
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: controlHover
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
onClicked: toggleList();
|
||||
}
|
||||
|
||||
function toggleList() {
|
||||
if (popup.visible) {
|
||||
hideList();
|
||||
} else {
|
||||
showList();
|
||||
}
|
||||
}
|
||||
|
||||
function showList() {
|
||||
var r = 20//desktop.mapFromItem(root, 0, 0, root.width, root.height);
|
||||
var y = 200;
|
||||
var bottom = 0 + scrollView.height;
|
||||
if (bottom > 720) {
|
||||
y -= bottom - 720 + 8;
|
||||
}
|
||||
scrollView.x = 0;
|
||||
scrollView.y = 0;
|
||||
popup.visible = true;
|
||||
popup.forceActiveFocus();
|
||||
listView.currentIndex = root.currentIndex;
|
||||
scrollView.hoverEnabled = true;
|
||||
}
|
||||
|
||||
function hideList() {
|
||||
popup.visible = false;
|
||||
scrollView.hoverEnabled = false;
|
||||
root.accepted();
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
id: popup
|
||||
parent: parent
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
focus: true
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: hideList();
|
||||
}
|
||||
|
||||
function previousItem() { listView.currentIndex = (listView.currentIndex + listView.count - 1) % listView.count; }
|
||||
function nextItem() { listView.currentIndex = (listView.currentIndex + listView.count + 1) % listView.count; }
|
||||
function selectCurrentItem() { root.currentIndex = listView.currentIndex; hideList(); }
|
||||
function selectSpecificItem(index) { root.currentIndex = index; hideList(); }
|
||||
|
||||
Keys.onUpPressed: previousItem();
|
||||
Keys.onDownPressed: nextItem();
|
||||
Keys.onSpacePressed: selectCurrentItem();
|
||||
Keys.onRightPressed: selectCurrentItem();
|
||||
Keys.onReturnPressed: selectCurrentItem();
|
||||
Keys.onEscapePressed: hideList();
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
height: 480
|
||||
width: root.width + 4
|
||||
property bool hoverEnabled: false;
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
height: textField.height * count * 1.4
|
||||
model: root.model
|
||||
delegate: Rectangle {
|
||||
width: root.width + 4
|
||||
height: popupText.implicitHeight * 1.4
|
||||
color: (listView.currentIndex === index) ? hifi.colors.primaryHighlight :
|
||||
(isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark)
|
||||
FiraSansSemiBold {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: hifi.dimensions.textPadding
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
id: popupText
|
||||
text: listView.model[index] ? listView.model[index] : ""
|
||||
size: hifi.fontSizes.textFieldInput
|
||||
color: hifi.colors.baseGray
|
||||
}
|
||||
MouseArea {
|
||||
id: popupHover
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: scrollView.hoverEnabled;
|
||||
onEntered: listView.currentIndex = index;
|
||||
onClicked: popup.selectSpecificItem(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Label {
|
||||
id: comboBoxLabel
|
||||
text: root.label
|
||||
colorScheme: root.colorScheme
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: 4
|
||||
visible: label != ""
|
||||
}
|
||||
}
|
138
interface/resources/qml/controls-uit/TabletContentSection.qml
Normal file
138
interface/resources/qml/controls-uit/TabletContentSection.qml
Normal file
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// ContentSection.qml
|
||||
//
|
||||
// Created by Dante Ruiz on 13 Feb 2017
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
Column {
|
||||
property string name: "Content Section"
|
||||
property bool isFirst: false
|
||||
property bool isCollapsible: false // Set at creation.
|
||||
property bool isCollapsed: false
|
||||
|
||||
spacing: 0 // Defer spacing decisions to individual controls.
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: hifi.dimensions.contentMargin.x
|
||||
right: parent.right
|
||||
rightMargin: hifi.dimensions.contentMargin.x
|
||||
}
|
||||
|
||||
function toggleCollapsed() {
|
||||
if (isCollapsible) {
|
||||
isCollapsed = !isCollapsed;
|
||||
for (var i = 1; i < children.length; i++) {
|
||||
children[i].visible = !isCollapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: sectionName
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: leadingSpace.height + topBar.height + heading.height + bottomBar.height
|
||||
|
||||
Item {
|
||||
id: leadingSpace
|
||||
width: 1
|
||||
height: isFirst ? 7 : 0
|
||||
anchors.top: parent.top
|
||||
}
|
||||
|
||||
Item {
|
||||
id: topBar
|
||||
visible: !isFirst
|
||||
height: visible ? 2 : 0
|
||||
anchors.top: leadingSpace.bottom
|
||||
|
||||
Rectangle {
|
||||
id: shadow
|
||||
width: 480
|
||||
height: 1
|
||||
color: hifi.colors.baseGrayShadow
|
||||
x: -hifi.dimensions.contentMargin.x
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 480
|
||||
height: 1
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
x: -hifi.dimensions.contentMargin.x
|
||||
anchors.top: shadow.bottom
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: heading
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: topBar.bottom
|
||||
}
|
||||
height: isCollapsible ? 36 : 28
|
||||
|
||||
RalewayRegular {
|
||||
id: title
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
topMargin: 12
|
||||
}
|
||||
size: hifi.fontSizes.sectionName
|
||||
font.capitalization: Font.AllUppercase
|
||||
text: name
|
||||
color: hifi.colors.lightGrayText
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
anchors {
|
||||
top: title.top
|
||||
topMargin: -9
|
||||
right: parent.right
|
||||
rightMargin: -4
|
||||
}
|
||||
size: hifi.fontSizes.disclosureButton
|
||||
text: isCollapsed ? hifi.glyphs.disclosureButtonExpand : hifi.glyphs.disclosureButtonCollapse
|
||||
color: hifi.colors.lightGrayText
|
||||
visible: isCollapsible
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
// Events are propogated so that any active control is defocused.
|
||||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
onPressed: {
|
||||
toggleCollapsed();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LinearGradient {
|
||||
id: bottomBar
|
||||
visible: false
|
||||
width: 480
|
||||
height: visible ? 4 : 0
|
||||
x: -hifi.dimensions.contentMargin.x
|
||||
anchors.top: heading.bottom
|
||||
start: Qt.point(0, 0)
|
||||
end: Qt.point(0, 4)
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: hifi.colors.darkGray }
|
||||
GradientStop { position: 1.0; color: hifi.colors.baseGray } // Equivalent of darkGray0 over baseGray background.
|
||||
}
|
||||
cached: true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
import "../../styles-uit"
|
||||
|
||||
|
@ -6,10 +6,16 @@ Item {
|
|||
id: tablet
|
||||
objectName: "tablet"
|
||||
property double micLevel: 0.8
|
||||
property bool micEnabled: true
|
||||
property int rowIndex: 0
|
||||
property int columnIndex: 0
|
||||
property int count: (flowMain.children.length - 1)
|
||||
|
||||
// called by C++ code to keep mic state updated
|
||||
function setMicEnabled(newMicEnabled) {
|
||||
tablet.micEnabled = newMicEnabled;
|
||||
}
|
||||
|
||||
// called by C++ code to keep audio bar updated
|
||||
function setMicLevel(newMicLevel) {
|
||||
tablet.micLevel = newMicLevel;
|
||||
|
@ -97,17 +103,38 @@ Item {
|
|||
anchors.topMargin: 0
|
||||
anchors.top: parent.top
|
||||
|
||||
|
||||
Image {
|
||||
id: muteIcon
|
||||
Item {
|
||||
id: audioIcon
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 40
|
||||
height: 40
|
||||
source: "../../../icons/tablet-mute-icon.svg"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 5
|
||||
|
||||
Image {
|
||||
id: micIcon
|
||||
source: "../../../icons/tablet-icons/mic.svg"
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: (!tablet.micEnabled && !toggleMuteMouseArea.containsMouse)
|
||||
|| (tablet.micEnabled && toggleMuteMouseArea.containsMouse)
|
||||
|
||||
Image {
|
||||
id: muteIcon
|
||||
source: "../../../icons/tablet-icons/mic-mute.svg"
|
||||
}
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: muteIcon
|
||||
source: muteIcon
|
||||
color: toggleMuteMouseArea.containsMouse ? "#a0a0a0" : "#ff0000"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: item1
|
||||
id: audioBar
|
||||
width: 170
|
||||
height: 10
|
||||
anchors.left: parent.left
|
||||
|
@ -157,6 +184,22 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: toggleMuteMouseArea
|
||||
anchors {
|
||||
left: audioIcon.left
|
||||
right: audioBar.right
|
||||
top: audioIcon.top
|
||||
bottom: audioIcon.bottom
|
||||
}
|
||||
|
||||
hoverEnabled: true
|
||||
preventStealing: true
|
||||
propagateComposedEvents: false
|
||||
scrollGestureEnabled: false
|
||||
onClicked: tabletRoot.toggleMicEnabled()
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: usernameText
|
||||
text: tablet.parent.parent.username
|
||||
|
@ -175,7 +218,6 @@ Item {
|
|||
GradientStop {
|
||||
position: 0
|
||||
color: "#2b2b2b"
|
||||
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
|
@ -225,7 +267,7 @@ Item {
|
|||
|
||||
PropertyChanges {
|
||||
target: muteIcon
|
||||
source: "../../../icons/tablet-unmute-icon.svg"
|
||||
visible: micEnabled
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// TabletGeneralSettings.qml
|
||||
// scripts/system/
|
||||
//
|
||||
// Created by Dante Ruiz on 9 Feb 2017
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import "tabletWindows"
|
||||
import "../../dialogs"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
StackView {
|
||||
id: profileRoot
|
||||
initialItem: root
|
||||
objectName: "stack"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
editRoot.push(Qt.reslovedUrl(path));
|
||||
}
|
||||
|
||||
function popSource() {
|
||||
|
||||
}
|
||||
|
||||
TabletPreferencesDialog {
|
||||
id: root
|
||||
objectName: "GeneralPreferencesDialog"
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect"]
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,7 @@ FocusScope {
|
|||
|
||||
property var rootMenu: Menu { objectName:"rootMenu" }
|
||||
property var point: Qt.point(50, 50)
|
||||
property string subMenu: ""
|
||||
|
||||
TabletMouseHandler { id: menuPopperUpper }
|
||||
|
||||
|
@ -101,6 +102,24 @@ FocusScope {
|
|||
buildMenu()
|
||||
}
|
||||
function buildMenu() {
|
||||
menuPopperUpper.popup(tabletMenu, rootMenu.items)
|
||||
// Build submenu if specified.
|
||||
if (subMenu !== "") {
|
||||
var index = 0;
|
||||
var found = false;
|
||||
while (!found && index < rootMenu.items.length) {
|
||||
found = rootMenu.items[index].title === subMenu;
|
||||
if (!found) {
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
subMenu = ""; // Continue with full menu after initially displaying submenu.
|
||||
if (found) {
|
||||
menuPopperUpper.popup(tabletMenu, rootMenu.items[index].items);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise build whole menu.
|
||||
menuPopperUpper.popup(tabletMenu, rootMenu.items);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,14 @@ Item {
|
|||
objectName: "tabletRoot"
|
||||
property string username: "Unknown user"
|
||||
property var eventBridge;
|
||||
property string option: ""
|
||||
|
||||
signal showDesktop();
|
||||
|
||||
function setOption(value) {
|
||||
option = value;
|
||||
}
|
||||
|
||||
function loadSource(url) {
|
||||
loader.source = url;
|
||||
}
|
||||
|
@ -42,6 +47,10 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
function toggleMicEnabled() {
|
||||
ApplicationInterface.toggleMuteAudio();
|
||||
}
|
||||
|
||||
function setUsername(newUsername) {
|
||||
username = newUsername;
|
||||
}
|
||||
|
@ -68,6 +77,9 @@ Item {
|
|||
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||
}
|
||||
if (loader.item.hasOwnProperty("subMenu")) {
|
||||
loader.item.subMenu = option;
|
||||
}
|
||||
loader.item.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,775 @@
|
|||
//
|
||||
// FileDialog.qml
|
||||
//
|
||||
// Created by Bradley Dante Ruiz on 13 Feb 2017
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import Qt.labs.folderlistmodel 2.1
|
||||
import Qt.labs.settings 1.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
|
||||
import ".."
|
||||
import "../../../controls-uit"
|
||||
import "../../../styles-uit"
|
||||
import "../../../windows"
|
||||
|
||||
import "../../../dialogs/fileDialog"
|
||||
|
||||
//FIXME implement shortcuts for favorite location
|
||||
Item {
|
||||
id: root
|
||||
anchors.top: parent.top
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
Settings {
|
||||
category: "FileDialog"
|
||||
property alias width: root.width
|
||||
property alias height: root.height
|
||||
property alias x: root.x
|
||||
property alias y: root.y
|
||||
}
|
||||
|
||||
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
// property alias caption: root.title;
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property alias dir: fileTableModel.folder;
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property alias filter: selectionType.filtersString;
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property int options; // <-- FIXME unused
|
||||
|
||||
property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : ""
|
||||
property int iconSize: 40
|
||||
|
||||
property bool selectDirectory: false;
|
||||
property bool showHidden: false;
|
||||
// FIXME implement
|
||||
property bool multiSelect: false;
|
||||
property bool saveDialog: false;
|
||||
property var helper: fileDialogHelper
|
||||
property alias model: fileTableView.model
|
||||
property var drives: helper.drives()
|
||||
|
||||
property int titleWidth: 0
|
||||
|
||||
signal selectedFile(var file);
|
||||
signal canceled();
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Helper " + helper + " drives " + drives);
|
||||
|
||||
fileDialogItem.keyboardEnabled = HMD.active;
|
||||
|
||||
// HACK: The following lines force the model to initialize properly such that the go-up button
|
||||
// works properly from the initial screen.
|
||||
var initialFolder = folderListModel.folder;
|
||||
fileTableModel.folder = helper.pathToUrl(drives[0]);
|
||||
fileTableModel.folder = initialFolder;
|
||||
|
||||
iconText = root.title !== "" ? hifi.glyphs.scriptUpload : "";
|
||||
|
||||
// Clear selection when click on external frame.
|
||||
//frameClicked.connect(function() { d.clearSelection(); });
|
||||
|
||||
if (selectDirectory) {
|
||||
currentSelection.text = d.capitalizeDrive(helper.urlToPath(initialFolder));
|
||||
d.currentSelectionIsFolder = true;
|
||||
d.currentSelectionUrl = initialFolder;
|
||||
}
|
||||
|
||||
helper.contentsChanged.connect(function() {
|
||||
if (folderListModel) {
|
||||
// Make folderListModel refresh.
|
||||
var save = folderListModel.folder;
|
||||
folderListModel.folder = "";
|
||||
folderListModel.folder = save;
|
||||
}
|
||||
});
|
||||
|
||||
fileTableView.forceActiveFocus();
|
||||
}
|
||||
|
||||
Item {
|
||||
id: fileDialogItem
|
||||
clip: true
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.margins: 0
|
||||
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
MouseArea {
|
||||
// Clear selection when click on internal unused area.
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: navControls
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: hifi.dimensions.contentMargin.y
|
||||
left: parent.left
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
||||
GlyphButton {
|
||||
id: upButton
|
||||
glyph: hifi.glyphs.levelUp
|
||||
width: height
|
||||
size: 30
|
||||
enabled: fileTableModel.parentFolder && fileTableModel.parentFolder !== ""
|
||||
onClicked: d.navigateUp();
|
||||
}
|
||||
|
||||
GlyphButton {
|
||||
id: homeButton
|
||||
property var destination: helper.home();
|
||||
glyph: hifi.glyphs.home
|
||||
size: 28
|
||||
width: height
|
||||
enabled: d.homeDestination ? true : false
|
||||
onClicked: d.navigateHome();
|
||||
}
|
||||
}
|
||||
|
||||
TabletComboBox {
|
||||
id: pathSelector
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: hifi.dimensions.contentMargin.y
|
||||
left: navControls.right
|
||||
leftMargin: hifi.dimensions.contentSpacing.x
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
property var lastValidFolder: helper.urlToPath(fileTableModel.folder)
|
||||
|
||||
function calculatePathChoices(folder) {
|
||||
var folders = folder.split("/"),
|
||||
choices = [],
|
||||
i, length;
|
||||
|
||||
if (folders[folders.length - 1] === "") {
|
||||
folders.pop();
|
||||
}
|
||||
|
||||
choices.push(folders[0]);
|
||||
|
||||
for (i = 1, length = folders.length; i < length; i++) {
|
||||
choices.push(choices[i - 1] + "/" + folders[i]);
|
||||
}
|
||||
|
||||
if (folders[0] === "") {
|
||||
// Special handling for OSX root dir.
|
||||
choices[0] = "/";
|
||||
}
|
||||
|
||||
choices.reverse();
|
||||
|
||||
if (drives && drives.length > 1) {
|
||||
choices.push("This PC");
|
||||
}
|
||||
|
||||
if (choices.length > 0) {
|
||||
pathSelector.model = choices;
|
||||
}
|
||||
}
|
||||
|
||||
onLastValidFolderChanged: {
|
||||
var folder = d.capitalizeDrive(lastValidFolder);
|
||||
calculatePathChoices(folder);
|
||||
}
|
||||
|
||||
onCurrentTextChanged: {
|
||||
var folder = currentText;
|
||||
|
||||
if (/^[a-zA-z]:$/.test(folder)) {
|
||||
folder = "file:///" + folder + "/";
|
||||
} else if (folder === "This PC") {
|
||||
folder = "file:///";
|
||||
} else {
|
||||
folder = helper.pathToUrl(folder);
|
||||
}
|
||||
|
||||
if (helper.urlToPath(folder).toLowerCase() !== helper.urlToPath(fileTableModel.folder).toLowerCase()) {
|
||||
if (root.selectDirectory) {
|
||||
currentSelection.text = currentText !== "This PC" ? currentText : "";
|
||||
d.currentSelectionUrl = helper.pathToUrl(currentText);
|
||||
}
|
||||
fileTableModel.folder = folder;
|
||||
fileTableView.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property var currentSelectionUrl;
|
||||
readonly property string currentSelectionPath: helper.urlToPath(currentSelectionUrl);
|
||||
property bool currentSelectionIsFolder;
|
||||
property var backStack: []
|
||||
property var tableViewConnection: Connections { target: fileTableView; onCurrentRowChanged: d.update(); }
|
||||
property var modelConnection: Connections { target: fileTableModel; onFolderChanged: d.update(); }
|
||||
property var homeDestination: helper.home();
|
||||
|
||||
function capitalizeDrive(path) {
|
||||
// Consistently capitalize drive letter for Windows.
|
||||
if (/[a-zA-Z]:/.test(path)) {
|
||||
return path.charAt(0).toUpperCase() + path.slice(1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function update() {
|
||||
var row = fileTableView.currentRow;
|
||||
|
||||
if (row === -1) {
|
||||
if (!root.selectDirectory) {
|
||||
currentSelection.text = "";
|
||||
currentSelectionIsFolder = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
|
||||
currentSelectionIsFolder = fileTableView.model.isFolder(row);
|
||||
if (root.selectDirectory || !currentSelectionIsFolder) {
|
||||
currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
|
||||
} else {
|
||||
currentSelection.text = "";
|
||||
}
|
||||
}
|
||||
|
||||
function navigateUp() {
|
||||
if (fileTableModel.parentFolder && fileTableModel.parentFolder !== "") {
|
||||
fileTableModel.folder = fileTableModel.parentFolder;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function navigateHome() {
|
||||
fileTableModel.folder = homeDestination;
|
||||
return true;
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
fileTableView.selection.clear();
|
||||
fileTableView.currentRow = -1;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
FolderListModel {
|
||||
id: folderListModel
|
||||
nameFilters: selectionType.currentFilter
|
||||
showDirsFirst: true
|
||||
showDotAndDotDot: false
|
||||
showFiles: !root.selectDirectory
|
||||
Component.onCompleted: {
|
||||
showFiles = !root.selectDirectory
|
||||
}
|
||||
|
||||
onFolderChanged: {
|
||||
fileTableModel.update(); // Update once the data from the folder change is available.
|
||||
}
|
||||
|
||||
function getItem(index, field) {
|
||||
return get(index, field);
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
// Emulates FolderListModel but contains drive data.
|
||||
id: driveListModel
|
||||
|
||||
property int count: 1
|
||||
|
||||
Component.onCompleted: initialize();
|
||||
|
||||
function initialize() {
|
||||
var drive,
|
||||
i;
|
||||
|
||||
count = drives.length;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
drive = drives[i].slice(0, -1); // Remove trailing "/".
|
||||
append({
|
||||
fileName: drive,
|
||||
fileModified: new Date(0),
|
||||
fileSize: 0,
|
||||
filePath: drive + "/",
|
||||
fileIsDir: true,
|
||||
fileNameSort: drive.toLowerCase()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getItem(index, field) {
|
||||
return get(index)[field];
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: fileTableModel
|
||||
|
||||
// FolderListModel has a couple of problems:
|
||||
// 1) Files and directories sort case-sensitively: https://bugreports.qt.io/browse/QTBUG-48757
|
||||
// 2) Cannot browse up to the "computer" level to view Windows drives: https://bugreports.qt.io/browse/QTBUG-42901
|
||||
//
|
||||
// To solve these problems an intermediary ListModel is used that implements proper sorting and can be populated with
|
||||
// drive information when viewing at the computer level.
|
||||
|
||||
property var folder
|
||||
property int sortOrder: Qt.AscendingOrder
|
||||
property int sortColumn: 0
|
||||
property var model: folderListModel
|
||||
property string parentFolder: calculateParentFolder();
|
||||
|
||||
readonly property string rootFolder: "file:///"
|
||||
|
||||
function calculateParentFolder() {
|
||||
if (model === folderListModel) {
|
||||
if (folderListModel.parentFolder.toString() === "" && driveListModel.count > 1) {
|
||||
return rootFolder;
|
||||
} else {
|
||||
return folderListModel.parentFolder;
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
onFolderChanged: {
|
||||
if (folder === rootFolder) {
|
||||
model = driveListModel;
|
||||
helper.monitorDirectory("");
|
||||
update();
|
||||
} else {
|
||||
var needsUpdate = model === driveListModel && folder === folderListModel.folder;
|
||||
|
||||
model = folderListModel;
|
||||
folderListModel.folder = folder;
|
||||
helper.monitorDirectory(helper.urlToPath(folder));
|
||||
|
||||
if (needsUpdate) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isFolder(row) {
|
||||
if (row === -1) {
|
||||
return false;
|
||||
}
|
||||
return get(row).fileIsDir;
|
||||
}
|
||||
|
||||
function update() {
|
||||
var dataFields = ["fileName", "fileModified", "fileSize"],
|
||||
sortFields = ["fileNameSort", "fileModified", "fileSize"],
|
||||
dataField = dataFields[sortColumn],
|
||||
sortField = sortFields[sortColumn],
|
||||
sortValue,
|
||||
fileName,
|
||||
fileIsDir,
|
||||
comparisonFunction,
|
||||
lower,
|
||||
middle,
|
||||
upper,
|
||||
rows = 0,
|
||||
i;
|
||||
|
||||
clear();
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
: function(a, b) { return a > b; }
|
||||
|
||||
for (i = 0; i < model.count; i++) {
|
||||
fileName = model.getItem(i, "fileName");
|
||||
fileIsDir = model.getItem(i, "fileIsDir");
|
||||
|
||||
sortValue = model.getItem(i, dataField);
|
||||
if (dataField === "fileName") {
|
||||
// Directories first by prefixing a "*".
|
||||
// Case-insensitive.
|
||||
sortValue = (fileIsDir ? "*" : "") + sortValue.toLowerCase();
|
||||
}
|
||||
|
||||
lower = 0;
|
||||
upper = rows;
|
||||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
lessThan = false;
|
||||
lower = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
filePath: model.getItem(i, "filePath"),
|
||||
fileIsDir: fileIsDir,
|
||||
fileNameSort: (fileIsDir ? "*" : "") + fileName.toLowerCase()
|
||||
});
|
||||
|
||||
rows++;
|
||||
}
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
Table {
|
||||
id: fileTableView
|
||||
colorScheme: hifi.colorSchemes.light
|
||||
anchors {
|
||||
top: navControls.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: currentSelection.top
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height
|
||||
}
|
||||
headerVisible: !selectDirectory
|
||||
onDoubleClicked: navigateToRow(row);
|
||||
focus: true
|
||||
Keys.onReturnPressed: navigateToCurrentRow();
|
||||
Keys.onEnterPressed: navigateToCurrentRow();
|
||||
|
||||
sortIndicatorColumn: 0
|
||||
sortIndicatorOrder: Qt.AscendingOrder
|
||||
sortIndicatorVisible: true
|
||||
|
||||
model: fileTableModel
|
||||
|
||||
function updateSort() {
|
||||
model.sortOrder = sortIndicatorOrder;
|
||||
model.sortColumn = sortIndicatorColumn;
|
||||
model.update();
|
||||
}
|
||||
|
||||
onSortIndicatorColumnChanged: { updateSort(); }
|
||||
|
||||
onSortIndicatorOrderChanged: { updateSort(); }
|
||||
|
||||
itemDelegate: Item {
|
||||
clip: true
|
||||
|
||||
//FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
|
||||
//FontLoader { id: firaSansRegular; source: "../../fonts/FiraSans-Regular.ttf"; }
|
||||
|
||||
FiraSansSemiBold {
|
||||
text: getText();
|
||||
elide: styleData.elideMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: hifi.dimensions.tablePadding
|
||||
right: parent.right
|
||||
rightMargin: hifi.dimensions.tablePadding
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
size: hifi.fontSizes.tableText
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
//font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir)
|
||||
//? firaSansSemiBold.name : firaSansRegular.name
|
||||
|
||||
function getText() {
|
||||
if (styleData.row === -1) {
|
||||
return styleData.value;
|
||||
}
|
||||
|
||||
switch (styleData.column) {
|
||||
case 1: return fileTableView.model.get(styleData.row).fileIsDir ? "" : styleData.value;
|
||||
case 2: return fileTableView.model.get(styleData.row).fileIsDir ? "" : formatSize(styleData.value);
|
||||
default: return styleData.value;
|
||||
}
|
||||
}
|
||||
function formatSize(size) {
|
||||
var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ];
|
||||
var suffixIndex = 0
|
||||
while ((size / 1024.0) > 1.1) {
|
||||
size /= 1024.0;
|
||||
++suffixIndex;
|
||||
}
|
||||
|
||||
size = Math.round(size*1000)/1000;
|
||||
size = size.toLocaleString()
|
||||
|
||||
return size + " " + suffixes[suffixIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableViewColumn {
|
||||
id: fileNameColumn
|
||||
role: "fileName"
|
||||
title: "Name"
|
||||
width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width
|
||||
movable: false
|
||||
resizable: true
|
||||
}
|
||||
TableViewColumn {
|
||||
id: fileMofifiedColumn
|
||||
role: "fileModified"
|
||||
title: "Date"
|
||||
width: 0.3 * fileTableView.width
|
||||
movable: false
|
||||
resizable: true
|
||||
visible: !selectDirectory
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "fileSize"
|
||||
title: "Size"
|
||||
width: fileTableView.width - fileNameColumn.width - fileMofifiedColumn.width
|
||||
movable: false
|
||||
resizable: true
|
||||
visible: !selectDirectory
|
||||
}
|
||||
|
||||
function navigateToRow(row) {
|
||||
currentRow = row;
|
||||
navigateToCurrentRow();
|
||||
}
|
||||
|
||||
function navigateToCurrentRow() {
|
||||
var row = fileTableView.currentRow
|
||||
var isFolder = model.isFolder(row);
|
||||
var file = model.get(row).filePath;
|
||||
if (isFolder) {
|
||||
fileTableView.model.folder = helper.pathToUrl(file);
|
||||
} else {
|
||||
okAction.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
property string prefix: ""
|
||||
|
||||
function addToPrefix(event) {
|
||||
if (!event.text || event.text === "") {
|
||||
return false;
|
||||
}
|
||||
var newPrefix = prefix + event.text.toLowerCase();
|
||||
var matchedIndex = -1;
|
||||
for (var i = 0; i < model.count; ++i) {
|
||||
var name = model.get(i).fileName.toLowerCase();
|
||||
if (0 === name.indexOf(newPrefix)) {
|
||||
matchedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedIndex !== -1) {
|
||||
fileTableView.selection.clear();
|
||||
fileTableView.selection.select(matchedIndex);
|
||||
fileTableView.currentRow = matchedIndex;
|
||||
fileTableView.prefix = newPrefix;
|
||||
}
|
||||
prefixClearTimer.restart();
|
||||
return true;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: prefixClearTimer
|
||||
interval: 1000
|
||||
repeat: false
|
||||
running: false
|
||||
onTriggered: fileTableView.prefix = "";
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Backspace:
|
||||
case Qt.Key_Tab:
|
||||
case Qt.Key_Backtab:
|
||||
event.accepted = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addToPrefix(event)) {
|
||||
event.accepted = true
|
||||
} else {
|
||||
event.accepted = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: currentSelection
|
||||
label: selectDirectory ? "Directory:" : "File name:"
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: selectionType.visible ? selectionType.left: parent.right
|
||||
rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0
|
||||
bottom: keyboard.top
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
readOnly: !root.saveDialog
|
||||
activeFocusOnTab: !readOnly
|
||||
onActiveFocusChanged: if (activeFocus) { selectAll(); }
|
||||
onAccepted: okAction.trigger();
|
||||
}
|
||||
|
||||
FileTypeSelection {
|
||||
id: selectionType
|
||||
anchors {
|
||||
top: currentSelection.top
|
||||
left: buttonRow.left
|
||||
right: parent.right
|
||||
}
|
||||
visible: !selectDirectory && filtersCount > 1
|
||||
KeyNavigation.left: fileTableView
|
||||
KeyNavigation.right: openButton
|
||||
}
|
||||
|
||||
Keyboard {
|
||||
id: keyboard
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: buttonRow.top
|
||||
bottomMargin: visible ? hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.y
|
||||
|
||||
Button {
|
||||
id: openButton
|
||||
color: hifi.buttons.blue
|
||||
action: okAction
|
||||
Keys.onReturnPressed: okAction.trigger()
|
||||
KeyNavigation.up: selectionType
|
||||
KeyNavigation.left: selectionType
|
||||
KeyNavigation.right: cancelButton
|
||||
}
|
||||
|
||||
Button {
|
||||
id: cancelButton
|
||||
action: cancelAction
|
||||
KeyNavigation.up: selectionType
|
||||
KeyNavigation.left: openButton
|
||||
KeyNavigation.right: fileTableView.contentItem
|
||||
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: okAction
|
||||
text: currentSelection.text ? (root.selectDirectory && fileTableView.currentRow === -1 ? "Choose" : (root.saveDialog ? "Save" : "Open")) : "Open"
|
||||
enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
|
||||
onTriggered: {
|
||||
if (!root.selectDirectory && !d.currentSelectionIsFolder
|
||||
|| root.selectDirectory && fileTableView.currentRow === -1) {
|
||||
okActionTimer.start();
|
||||
} else {
|
||||
fileTableView.navigateToCurrentRow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: okActionTimer
|
||||
interval: 50
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (!root.saveDialog) {
|
||||
selectedFile(d.currentSelectionUrl);
|
||||
profileRoot.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the ambiguity between different cases
|
||||
// * typed name (with or without extension)
|
||||
// * full path vs relative vs filename only
|
||||
var selection = helper.saveHelper(currentSelection.text, root.dir, selectionType.currentFilter);
|
||||
|
||||
if (!selection) {
|
||||
desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Warning, text: "Unable to parse selection" })
|
||||
return;
|
||||
}
|
||||
|
||||
if (helper.urlIsDir(selection)) {
|
||||
root.dir = selection;
|
||||
currentSelection.text = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the file is a valid target
|
||||
if (!helper.urlIsWritable(selection)) {
|
||||
desktop.messageBox({
|
||||
icon: OriginalDialogs.StandardIcon.Warning,
|
||||
text: "Unable to write to location " + selection
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
if (helper.urlExists(selection)) {
|
||||
var messageBox = desktop.messageBox({
|
||||
icon: OriginalDialogs.StandardIcon.Question,
|
||||
buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
|
||||
text: "Do you wish to overwrite " + selection + "?",
|
||||
});
|
||||
var result = messageBox.exec();
|
||||
if (OriginalDialogs.StandardButton.Yes !== result) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Selecting " + selection)
|
||||
selectedFile(selection);
|
||||
//root.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: cancelAction
|
||||
text: "Cancel"
|
||||
onTriggered: { profileRoot.pop(); }
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Backspace:
|
||||
event.accepted = d.navigateUp();
|
||||
break;
|
||||
|
||||
case Qt.Key_Home:
|
||||
event.accepted = d.navigateHome();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
//
|
||||
// TabletPreferencesDialog.qml
|
||||
//
|
||||
// Created by Dante Ruiz on 9 Feb 2017
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
|
||||
import "."
|
||||
import "./preferences"
|
||||
import "../../../styles-uit"
|
||||
import "../../../controls-uit" as HifiControls
|
||||
|
||||
Item {
|
||||
id: dialog
|
||||
width: 480
|
||||
height: 720
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
property var sections: []
|
||||
property var showCategories: []
|
||||
|
||||
function saveAll() {
|
||||
for (var i = 0; i < sections.length; ++i) {
|
||||
var section = sections[i];
|
||||
section.saveAll();
|
||||
}
|
||||
}
|
||||
|
||||
function restoreAll() {
|
||||
for (var i = 0; i < sections.length; ++i) {
|
||||
var section = sections[i];
|
||||
section.restoreAll();
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: main
|
||||
height: parent.height - 40
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: footer.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0
|
||||
color: "#2b2b2b"
|
||||
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
position: 1
|
||||
color: "#0f212e"
|
||||
}
|
||||
}
|
||||
Flickable {
|
||||
id: scrollView
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
contentWidth: parent.width
|
||||
contentHeight: getSectionsHeight();
|
||||
Column {
|
||||
width: 480
|
||||
Component {
|
||||
id: sectionBuilder
|
||||
Section {}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
var categories = Preferences.categories;
|
||||
var i;
|
||||
|
||||
// build a map of valid categories.
|
||||
var categoryMap = {};
|
||||
for (i = 0; i < categories.length; i++) {
|
||||
categoryMap[categories[i]] = true;
|
||||
}
|
||||
|
||||
// create a section for each valid category in showCategories
|
||||
// NOTE: the sort order of items in the showCategories array is the same order in the dialog.
|
||||
for (i = 0; i < showCategories.length; i++) {
|
||||
if (categoryMap[showCategories[i]]) {
|
||||
sections.push(sectionBuilder.createObject(prefControls, {name: showCategories[i]}));
|
||||
}
|
||||
}
|
||||
|
||||
if (sections.length) {
|
||||
// Default sections to expanded/collapsed as appropriate for dialog.
|
||||
if (sections.length === 1) {
|
||||
sections[0].collapsable = false
|
||||
sections[0].expanded = true
|
||||
} else {
|
||||
for (i = 0; i < sections.length; i++) {
|
||||
sections[i].collapsable = false;
|
||||
sections[i].expanded = true;
|
||||
}
|
||||
}
|
||||
sections[0].isFirst = true;
|
||||
sections[sections.length - 1].isLast = true;
|
||||
}
|
||||
|
||||
scrollView.contentHeight = scrollView.getSectionsHeight();
|
||||
|
||||
}
|
||||
|
||||
|
||||
Column {
|
||||
id: prefControls
|
||||
width: 480
|
||||
}
|
||||
}
|
||||
|
||||
function getSectionsHeight() {
|
||||
var totalHeight = 0;
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
totalHeight += sections[i].height + sections[i].getPreferencesHeight();
|
||||
}
|
||||
console.log(totalHeight);
|
||||
return totalHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: footer
|
||||
height: 40
|
||||
|
||||
anchors {
|
||||
top: main.bottom
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0
|
||||
color: "#2b2b2b"
|
||||
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
position: 1
|
||||
color: "#0f212e"
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors {
|
||||
top: parent,top
|
||||
right: parent.right
|
||||
rightMargin: hifi.dimensions.contentMargin.x
|
||||
}
|
||||
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
HifiControls.Button {
|
||||
text: "Save changes"
|
||||
color: hifi.buttons.blue
|
||||
onClicked: root.saveAll()
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
text: "Cancel"
|
||||
color: hifi.buttons.white
|
||||
onClicked: root.restoreAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Preference.qml
|
||||
//
|
||||
// Created by Bradley Dante Ruiz on 13 Feb 2017
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
Item {
|
||||
id: root
|
||||
anchors { left: parent.left; right: parent.right }
|
||||
property var preference;
|
||||
property string label: preference ? preference.name : "";
|
||||
property bool isFirstCheckBox;
|
||||
Component.onCompleted: {
|
||||
if (preference) {
|
||||
preference.load();
|
||||
enabled = Qt.binding(function() { return preference.enabled; } );
|
||||
}
|
||||
}
|
||||
|
||||
function restore() { }
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
//
|
||||
// Section.qml
|
||||
//
|
||||
// Created by Bradley Dante Ruiz on 13 Feb 2017
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import Hifi 1.0
|
||||
|
||||
import "../../../../dialogs/preferences"
|
||||
import "../../../../controls-uit" as HiFiControls
|
||||
import "../../../../styles-uit"
|
||||
import "."
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
property bool collapsable: false
|
||||
property bool expanded: false
|
||||
property bool isFirst: false
|
||||
property bool isLast: false
|
||||
property string name: "Header"
|
||||
property real spacing: 8
|
||||
default property alias preferences: contentContainer.children
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
function saveAll() {
|
||||
for (var i = 0; i < d.preferences.length; ++i) {
|
||||
var preference = d.preferences[i];
|
||||
preference.save();
|
||||
}
|
||||
}
|
||||
|
||||
function restoreAll() {
|
||||
for (var i = 0; i < d.preferences.length; ++i) {
|
||||
var preference = d.preferences[i];
|
||||
preference.restore();
|
||||
}
|
||||
}
|
||||
|
||||
function getPreferencesHeight() {
|
||||
var height = 0;
|
||||
for (var index = 0; index < d.preferences.length; index++) {
|
||||
height += d.preferences[index].height;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
children: [ contentContainer ]
|
||||
|
||||
height: contentContainer.height + (contentContainer.isCollapsed ? 0 : hifi.dimensions.controlInterlineHeight)
|
||||
|
||||
Component.onCompleted: d.buildPreferences();
|
||||
|
||||
HiFiControls.TabletContentSection {
|
||||
id: contentContainer
|
||||
name: root.name
|
||||
isFirst: root.isFirst
|
||||
isCollapsible: root.collapsable
|
||||
isCollapsed: !root.expanded
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 0
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property var editableBuilder: Component { EditablePreference { } }
|
||||
property var browsableBuilder: Component { TabletBrowsablePreference { } }
|
||||
property var spinnerBuilder: Component { SpinBoxPreference { } }
|
||||
property var checkboxBuilder: Component { CheckBoxPreference { } }
|
||||
property var sliderBuilder: Component { SliderPreference { } }
|
||||
property var avatarBuilder: Component { AvatarPreference { } }
|
||||
property var buttonBuilder: Component { ButtonPreference { } }
|
||||
property var comboBoxBuilder: Component { ComboBoxPreference { } }
|
||||
property var preferences: []
|
||||
property int checkBoxCount: 0
|
||||
|
||||
function buildPreferences() {
|
||||
var categoryPreferences = Preferences.preferencesByCategory[root.name];
|
||||
if (categoryPreferences) {
|
||||
console.log("Category " + root.name + " with " + categoryPreferences.length + " preferences");
|
||||
for (var j = 0; j < categoryPreferences.length; ++j) {
|
||||
buildPreference(categoryPreferences[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildPreference(preference) {
|
||||
console.log("\tPreference type " + preference.type + " name " + preference.name)
|
||||
var builder;
|
||||
switch (preference.type) {
|
||||
case Preference.Editable:
|
||||
checkBoxCount = 0;
|
||||
builder = editableBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Browsable:
|
||||
checkBoxCount = 0;
|
||||
builder = browsableBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Spinner:
|
||||
checkBoxCount = 0;
|
||||
builder = spinnerBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Slider:
|
||||
checkBoxCount = 0;
|
||||
builder = sliderBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Checkbox:
|
||||
checkBoxCount++;
|
||||
builder = checkboxBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Avatar:
|
||||
checkBoxCount = 0;
|
||||
builder = avatarBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Button:
|
||||
checkBoxCount = 0;
|
||||
builder = buttonBuilder;
|
||||
break;
|
||||
|
||||
case Preference.ComboBox:
|
||||
checkBoxCount = 0;
|
||||
builder = comboBoxBuilder;
|
||||
break;
|
||||
};
|
||||
|
||||
if (builder) {
|
||||
preferences.push(builder.createObject(contentContainer, { preference: preference, isFirstCheckBox: (checkBoxCount === 1) }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// BrowsablePreference.qml
|
||||
//
|
||||
// Created by Dante Ruiz Davis on 13 Feb 2017
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
import "../../../../dialogs"
|
||||
import "../../../../controls-uit"
|
||||
import "../"
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
property alias text: dataTextField.text
|
||||
property alias placeholderText: dataTextField.placeholderText
|
||||
height: control.height + hifi.dimensions.controlInterlineHeight
|
||||
|
||||
Component.onCompleted: {
|
||||
dataTextField.text = preference.value;
|
||||
}
|
||||
|
||||
function save() {
|
||||
preference.value = dataTextField.text;
|
||||
preference.save();
|
||||
}
|
||||
|
||||
Item {
|
||||
id: control
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
height: Math.max(dataTextField.controlHeight, button.height)
|
||||
|
||||
TextField {
|
||||
id: dataTextField
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: button.left
|
||||
rightMargin: hifi.dimensions.contentSpacing.x
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
label: root.label
|
||||
placeholderText: root.placeholderText
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fileBrowserBuilder;
|
||||
TabletFileDialog { selectDirectory: true }
|
||||
}
|
||||
|
||||
Button {
|
||||
id: button
|
||||
text: preference.browseLabel
|
||||
anchors {
|
||||
right: parent.right
|
||||
verticalCenter: dataTextField.verticalCenter
|
||||
}
|
||||
onClicked: {
|
||||
var browser = fileBrowserBuilder.createObject({
|
||||
selectDirectory: true,
|
||||
dir: fileDialogHelper.pathToUrl(preference.value)
|
||||
});
|
||||
|
||||
browser.selectedFile.connect(function(fileUrl){
|
||||
console.log(fileUrl);
|
||||
dataTextField.text = fileDialogHelper.urlToPath(fileUrl);
|
||||
});
|
||||
|
||||
profileRoot.push(browser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -296,6 +296,10 @@ Fadable {
|
|||
// fall through
|
||||
|
||||
default:
|
||||
if (MyAvatar.isAway) {
|
||||
// If stuck in a window and a key is pressed this should exit paused mode
|
||||
MyAvatar.isAway = false;
|
||||
}
|
||||
// Consume unmodified keyboard entries while the window is focused, to prevent them
|
||||
// from propagating to the application
|
||||
if (event.modifiers === Qt.NoModifier) {
|
||||
|
|
|
@ -6853,3 +6853,8 @@ void Application::updateThreadPoolCount() const {
|
|||
qCDebug(interfaceapp) << "Setting thread pool size to " << threadPoolSize;
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(threadPoolSize);
|
||||
}
|
||||
|
||||
void Application::toggleMuteAudio() {
|
||||
auto menu = Menu::getInstance();
|
||||
menu->setIsOptionChecked(MenuOption::MuteAudio, !menu->isOptionChecked(MenuOption::MuteAudio));
|
||||
}
|
||||
|
|
|
@ -386,6 +386,8 @@ public slots:
|
|||
|
||||
void addAssetToWorldMessageClose();
|
||||
|
||||
Q_INVOKABLE void toggleMuteAudio();
|
||||
|
||||
private slots:
|
||||
void showDesktop();
|
||||
void clearDomainOctreeDetails();
|
||||
|
|
|
@ -88,6 +88,7 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
|||
_isPushing(false),
|
||||
_isBeingPushed(false),
|
||||
_isBraking(false),
|
||||
_isAway(false),
|
||||
_boomLength(ZOOM_DEFAULT),
|
||||
_yawSpeed(YAW_SPEED_DEFAULT),
|
||||
_pitchSpeed(PITCH_SPEED_DEFAULT),
|
||||
|
@ -2361,6 +2362,15 @@ bool MyAvatar::hasDriveInput() const {
|
|||
return fabsf(_driveKeys[TRANSLATE_X]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Y]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Z]) > 0.0f;
|
||||
}
|
||||
|
||||
void MyAvatar::setAway(bool value) {
|
||||
_isAway = value;
|
||||
if (_isAway) {
|
||||
emit wentAway();
|
||||
} else {
|
||||
emit wentActive();
|
||||
}
|
||||
}
|
||||
|
||||
// The resulting matrix is used to render the hand controllers, even if the camera is decoupled from the avatar.
|
||||
// Specificly, if we are rendering using a third person camera. We would like to render the hand controllers in front of the camera,
|
||||
// not in front of the avatar.
|
||||
|
|
|
@ -82,6 +82,7 @@ class MyAvatar : public Avatar {
|
|||
Q_PROPERTY(controller::Pose rightHandTipPose READ getRightHandTipPose)
|
||||
|
||||
Q_PROPERTY(float energy READ getEnergy WRITE setEnergy)
|
||||
Q_PROPERTY(float isAway READ getIsAway WRITE setAway)
|
||||
|
||||
Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled)
|
||||
Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled)
|
||||
|
@ -328,6 +329,8 @@ signals:
|
|||
void energyChanged(float newEnergy);
|
||||
void positionGoneTo();
|
||||
void onLoadComplete();
|
||||
void wentAway();
|
||||
void wentActive();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -385,6 +388,7 @@ private:
|
|||
bool _isPushing;
|
||||
bool _isBeingPushed;
|
||||
bool _isBraking;
|
||||
bool _isAway;
|
||||
|
||||
float _boomLength;
|
||||
float _yawSpeed; // degrees/sec
|
||||
|
@ -521,6 +525,8 @@ private:
|
|||
float getEnergy();
|
||||
void setEnergy(float value);
|
||||
bool didTeleport();
|
||||
bool getIsAway() const { return _isAway; }
|
||||
void setAway(bool value);
|
||||
};
|
||||
|
||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include <AddressManager.h>
|
||||
#include "scripting/AccountScriptingInterface.h"
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
#include <Preferences.h>
|
||||
#include "FileDialogHelper.h"
|
||||
|
||||
static const float DPI = 30.47f;
|
||||
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
|
||||
|
@ -158,6 +160,7 @@ void Web3DOverlay::loadSourceURL() {
|
|||
_webSurface->getRootContext()->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
_webSurface->getRootContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
_webSurface->getRootContext()->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
_webSurface->getRootContext()->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
|
||||
|
||||
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
|
@ -166,6 +169,7 @@ void Web3DOverlay::loadSourceURL() {
|
|||
_webSurface->getRootContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||
_webSurface->getRootContext()->setContextProperty("Account", AccountScriptingInterface::getInstance());
|
||||
_webSurface->getRootContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
_webSurface->getRootContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
|
||||
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data());
|
||||
|
||||
// Override min fps for tablet UI, for silky smooth scrolling
|
||||
|
|
|
@ -213,10 +213,11 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr
|
|||
}
|
||||
}
|
||||
|
||||
void TabletProxy::gotoMenuScreen() {
|
||||
void TabletProxy::gotoMenuScreen(const QString& submenu) {
|
||||
if (_qmlTabletRoot) {
|
||||
if (_state != State::Menu) {
|
||||
removeButtonsFromHomeScreen();
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "setOption", Q_ARG(const QVariant&, QVariant(submenu)));
|
||||
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
||||
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen()), Qt::DirectConnection);
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL)));
|
||||
|
@ -338,6 +339,15 @@ void TabletProxy::removeButton(QObject* tabletButtonProxy) {
|
|||
}
|
||||
}
|
||||
|
||||
void TabletProxy::updateMicEnabled(const bool micOn) {
|
||||
auto tablet = getQmlTablet();
|
||||
if (!tablet) {
|
||||
//qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
||||
} else {
|
||||
QMetaObject::invokeMethod(tablet, "setMicEnabled", Qt::AutoConnection, Q_ARG(QVariant, QVariant(micOn)));
|
||||
}
|
||||
}
|
||||
|
||||
void TabletProxy::updateAudioBar(const double micLevel) {
|
||||
auto tablet = getQmlTablet();
|
||||
if (!tablet) {
|
||||
|
@ -388,13 +398,13 @@ void TabletProxy::addButtonsToMenuScreen() {
|
|||
}
|
||||
|
||||
QQuickItem* VrMenu = loader->findChild<QQuickItem*>("tabletMenu");
|
||||
if (!VrMenu) {
|
||||
return;
|
||||
if (VrMenu) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QObject* menu = offscreenUi->getRootMenu();
|
||||
QMetaObject::invokeMethod(VrMenu, "setRootMenu", Qt::AutoConnection, Q_ARG(QVariant, QVariant::fromValue(menu)));
|
||||
}
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QObject* menu = offscreenUi->getRootMenu();
|
||||
QMetaObject::invokeMethod(VrMenu, "setRootMenu", Qt::AutoConnection, Q_ARG(QVariant, QVariant::fromValue(menu)));
|
||||
QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen()));
|
||||
}
|
||||
|
||||
void TabletProxy::removeButtonsFromHomeScreen() {
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
|
||||
void setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface);
|
||||
|
||||
Q_INVOKABLE void gotoMenuScreen();
|
||||
Q_INVOKABLE void gotoMenuScreen(const QString& submenu = "");
|
||||
|
||||
/**jsdoc
|
||||
* transition to the home screen
|
||||
|
@ -108,6 +108,13 @@ public:
|
|||
*/
|
||||
Q_INVOKABLE void removeButton(QObject* tabletButtonProxy);
|
||||
|
||||
/**jsdoc
|
||||
* Updates the tablet's mic enabled state
|
||||
* @function TabletProxy#updateMicEnabled
|
||||
* @param micEnabled {bool} mic enabled state
|
||||
*/
|
||||
Q_INVOKABLE void updateMicEnabled(const bool micEnabled);
|
||||
|
||||
/**jsdoc
|
||||
* Updates the audio bar in tablet to reflect latest mic level
|
||||
* @function TabletProxy#updateAudioBar
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
var DEFAULT_SCRIPTS = [
|
||||
"system/progress.js",
|
||||
"system/away.js",
|
||||
"system/mute.js",
|
||||
"system/audio.js",
|
||||
"system/hmd.js",
|
||||
"system/menu.js",
|
||||
"system/bubble.js",
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
//
|
||||
// goto.js
|
||||
// scripts/system/
|
||||
// audio.js
|
||||
//
|
||||
// Created by Howard Stearns on 2 Jun 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
|
@ -14,22 +13,33 @@
|
|||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
var button;
|
||||
var buttonName = "MUTE";
|
||||
var TOOLBAR_BUTTON_NAME = "MUTE";
|
||||
var TABLET_BUTTON_NAME = "AUDIO";
|
||||
var toolBar = null;
|
||||
var tablet = null;
|
||||
var isHUDUIEnabled = Settings.getValue("HUDUIEnabled");
|
||||
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
|
||||
|
||||
function onMuteToggled() {
|
||||
button.editProperties({isActive: AudioDevice.getMuted()});
|
||||
if (isHUDUIEnabled) {
|
||||
button.editProperties({ isActive: AudioDevice.getMuted() });
|
||||
}
|
||||
}
|
||||
function onClicked(){
|
||||
var menuItem = "Mute Microphone";
|
||||
Menu.setIsOptionChecked(menuItem, !Menu.isOptionChecked(menuItem));
|
||||
if (isHUDUIEnabled) {
|
||||
var menuItem = "Mute Microphone";
|
||||
Menu.setIsOptionChecked(menuItem, !Menu.isOptionChecked(menuItem));
|
||||
} else {
|
||||
var entity = HMD.tabletID;
|
||||
Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) });
|
||||
tablet.gotoMenuScreen("Audio");
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings.getValue("HUDUIEnabled")) {
|
||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
button = toolBar.addButton({
|
||||
objectName: buttonName,
|
||||
objectName: TOOLBAR_BUTTON_NAME,
|
||||
imageURL: Script.resolvePath("assets/images/tools/mic.svg"),
|
||||
visible: true,
|
||||
alpha: 0.9
|
||||
|
@ -37,12 +47,8 @@ if (Settings.getValue("HUDUIEnabled")) {
|
|||
} else {
|
||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
button = tablet.addButton({
|
||||
icon: "icons/tablet-icons/mic-unmute-i.svg",
|
||||
hoverIcon: "icons/tablet-icons/mic-mute-i.svg",
|
||||
activeIcon: "icons/tablet-icons/mic-mute-a.svg",
|
||||
activeHoverIcon: "icons/tablet-icons/mic-unmute-a.svg",
|
||||
text: "MUTE",
|
||||
activeText: "UNMUTE",
|
||||
icon: "icons/tablet-icons/mic-i.svg",
|
||||
text: TABLET_BUTTON_NAME,
|
||||
sortOrder: 1
|
||||
});
|
||||
}
|
||||
|
@ -58,7 +64,7 @@ Script.scriptEnding.connect(function () {
|
|||
tablet.removeButton(button);
|
||||
}
|
||||
if (toolBar) {
|
||||
toolBar.removeButton(buttonName);
|
||||
toolBar.removeButton(TOOLBAR_BUTTON_NAME);
|
||||
}
|
||||
});
|
||||
|
|
@ -165,9 +165,36 @@ function goAway(fromStartup) {
|
|||
if (!isEnabled || isAway) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If we're entering away mode from some other state than startup, then we create our move timer immediately.
|
||||
// However if we're just stating up, we need to delay this process so that we don't think the initial teleport
|
||||
// is actually a move.
|
||||
if (fromStartup === undefined || fromStartup === false) {
|
||||
avatarMovedInterval = Script.setInterval(ifAvatarMovedGoActive, BASIC_TIMER_INTERVAL);
|
||||
} else {
|
||||
var WAIT_FOR_MOVE_ON_STARTUP = 3000; // 3 seconds
|
||||
Script.setTimeout(function() {
|
||||
avatarMovedInterval = Script.setInterval(ifAvatarMovedGoActive, BASIC_TIMER_INTERVAL);
|
||||
}, WAIT_FOR_MOVE_ON_STARTUP);
|
||||
}
|
||||
|
||||
UserActivityLogger.toggledAway(true);
|
||||
MyAvatar.isAway = true;
|
||||
}
|
||||
|
||||
function goActive() {
|
||||
if (!isAway) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserActivityLogger.toggledAway(false);
|
||||
MyAvatar.isAway = false;
|
||||
}
|
||||
|
||||
MyAvatar.wentAway.connect(setAwayProperties)
|
||||
MyAvatar.wentActive.connect(setActiveProperties)
|
||||
|
||||
function setAwayProperties() {
|
||||
isAway = true;
|
||||
wasMuted = AudioDevice.getMuted();
|
||||
if (!wasMuted) {
|
||||
|
@ -189,27 +216,9 @@ function goAway(fromStartup) {
|
|||
wasHmdMounted = HMD.mounted; // always remember the correct state
|
||||
|
||||
avatarPosition = MyAvatar.position;
|
||||
|
||||
// If we're entering away mode from some other state than startup, then we create our move timer immediately.
|
||||
// However if we're just stating up, we need to delay this process so that we don't think the initial teleport
|
||||
// is actually a move.
|
||||
if (fromStartup === undefined || fromStartup === false) {
|
||||
avatarMovedInterval = Script.setInterval(ifAvatarMovedGoActive, BASIC_TIMER_INTERVAL);
|
||||
} else {
|
||||
var WAIT_FOR_MOVE_ON_STARTUP = 3000; // 3 seconds
|
||||
Script.setTimeout(function() {
|
||||
avatarMovedInterval = Script.setInterval(ifAvatarMovedGoActive, BASIC_TIMER_INTERVAL);
|
||||
}, WAIT_FOR_MOVE_ON_STARTUP);
|
||||
}
|
||||
}
|
||||
|
||||
function goActive() {
|
||||
if (!isAway) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserActivityLogger.toggledAway(false);
|
||||
|
||||
function setActiveProperties() {
|
||||
isAway = false;
|
||||
if (!wasMuted) {
|
||||
AudioDevice.toggleMute();
|
||||
|
|
57
scripts/system/generalSettings.js
Normal file
57
scripts/system/generalSettings.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
"use strict";
|
||||
|
||||
//
|
||||
// generalSettings.js
|
||||
// scripts/system/
|
||||
//
|
||||
// Created by Dante Ruiz on 9 Feb 2017
|
||||
// Copyright 2016 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
|
||||
//
|
||||
/* globals Tablet, Toolbars, Script, HMD, DialogsManager */
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
var button;
|
||||
var buttonName = "Settings";
|
||||
var toolBar = null;
|
||||
var tablet = null;
|
||||
var settings = "TabletGeneralSettings.qml"
|
||||
function onClicked(){
|
||||
if (tablet) {
|
||||
tablet.loadQMLSource(settings);
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings.getValue("HUDUIEnabled")) {
|
||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
button = toolBar.addButton({
|
||||
objectName: buttonName,
|
||||
imageURL: Script.resolvePath("assets/images/tools/directory.svg"),
|
||||
visible: true,
|
||||
alpha: 0.9
|
||||
});
|
||||
} else {
|
||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
button = tablet.addButton({
|
||||
icon: "icons/tablet-icons/goto-i.svg",
|
||||
text: buttonName,
|
||||
sortOrder: 8
|
||||
});
|
||||
}
|
||||
|
||||
button.clicked.connect(onClicked);
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
button.clicked.disconnect(onClicked);
|
||||
if (tablet) {
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
if (toolBar) {
|
||||
toolBar.removeButton(buttonName);
|
||||
}
|
||||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
|
@ -52,33 +52,7 @@ var selectedInputMenu = "";
|
|||
var selectedOutputMenu = "";
|
||||
|
||||
function setupAudioMenus() {
|
||||
Menu.addMenu("Audio > Devices");
|
||||
Menu.addSeparator("Audio > Devices","Output Audio Device");
|
||||
|
||||
var outputDeviceSetting = Settings.getValue(OUTPUT_DEVICE_SETTING);
|
||||
var outputDevices = AudioDevice.getOutputDevices();
|
||||
var selectedOutputDevice = AudioDevice.getOutputDevice();
|
||||
if (outputDevices.indexOf(outputDeviceSetting) != -1 && selectedOutputDevice != outputDeviceSetting) {
|
||||
if (AudioDevice.setOutputDevice(outputDeviceSetting)) {
|
||||
selectedOutputDevice = outputDeviceSetting;
|
||||
}
|
||||
}
|
||||
print("audio output devices: " + outputDevices);
|
||||
for(var i = 0; i < outputDevices.length; i++) {
|
||||
var thisDeviceSelected = (outputDevices[i] == selectedOutputDevice);
|
||||
var menuItem = "Use " + outputDevices[i] + " for Output";
|
||||
Menu.addMenuItem({
|
||||
menuName: "Audio > Devices",
|
||||
menuItemName: menuItem,
|
||||
isCheckable: true,
|
||||
isChecked: thisDeviceSelected
|
||||
});
|
||||
if (thisDeviceSelected) {
|
||||
selectedOutputMenu = menuItem;
|
||||
}
|
||||
}
|
||||
|
||||
Menu.addSeparator("Audio > Devices","Input Audio Device");
|
||||
Menu.addSeparator("Audio", "Input Audio Device");
|
||||
|
||||
var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING);
|
||||
var inputDevices = AudioDevice.getInputDevices();
|
||||
|
@ -93,7 +67,7 @@ function setupAudioMenus() {
|
|||
var thisDeviceSelected = (inputDevices[i] == selectedInputDevice);
|
||||
var menuItem = "Use " + inputDevices[i] + " for Input";
|
||||
Menu.addMenuItem({
|
||||
menuName: "Audio > Devices",
|
||||
menuName: "Audio",
|
||||
menuItemName: menuItem,
|
||||
isCheckable: true,
|
||||
isChecked: thisDeviceSelected
|
||||
|
@ -102,6 +76,31 @@ function setupAudioMenus() {
|
|||
selectedInputMenu = menuItem;
|
||||
}
|
||||
}
|
||||
|
||||
Menu.addSeparator("Audio", "Output Audio Device");
|
||||
|
||||
var outputDeviceSetting = Settings.getValue(OUTPUT_DEVICE_SETTING);
|
||||
var outputDevices = AudioDevice.getOutputDevices();
|
||||
var selectedOutputDevice = AudioDevice.getOutputDevice();
|
||||
if (outputDevices.indexOf(outputDeviceSetting) != -1 && selectedOutputDevice != outputDeviceSetting) {
|
||||
if (AudioDevice.setOutputDevice(outputDeviceSetting)) {
|
||||
selectedOutputDevice = outputDeviceSetting;
|
||||
}
|
||||
}
|
||||
print("audio output devices: " + outputDevices);
|
||||
for (var i = 0; i < outputDevices.length; i++) {
|
||||
var thisDeviceSelected = (outputDevices[i] == selectedOutputDevice);
|
||||
var menuItem = "Use " + outputDevices[i] + " for Output";
|
||||
Menu.addMenuItem({
|
||||
menuName: "Audio",
|
||||
menuItemName: menuItem,
|
||||
isCheckable: true,
|
||||
isChecked: thisDeviceSelected
|
||||
});
|
||||
if (thisDeviceSelected) {
|
||||
selectedOutputMenu = menuItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onDevicechanged() {
|
||||
|
|
|
@ -53,8 +53,11 @@
|
|||
|
||||
function updateShowTablet() {
|
||||
if (tabletShown) {
|
||||
var MUTE_MICROPHONE_MENU_ITEM = "Mute Microphone";
|
||||
var currentMicEnabled = !Menu.isOptionChecked(MUTE_MICROPHONE_MENU_ITEM);
|
||||
var currentMicLevel = getMicLevel();
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
tablet.updateMicEnabled(currentMicEnabled);
|
||||
tablet.updateAudioBar(currentMicLevel);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue