Simplified UI v1

This commit is contained in:
Zach Fox 2019-05-10 10:49:25 -07:00
parent 930032bcc6
commit 314c04ab96
45 changed files with 5094 additions and 1 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,227 @@
//
// AvatarApp.qml
//
// Created by Zach Fox on 2019-05-02
// Copyright 2019 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.10
import "../simplifiedConstants" as SimplifiedConstants
import "./components" as AvatarAppComponents
import stylesUit 1.0 as HifiStylesUit
import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere.
Rectangle {
id: root
property bool inventoryReceived: false
property bool isDebuggingFirstUseTutorial: false
property bool keyboardRaised: false
property int numUpdatesAvailable: 0
property string avatarPreviewUrl: ""
onAvatarPreviewUrlChanged: {
sendToScript({
"source": "AvatarApp.qml",
"method": "updateAvatarThumbnailURL",
"data": {
"avatarThumbnailURL": root.avatarPreviewUrl
}
});
}
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
color: simplifiedUI.colors.darkBackground
Component.onCompleted: {
Commerce.getLoginStatus();
}
Connections {
target: MyAvatar
onSkeletonModelURLChanged: {
root.updatePreviewUrl();
}
}
Connections {
target: Commerce
onLoginStatusResult: {
if (isLoggedIn) {
Commerce.getWalletStatus();
} else {
// Show some error to the user
}
}
onWalletStatusResult: {
if (walletStatus === 5) {
getInventory();
} else {
// Show some error to the user
}
}
onInventoryResult: {
inventoryModel.handlePage(result.status !== "success" && result.message, result);
root.updatePreviewUrl();
}
}
Image {
id: accent
source: "../images/accent.svg"
anchors.top: parent.top
anchors.right: parent.right
width: 60
height: 103
transform: Scale {
yScale: -1
origin.x: accent.width / 2
origin.y: accent.height / 2
}
}
AvatarAppComponents.DisplayNameHeader {
id: displayNameHeader
previewUrl: avatarPreviewUrl
loading: !inventoryContentsList.visible
anchors.top: parent.top
anchors.topMargin: 30
anchors.left: parent.left
anchors.leftMargin: 24
anchors.right: parent.right
anchors.rightMargin: 24
}
Item {
id: avatarInfoTextContainer
width: parent.implicitWidth
height: childrenRect.height
anchors.top: displayNameHeader.bottom
anchors.topMargin: 30
anchors.left: parent.left
anchors.leftMargin: 24
anchors.right: parent.right
anchors.rightMargin: 24
HifiStylesUit.GraphikRegular {
id: yourAvatarsTitle
text: "Your Avatars"
anchors.top: parent.top
verticalAlignment: TextInput.AlignVCenter
horizontalAlignment: TextInput.AlignLeft
color: simplifiedUI.colors.text.white
size: 22
}
HifiStylesUit.GraphikRegular {
id: yourAvatarsSubtitle
text: "These are the avatars that you've created and uploaded via the Avatar Creator."
width: parent.width
wrapMode: Text.WordWrap
anchors.top: yourAvatarsTitle.bottom
anchors.topMargin: 6
verticalAlignment: TextInput.AlignVCenter
horizontalAlignment: TextInput.AlignLeft
color: simplifiedUI.colors.text.darkGrey
size: 14
}
}
HifiModels.PSFListModel {
id: inventoryModel
itemsPerPage: 4
listModelName: 'inventory'
listView: inventoryContentsList
getPage: function () {
var editionFilter = "";
var primaryFilter = "avatar";
var titleFilter = "";
Commerce.inventory(
editionFilter,
primaryFilter,
titleFilter,
inventoryModel.currentPageToRetrieve,
inventoryModel.itemsPerPage
);
}
processPage: function(data) {
inventoryReceived = true;
data.assets.forEach(function (item) {
if (item.status.length > 1) { console.warn("Unrecognized inventory status", item); }
item.status = item.status[0];
});
return data.assets;
}
}
Item {
anchors.top: avatarInfoTextContainer.bottom
anchors.topMargin: 16
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
AnimatedImage {
visible: !inventoryContentsList.visible
anchors.centerIn: parent
width: 72
height: width
source: "../images/loading.gif"
}
ListView {
id: inventoryContentsList
visible: inventoryModel.count !== 0
interactive: contentItem.height > height
clip: true
model: inventoryModel
anchors.fill: parent
width: parent.width
delegate: AvatarAppComponents.AvatarAppListDelegate {
id: avatarAppListDelegate
itemName: title
itemPreviewImageUrl: preview
itemHref: download_url
standaloneOptimized: model.standalone_optimized
standaloneIncompatible: model.standalone_incompatible
}
}
}
function getInventory() {
inventoryModel.getFirstPage();
}
function updatePreviewUrl() {
var previewUrl = "";
var downloadUrl = "";
for (var i = 0; i < inventoryModel.count; ++i) {
downloadUrl = inventoryModel.get(i).download_url;
previewUrl = inventoryModel.get(i).preview;
if (MyAvatar.skeletonModelURL === downloadUrl) {
avatarPreviewUrl = previewUrl;
return;
}
}
}
function fromScript(message) {
switch (message.method) {
default:
console.log('AvatarApp.qml: Unrecognized message from JS');
break;
}
}
signal sendToScript(var message);
}

View file

@ -0,0 +1,108 @@
//
// AvatarAppListDelegate.qml
//
// Created by Zach Fox on 2019-05-09
// Copyright 2019 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.10
import "../../simplifiedConstants" as SimplifiedConstants
import "../../simplifiedControls" as SimplifiedControls
import stylesUit 1.0 as HifiStylesUit
import QtGraphicalEffects 1.0
Rectangle {
id: root;
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
property string itemName;
property string itemPreviewImageUrl;
property string itemHref;
property bool standaloneOptimized;
property bool standaloneIncompatible;
property bool isCurrentItem;
property bool isHovering: mouseArea.containsMouse || wearButton.hovered || wearButton.down
height: 102;
width: parent.width;
color: root.isHovering ? simplifiedUI.colors.darkBackgroundHighlight : "transparent"
Rectangle {
id: borderMask
visible: root.isHovering
width: itemPreviewImage.width + 4
height: width
radius: width
anchors.centerIn: itemPreviewImage
color: "#FFFFFF"
}
Image {
id: itemPreviewImage
source: root.itemPreviewImageUrl
anchors.left: parent.left
anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
height: 60
width: height
fillMode: Image.PreserveAspectCrop
mipmap: true
layer.enabled: true
layer.effect: OpacityMask {
maskSource: mask
}
Rectangle {
id: mask
width: itemPreviewImage.width
height: itemPreviewImage.height
radius: itemPreviewImage.width / 2
visible: false
}
}
HifiStylesUit.GraphikRegular {
id: avatarName
text: root.itemName
anchors.left: itemPreviewImage.right
anchors.leftMargin: 20
anchors.right: root.isHovering ? wearButton.left : parent.right
anchors.rightMargin: 20
anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight
height: parent.height
size: 20
color: simplifiedUI.colors.text.almostWhite
}
SimplifiedControls.Button {
id: wearButton;
visible: MyAvatar.skeletonModelURL !== root.itemHref && root.isHovering;
anchors.right: parent.right;
anchors.rightMargin: 24;
anchors.verticalCenter: parent.verticalCenter
width: 165;
height: 32;
text: "WEAR"
onClicked: {
MyAvatar.useFullAvatarURL(root.itemHref);
}
}
MouseArea {
z: -1
id: mouseArea
anchors.fill: parent
hoverEnabled: true
}
}

View file

@ -0,0 +1,133 @@
//
// DisplayNameHeader.qml
//
// Created by Wayne Chen on 2019-05-03
// Copyright 2019 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.10
import "../../simplifiedConstants" as SimplifiedConstants
import stylesUit 1.0 as HifiStylesUit
import controlsUit 1.0 as HifiControlsUit
import QtGraphicalEffects 1.0
Item {
id: root
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
height: itemPreviewImage.height
property string previewUrl: ""
property bool loading: true
AnimatedImage {
visible: root.loading
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
height: 72
width: height
source: "../../images/loading.gif"
}
Image {
id: itemPreviewImage
visible: !root.loading
source: root.previewUrl
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
height: 100
width: height
fillMode: Image.PreserveAspectCrop
layer.enabled: true
layer.effect: OpacityMask {
maskSource: mask
}
mipmap: true
Rectangle {
id: mask
width: itemPreviewImage.width
height: width
radius: width
visible: false
}
}
Item {
id: displayNameContainer
height: itemPreviewImage.height
anchors.right: parent.right
anchors.left: itemPreviewImage.right
anchors.leftMargin: 21
anchors.verticalCenter: parent.verticalCenter
HifiStylesUit.GraphikRegular {
id: displayNameLabel
text: "Display Name"
color: simplifiedUI.colors.text.lightGrey
size: 16
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.verticalCenter
anchors.left: parent.left
verticalAlignment: Text.AlignBottom
}
Item {
id: myDisplayNameContainer
// Size
width: parent.width
height: 40
anchors.top: parent.verticalCenter
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.left: parent.left
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: {
myDisplayNameText.focus = true;
myDisplayNameText.cursorPosition = myDisplayNameText.positionAt(mouseX - myDisplayNameText.anchors.leftMargin, mouseY, TextInput.CursorOnCharacter);
}
onDoubleClicked: {
myDisplayNameText.selectAll();
myDisplayNameText.focus = true;
}
}
TextInput {
id: myDisplayNameText
text: MyAvatar.displayName
maximumLength: 256
clip: true
anchors.fill: parent
color: simplifiedUI.colors.text.white
font.family: "Graphik Medium"
font.pixelSize: 22
selectionColor: simplifiedUI.colors.text.white
selectedTextColor: simplifiedUI.colors.text.darkGrey
verticalAlignment: TextInput.AlignVCenter
horizontalAlignment: TextInput.AlignLeft
autoScroll: false
onEditingFinished: {
if (MyAvatar.displayName !== text) {
MyAvatar.displayName = text;
}
myDisplayNameText.focus = false;
}
onFocusChanged: {
if (!focus) {
cursorPosition = 0;
}
myDisplayNameText.autoScroll = focus;
}
}
}
}
}

View file

@ -0,0 +1,4 @@
<svg width="94" height="175" viewBox="0 0 94 175" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 175L93.4322 175L73.3124 166.208L0 175Z" fill="#009036"/>
<path d="M73.3124 166.208L93.4322 175L93.4322 -1.34999e-05L73.3124 166.208Z" fill="#FF42A7"/>
</svg>

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View file

@ -0,0 +1,193 @@
//
// InputDeviceButton.qml
//
// Created by Zach Fox on 2019-05-02
// Based off of MicBarApplication.qml by Zach Pomerantz and Wayne Chen
// Copyright 2019 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.10
import QtGraphicalEffects 1.0
import stylesUit 1.0
import TabletScriptingInterface 1.0
import "../simplifiedConstants" as SimplifiedConstants
Rectangle {
id: micBar;
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
readonly property var level: AudioScriptingInterface.inputLevel;
readonly property var clipping: AudioScriptingInterface.clipping;
property var muted: AudioScriptingInterface.muted;
property var pushToTalk: AudioScriptingInterface.pushToTalk;
property var pushingToTalk: AudioScriptingInterface.pushingToTalk;
readonly property var userSpeakingLevel: 0.4;
property bool gated: false;
readonly property string unmutedIcon: "images/mic-unmute-i.svg";
readonly property string mutedIcon: "images/mic-mute-i.svg";
readonly property string pushToTalkIcon: "images/mic-ptt-i.svg";
readonly property string clippingIcon: "images/mic-clip-i.svg";
readonly property string gatedIcon: "images/mic-gate-i.svg";
Connections {
target: AudioScriptingInterface;
onNoiseGateOpened: {
gated = false;
}
onNoiseGateClosed: {
gated = false;
}
}
height: parent.height;
width: 40;
radius: 5;
opacity: 0.7;
onLevelChanged: {
var rectOpacity = (muted && (level >= userSpeakingLevel)) ? 1.0 : 0.7;
if (pushToTalk && !pushingToTalk) {
rectOpacity = (mouseArea.containsMouse) ? 1.0 : 0.7;
} else if (mouseArea.containsMouse && rectOpacity != 1.0) {
rectOpacity = 1.0;
}
micBar.opacity = rectOpacity;
}
color: "#00000000";
MouseArea {
id: mouseArea;
anchors {
left: icon.left;
right: bar.right;
top: icon.top;
bottom: icon.bottom;
}
hoverEnabled: true;
scrollGestureEnabled: false;
onClicked: {
if (pushToTalk) {
return;
}
AudioScriptingInterface.muted = !muted;
Tablet.playSound(TabletEnums.ButtonClick);
muted = Qt.binding(function() { return AudioScriptingInterface.muted; }); // restore binding
}
onContainsMouseChanged: {
if (containsMouse) {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
}
QtObject {
id: colors;
readonly property string unmutedColor: simplifiedUI.colors.controls.inputVolumeButton.text.noisy;
readonly property string gatedColor: "#00BDFF";
readonly property string mutedColor: simplifiedUI.colors.controls.inputVolumeButton.text.muted;
readonly property string gutter: "#575757";
readonly property string greenStart: "#39A38F";
readonly property string greenEnd: "#1FC6A6";
readonly property string yellow: "#C0C000";
readonly property string fill: "#55000000";
readonly property string icon: (muted || clipping) ? mutedColor : gated ? gatedColor : unmutedColor;
}
Item {
id: icon;
width: parent.width - bar.width - bar.anchors.leftMargin;
height: parent.height - 4;
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
Item {
anchors.fill: parent
opacity: mouseArea.containsMouse ? 1.0 : 0.7
Image {
id: image;
source: (pushToTalk) ? pushToTalkIcon : muted ? mutedIcon :
clipping ? clippingIcon : gated ? gatedIcon : unmutedIcon;
anchors.fill: parent
fillMode: Image.PreserveAspectFit
}
ColorOverlay {
id: imageOverlay
anchors { fill: image }
source: image;
color: pushToTalk ? (pushingToTalk ? colors.unmutedColor : colors.mutedColor) : colors.icon;
}
}
}
Item {
id: bar;
anchors {
left: icon.right;
leftMargin: 0;
verticalCenter: icon.verticalCenter;
}
width: 6;
height: parent.height - 12;
Rectangle { // base
id: baseBar
radius: 4;
anchors { fill: parent }
color: colors.gutter;
}
Rectangle { // mask
id: mask;
height: micBar.muted ? parent.height : parent.height * level;
color: micBar.muted ? colors.mutedColor : "white"
width: parent.width;
radius: 5;
anchors {
bottom: parent.bottom;
bottomMargin: 0;
left: parent.left;
leftMargin: 0;
}
}
LinearGradient {
anchors { fill: mask }
visible: mask.visible && !micBar.muted
source: mask
start: Qt.point(0, 0);
end: Qt.point(0, bar.height);
rotation: 180
gradient: Gradient {
GradientStop {
position: 0.0;
color: colors.greenStart;
}
GradientStop {
position: 0.5;
color: colors.greenEnd;
}
GradientStop {
position: 1.0;
color: colors.yellow;
}
}
}
}
}

View file

@ -0,0 +1,10 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.3383 4.13446L23.8713 5.60152C21.9374 3.46761 19.2033 2.06723 16.0691 2.06723C13.0683 2.06723 10.4009 3.40093 8.46707 5.40147L7 3.9344C9.26728 1.53375 12.5348 0 16.0691 0C19.7368 0 23.071 1.60044 25.3383 4.13446ZM21.9376 7.53584L20.4705 9.0029C19.4703 7.66921 17.8698 6.86899 16.0693 6.86899C14.4022 6.86899 12.9351 7.66921 11.8682 8.80285L10.4011 7.33578C11.8015 5.80203 13.802 4.80176 16.0693 4.80176C18.4033 4.80176 20.5372 5.86871 21.9376 7.53584ZM17.9575 30.1572C17.9575 31.1771 17.1307 32.0039 16.1108 32.0039C15.0909 32.0039 14.2642 31.1771 14.2642 30.1572C14.2642 29.1373 15.0909 28.3105 16.1108 28.3105C17.1307 28.3105 17.9575 29.1373 17.9575 30.1572ZM18.3632 11.0801H14.1597L15.0116 25.8539H17.4867L18.3632 11.0801Z" fill="#EA4C5F"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.1999 4.72587C17.5049 4.72587 18.5628 3.66795 18.5628 2.36294C18.5628 1.05792 17.5049 0 16.1999 0C14.8948 0 13.8369 1.05792 13.8369 2.36294C13.8369 3.66795 14.8948 4.72587 16.1999 4.72587ZM18.6667 11.8004V14.7337H13.7334V11.8004C13.7334 10.467 14.8667 9.40039 16.2 9.40039C17.6 9.40039 18.6667 10.467 18.6667 11.8004ZM13.7334 20.1332V17.2666H18.6667V20.1332C18.6667 21.4665 17.5333 22.5332 16.2 22.5332C14.8667 22.5332 13.7334 21.4665 13.7334 20.1332ZM23.6665 20.6V17.0667C23.6665 16.4 23.0665 15.9334 22.4665 15.9334C21.7998 15.9334 21.3332 16.4667 21.3332 17.1333V20.6C21.3332 23.0666 19.0665 25.0666 16.3332 25.0666C13.5999 25.0666 11.3333 23.0666 11.3333 20.6V17.0667C11.3333 16.4 10.8666 15.8667 10.2666 15.8667C9.59999 15.8 9 16.2667 9 16.9333V20.6C9 23.9999 11.6666 26.7999 15.1333 27.3332V29.5998H12.2666C11.6 29.5998 11.0666 30.1332 11.0666 30.7998C11.0666 31.4665 11.6 31.9998 12.2666 31.9998H20.4665C21.1332 31.9998 21.6665 31.4665 21.6665 30.7998C21.6665 30.1332 21.1332 29.5998 20.4665 29.5998H17.5332V27.3332C20.9998 26.7332 23.6665 23.9999 23.6665 20.6Z" fill="#00B4EF" fill-opacity="0.7"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.6441 4.13328L24.1775 5.59992C22.2442 3.46662 19.5109 2.06664 16.3776 2.06664C13.3776 2.06664 10.711 3.39995 8.77768 5.39993L7.31104 3.93328C9.57767 1.53331 12.8443 0 16.3776 0C20.0442 0 23.3775 1.59998 25.6441 4.13328ZM20.7777 9.00072L22.2444 7.53408C20.8444 5.86743 18.7111 4.80078 16.3778 4.80078C14.1111 4.80078 12.1112 5.80077 10.7112 7.33408L12.1778 8.80073C13.2445 7.66741 14.7111 6.86742 16.3778 6.86742C18.1777 6.86742 19.7777 7.66741 20.7777 9.00072ZM18.8803 12.0758V11.7496C18.8803 10.4445 17.7763 9.40039 16.4775 9.40039C15.1787 9.40039 14.0747 10.4445 14.0747 11.7496V16.2521L18.8803 12.0758ZM14.543 21.5129L12.6113 23.2103C13.4959 24.2599 14.9141 24.9311 16.4774 24.9311C19.14 24.9311 21.348 22.9735 21.348 20.559V17.1658C21.348 16.5132 21.8026 15.9912 22.452 15.9912C23.0364 15.9912 23.6209 16.448 23.6209 17.1005V20.559C23.6209 23.887 21.0233 26.6277 17.6464 27.1498V29.3684H20.5038C21.1532 29.3684 21.6727 29.8905 21.6727 30.543C21.6727 31.1956 21.1532 31.7176 20.5038 31.7176H12.5161C11.8667 31.7176 11.3471 31.1956 11.3471 30.543C11.3471 29.8905 11.8667 29.3684 12.5161 29.3684H15.3085V27.1498C13.5328 26.915 11.9589 26.0045 10.8771 24.7343L8.9443 26.4327C8.48972 26.8242 7.77537 26.759 7.38573 26.3022L7.25585 26.1717C6.8662 25.7149 6.93114 24.9971 7.38573 24.6056L23.8806 9.98853C24.3352 9.597 25.0495 9.66226 25.4392 10.119L25.5691 10.2495C25.9587 10.7716 25.8938 11.4241 25.5041 11.8809L18.8803 17.7015V20.1017C18.8803 21.4068 17.7763 22.4509 16.4775 22.4509C15.6689 22.4509 14.9744 22.0838 14.543 21.5129ZM10.5679 15.9919C11.1523 15.9919 11.6069 16.5139 11.6069 17.1664V18.4715L9.33398 20.4944V17.0359C9.39892 16.4486 9.91845 15.9266 10.5679 15.9919Z" fill="#EA4C5F"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.6441 4.13328L24.1775 5.59992C22.2442 3.46662 19.5109 2.06664 16.3776 2.06664C13.3776 2.06664 10.711 3.39995 8.77768 5.39993L7.31104 3.93328C9.57767 1.53331 12.8443 0 16.3776 0C20.0442 0 23.3775 1.59998 25.6441 4.13328ZM20.7777 9.00072L22.2444 7.53408C20.8444 5.86743 18.7111 4.80078 16.3778 4.80078C14.1111 4.80078 12.1112 5.80077 10.7112 7.33408L12.1778 8.80073C13.2445 7.66741 14.7111 6.86742 16.3778 6.86742C18.1777 6.86742 19.7777 7.66741 20.7777 9.00072ZM18.8803 12.0758V11.7496C18.8803 10.4445 17.7763 9.40039 16.4775 9.40039C15.1787 9.40039 14.0747 10.4445 14.0747 11.7496V16.2521L18.8803 12.0758ZM14.543 21.5129L12.6113 23.2103C13.4959 24.2599 14.9141 24.9311 16.4774 24.9311C19.14 24.9311 21.348 22.9735 21.348 20.559V17.1658C21.348 16.5132 21.8026 15.9912 22.452 15.9912C23.0364 15.9912 23.6209 16.448 23.6209 17.1005V20.559C23.6209 23.887 21.0233 26.6277 17.6464 27.1498V29.3684H20.5038C21.1532 29.3684 21.6727 29.8905 21.6727 30.543C21.6727 31.1956 21.1532 31.7176 20.5038 31.7176H12.5161C11.8667 31.7176 11.3471 31.1956 11.3471 30.543C11.3471 29.8905 11.8667 29.3684 12.5161 29.3684H15.3085V27.1498C13.5328 26.915 11.9589 26.0045 10.8771 24.7343L8.9443 26.4327C8.48972 26.8242 7.77537 26.759 7.38573 26.3022L7.25585 26.1717C6.8662 25.7149 6.93114 24.9971 7.38573 24.6056L23.8806 9.98853C24.3352 9.597 25.0495 9.66226 25.4392 10.119L25.5691 10.2495C25.9587 10.7716 25.8938 11.4241 25.5041 11.8809L18.8803 17.7015V20.1017C18.8803 21.4068 17.7763 22.4509 16.4775 22.4509C15.6689 22.4509 14.9744 22.0838 14.543 21.5129ZM10.5679 15.9919C11.1523 15.9919 11.6069 16.5139 11.6069 17.1664V18.4715L9.33398 20.4944V17.0359C9.39893 16.4486 9.91845 15.9266 10.5679 15.9919Z" fill="#EA4C5F"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1 @@
<svg id="Art" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><defs><style>.cls-1{fill-rule:evenodd;}</style></defs><title>mic-ptt-a</title><path class="cls-1" d="M34.52,10.09l-1.85,1.85a13.19,13.19,0,0,0-9.82-4.46,13.35,13.35,0,0,0-9.58,4.2L11.42,9.84a15.66,15.66,0,0,1,23.1.25Zm-6.13,6.13,1.85-1.85a9.62,9.62,0,0,0-14.53-.25L17.55,16a7.34,7.34,0,0,1,5.3-2.44A6.85,6.85,0,0,1,28.39,16.22ZM23,16a3.58,3.58,0,0,1,1.51.3,3.68,3.68,0,0,1,1.26.88,3.88,3.88,0,0,1,.84,1.3A3.94,3.94,0,0,1,26.9,20v5.07a1.91,1.91,0,0,1,.48-.05A3.93,3.93,0,0,1,30,26.07a3.38,3.38,0,0,1,1.5-.32,3.27,3.27,0,0,1,2.77,1.36,2.75,2.75,0,0,1,.85-.1,3.35,3.35,0,0,1,1.33.25,3.18,3.18,0,0,1,1.12.76,3.23,3.23,0,0,1,.73,1.13,3.32,3.32,0,0,1,.24,1.32v3.31a12.27,12.27,0,0,1-.43,3.41l-1.36,5.65a2.67,2.67,0,0,1-1,1.55A2.89,2.89,0,0,1,34,45H23a4.47,4.47,0,0,1-1.76-.43,3.88,3.88,0,0,1-1.36-1.12L14.1,35.7a3.72,3.72,0,0,1-.8-2.35,3.64,3.64,0,0,1,.28-1.5,3.75,3.75,0,0,1,.84-1.27,3.9,3.9,0,0,1,2.77-1.18,4.5,4.5,0,0,1,2,.54V19.88a4.06,4.06,0,0,1,1.13-2.78,3.74,3.74,0,0,1,1.25-.83A3.85,3.85,0,0,1,23,16Zm0,2a1.89,1.89,0,0,0-.74.12,2,2,0,0,0-1.06,1,1.92,1.92,0,0,0-.15.74V35.21l-2.32-3.06a2,2,0,0,0-.7-.59,1.88,1.88,0,0,0-.9-.2,1.85,1.85,0,0,0-.74.15,2,2,0,0,0-.63.43,2,2,0,0,0-.4.63,1.9,1.9,0,0,0-.13.74,2,2,0,0,0,.38,1.17l5.86,7.79a1.79,1.79,0,0,0,.68.57A1.74,1.74,0,0,0,23,43H34a1.23,1.23,0,0,0,.59-.15.88.88,0,0,0,.24-.23.71.71,0,0,0,.13-.31l1.37-5.6a12,12,0,0,0,.37-3V30.43a1.7,1.7,0,0,0-.43-1.07,1.31,1.31,0,0,0-.47-.37,1.35,1.35,0,0,0-.59-.11,1.46,1.46,0,0,0-.55.11,1.23,1.23,0,0,0-.46.32,1.64,1.64,0,0,0-.43,1.07h-.48v-1a1.52,1.52,0,0,0-.12-.66,1.61,1.61,0,0,0-.37-.56,1.63,1.63,0,0,0-1.22-.54,2,2,0,0,0-1.23.54,1.77,1.77,0,0,0-.36.53,1.57,1.57,0,0,0-.11.64v1h-.49V29a2.22,2.22,0,0,0-.58-1.44,1.71,1.71,0,0,0-.62-.44A1.88,1.88,0,0,0,27.4,27a2,2,0,0,0-.74.13,1.85,1.85,0,0,0-.63.41,2,2,0,0,0-.53,1.36v1.5h-.57V20a2,2,0,0,0-.54-1.44,1.75,1.75,0,0,0-.63-.44A1.73,1.73,0,0,0,23,18Z"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Art" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<path class="st0" d="M16.7,13.2c-0.3,0.3-0.7,0.6-1,0.9l1.8,1.9c1.4-1.5,3.3-2.4,5.3-2.4c2.2,0,4.2,0.9,5.5,2.7l1.8-1.8
C26.8,10.3,20.8,9.8,16.7,13.2z M32.7,11.9l1.9-1.9c-0.3-0.3-0.6-0.7-1-1c-6.3-5.9-16.2-5.6-22.1,0.7l1.9,1.8
c2.5-2.6,5.9-4.2,9.6-4.2C26.6,7.5,30.2,9.1,32.7,11.9z M38.3,29.1c-0.2-0.4-0.4-0.8-0.7-1.1c-0.3-0.3-0.7-0.6-1.1-0.8
C36,27.1,35.6,27,35.1,27c-0.3,0-0.6,0-0.8,0.1c-0.6-0.9-1.7-1.4-2.8-1.4c-0.5,0-1,0.1-1.5,0.3c-0.7-0.7-1.6-1-2.6-1.1
c-0.2,0-0.3,0-0.5,0.1V20c0-0.5-0.1-1-0.3-1.5c-0.2-0.5-0.5-0.9-0.8-1.3c-0.4-0.4-0.8-0.7-1.3-0.9C24,16.1,23.5,16,23,16
c-0.5,0-1,0.1-1.4,0.3c-0.5,0.2-0.9,0.5-1.3,0.8c-0.7,0.7-1.1,1.7-1.1,2.8v10.1c-0.6-0.3-1.3-0.5-2-0.5c-1,0-2,0.4-2.8,1.2
c-0.4,0.4-0.6,0.8-0.8,1.3c-0.2,0.5-0.3,1-0.3,1.5c0,0.9,0.3,1.7,0.8,2.4l5.8,7.8c0.4,0.5,0.8,0.9,1.4,1.1c0.6,0.3,1.2,0.4,1.8,0.4
h11c0.6,0,1.2-0.2,1.8-0.6c0.5-0.4,0.9-0.9,1-1.6l1.4-5.6c0.3-1.1,0.4-2.3,0.4-3.4v-3.3C38.6,30,38.5,29.6,38.3,29.1z M36.7,33.7
c0,1-0.1,2-0.4,3L35,42.3c0,0.1-0.1,0.2-0.1,0.3c-0.1,0.1-0.1,0.2-0.2,0.2C34.4,42.9,34.2,43,34,43H23c-0.3,0-0.6,0-0.8-0.2
c-0.3-0.1-0.5-0.3-0.7-0.6l-5.9-7.8c-0.2-0.3-0.4-0.7-0.4-1.2c0-0.3,0-0.5,0.1-0.7c0.1-0.2,0.2-0.4,0.4-0.6c0.2-0.2,0.4-0.3,0.6-0.4
c0.2-0.1,0.5-0.2,0.7-0.2c0.3,0,0.6,0.1,0.9,0.2c0.3,0.1,0.5,0.3,0.7,0.6l2.3,3.1V19.9c0-0.3,0.1-0.5,0.2-0.7c0.2-0.5,0.6-0.8,1.1-1
C22.5,18,22.7,18,23,18c0.3,0,0.5,0,0.8,0.1c0.2,0.1,0.5,0.2,0.6,0.4c0.4,0.4,0.6,0.9,0.5,1.4v10.4h0.6v-1.5c0-0.5,0.2-1,0.5-1.4
c0.2-0.2,0.4-0.3,0.6-0.4c0.2-0.1,0.5-0.1,0.7-0.1c0.3,0,0.5,0,0.8,0.1c0.2,0.1,0.4,0.2,0.6,0.4c0.4,0.4,0.6,0.9,0.6,1.4v1.3h0.5v-1
c0-0.2,0-0.4,0.1-0.6c0.1-0.2,0.2-0.4,0.4-0.5c0.3-0.3,0.8-0.5,1.2-0.5c0.5,0,0.9,0.2,1.2,0.5c0.2,0.2,0.3,0.3,0.4,0.6
c0.1,0.2,0.1,0.4,0.1,0.7v1h0.5c0-0.4,0.2-0.8,0.4-1.1c0.1-0.1,0.3-0.3,0.5-0.3c0.2-0.1,0.4-0.1,0.6-0.1c0.2,0,0.4,0,0.6,0.1
c0.2,0.1,0.3,0.2,0.5,0.4c0.3,0.3,0.4,0.7,0.4,1.1V33.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.8664 5.59992L25.3331 4.13328C23.0664 1.59998 19.7332 0 16.0665 0C12.5333 0 9.26664 1.53331 7 3.93328L8.46665 5.39993C10.4 3.39995 13.0666 2.06664 16.0665 2.06664C19.1998 2.06664 21.9331 3.46662 23.8664 5.59992ZM20.4664 8.99975L21.9331 7.5331C20.5331 5.86646 18.3998 4.7998 16.0665 4.7998C13.7999 4.7998 11.7999 5.79979 10.3999 7.3331L11.8665 8.79975C12.9332 7.66643 14.3998 6.86644 16.0665 6.86644C17.8665 6.86644 19.4664 7.66643 20.4664 8.99975ZM18.5334 11.8004V14.7337H13.6001V11.8004C13.6001 10.467 14.7334 9.40039 16.0667 9.40039C17.4667 9.40039 18.5334 10.467 18.5334 11.8004ZM13.6001 17.2666V20.1332C13.6001 21.4665 14.7334 22.5332 16.0667 22.5332C17.4 22.5332 18.5334 21.4665 18.5334 20.1332V17.2666H13.6001ZM23.5332 17.0667V20.6C23.5332 23.9999 20.8665 26.7332 17.3999 27.3332V29.5998H20.3332C20.9999 29.5998 21.5332 30.1332 21.5332 30.7998C21.5332 31.4665 20.9999 31.9998 20.3332 31.9998H12.1333C11.4667 31.9998 10.9333 31.4665 10.9333 30.7998C10.9333 30.1332 11.4667 29.5998 12.1333 29.5998H14.9999V27.3332C11.5333 26.7999 8.8667 23.9999 8.8667 20.6V16.9333C8.8667 16.2667 9.46669 15.8 10.1333 15.8667C10.7333 15.8667 11.2 16.4 11.2 17.0667V20.6C11.2 23.0666 13.4666 25.0666 16.1999 25.0666C18.9332 25.0666 21.1999 23.0666 21.1999 20.6V17.1333C21.1999 16.4667 21.6665 15.9334 22.3332 15.9334C22.9332 15.9334 23.5332 16.4 23.5332 17.0667Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.8664 5.59992L25.3331 4.13328C23.0664 1.59998 19.7332 0 16.0665 0C12.5333 0 9.26664 1.53331 7 3.93328L8.46665 5.39993C10.4 3.39995 13.0666 2.06664 16.0665 2.06664C19.1998 2.06664 21.9331 3.46662 23.8664 5.59992ZM20.4664 8.99975L21.9331 7.5331C20.5331 5.86646 18.3998 4.7998 16.0665 4.7998C13.7999 4.7998 11.7999 5.79979 10.3999 7.3331L11.8665 8.79975C12.9332 7.66643 14.3998 6.86644 16.0665 6.86644C17.8665 6.86644 19.4664 7.66643 20.4664 8.99975ZM18.5334 11.8004V14.7337H13.6001V11.8004C13.6001 10.467 14.7334 9.40039 16.0667 9.40039C17.4667 9.40039 18.5334 10.467 18.5334 11.8004ZM13.6001 17.2666V20.1332C13.6001 21.4665 14.7334 22.5332 16.0667 22.5332C17.4 22.5332 18.5334 21.4665 18.5334 20.1332V17.2666H13.6001ZM23.5332 17.0667V20.6C23.5332 23.9999 20.8665 26.7332 17.3999 27.3332V29.5998H20.3332C20.9999 29.5998 21.5332 30.1332 21.5332 30.7998C21.5332 31.4665 20.9999 31.9998 20.3332 31.9998H12.1333C11.4667 31.9998 10.9333 31.4665 10.9333 30.7998C10.9333 30.1332 11.4667 29.5998 12.1333 29.5998H14.9999V27.3332C11.5333 26.7999 8.8667 23.9999 8.8667 20.6V16.9333C8.8667 16.2667 9.46669 15.8 10.1333 15.8667C10.7333 15.8667 11.2 16.4 11.2 17.0667V20.6C11.2 23.0666 13.4666 25.0666 16.1999 25.0666C18.9332 25.0666 21.1999 23.0666 21.1999 20.6V17.1333C21.1999 16.4667 21.6665 15.9334 22.3332 15.9334C22.9332 15.9334 23.5332 16.4 23.5332 17.0667Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,147 @@
//
// SettingsApp.qml
//
// Created by Zach Fox on 2019-05-02
// Copyright 2019 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.10
import "../simplifiedConstants" as SimplifiedConstants
import stylesUit 1.0 as HifiStylesUit
import "./audio" as AudioSettings
import "./general" as GeneralSettings
import "./vr" as VrSettings
Rectangle {
property string activeTabView: "generalTabView"
id: root
color: simplifiedUI.colors.darkBackground
anchors.fill: parent
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
Rectangle {
id: tabContainer
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 64
color: simplifiedUI.colors.highlightOnDark
ListModel {
id: tabListModel
ListElement {
tabTitle: "General"
tabViewName: "generalTabView"
}
ListElement {
tabTitle: "Audio"
tabViewName: "audioTabView"
}
ListElement {
tabTitle: "VR"
tabViewName: "vrTabView"
}
}
Component {
id: highlightBar
Rectangle {
color: simplifiedUI.colors.darkBackground
}
}
ListView {
id: tabListView
anchors.fill: parent
contentHeight: parent.height
contentWidth: childrenRect.width
orientation: ListView.Horizontal
model: tabListModel
highlight: highlightBar
interactive: contentItem.width > width
delegate: Item {
width: tabTitleText.paintedWidth + 64
height: parent.height
HifiStylesUit.GraphikRegular {
id: tabTitleText
color: simplifiedUI.colors.text.white
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: model.tabTitle
size: 24
}
MouseArea {
anchors.fill: parent
onClicked: {
tabListView.currentIndex = index;
root.activeTabView = model.tabViewName;
}
}
}
}
}
Item {
id: tabViewContainers
anchors.top: tabContainer.bottom
anchors.left: parent.left
anchors.leftMargin: 26
anchors.right: parent.right
anchors.rightMargin: 26
anchors.bottom: parent.bottom
GeneralSettings.General {
id: generalTabViewContainer
visible: activeTabView === "generalTabView"
anchors.fill: parent
onSendNameTagInfo: {
sendToScript(message);
}
}
AudioSettings.Audio {
id: audioTabViewContainer
visible: activeTabView === "audioTabView"
anchors.fill: parent
}
VrSettings.VR {
id: vrTabViewContainer
visible: activeTabView === "vrTabView"
anchors.fill: parent
}
}
Image {
source: "../images/accent.svg"
anchors.right: parent.right
anchors.bottom: parent.bottom
width: 94
height: 175
}
function fromScript(message) {
switch (message.method) {
default:
console.log('SettingsApp.qml: Unrecognized message from JS');
break;
}
}
signal sendToScript(var message);
}

View file

@ -0,0 +1,405 @@
//
// Audio.qml
//
// Created by Zach Fox on 2019-05-06
// Copyright 2019 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.10
import QtQuick.Controls 2.3
import "../../simplifiedConstants" as SimplifiedConstants
import "../../simplifiedControls" as SimplifiedControls
import stylesUit 1.0 as HifiStylesUit
import QtQuick.Layouts 1.3
Flickable {
id: root;
contentWidth: parent.width;
contentHeight: audioColumnLayout.height;
topMargin: 16
bottomMargin: 16
clip: true;
function changePeakValuesEnabled(enabled) {
if (!enabled) {
AudioScriptingInterface.devices.input.peakValuesEnabled = true;
}
}
onVisibleChanged: {
AudioScriptingInterface.devices.input.peakValuesEnabled = visible;
if (visible) {
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.connect(changePeakValuesEnabled);
} else {
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.disconnect(changePeakValuesEnabled);
}
}
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
ColumnLayout {
id: audioColumnLayout
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
ColumnLayout {
id: volumeControlsContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: volumeControlsTitle
text: "Volume Controls"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: volumeControlsSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "Set your HQ's audio output levels. Change \"People Volume\" to control how loud others sound to you."
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
SimplifiedControls.Slider {
id: peopleVolume
anchors.left: parent.left
anchors.right: parent.right
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
height: 30
labelText: "People Volume"
from: -60
to: 10
defaultValue: 0.0
value: AudioScriptingInterface.getAvatarGain()
live: true
onValueChanged: {
if (AudioScriptingInterface.getAvatarGain() != peopleVolume.value) {
AudioScriptingInterface.setAvatarGain(peopleVolume.value);
}
}
}
SimplifiedControls.Slider {
id: environmentVolume
anchors.left: parent.left
anchors.right: parent.right
Layout.topMargin: 2
height: 30
labelText: "Environment Volume"
from: -60
to: 10
defaultValue: 0.0
value: AudioScriptingInterface.getInjectorGain()
live: true
onValueChanged: {
if (AudioScriptingInterface.getInjectorGain() != environmentVolume.value) {
AudioScriptingInterface.setInjectorGain(environmentVolume.value);
}
}
}
SimplifiedControls.Slider {
id: systemSoundVolume
anchors.left: parent.left
anchors.right: parent.right
Layout.topMargin: 2
height: 30
labelText: "System Sound Volume"
from: -60
to: 10
defaultValue: 0.0
value: AudioScriptingInterface.getSystemInjectorGain()
live: true
onValueChanged: {
if (AudioScriptingInterface.getSystemInjectorGain() != systemSoundVolume.value) {
AudioScriptingInterface.setSystemInjectorGain(systemSoundVolume.value);
}
}
}
}
ColumnLayout {
id: micControlsContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: micControlsTitle
text: "Default Mute Controls"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: micControlsSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "These settings let you configure how you communicate with others in your HQ while in Desktop mode. Push to Talk works like a walkie-talkie!"
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ColumnLayout {
id: micControlsSwitchGroup
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
SimplifiedControls.Switch {
id: muteMicrophoneSwitch
width: parent.width
height: simplifiedUI.sizes.controls.simplifiedSwitch.switchBackgroundHeight
labelTextOn: "Mute Microphone"
checked: AudioScriptingInterface.mutedDesktop
onClicked: {
AudioScriptingInterface.mutedDesktop = !AudioScriptingInterface.mutedDesktop;
}
}
SimplifiedControls.Switch {
id: pushToTalkSwitch
width: parent.width
height: simplifiedUI.sizes.controls.simplifiedSwitch.switchBackgroundHeight
labelTextOn: "Push to Talk - Press and Hold \"T\" to Talk"
checked: AudioScriptingInterface.pushToTalkDesktop
onClicked: {
AudioScriptingInterface.pushToTalkDesktop = !AudioScriptingInterface.pushToTalkDesktop;
}
}
}
}
ColumnLayout {
id: inputDeviceContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: inputDeviceTitle
text: "Which input device?"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: inputDeviceSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "Here are all of the input devices and microphones that we found. Select the one you'd like to use in your HQ while in Desktop mode."
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ButtonGroup { id: inputDeviceButtonGroup }
ListView {
id: inputDeviceListView;
anchors.left: parent.left
anchors.right: parent.right
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false;
height: contentItem.height;
spacing: 4;
clip: true;
model: AudioScriptingInterface.devices.input;
delegate: Item {
width: parent.width
height: inputDeviceCheckbox.height
SimplifiedControls.RadioButton {
id: inputDeviceCheckbox
anchors.left: parent.left
width: parent.width - inputLevel.width
checked: selectedDesktop;
text: model.devicename
ButtonGroup.group: inputDeviceButtonGroup
onClicked: {
AudioScriptingInterface.setStereoInput(false); // the next selected audio device might not support stereo
AudioScriptingInterface.setInputDevice(model.info, false); // `false` argument for Desktop mode setting
}
}
SimplifiedControls.InputPeak {
id: inputLevel
showMuted: AudioScriptingInterface.mutedDesktop
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
peak: model.peak;
visible: AudioScriptingInterface.devices.input.peakValuesAvailable;
}
}
}
SimplifiedControls.Button {
property bool audioLoopedBack: AudioScriptingInterface.getLocalEcho()
function startAudioLoopback() {
if (!audioLoopedBack) {
audioLoopedBack = true;
AudioScriptingInterface.setLocalEcho(true);
}
}
function stopAudioLoopback() {
if (audioLoopedBack) {
audioLoopedBack = false;
AudioScriptingInterface.setLocalEcho(false);
}
}
Timer {
id: loopbackTimer
interval: 8000;
running: false;
repeat: false;
onTriggered: {
stopAudioLoopback();
}
}
id: testYourMicButton
enabled: !HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32
text: audioLoopedBack ? "STOP TESTING" : "TEST YOUR MIC"
onClicked: {
if (audioLoopedBack) {
loopbackTimer.stop();
stopAudioLoopback();
} else {
loopbackTimer.restart();
startAudioLoopback();
}
}
}
}
ColumnLayout {
id: outputDeviceContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: outputDeviceTitle
text: "Which output device?"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: outputDeviceSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "Here are all of the output devices that we found. Select the one you'd like to use in your HQ while in Desktop mode."
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ButtonGroup { id: outputDeviceButtonGroup }
ListView {
id: outputDeviceListView;
anchors.left: parent.left
anchors.right: parent.right
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false;
height: contentItem.height;
spacing: 4;
clip: true;
model: AudioScriptingInterface.devices.output;
delegate: Item {
width: parent.width
height: outputDeviceCheckbox.height
SimplifiedControls.RadioButton {
id: outputDeviceCheckbox
anchors.left: parent.left
width: parent.width
checked: selectedDesktop;
text: model.devicename
ButtonGroup.group: outputDeviceButtonGroup
onClicked: {
AudioScriptingInterface.setOutputDevice(model.info, false); // `false` argument for Desktop mode setting
}
}
}
}
SimplifiedControls.Button {
property var sound: null;
property var sample: null;
property bool isPlaying: false;
function createSampleSound() {
sound = ApplicationInterface.getSampleSound();
sample = null;
}
function playSound() {
// FIXME: MyAvatar is not properly exposed to QML; MyAvatar.qmlPosition is a stopgap
// FIXME: AudioScriptingInterface.playSystemSound should not require position
if (sample === null && !isPlaying) {
sample = AudioScriptingInterface.playSystemSound(sound, MyAvatar.qmlPosition);
isPlaying = true;
sample.finished.connect(reset);
}
}
function stopSound() {
if (sample && isPlaying) {
sample.stop();
}
}
function reset() {
sample.finished.disconnect(reset);
isPlaying = false;
sample = null;
}
Component.onCompleted: createSampleSound();
Component.onDestruction: stopSound();
onVisibleChanged: {
if (!visible) {
stopSound();
}
}
id: testYourSoundButton
enabled: !HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32
text: isPlaying ? "STOP TESTING" : "TEST YOUR SOUND"
onClicked: {
isPlaying ? stopSound() : playSound();
}
}
}
}
}

View file

@ -0,0 +1,236 @@
//
// General.qml
//
// Created by Zach Fox on 2019-05-06
// Copyright 2019 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.10
import "../../simplifiedConstants" as SimplifiedConstants
import "../../simplifiedControls" as SimplifiedControls
import stylesUit 1.0 as HifiStylesUit
import QtQuick.Layouts 1.3
Flickable {
property string avatarNametagMode: Settings.getValue("simplifiedNametag/avatarNametagMode", "on");
id: root;
contentWidth: parent.width;
contentHeight: generalColumnLayout.height;
topMargin: 16
bottomMargin: 16
clip: true;
onAvatarNametagModeChanged: {
sendNameTagInfo({method: 'handleAvatarNametagMode', avatarNametagMode: root.avatarNametagMode, source: "SettingsApp.qml"});
}
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
ColumnLayout {
id: generalColumnLayout
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
ColumnLayout {
id: avatarNameTagsContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: avatarNameTagsTitle
text: "Avatar Name Tags"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: avatarNameTagsSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "Control how nametags appear over other peoples' heads in your HQ. \"Click to View\" allows you to click anyone to see their name."
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ColumnLayout {
id: avatarNameTagsRadioButtonGroup
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
SimplifiedControls.RadioButton {
id: avatarNameTagsOff
text: "Off"
checked: root.avatarNametagMode === "off"
onClicked: {
root.avatarNametagMode = "off"
}
}
SimplifiedControls.RadioButton {
id: avatarNameTagsAlwaysOn
text: "Always On"
checked: root.avatarNametagMode === "alwaysOn"
onClicked: {
root.avatarNametagMode = "alwaysOn"
}
}
SimplifiedControls.RadioButton {
id: avatarNameTagsClickToView
text: "Click to View"
checked: root.avatarNametagMode === "on"
onClicked: {
root.avatarNametagMode = "on"
}
}
}
}
ColumnLayout {
id: performanceContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: performanceTitle
text: "Performance"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: performanceSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "Modify how this application uses system resources and impacts battery life."
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ColumnLayout {
id: performanceRadioButtonGroup
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
SimplifiedControls.RadioButton {
id: performanceLow
text: "Eco"
}
SimplifiedControls.RadioButton {
id: performanceMedium
text: "Interactive"
}
SimplifiedControls.RadioButton {
id: performanceHigh
text: "Realtime"
}
}
}
ColumnLayout {
id: cameraContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: cameraTitle
text: "Camera View"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: cameraSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "Change your point of view by selecting either first or third person view. Try scrolling your mouse wheel."
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ColumnLayout {
id: cameraRadioButtonGroup
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
SimplifiedControls.RadioButton {
id: firstPerson
text: "First Person View"
checked: Camera.mode === "first person"
onClicked: {
Camera.mode = "first person"
}
}
SimplifiedControls.RadioButton {
id: thirdPerson
text: "Third Person View"
checked: Camera.mode === "third person"
onClicked: {
Camera.mode = "third person"
}
}
Connections {
target: Camera;
onModeUpdated: {
if (Camera.mode === "first person") {
firstPerson.checked = true
} else if (Camera.mode === "third person") {
thirdPerson.checked = true
}
}
}
}
}
HifiStylesUit.GraphikRegular {
id: logoutText
text: (AccountServices.username === "Unknown user" ? "Log In" : "Logout " + AccountServices.username)
wrapMode: Text.Wrap
width: paintedWidth
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.lightBlue
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
parent.color = simplifiedUI.colors.text.lightBlueHover;
}
onExited: {
parent.color = simplifiedUI.colors.text.lightBlue;
}
onClicked: {
if (Account.loggedIn) {
AccountServices.logOut();
} else {
DialogsManager.showLoginDialog();
}
}
}
}
}
signal sendNameTagInfo(var message);
}

View file

@ -0,0 +1,418 @@
//
// VR.qml
//
// Created by Zach Fox on 2019-05-08
// Copyright 2019 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.10
import QtQuick.Controls 2.3
import "../../simplifiedConstants" as SimplifiedConstants
import "../../simplifiedControls" as SimplifiedControls
import stylesUit 1.0 as HifiStylesUit
import QtQuick.Layouts 1.3
Flickable {
id: root;
contentWidth: parent.width;
contentHeight: vrColumnLayout.height;
topMargin: 16
bottomMargin: 16
clip: true;
function changePeakValuesEnabled(enabled) {
if (!enabled) {
AudioScriptingInterface.devices.input.peakValuesEnabled = true;
}
}
onVisibleChanged: {
AudioScriptingInterface.devices.input.peakValuesEnabled = visible;
if (visible) {
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.connect(changePeakValuesEnabled);
} else {
AudioScriptingInterface.devices.input.peakValuesEnabledChanged.disconnect(changePeakValuesEnabled);
}
}
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
ColumnLayout {
id: vrColumnLayout
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
spacing: simplifiedUI.margins.settings.spacingBetweenSettings
ColumnLayout {
id: controlsContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: controlsTitle
text: "VR Movement Controls"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: controlsSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "Everyone responds to VR movement differently. Choose the setting that is most comfortable for you. Try using \"Default\" first."
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ColumnLayout {
id: controlsRadioButtonGroup
width: parent.width
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
ButtonGroup { id: controlsButtonGroup }
SimplifiedControls.RadioButton {
id: controlsDefault
text: "Default"
ButtonGroup.group: controlsButtonGroup
checked: MyAvatar.getControlScheme() === 0
onClicked: {
MyAvatar.setControlScheme(0);
}
}
SimplifiedControls.RadioButton {
id: controlsAnalog
text: "Analog"
ButtonGroup.group: controlsButtonGroup
checked: MyAvatar.getControlScheme() === 1
onClicked: {
MyAvatar.setControlScheme(1);
}
}
Item {
id: controlsAdvancedContainer
Layout.minimumWidth: parent.width
Layout.minimumHeight: 14
SimplifiedControls.RadioButton {
id: controlsAdvanced
text: "Advanced"
ButtonGroup.group: controlsButtonGroup
checked: MyAvatar.getControlScheme() === 2
onClicked: {
MyAvatar.setControlScheme(2);
}
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
height: 14
}
SimplifiedControls.Slider {
id: controlsAdvancedMovementSpeed
anchors.top: parent.top
anchors.topMargin: 4 // For perfect alignment
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 300
height: 14
labelText: "Movement Speed"
labelTextColor: simplifiedUI.colors.text.darkGrey
from: 3
to: 30
defaultValue: 6
value: MyAvatar.analogPlusWalkSpeed
live: true
onValueChanged: {
if (MyAvatar.analogPlusWalkSpeed != controlsAdvancedMovementSpeed.value) {
MyAvatar.analogPlusWalkSpeed = controlsAdvancedMovementSpeed.value;
}
}
}
}
}
}
ColumnLayout {
id: micControlsContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: micControlsTitle
text: "Default Mute Controls"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: micControlsSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "These settings let you configure how you communicate with others in your HQ while in VR mode. Push to Talk works like a walkie-talkie!"
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ColumnLayout {
id: micControlsSwitchGroup
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
SimplifiedControls.Switch {
id: muteMicrophoneSwitch
width: parent.width
height: simplifiedUI.sizes.controls.simplifiedSwitch.switchBackgroundHeight
labelTextOn: "Mute Microphone"
checked: AudioScriptingInterface.mutedHMD
onClicked: {
AudioScriptingInterface.mutedHMD = !AudioScriptingInterface.mutedHMD;
}
}
SimplifiedControls.Switch {
id: pushToTalkSwitch
width: parent.width
height: simplifiedUI.sizes.controls.simplifiedSwitch.switchBackgroundHeight
labelTextOn: "Push to Talk - Press and Hold Grip Triggers to Talk"
checked: AudioScriptingInterface.pushToTalkHMD
onClicked: {
AudioScriptingInterface.pushToTalkHMD = !AudioScriptingInterface.pushToTalkHMD;
}
}
}
}
ColumnLayout {
id: inputDeviceContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: inputDeviceTitle
text: "Which input device?"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: inputDeviceSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "Here are all of the input devices and microphones that we found. Select the one you'd like to use in your HQ while in VR mode."
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ButtonGroup { id: inputDeviceButtonGroup }
ListView {
id: inputDeviceListView;
anchors.left: parent.left
anchors.right: parent.right
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false;
height: contentItem.height;
spacing: 4;
clip: true;
model: AudioScriptingInterface.devices.input;
delegate: Item {
width: parent.width
height: inputDeviceCheckbox.height
SimplifiedControls.RadioButton {
id: inputDeviceCheckbox
anchors.left: parent.left
width: parent.width - inputLevel.width
checked: selectedHMD;
text: model.devicename
ButtonGroup.group: inputDeviceButtonGroup
onClicked: {
AudioScriptingInterface.setStereoInput(false); // the next selected audio device might not support stereo
AudioScriptingInterface.setInputDevice(model.info, true); // `true` argument for HMD mode setting
}
}
SimplifiedControls.InputPeak {
id: inputLevel
showMuted: AudioScriptingInterface.mutedHMD
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
peak: model.peak;
visible: AudioScriptingInterface.devices.input.peakValuesAvailable;
}
}
}
SimplifiedControls.Button {
property bool audioLoopedBack: AudioScriptingInterface.getLocalEcho()
function startAudioLoopback() {
if (!audioLoopedBack) {
audioLoopedBack = true;
AudioScriptingInterface.setLocalEcho(true);
}
}
function stopAudioLoopback() {
if (audioLoopedBack) {
audioLoopedBack = false;
AudioScriptingInterface.setLocalEcho(false);
}
}
Timer {
id: loopbackTimer
interval: 8000;
running: false;
repeat: false;
onTriggered: {
stopAudioLoopback();
}
}
id: testYourMicButton
enabled: HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32
text: audioLoopedBack ? "STOP TESTING" : "TEST YOUR MIC"
onClicked: {
if (audioLoopedBack) {
loopbackTimer.stop();
stopAudioLoopback();
} else {
loopbackTimer.restart();
startAudioLoopback();
}
}
}
}
ColumnLayout {
id: outputDeviceContainer
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikRegular {
id: outputDeviceTitle
text: "Which output device?"
Layout.maximumWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
HifiStylesUit.GraphikRegular {
id: outputDeviceSubtitle
Layout.topMargin: simplifiedUI.margins.settings.subtitleTopMargin
text: "Here are all of the output devices that we found. Select the one you'd like to use in your HQ while in VR mode."
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
height: paintedHeight
size: 14
color: simplifiedUI.colors.text.darkGrey
}
ButtonGroup { id: outputDeviceButtonGroup }
ListView {
id: outputDeviceListView;
anchors.left: parent.left
anchors.right: parent.right
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false;
height: contentItem.height;
spacing: 4;
clip: true;
model: AudioScriptingInterface.devices.output;
delegate: Item {
width: parent.width
height: outputDeviceCheckbox.height
SimplifiedControls.RadioButton {
id: outputDeviceCheckbox
anchors.left: parent.left
width: parent.width
checked: selectedDesktop;
text: model.devicename
ButtonGroup.group: outputDeviceButtonGroup
onClicked: {
AudioScriptingInterface.setOutputDevice(model.info, true); // `false` argument for Desktop mode setting
}
}
}
}
SimplifiedControls.Button {
property var sound: null;
property var sample: null;
property bool isPlaying: false;
function createSampleSound() {
sound = ApplicationInterface.getSampleSound();
sample = null;
}
function playSound() {
// FIXME: MyAvatar is not properly exposed to QML; MyAvatar.qmlPosition is a stopgap
// FIXME: AudioScriptingInterface.playSystemSound should not require position
if (sample === null && !isPlaying) {
sample = AudioScriptingInterface.playSystemSound(sound, MyAvatar.qmlPosition);
isPlaying = true;
sample.finished.connect(reset);
}
}
function stopSound() {
if (sample && isPlaying) {
sample.stop();
}
}
function reset() {
sample.finished.disconnect(reset);
isPlaying = false;
sample = null;
}
Component.onCompleted: createSampleSound();
Component.onDestruction: stopSound();
onVisibleChanged: {
if (!visible) {
stopSound();
}
}
id: testYourSoundButton
enabled: HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32
text: isPlaying ? "STOP TESTING" : "TEST YOUR SOUND"
onClicked: {
isPlaying ? stopSound() : playSound();
}
}
}
}
}

View file

@ -0,0 +1,169 @@
//
// SimplifiedConstants.qml
//
// Created by Zach Fox on 2019-05-02
// Copyright 2019 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.10
QtObject {
readonly property QtObject colors: QtObject {
readonly property QtObject text: QtObject {
readonly property color almostWhite: "#FAFAFA"
readonly property color lightGrey: "#CCCCCC"
readonly property color darkGrey: "#8F8F8F"
readonly property color white: "#FFFFFF"
readonly property color lightBlue: "#00B4EF"
readonly property color lightBlueHover: "#3dcfff"
}
readonly property QtObject controls: QtObject {
readonly property QtObject radioButton: QtObject {
readonly property QtObject checked: QtObject {
readonly property color startColor: "#7d7d7d"
readonly property color checkboxFinish: "#6b6a6b"
}
readonly property QtObject unchecked: QtObject {
readonly property color startColor: "#7d7d7d"
readonly property color checkboxFinish: "#6b6a6b"
}
}
readonly property QtObject slider: QtObject {
readonly property QtObject background: QtObject {
readonly property color empty: "#252525"
readonly property QtObject filled: QtObject {
readonly property color start: "#0093C5"
readonly property color finish: "#00B4EF"
}
}
readonly property QtObject handle: QtObject {
readonly property color border: "#000000"
readonly property QtObject normal: QtObject {
readonly property color start: "#828282"
readonly property color finish: "#6A6A6A"
}
readonly property QtObject pressed: QtObject {
readonly property color start: "#6A6A6A"
readonly property color finish: "#828282"
}
}
}
readonly property QtObject simplifiedSwitch: QtObject {
readonly property QtObject background: QtObject {
readonly property color off: "#252525"
readonly property color hover: "#00b4ef"
readonly property color pressed: "#ffffff"
readonly property color on: "#ffffff"
}
readonly property QtObject handle: QtObject {
readonly property color off: "#6A6A6A"
readonly property color hover: "#00b4ef"
readonly property color pressed: "#0093C5"
readonly property color on: "#0093C5"
}
readonly property QtObject text: QtObject {
readonly property color off: "#8F8F8F"
readonly property color on: "#ffffff"
}
}
readonly property QtObject button: QtObject {
readonly property QtObject background: QtObject {
readonly property color disabled: "#191919"
readonly property color enabled: "#191919"
readonly property color hover: "#00B4EF"
readonly property color active: "#00B4EF"
}
readonly property QtObject border: QtObject {
readonly property color disabled: "#8F8F8F"
readonly property color enabled: "#FFFFFF"
readonly property color hover: "#FFFFFF"
readonly property color active: "#FFFFFF"
}
readonly property QtObject text: QtObject {
readonly property color disabled: "#8F8F8F"
readonly property color enabled: "#FFFFFF"
}
}
readonly property QtObject outputVolumeButton: QtObject {
readonly property QtObject text: QtObject {
readonly property color muted: "#b20012"
readonly property color noisy: "#FFFFFF"
}
}
readonly property QtObject inputVolumeButton: QtObject {
readonly property QtObject text: QtObject {
readonly property color muted: "#b20012"
readonly property color noisy: "#FFFFFF"
}
}
}
readonly property color darkSeparator: "#595959"
readonly property color darkBackground: "#1A1A1A"
readonly property color darkBackgroundHighlight: "#575757"
readonly property color highlightOnDark: Qt.rgba(1, 1, 1, 0.2)
readonly property color white: "#FFFFFF"
}
readonly property QtObject glyphs: QtObject {
readonly property string gear: "@"
readonly property string editPencil: "\ue00d"
readonly property string playback_play: "\ue01d"
readonly property string stop_square: "\ue01e"
readonly property string hmd: "b"
readonly property string screen: "c"
readonly property string vol_0: "\ue00e"
readonly property string vol_1: "\ue00f"
readonly property string vol_2: "\ue010"
readonly property string vol_3: "\ue011"
readonly property string vol_4: "\ue012"
readonly property string vol_x_0: "\ue013"
readonly property string vol_x_1: "\ue014"
readonly property string vol_x_2: "\ue015"
readonly property string vol_x_3: "\ue016"
readonly property string vol_x_4: "\ue017"
}
readonly property QtObject margins: QtObject {
readonly property QtObject controls: QtObject {
readonly property QtObject radioButton: QtObject {
readonly property int labelLeftMargin: 6
}
readonly property QtObject simplifiedSwitch: QtObject {
readonly property int handleMargins: 2
}
}
readonly property QtObject settings: QtObject {
property real subtitleTopMargin: 2
property real settingsGroupTopMargin: 10
property real spacingBetweenSettings: 24
}
}
readonly property QtObject sizes: QtObject {
readonly property QtObject controls: QtObject {
readonly property QtObject slider: QtObject {
readonly property int height: 14
readonly property int labelTextSize: 14
readonly property int backgroundHeight: 8
}
readonly property QtObject simplifiedSwitch: QtObject {
readonly property int switchBackgroundHeight: 18
readonly property int switchBackgroundWidth: 47
readonly property int labelTextSize: 14
readonly property int labelGlyphSize: 32
}
readonly property QtObject button: QtObject {
readonly property int borderWidth: 1
readonly property int textPadding: 16
readonly property int width: 160
readonly property int height: 32
readonly property int textSize: 14
}
}
}
}

View file

@ -0,0 +1,106 @@
//
// Button.qml
//
// Created by Zach Fox on 2019-05-08
// Copyright 2019 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.10
import QtQuick.Controls 2.3 as Original
import stylesUit 1.0 as HifiStylesUit
import "../simplifiedConstants" as SimplifiedConstants
import TabletScriptingInterface 1.0
Original.Button {
id: root
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
hoverEnabled: true
width: simplifiedUI.sizes.controls.button.width
height: simplifiedUI.sizes.controls.button.height
onHoveredChanged: {
if (hovered && enabled) {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onFocusChanged: {
if (focus && enabled) {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
if (enabled) {
Tablet.playSound(TabletEnums.ButtonClick);
}
}
background: Rectangle {
implicitWidth: root.width
implicitHeight: root.height
color: {
if (root.enabled) {
if (root.hovered) {
simplifiedUI.colors.controls.button.background.enabled
} else if (root.down) {
simplifiedUI.colors.controls.button.background.active
} else {
simplifiedUI.colors.controls.button.background.enabled
}
} else {
simplifiedUI.colors.controls.button.background.disabled
}
}
border.width: simplifiedUI.sizes.controls.button.borderWidth
border.color: root.enabled ? simplifiedUI.colors.controls.button.border.enabled : simplifiedUI.colors.controls.button.border.disabled
Item {
clip: true;
visible: root.enabled
anchors.centerIn: parent
width: parent.width - parent.border.width * 2
height: parent.height - parent.border.width * 2
Rectangle {
z: -1
clip: true
width: root.down ? parent.width * 1.5 : (root.hovered ? parent.width * 9 / 10 : 0)
height: parent.height
anchors.horizontalCenter: parent.horizontalCenter
anchors.horizontalCenterOffset: -14
color: simplifiedUI.colors.controls.button.background.active
Behavior on width {
enabled: true
SmoothedAnimation { velocity: 400 }
}
transform: Matrix4x4 {
property real a: Math.PI / 4
matrix: Qt.matrix4x4(1, Math.tan(a), 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1)
}
}
}
}
contentItem: HifiStylesUit.GraphikMedium {
id: buttonText
topPadding: -2 // Necessary for proper alignment using Graphik Medium
wrapMode: Text.Wrap
color: enabled ? simplifiedUI.colors.controls.button.text.enabled : simplifiedUI.colors.controls.button.text.disabled
size: simplifiedUI.sizes.controls.button.textSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: root.text
}
}

View file

@ -0,0 +1,101 @@
//
// InputPeak.qml
//
// Created by Zach Pomerantz on 6/20/2017
// Copyright 2017 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.10
import QtGraphicalEffects 1.0
Item {
property var peak;
property alias showMuted: status.visible
width: 70;
height: 8;
QtObject {
id: colors;
readonly property string unmuted: "#FFF";
readonly property string muted: "#E2334D";
readonly property string gutter: "#575757";
readonly property string greenStart: "#39A38F";
readonly property string greenEnd: "#1FC6A6";
readonly property string yellow: "#C0C000";
readonly property string red: colors.muted;
readonly property string fill: "#55000000";
}
Text {
id: status;
anchors {
horizontalCenter: parent.horizontalCenter;
verticalCenter: parent.verticalCenter;
}
visible: false;
color: colors.muted;
text: "MUTED";
font.pointSize: 10;
}
Item {
id: bar;
width: parent.width;
height: parent.height;
anchors { fill: parent }
visible: !status.visible;
Rectangle { // base
radius: 4;
anchors { fill: parent }
color: colors.gutter;
}
Rectangle { // mask
id: mask;
width: parent.width * peak;
radius: 5;
anchors {
bottom: parent.bottom;
bottomMargin: 0;
top: parent.top;
topMargin: 0;
left: parent.left;
leftMargin: 0;
}
}
LinearGradient {
anchors { fill: mask }
source: mask
start: Qt.point(0, 0);
end: Qt.point(bar.width, 0);
gradient: Gradient {
GradientStop {
position: 0;
color: colors.greenStart;
}
GradientStop {
position: 0.5;
color: colors.greenEnd;
}
GradientStop {
position: 1;
color: colors.yellow;
}
}
}
}
}

View file

@ -0,0 +1,119 @@
//
// RadioButton.qml
//
// Created by Zach Fox on 2019-05-06
// Copyright 2019 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.10
import QtQuick.Controls 2.3
import TabletScriptingInterface 1.0
import "../simplifiedConstants" as SimplifiedConstants
RadioButton {
id: root
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
padding: 0
property alias labelTextColor: radioButtonLabel.color
property alias labelFontSize: radioButtonLabel.font.pixelSize
property int radioButtonRadius: 14
property int labelLeftMargin: simplifiedUI.margins.controls.radioButton.labelLeftMargin
property bool wrapLabel: true;
readonly property int checkSize: Math.max(root.radioButtonRadius - 8, 10)
focusPolicy: Qt.ClickFocus
hoverEnabled: true
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
}
onHoveredChanged: {
if (hovered) {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
indicator: Rectangle {
id: radioButtonIndicator
implicitWidth: root.radioButtonRadius
implicitHeight: root.radioButtonRadius
radius: root.radioButtonRadius
y: parent.height / 2 - height / 2
border.width: 1
border.color: pressed || hovered
? hifi.colors.checkboxCheckedBorder
: hifi.colors.checkboxDarkFinish
gradient: Gradient {
GradientStop {
position: 0.2
color: pressed || hovered
? hifi.colors.checkboxLightStart
: hifi.colors.checkboxDarkStart
}
GradientStop {
position: 1.0
color: pressed || hovered
? hifi.colors.checkboxLightFinish
: hifi.colors.checkboxDarkFinish
}
}
Rectangle {
id: innerBox
visible: pressed || hovered
anchors.centerIn: parent
width: checkSize - 4
height: width
radius: checkSize / 2
color: hifi.colors.checkboxCheckedBorder
}
Rectangle {
id: check
width: checkSize
height: checkSize
radius: checkSize / 2
anchors.centerIn: parent
color: hifi.colors.checkboxChecked
border.width: 2
border.color: hifi.colors.checkboxCheckedBorder
visible: checked && !pressed || !checked && pressed
}
Rectangle {
id: disabledOverlay
visible: !enabled
width: root.radioButtonRadius
height: root.radioButtonRadius
radius: root.radioButtonRadius / 2
border.width: 1
border.color: hifi.colors.baseGrayHighlight
color: hifi.colors.baseGrayHighlight
opacity: 0.5
}
}
contentItem: Text {
id: radioButtonLabel
height: root.radioButtonRadius
font.pixelSize: 14
font.family: "Graphik"
font.weight: Font.Normal
text: root.text
color: simplifiedUI.colors.text.white
x: 2
wrapMode: root.wrapLabel ? Text.Wrap : Text.NoWrap
elide: root.wrapLabel ? Text.ElideNone : Text.ElideRight
enabled: root.enabled
verticalAlignment: Text.AlignVCenter
leftPadding: radioButtonIndicator.width + root.labelLeftMargin
}
}

View file

@ -0,0 +1,120 @@
//
// Slider.qml
//
// Created by Zach Fox on 2019-05-06
// Copyright 2019 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.10
import QtQuick.Controls 2.3
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
import "../simplifiedConstants" as SimplifiedConstants
Item {
id: root
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
property alias labelText: sliderText.text
property alias labelTextSize: sliderText.size
property alias labelTextColor: sliderText.color
property alias value: sliderControl.value
property alias from: sliderControl.from
property alias to: sliderControl.to
property alias live: sliderControl.live
property alias stepSize: sliderControl.stepSize
property alias snapMode: sliderControl.snapMode
property real defaultValue: 0.0
HifiStylesUit.GraphikRegular {
id: sliderText
text: ""
anchors.right: sliderControl.left
anchors.rightMargin: 8
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: -4 // Necessary for vertical alignment
anchors.bottom: parent.bottom
horizontalAlignment: Text.AlignRight
visible: sliderText.text != ""
color: simplifiedUI.colors.text.white
size: simplifiedUI.sizes.controls.slider.labelTextSize
}
Slider {
id: sliderControl
height: simplifiedUI.sizes.controls.slider.height
width: root.width * 0.6
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
onPressedChanged: {
if (pressed) {
Tablet.playSound(TabletEnums.ButtonClick);
}
}
onHoveredChanged: {
if (hovered) {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
background: Rectangle {
id: sliderBackground
width: sliderControl.width
height: simplifiedUI.sizes.controls.slider.backgroundHeight
y: sliderControl.height / 2 - height / 2
radius: height / 2
color: simplifiedUI.colors.controls.slider.background.empty
Rectangle {
width: sliderControl.visualPosition * sliderControl.width
height: parent.height
radius: height / 2
gradient: Gradient {
GradientStop { position: 0.0; color: simplifiedUI.colors.controls.slider.background.filled.start }
GradientStop { position: 1.0; color: simplifiedUI.colors.controls.slider.background.filled.finish }
}
}
}
handle: Rectangle {
width: sliderControl.height
height: sliderControl.height
x: sliderControl.visualPosition * (sliderControl.width - width)
y: sliderControl.height / 2 - height / 2
radius: height / 2
gradient: Gradient {
GradientStop {
position: 0.0
color: sliderControl.pressed
? (simplifiedUI.colors.controls.slider.handle.pressed.start)
: (simplifiedUI.colors.controls.slider.handle.normal.start)
}
GradientStop {
position: 1.0
color: sliderControl.pressed
? (simplifiedUI.colors.controls.slider.handle.pressed.finish)
: (simplifiedUI.colors.controls.slider.handle.normal.finish)
}
}
Rectangle {
height: parent.height - 2
width: height
radius: height / 2
anchors.centerIn: parent
color: "transparent"
border.width: 1
border.color: simplifiedUI.colors.controls.slider.handle.border
}
}
}
}

View file

@ -0,0 +1,204 @@
//
// Switch.qml
//
// Created by Zach Fox on 2019-05-08
// Copyright 2019 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.10
import QtQuick.Controls 2.3 as Original
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
import "../simplifiedConstants" as SimplifiedConstants
Item {
id: root
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
property alias switchWidth: switchBackground.width
property alias labelTextOff: labelOff.text
property alias labelTextOffSize: labelOff.size
property alias labelGlyphOffText: labelGlyphOff.text
property alias labelGlyphOffSize: labelGlyphOff.size
property alias labelTextOn: labelOn.text
property alias labelTextOnSize: labelOn.size
property alias labelGlyphOnText: labelGlyphOn.text
property alias labelGlyphOnSize: labelGlyphOn.size
property alias checked: originalSwitch.checked
property string backgroundOnColor: "#252525"
signal clicked
function changeColor() {
if (originalSwitch.checked) {
if (originalSwitch.hovered) {
switchHandle.color = simplifiedUI.colors.controls.simplifiedSwitch.handle.hover;
} else {
switchHandle.color = simplifiedUI.colors.controls.simplifiedSwitch.handle.on;
}
} else {
if (originalSwitch.hovered) {
switchHandle.color = simplifiedUI.colors.controls.simplifiedSwitch.handle.hover;
} else {
switchHandle.color = simplifiedUI.colors.controls.simplifiedSwitch.handle.off;
}
}
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
}
Original.Switch {
id: originalSwitch
focusPolicy: Qt.ClickFocus
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: labelOff.text === "" ? undefined : parent.horizontalCenter
anchors.left: labelOff.text === "" ? parent.left : undefined
width: simplifiedUI.sizes.controls.simplifiedSwitch.switchBackgroundWidth
hoverEnabled: true
onCheckedChanged: {
root.checkedChanged();
Tablet.playSound(TabletEnums.ButtonClick);
root.changeColor();
}
onClicked: {
root.clicked();
root.changeColor();
}
onHoveredChanged: {
if (hovered) {
Tablet.playSound(TabletEnums.ButtonHover);
}
root.changeColor();
}
background: Rectangle {
id: switchBackground
anchors.verticalCenter: parent.verticalCenter
color: originalSwitch.checked ? simplifiedUI.colors.controls.simplifiedSwitch.background.on : simplifiedUI.colors.controls.simplifiedSwitch.background.off
width: originalSwitch.width
height: root.height
radius: height/2
}
indicator: Rectangle {
id: switchHandle
anchors.verticalCenter: parent.verticalCenter
width: switchBackground.height - (2 * simplifiedUI.margins.controls.simplifiedSwitch.handleMargins)
height: switchHandle.width
radius: switchHandle.width/2
color: originalSwitch.checked ? simplifiedUI.colors.controls.simplifiedSwitch.handle.on : simplifiedUI.colors.controls.simplifiedSwitch.handle.off
x: originalSwitch.visualPosition * switchBackground.width - (switchHandle.width / 2) + (originalSwitch.checked ? -5 * simplifiedUI.margins.controls.simplifiedSwitch.handleMargins : 5 * simplifiedUI.margins.controls.simplifiedSwitch.handleMargins)
y: simplifiedUI.margins.controls.simplifiedSwitch.handleMargins
Behavior on x {
enabled: !originalSwitch.down
SmoothedAnimation { velocity: 200 }
}
}
}
// OFF Label
Item {
anchors.right: originalSwitch.left
anchors.rightMargin: 10
anchors.top: parent.top
anchors.bottom: parent.bottom
HifiStylesUit.GraphikRegular {
id: labelOff
text: ""
size: simplifiedUI.sizes.controls.simplifiedSwitch.labelTextSize
color: originalSwitch.checked ? simplifiedUI.colors.controls.simplifiedSwitch.text.off : simplifiedUI.colors.controls.simplifiedSwitch.text.on
anchors.top: parent.top
anchors.topMargin: -2 // Necessary for text alignment
anchors.bottom: parent.bottom
anchors.right: parent.right
width: paintedWidth
verticalAlignment: Text.AlignVCenter
}
HifiStylesUit.HiFiGlyphs {
id: labelGlyphOff
text: ""
size: simplifiedUI.sizes.controls.simplifiedSwitch.labelGlyphSize
color: labelOff.color
anchors.top: parent.top
anchors.topMargin: 2
anchors.right: labelOff.left
anchors.rightMargin: 4
}
MouseArea {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: labelGlyphOff.left
anchors.right: labelOff.right
onClicked: {
if (labelOn.text === "" && labelGlyphOn.text === "") {
originalSwitch.checked = !originalSwitch.checked;
} else {
originalSwitch.checked = false;
}
root.clicked();
}
}
}
// ON Label
Item {
anchors.left: originalSwitch.right
anchors.leftMargin: 10
anchors.top: parent.top
anchors.bottom: parent.bottom
HifiStylesUit.GraphikRegular {
id: labelOn
text: ""
size: simplifiedUI.sizes.controls.simplifiedSwitch.labelTextSize
color: originalSwitch.checked ? simplifiedUI.colors.controls.simplifiedSwitch.text.on : simplifiedUI.colors.controls.simplifiedSwitch.text.off
anchors.top: parent.top
anchors.topMargin: -2 // Necessary for text alignment
anchors.left: parent.left
width: paintedWidth
height: parent.height
verticalAlignment: Text.AlignVCenter
}
HifiStylesUit.HiFiGlyphs {
id: labelGlyphOn
text: ""
size: simplifiedUI.sizes.controls.simplifiedSwitch.labelGlyphSize
color: labelOn.color
anchors.top: parent.top
anchors.topMargin: 2
anchors.left: labelOn.right
anchors.leftMargin: 4
}
MouseArea {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: labelOn.left
anchors.right: labelGlyphOn.right
onClicked: {
if (labelOff.text === "" && labelGlyphOff.text === "") {
originalSwitch.checked = !originalSwitch.checked;
} else {
originalSwitch.checked = true;
}
root.clicked();
}
}
}
}

View file

@ -0,0 +1,238 @@
//
// SimplifiedTopBar.qml
//
// Created by Zach Fox on 2019-05-02
// Copyright 2019 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.10
import "../simplifiedConstants" as SimplifiedConstants
import "../inputDeviceButton" as InputDeviceButton
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
import QtGraphicalEffects 1.0
Rectangle {
id: root
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
color: simplifiedUI.colors.darkBackground
anchors.fill: parent;
Item {
id: avatarButtonContainer
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: 16
width: height
Image {
id: avatarButtonImage
source: "images/defaultAvatar.jpg"
anchors.centerIn: parent
width: parent.width - 10
height: width
mipmap: true
fillMode: Image.PreserveAspectCrop
layer.enabled: true
layer.effect: OpacityMask {
maskSource: mask
}
MouseArea {
id: avatarButtonImageMouseArea
anchors.fill: parent
hoverEnabled: enabled
onEntered: {
Tablet.playSound(TabletEnums.ButtonHover);
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
if (Account.loggedIn) {
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "toggleAvatarApp"
});
} else {
DialogsManager.showLoginDialog();
}
}
}
}
Rectangle {
z: -1
id: borderMask
visible: avatarButtonImageMouseArea.containsMouse
width: avatarButtonImage.width + 4
height: width
radius: width
anchors.centerIn: avatarButtonImage
color: "#FFFFFF"
}
Rectangle {
id: mask
anchors.fill: avatarButtonImage
radius: avatarButtonImage.width
visible: false
}
}
InputDeviceButton.InputDeviceButton {
id: inputDeviceButton
anchors.left: avatarButtonContainer.right
anchors.leftMargin: 8
anchors.top: parent.top
anchors.bottom: parent.bottom
}
Item {
id: outputDeviceButtonContainer
anchors.left: inputDeviceButton.right
anchors.leftMargin: 8
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 40
HifiStylesUit.HiFiGlyphs {
property bool outputMuted: false
id: outputDeviceButton
text: (outputDeviceButton.outputMuted ? simplifiedUI.glyphs.vol_0 : simplifiedUI.glyphs.vol_3)
color: (outputDeviceButton.outputMuted ? simplifiedUI.colors.controls.outputVolumeButton.text.muted : simplifiedUI.colors.controls.outputVolumeButton.text.noisy)
opacity: outputDeviceButtonMouseArea.containsMouse ? 1.0 : 0.7
size: 40
anchors.centerIn: parent
width: 35
height: parent.height
horizontalAlignment: Text.AlignHCenter
MouseArea {
id: outputDeviceButtonMouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: {
Tablet.playSound(TabletEnums.ButtonHover);
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
outputDeviceButton.outputMuted = !outputDeviceButton.outputMuted;
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "setOutputMuted",
"data": {
"outputMuted": outputDeviceButton.outputMuted
}
});
}
}
}
}
Item {
id: hmdButtonContainer
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: settingsButtonContainer.left
anchors.rightMargin: 8
width: height
HifiStylesUit.HiFiGlyphs {
id: hmdGlyph
text: HMD.active ? simplifiedUI.glyphs.hmd : simplifiedUI.glyphs.screen
color: simplifiedUI.colors.text.white
opacity: hmdGlyphMouseArea.containsMouse ? 1.0 : 0.7
size: 40
anchors.centerIn: parent
width: 35
height: parent.height
horizontalAlignment: Text.AlignHCenter
MouseArea {
id: hmdGlyphMouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: {
Tablet.playSound(TabletEnums.ButtonHover);
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
// TODO: actually do this right and change the display plugin
HMD.active = !HMD.active;
}
}
}
}
Item {
id: settingsButtonContainer
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin: 16
width: height
HifiStylesUit.HiFiGlyphs {
id: settingsGlyph
text: simplifiedUI.glyphs.gear
color: simplifiedUI.colors.text.white
opacity: settingsGlyphMouseArea.containsMouse ? 1.0 : 0.7
size: 40
anchors.centerIn: parent
width: 35
height: parent.height
horizontalAlignment: Text.AlignHCenter
MouseArea {
id: settingsGlyphMouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: {
Tablet.playSound(TabletEnums.ButtonHover);
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "toggleSettingsApp"
});
}
}
}
}
function fromScript(message) {
if (message.source !== "simplifiedUI.js") {
return;
}
switch (message.method) {
case "updateAvatarThumbnailURL":
avatarButtonImage.source = message.data.avatarThumbnailURL;
break;
case "updateOutputMuted":
outputDeviceButton.outputMuted = message.data.outputMuted;
break;
default:
console.log('SimplifiedTopBar.qml: Unrecognized message from JS');
break;
}
}
signal sendToScript(var message);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View file

@ -0,0 +1,21 @@
//
// GraphikMedium.qml
//
// Created by Wayne Chen on 3 May 2019
// Copyright 2019 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.7
Text {
id: root
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: "Graphik"
font.weight: Font.Medium
}

View file

@ -0,0 +1,20 @@
//
// GraphikRegular.qml
//
// Created by Wayne Chen on 2 May 2019
// Copyright 2019 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.7
Text {
id: root
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: "Graphik"
}

View file

@ -0,0 +1,21 @@
//
// GraphikSemiBold.qml
//
// Created by Wayne Chen on 2 May 2019
// Copyright 2019 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.7
Text {
id: root
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
font.family: "Graphik"
font.weight: Font.DemiBold
}

View file

@ -5,12 +5,16 @@ FiraSansRegular 1.0 FiraSansRegular.qml
FiraSansSemiBold 1.0 FiraSansSemiBold.qml
HifiConstants 1.0 HifiConstants.qml
HiFiGlyphs 1.0 HiFiGlyphs.qml
GraphikMedium 1.0 GraphikMedium.qml
GraphikRegular 1.0 GraphikRegular.qml
GraphikSemiBold 1.0 GraphikSemiBold.qml
IconButton 1.0 IconButton.qml
InfoItem 1.0 InfoItem.qml
InputLabel 1.0 InputLabel.qml
ListItem 1.0 ListItem.qml
Logs 1.0 Logs.qml
OverlayTitle 1.0 OverlayTitle.qml
Rawline 1.0 Rawline.qml
RalewayBold 1.0 RalewayBold.qml
RalewayLight 1.0 RalewayLight.qml
RalewayRegular 1.0 RalewayRegular.qml
@ -19,4 +23,4 @@ SectionName 1.0 SectionName.qml
Separator 1.0 Separator.qml
ShortcutText 1.0 ShortcutText.qml
TabName 1.0 TabName.qml
TextFieldInput 1.0 TextFieldInput.qml
TextFieldInput 1.0 TextFieldInput.qml

View file

@ -1116,6 +1116,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-Bold.ttf");
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Raleway-SemiBold.ttf");
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Cairo-SemiBold.ttf");
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Graphik-SemiBold.ttf");
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Graphik-Regular.ttf");
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Graphik-Medium.ttf");
_window->setWindowTitle("High Fidelity Interface");
Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us
@ -3062,6 +3065,7 @@ void Application::initializeUi() {
QmlContextCallback commerceCallback = [](QQmlContext* context) {
context->setContextProperty("Commerce", DependencyManager::get<QmlCommerce>().data());
};
OffscreenQmlSurface::addWhitelistContextHandler({
QUrl{ "hifi/commerce/checkout/Checkout.qml" },
QUrl{ "hifi/commerce/common/CommerceLightbox.qml" },
@ -3087,6 +3091,7 @@ void Application::initializeUi() {
QUrl{ "hifi/dialogs/security/SecurityImageSelection.qml" },
QUrl{ "hifi/tablet/TabletMenu.qml" },
QUrl{ "hifi/commerce/marketplace/Marketplace.qml" },
QUrl{ "hifi/simplifiedUI/avatarApp/AvatarApp.qml" },
}, commerceCallback);
QmlContextCallback marketplaceCallback = [](QQmlContext* context) {

View file

@ -370,6 +370,8 @@ class MyAvatar : public Avatar {
Q_PROPERTY(QUuid SELF_ID READ getSelfID CONSTANT)
Q_PROPERTY(float walkSpeed READ getWalkSpeed WRITE setWalkSpeed);
Q_PROPERTY(float analogPlusWalkSpeed READ getAnalogPlusWalkSpeed WRITE setAnalogPlusWalkSpeed);
Q_PROPERTY(float analogPlusSprintSpeed READ getAnalogPlusSprintSpeed WRITE setAnalogPlusSprintSpeed);
Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed);
Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed);
Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState);

View file

@ -0,0 +1,26 @@
//
// Simplified Nametag
// defaultLocalEntityProps.js
// Created by Milad Nazeri on 2019-03-09
// Copyright 2019 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
//
// Base properties for the Local Entities
//
var localEntityProps = {
dimensions: [1, 0.1, 0],
type: "Text",
lineHeight: 0.1,
textColor: "#ffffff",
textAlpha: 1.0,
backgroundColor: "#2d2d2d",
backgroundAlpha: 0.6,
billboardMode: "full",
lifetime: 3,
canCastShadow: true
};
module.exports = localEntityProps;

View file

@ -0,0 +1,154 @@
//
// Simplified Nametag
// entityMaker.js
// Created by Milad Nazeri on 2019-02-19
// Copyright 2019 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
//
// A helper library to make entities
//
Script.require('./objectAssign.js');
function EntityMaker(type) {
this.properties = {};
this.cache = {};
this.id = null;
this.created = null;
this.type = type;
}
// *************************************
// START API
// *************************************
// #region API
// Add properties to the cache / temporary storage
function add(props){
// You can either add an object of props or 2 arguments as key and value
if (arguments.length === 2) {
var property = arguments[0];
var value = arguments[1];
props = {};
props[property] = value;
}
this.properties = Object.assign({}, this.properties, props);
this.cache = Object.assign({}, this.cache, this.properties);
return this;
}
// Sends the current temporary stroage to edit the entity
function sync(){
Entities.editEntity(this.id, this.properties);
this.properties = {};
return this;
}
// Immediately edit the entity with the properties given
function edit(props){
if (arguments.length === 2) {
var property = arguments[0];
var value = arguments[1];
props = {};
props[property] = value;
}
this.properties = Object.assign({}, this.properties, props);
this.cache = Object.assign({}, this.cache, this.properties);
this.sync();
return this;
}
// Get a property either from the cache or by querying the entity directly
function get(propertyKeys, queryEntity){
if (queryEntity && typeof propertyKeys === 'string') {
var propertyValue = Entities.getEntityProperties(this.id, propertyKeys)[propertyKeys];
this.properties[propertyKeys] = propertyValue;
this.cache = Object.assign({}, this.cache, this.properties);
return propertyValue;
}
if (queryEntity && Array.isArray(propertyKeys)) {
var entityProps = Entities.getEntityProperties(this.id, propertyKeys);
for (var prop in entityProps) {
if (propertyKeys.indexOf(prop) === -1) {
delete entityProps[prop];
} else {
this.properties[prop] = entityProps[prop];
}
}
return entityProps;
}
if (Array.isArray(propertyKeys)) {
var recombinedProps = {};
propertyKeys.forEach(function (prop) {
recombinedProps[prop] = this.cache[prop];
}, this);
return recombinedProps;
}
return this.cache[propertyKeys];
}
// Show the entity
function show(){
this.edit({ visible: true });
return this;
}
// Hide the enity
function hide(){
this.edit({ visible: false });
}
// Add an entity if it isn't created
function create(clearPropertiesAfter){
this.id = Entities.addEntity(this.properties, this.type);
if (clearPropertiesAfter) {
this.properties = {};
}
return this;
}
// Delete the entity
function destroy(){
Entities.deleteEntity(this.id);
return this;
}
// #endregion
// *************************************
// END API
// *************************************
EntityMaker.prototype = {
add: add,
sync: sync,
edit: edit,
get: get,
show: show,
hide: hide,
create: create,
destroy: destroy
};
module.exports = EntityMaker;

View file

@ -0,0 +1,687 @@
//
// Simplified Nametag
// nameTagListManager.js
// Created by Milad Nazeri on 2019-03-09
// Copyright 2019 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
//
// Helps manage the list of avatars added to the nametag list
//
var ON = 'ON';
var OFF = 'OFF';
var DEBUG_ON = true;
var DEBUG_OFF = false;
var log = Script.require(
'https://hifi-content.s3.amazonaws.com/milad/ROLC/d/ROLC_High-Fidelity/02_Organize/O_Projects/Repos/hifi-content/developerTools/sharedLibraries/easyLog/easyLog.js?'
+ Date.now())(DEBUG_OFF, 'nameTagListManager.js');
var EntityMaker = Script.require('./entityMaker.js?' + Date.now());
var entityProps = Script.require('./defaultLocalEntityProps.js?' + Date.now());
var textHelper = new (Script.require('./textHelper.js?' + Date.now()));
var X = 0;
var Y = 1;
var Z = 2;
var HALF = 0.5;
var CLEAR_ENTITY_EDIT_PROPS = true;
var MILISECONDS_IN_SECOND = 1000;
// *************************************
// START UTILTY
// *************************************
// #region UTILTY
// Properties to give new avatars added to the list
function NewAvatarProps() {
return {
avatarInfo: null,
previousDistance: null,
currentDistance: null,
initialDistance: null,
initialDimensions: null,
previousName: null,
timeoutStarted: false
};
}
// Makes sure clear interval exists before changing
function maybeClearInterval() {
if (_this.redrawTimeout) {
Script.clearInterval(_this.redrawTimeout);
_this.redrawTimeout = null;
}
}
// Calculate our initial properties for the nametag
var Z_SIZE = 0.01;
var LINE_HEIGHT_SCALER = 0.99;
var DISTANCE_SCALER_ON = 0.35;
var DISTANCE_SCALER_ALWAYS_ON = 0.65;
var distanceScaler = DISTANCE_SCALER_ON;
var userScaler = 1.0;
var DEFAULT_LINE_HEIGHT = entityProps.lineHeight;
function calculateInitialProperties(uuid) {
var avatar = _this.avatars[uuid];
var avatarInfo = avatar.avatarInfo;
var adjustedScaler = null;
var distance = null;
var dimensions = null;
var lineHeight = null;
var scaledDimensions = null;
var name = null;
// Handle if we are asking for the main or sub properties
name = avatarInfo.displayName;
// Use the text helper to calculate what our dimensions for the text box should be
textHelper
.setText(name)
.setLineHeight(DEFAULT_LINE_HEIGHT);
// Calculate the distance from the camera to the target avatar
distance = getDistance(uuid);
// Adjust the distance by the distance scaler
distanceScaler = avatarNametagMode === "on" ? DISTANCE_SCALER_ON : DISTANCE_SCALER_ALWAYS_ON;
adjustedScaler = distance * distanceScaler;
// Get the new dimensions from the text helper
dimensions = [textHelper.getTotalTextLength(), DEFAULT_LINE_HEIGHT, Z_SIZE];
// Adjust the dimensions by the modified distance scaler
scaledDimensions = Vec3.multiply(dimensions, adjustedScaler);
// Adjust the lineheight to be the new scaled dimensions Y
lineHeight = scaledDimensions[Y] * LINE_HEIGHT_SCALER;
return {
distance: distance,
scaledDimensions: scaledDimensions,
lineHeight: lineHeight
};
}
// Used in alwaysOn mode to show or hide if they reached the max radius
function showHide(uuid, type) {
var avatar = _this.avatars[uuid];
var nametag = avatar.nametag;
if (type === "show") {
nametag.show();
} else {
nametag.hide();
}
}
// Go through the selected avatar list and see if any of the avatars need a redraw
function checkAllSelectedForRedraw() {
for (var avatar in _this.selectedAvatars) {
maybeRedraw(avatar);
}
}
// Remake the nametags if the display name changes
function updateName(uuid) {
var avatar = _this.avatars[uuid];
avatar.nametag.destroy();
avatar.nametag = new EntityMaker('local').add(entityProps);
makeNameTag(uuid);
}
// Get the current data for an avatar.
function getAvatarData(uuid) {
var avatar = _this.avatars[uuid];
var avatarInfo = avatar.avatarInfo;
var newAvatarInfo = AvatarManager.getAvatar(uuid);
// Save the username so it doesn't get overwritten when grabbing new avatarData
var combinedAvatarInfo = Object.assign({}, newAvatarInfo, {
username: avatarInfo === null ? null : avatarInfo.username
});
// Now combine that avatar data with the main avatar object
_this.avatars[uuid] = Object.assign({}, avatar, { avatarInfo: combinedAvatarInfo });
return _this;
}
// Calculate the distance between the camera and the target avatar
function getDistance(uuid, checkAvatar, shouldSave) {
checkAvatar = checkAvatar || false;
shouldSave = shouldSave || true;
var eye = checkAvatar ? MyAvatar.position : Camera.position;
var avatar = _this.avatars[uuid];
var avatarInfo = avatar.avatarInfo;
var target = avatarInfo.position;
var currentDistance = Vec3.distance(target, eye);
if (!checkAvatar && shouldSave) {
avatar.previousDistance = avatar.currentDistance;
avatar.currentDistance = currentDistance;
}
return currentDistance;
}
// Check to see if we need to toggle our interval check because we went to 0 avatars
// or if we got our first avatar in the select list
function shouldToggleInterval() {
var currentNumberOfAvatarsSelected = Object.keys(_this.selectedAvatars).length;
if (currentNumberOfAvatarsSelected === 0 && _this.redrawTimeout) {
toggleInterval();
return;
}
if (currentNumberOfAvatarsSelected > 0 && !_this.redrawTimeout) {
toggleInterval();
return;
}
}
// Turn off and on the redraw check
var INTERVAL_CHECK_MS = 30;
function toggleInterval() {
if (_this.redrawTimeout) {
maybeClearInterval();
} else {
_this.redrawTimeout =
Script.setInterval(checkAllSelectedForRedraw, INTERVAL_CHECK_MS);
}
}
// handle turning the peristenet mode on
function handleAlwaysOnMode(shouldTurnOnAlwaysOnMode) {
_this.reset();
if (shouldTurnOnAlwaysOnMode) {
AvatarManager
.getAvatarIdentifiers()
.forEach(function (avatar) {
if (avatar) {
add(avatar);
}
});
}
}
// #endregion
// *************************************
// END UTILTY
// *************************************
// *************************************
// START Nametag
// *************************************
// #region Nametag
var _this = null;
function nameTagListManager() {
_this = this;
_this.avatars = {};
_this.selectedAvatars = {};
_this.redrawTimeout = null;
}
// Create or make visible either the sub or the main tag.
var REDRAW_TIMEOUT_AMOUNT_MS = 500;
var LEFT_MARGIN_SCALER = 0.15;
var RIGHT_MARGIN_SCALER = 0.10;
var TOP_MARGIN_SCALER = 0.07;
var BOTTOM_MARGIN_SCALER = 0.03;
var ABOVE_HEAD_OFFSET = 0.30;
var DISTANCE_SCALER_INTERPOLATION_OFFSET_ALWAYSON = 25;
var DISTANCE_SCALER_INTERPOLATION_OFFSET_ON = 10;
var maxDistance = MAX_RADIUS_IGNORE_METERS;
var onModeScalar = 0.60;
var alwaysOnModeScalar = -0.55;
function makeNameTag(uuid) {
var avatar = _this.avatars[uuid];
var avatarInfo = avatar.avatarInfo;
var nametag = avatar.nametag;
// Make sure an anonymous name is covered before sending to calculate
avatarInfo.displayName = avatarInfo.displayName === "" ? "anonymous" : avatarInfo.displayName.trim();
avatar.previousName = avatarInfo.displayName;
// Returns back the properties we need based on what we are looking for and the distance from the avatar
var calculatedProps = calculateInitialProperties(uuid);
var distance = calculatedProps.distance;
var scaledDimensions = calculatedProps.scaledDimensions;
var lineHeight = calculatedProps.lineHeight;
// Capture the inital dimensions, distance, and displayName in case we need to redraw
avatar.previousDisplayName = avatarInfo.displayName;
avatar.initialDimensions = scaledDimensions;
avatar.initialDistance = distance;
var name = avatarInfo.displayName;
var parentID = uuid;
nametag.add("text", name);
// Multiply the new dimensions and line height with the user selected scaler
scaledDimensions = Vec3.multiply(scaledDimensions, userScaler);
maxDistance = avatarNametagMode === "on"
? MAX_ON_MODE_DISTANCE + DISTANCE_SCALER_INTERPOLATION_OFFSET_ON
: MAX_RADIUS_IGNORE_METERS + DISTANCE_SCALER_INTERPOLATION_OFFSET_ALWAYSON;
var finalScaler = (distance - maxDistance) / (MIN_DISTANCE - maxDistance);
var remainder = 1 - finalScaler;
var multipliedRemainderOn = remainder * onModeScalar;
var multipliedRemainderAlwaysOn = remainder * alwaysOnModeScalar;
finalScaler = avatarNametagMode === "on" ? finalScaler + multipliedRemainderOn : finalScaler + multipliedRemainderAlwaysOn;
scaledDimensions = Vec3.multiply(scaledDimensions, finalScaler);
lineHeight = scaledDimensions[Y] * LINE_HEIGHT_SCALER;
// Add some room for the margin by using lineHeight as a reference
scaledDimensions[X] += (lineHeight * LEFT_MARGIN_SCALER) + (lineHeight * RIGHT_MARGIN_SCALER);
scaledDimensions[Y] += (lineHeight * TOP_MARGIN_SCALER) + (lineHeight * BOTTOM_MARGIN_SCALER);
var scaledDimenionsYHalf = scaledDimensions[Y] * HALF;
var AvatarData = AvatarManager.getAvatar(uuid);
var headJointIndex = AvatarData.getJointIndex("Head");
var jointInObjectFrame = AvatarData.getAbsoluteJointTranslationInObjectFrame(headJointIndex);
var nameTagPosition = jointInObjectFrame.y + scaledDimenionsYHalf + ABOVE_HEAD_OFFSET;
var localPosition = [0, nameTagPosition, 0];
var visible = true;
if (avatarNametagMode === "alwaysOn") {
var currentDistance = getDistance(uuid, CHECK_AVATAR, false);
visible = currentDistance > MAX_RADIUS_IGNORE_METERS ? false : true;
}
nametag
.add("leftMargin", lineHeight * LEFT_MARGIN_SCALER)
.add("rightMargin", lineHeight * RIGHT_MARGIN_SCALER)
.add("topMargin", lineHeight * TOP_MARGIN_SCALER)
.add("bottomMargin", lineHeight * BOTTOM_MARGIN_SCALER)
.add("lineHeight", lineHeight)
.add("dimensions", scaledDimensions)
.add("parentID", parentID)
.add("localPosition", localPosition)
.add("visible", visible)
.create(CLEAR_ENTITY_EDIT_PROPS);
Script.setTimeout(function () {
nametag.edit("visible", true);
}, REDRAW_TIMEOUT_AMOUNT_MS);
}
// Check to see if the display named changed or if the distance is big enough to need a redraw.
var MAX_RADIUS_IGNORE_METERS = 22;
var MAX_ON_MODE_DISTANCE = 30;
var CHECK_AVATAR = true;
var MIN_DISTANCE = 0.2;
function maybeRedraw(uuid) {
var avatar = _this.avatars[uuid];
var avatarInfo = avatar.avatarInfo;
getAvatarData(uuid);
getDistance(uuid);
var avatarDistance = getDistance(uuid, CHECK_AVATAR, false);
if (avatarNametagMode === "alwaysOn" && avatarDistance > MAX_RADIUS_IGNORE_METERS) {
showHide(uuid, "hide");
}
if (avatarNametagMode === "alwaysOn" && avatarDistance < MAX_RADIUS_IGNORE_METERS) {
showHide(uuid, "show");
}
avatarInfo.displayName = avatarInfo.displayName === "" ? "anonymous" : avatarInfo.displayName.trim();
if (avatar.previousName !== avatarInfo.displayName) {
updateName(uuid, avatarInfo.displayName);
} else {
redraw(uuid);
}
}
// Handle redrawing if needed
function redraw(uuid) {
var avatar = _this.avatars[uuid];
var nametag = avatar.nametag;
var initialDimensions = null;
var initialDistance = null;
var currentDistance = null;
var newDimensions = null;
var lineHeight = null;
initialDistance = avatar.initialDistance;
currentDistance = avatar.currentDistance;
initialDimensions = avatar.initialDimensions;
// Find our new dimensions from the new distance
newDimensions = [
(initialDimensions[X] / initialDistance) * currentDistance,
(initialDimensions[Y] / initialDistance) * currentDistance,
(initialDimensions[Z] / initialDistance) * currentDistance
];
// Multiply the new dimensions and line height with the user selected scaler
newDimensions = Vec3.multiply(newDimensions, userScaler);
var distance = getDistance(uuid, false, false);
maxDistance = avatarNametagMode === "on"
? MAX_ON_MODE_DISTANCE + DISTANCE_SCALER_INTERPOLATION_OFFSET_ON
: MAX_RADIUS_IGNORE_METERS + DISTANCE_SCALER_INTERPOLATION_OFFSET_ALWAYSON;
var finalScaler = (distance - maxDistance) / (MIN_DISTANCE - maxDistance);
var remainder = 1 - finalScaler;
var multipliedRemainderOn = remainder * onModeScalar;
var multipliedRemainderAlwaysOn = remainder * alwaysOnModeScalar;
finalScaler = avatarNametagMode === "on" ? finalScaler + multipliedRemainderOn : finalScaler + multipliedRemainderAlwaysOn;
newDimensions = Vec3.multiply(newDimensions, finalScaler);
lineHeight = newDimensions[Y] * LINE_HEIGHT_SCALER;
// Add some room for the margin by using lineHeight as a reference
newDimensions[X] += (lineHeight * LEFT_MARGIN_SCALER) + (lineHeight * RIGHT_MARGIN_SCALER);
newDimensions[Y] += (lineHeight * TOP_MARGIN_SCALER) + (lineHeight * BOTTOM_MARGIN_SCALER);
// We can generalize some of the processes that are similar in makeNameTag() and redraw() if we wanted to reduce some code
var newDimenionsYHalf = newDimensions[Y] * HALF;
var AvatarData = AvatarManager.getAvatar(uuid);
var headJointIndex = AvatarData.getJointIndex("Head");
var jointInObjectFrame = AvatarData.getAbsoluteJointTranslationInObjectFrame(headJointIndex);
var nameTagPosition = jointInObjectFrame.y + newDimenionsYHalf + ABOVE_HEAD_OFFSET;
var localPosition = [0, nameTagPosition, 0];
nametag
.add("leftMargin", lineHeight * LEFT_MARGIN_SCALER)
.add("rightMargin", lineHeight * RIGHT_MARGIN_SCALER)
.add("topMargin", lineHeight * TOP_MARGIN_SCALER)
.add("bottomMargin", lineHeight * BOTTOM_MARGIN_SCALER)
.add("lineHeight", lineHeight)
.add("dimensions", newDimensions)
.add("localPosition", localPosition)
.sync();
}
// Add a user to the list.
var DEFAULT_LIFETIME = entityProps.lifetime;
// setup to get the outline in on mode
var NAMETAG_SELECTION_LIST = "NAMETAG_SELECTION_LIST";
var nametagSelectionProps = {
outlineUnoccludedColor: { red: 255, green: 255, blue: 255 },
outlineOccludedColor: { red: 235, green: 87, blue: 87 },
fillUnoccludedColor: { red: 235, green: 87, blue: 87 },
fillOccludedColor: { red: 235, green: 87, blue: 87 },
outlineUnoccludedAlpha: 1,
outlineOccludedAlpha: 0,
fillUnoccludedAlpha: 0,
fillOccludedAlpha: 0,
outlineWidth: 3,
isOutlineSmooth: true
};
Selection.enableListHighlight(NAMETAG_SELECTION_LIST, nametagSelectionProps);
// add a user to our current selections
function add(uuid) {
// User Doesn't exist so give them new props and save in the cache, and get their current avatar info.
if (!_this.avatars[uuid]) {
_this.avatars[uuid] = new NewAvatarProps();
getAvatarData(uuid);
}
var avatar = _this.avatars[uuid];
_this.selectedAvatars[uuid] = true;
if (avatarNametagMode === "alwaysOn") {
entityProps.lifetime = -1;
} else {
entityProps.lifetime = DEFAULT_LIFETIME;
}
avatar.nametag = new EntityMaker('local').add(entityProps);
// When the user clicks someone, we create their nametag
makeNameTag(uuid);
var deleteEnttyInMiliseconds = entityProps.lifetime * MILISECONDS_IN_SECOND;
// Remove from list after lifetime is over
if (avatarNametagMode === "on") {
Selection.addToSelectedItemsList(NAMETAG_SELECTION_LIST, "avatar", uuid);
avatar.timeoutStarted = Script.setTimeout(function () {
removeNametag(uuid);
}, deleteEnttyInMiliseconds);
}
// Check to see if anyone is in the selected list now to see if we need to start the interval checking
shouldToggleInterval();
return _this;
}
// Remove the avatar from the list.
function remove(uuid) {
if (_this.selectedAvatars[uuid]) {
delete _this.selectedAvatars[uuid];
}
removeNametag(uuid);
shouldToggleInterval();
delete _this.avatars[uuid];
return _this;
}
// Remove all the current nametags.
function removeAllNametags() {
for (var uuid in _this.selectedAvatars) {
removeNametag(uuid);
}
return _this;
}
// Remove a single Nametag.
function removeNametag(uuid) {
var avatar = _this.avatars[uuid];
if (avatar) {
avatar.nametag.destroy();
delete _this.selectedAvatars[uuid];
Selection.removeFromSelectedItemsList(NAMETAG_SELECTION_LIST, "avatar", uuid);
return _this;
}
}
// #endregion
// *************************************
// END Nametag
// *************************************
// *************************************
// START API
// *************************************
// #region API
// Create the manager and hook up username signal
function create() {
return _this;
}
// Destory the manager and disconnect from username signal
function destroy() {
_this.reset();
return _this;
}
// Check to see if we need to delete any close by nametags
var MAX_DELETE_RANGE = 4;
function checkIfAnyAreClose(target) {
var targetPosition = AvatarManager.getAvatar(target).position;
for (var uuid in _this.selectedAvatars) {
var position = AvatarManager.getAvatar(uuid).position;
var distance = Vec3.distance(position, targetPosition);
if (distance <= MAX_DELETE_RANGE) {
var timeoutStarted = _this.avatars[uuid].timeoutStarted;
if (timeoutStarted) {
Script.clearTimeout(timeoutStarted);
timeoutStarted = null;
}
removeNametag(uuid);
}
}
}
// Handles what happens when an avatar gets triggered on
function handleSelect(uuid) {
if (avatarNametagMode === "off" || avatarNametagMode === "alwaysOn") {
return;
}
var inSelected = uuid in _this.selectedAvatars;
if (inSelected) {
if (avatarNametagMode === "on") {
var timeoutStarted = _this.avatars[uuid].timeoutStarted;
if (timeoutStarted) {
Script.clearTimeout(timeoutStarted);
timeoutStarted = null;
}
}
removeNametag(uuid);
} else {
checkIfAnyAreClose(uuid);
add(uuid);
}
}
// Check to see if we need to clear timeouts for avatars
function maybeClearAllTimeouts() {
for (var uuid in _this.selectedAvatars) {
var timeoutStarted = _this.avatars[uuid].timeoutStarted;
if (timeoutStarted) {
Script.clearTimeout(timeoutStarted);
timeoutStarted = null;
}
}
}
// Check to see if the uuid is in the avatars list before removing
function maybeRemove(uuid) {
if (uuid in _this.avatars) {
remove(uuid);
}
}
// Check to see if we need to add this user to our list
function maybeAdd(uuid) {
if (uuid && avatarNametagMode === "alwaysOn" && !(uuid in _this.avatars)) {
add(uuid);
}
}
// Register the beggining scaler in case it was saved from a previous session
function registerInitialScaler(initalScaler) {
userScaler = initalScaler;
}
// Handle the user updating scale
function updateUserScaler(newUSerScaler) {
userScaler = newUSerScaler;
for (var avatar in _this.selectedAvatars) {
redraw(avatar);
}
}
// Reset the avatar list
function reset() {
maybeClearAllTimeouts();
removeAllNametags();
_this.avatars = {};
shouldToggleInterval();
return _this;
}
// Update the nametag display mode
var avatarNametagMode = "on";
function handleAvatarNametagMode(newAvatarNametagMode) {
if (avatarNametagMode === "alwaysOn") {
handleAlwaysOnMode(false);
}
avatarNametagMode = newAvatarNametagMode;
if (avatarNametagMode === "alwaysOn") {
handleAlwaysOnMode(true);
}
if (avatarNametagMode === "off" || avatarNametagMode === "on") {
reset();
}
}
// #endregion
// *************************************
// END API
// *************************************
nameTagListManager.prototype = {
create: create,
destroy: destroy,
handleSelect: handleSelect,
maybeRemove: maybeRemove,
maybeAdd: maybeAdd,
registerInitialScaler: registerInitialScaler,
updateUserScaler: updateUserScaler,
handleAvatarNametagMode: handleAvatarNametagMode,
reset: reset
};
module.exports = nameTagListManager;

View file

@ -0,0 +1,32 @@
// taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}

View file

@ -0,0 +1,305 @@
//
// Simplified Nametag
// pickRayController.js
// Created by Milad Nazeri on 2019-03-08
// Copyright 2019 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
//
// Easy pickray controllers for Entities, Overlays, and Avatars
//
var _this;
function PickRayController(){
_this = this;
_this.rayType = null;
_this.eventHandler = null;
_this.intersection = null;
_this.lastPick = null;
_this.currentPick = null;
_this.mappingName = null;
_this.mapping = null;
_this._boundMousePressHandler = null;
_this.shouldDoublePress = null;
_this.controllEnabled = false;
}
// *************************************
// START UTILITY
// *************************************
// #region UTILITY
// Returns the right UUID based on hand triggered
function getUUIDFromLaser(hand) {
hand = hand === Controller.Standard.LeftHand
? Controller.Standard.LeftHand
: Controller.Standard.RightHand;
var pose = getControllerWorldLocation(hand);
var start = pose.position;
// Get the direction that the hand is facing in the world
var direction = Vec3.multiplyQbyV(pose.orientation, [0, 1, 0]);
pickRayTypeHandler(start, direction);
if (_this.currentPick) {
_this.eventHandler(_this.currentPick, _this.intersection);
}
}
// The following two functions are a modified version of what's found in scripts/system/libraries/controllers.js
// Utility function for the ControllerWorldLocation offset
function getGrabPointSphereOffset(handController) {
// These values must match what's in scripts/system/libraries/controllers.js
// x = upward, y = forward, z = lateral
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 };
var offset = GRAB_POINT_SPHERE_OFFSET;
if (handController === Controller.Standard.LeftHand) {
offset = {
x: -GRAB_POINT_SPHERE_OFFSET.x,
y: GRAB_POINT_SPHERE_OFFSET.y,
z: GRAB_POINT_SPHERE_OFFSET.z
};
}
return Vec3.multiply(MyAvatar.sensorToWorldScale, offset);
}
// controllerWorldLocation is where the controller would be, in-world, with an added offset
function getControllerWorldLocation(handController, doOffset) {
var orientation;
var position;
var valid = false;
if (handController >= 0) {
var pose = Controller.getPoseValue(handController);
valid = pose.valid;
var controllerJointIndex;
if (pose.valid) {
if (handController === Controller.Standard.RightHand) {
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND");
} else {
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
}
orientation = Quat.multiply(MyAvatar.orientation, MyAvatar.getAbsoluteJointRotationInObjectFrame(controllerJointIndex));
position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, MyAvatar.getAbsoluteJointTranslationInObjectFrame(controllerJointIndex)));
// add to the real position so the grab-point is out in front of the hand, a bit
if (doOffset) {
var offset = getGrabPointSphereOffset(handController);
position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, offset));
}
} else if (!HMD.isHandControllerAvailable()) {
// NOTE: keep _this offset in sync with scripts/system/controllers/handControllerPointer.js:493
var VERTICAL_HEAD_LASER_OFFSET = 0.1 * MyAvatar.sensorToWorldScale;
position = Vec3.sum(Camera.position, Vec3.multiplyQbyV(Camera.orientation, { x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0 }));
orientation = Quat.multiply(Camera.orientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }));
valid = true;
}
}
return {
position: position,
translation: position,
orientation: orientation,
rotation: orientation,
valid: valid
};
}
// Handle if the uuid picked on is new or different
function handleUUID(uuid){
if (!_this.lastPick && !_this.currentPick) {
_this.currentPick = uuid;
_this.lastPick = uuid;
} else {
_this.lastPick = _this.currentPick;
_this.currentPick = uuid;
}
}
function pickRayTypeHandler(pickRay){
// Handle if pickray is system generated or user generated
if (arguments.length === 2) {
pickRay = { origin: arguments[0], direction: arguments[1] };
}
// Each different ray pick type needs a different findRayIntersection function
switch (_this.rayType) {
case 'avatar':
var avatarIntersection = AvatarList.findRayIntersection(pickRay, [], [MyAvatar.sessionUUID], false);
_this.intersection = avatarIntersection;
handleUUID(avatarIntersection.avatarID);
break;
case 'local':
var overlayIntersection = Overlays.findRayIntersection(pickRay, [], []);
_this.intersection = overlayIntersection;
handleUUID(overlayIntersection.overlayID);
break;
case 'entity':
var entityIntersection = Entities.findRayIntersection(pickRay, [], []);
_this.intersection = entityIntersection;
handleUUID(entityIntersection.avatarID);
break;
default:
console.log("ray type not handled");
}
}
// Handle the interaction when in desktop and a mouse is pressed
function mousePressHandler(event) {
if (HMD.active || !event.isLeftButton) {
return;
}
var pickRay = Camera.computePickRay(event.x, event.y);
pickRayTypeHandler(pickRay);
if (_this.currentPick) {
_this.eventHandler(_this.currentPick, _this.intersection);
}
}
// Function to call when double press is singled
function doublePressHandler(event) {
mousePressHandler(event);
}
// #endregion
// *************************************
// END UTILITY
// *************************************
// *************************************
// START API
// *************************************
// #region API
// After setup is given, this gets the Controller ready to be enabled
function create(){
_this.mapping = Controller.newMapping(_this.mappingName);
_this.mapping.from(Controller.Standard.LTClick).to(function (value) {
if (value === 0) {
return;
}
getUUIDFromLaser(Controller.Standard.LeftHand);
});
_this.mapping.from(Controller.Standard.RTClick).to(function (value) {
if (value === 0) {
return;
}
getUUIDFromLaser(Controller.Standard.RightHand);
});
return _this;
}
// Set type of raypick for what kind of uuids to return
function setType(type){
_this.rayType = type;
return _this;
}
// Set if double presses should register as well
function setShouldDoublePress(shouldDoublePress){
_this.shouldDoublePress = shouldDoublePress;
return _this;
}
// Set the mapping name for the controller
function setMapName(name) {
_this.mappingName = name;
return _this;
}
// Enables mouse press and trigger events
function enable(){
if (!_this.controllEnabled) {
Controller.mousePressEvent.connect(mousePressHandler);
if (_this.shouldDoublePress) {
Controller.mouseDoublePressEvent.connect(doublePressHandler);
}
Controller.enableMapping(_this.mappingName);
_this.controllEnabled = true;
return _this;
}
return -1;
}
// Disable the controller and mouse press
function disable(){
if (_this.controllEnabled) {
Controller.mousePressEvent.disconnect(mousePressHandler);
if (_this.shouldDoublePress){
Controller.mouseDoublePressEvent.disconnect(doublePressHandler);
}
Controller.disableMapping(_this.mappingName);
_this.controllEnabled = false;
return _this;
}
return -1;
}
// Synonym for disable
function destroy(){
_this.disable();
}
// Register the function to be called on a click
function registerEventHandler(fn){
_this.eventHandler = fn;
return _this;
}
// #endregion
// *************************************
// END API
// *************************************
PickRayController.prototype = {
create: create,
setType: setType,
setShouldDoublePress: setShouldDoublePress,
setMapName: setMapName,
enable: enable,
disable: disable,
destroy: destroy,
registerEventHandler: registerEventHandler
};
module.exports = PickRayController;

View file

@ -0,0 +1,224 @@
//
// Simplified Nametag
// textHelper.js
// Created by Milad Nazeri on 2019-03-08
// Copyright 2019 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
//
// Module to help calculate text size
//
// *************************************
// START MAPS
// *************************************
// #region MAPS
var charMap = {
a: 0.05,
b: 0.051,
c: 0.05,
d: 0.051,
e: 0.05,
f: 0.035,
g: 0.051,
h: 0.051,
i: 0.025,
j: 0.025,
k: 0.05,
l: 0.025,
m: 0.0775,
n: 0.051,
o: 0.051,
p: 0.051,
q: 0.051,
r: 0.035,
s: 0.05,
t: 0.035,
u: 0.051,
v: 0.05,
w: 0.07,
x: 0.05,
y: 0.05,
z: 0.05,
A: 0.06,
B: 0.06,
C: 0.06,
D: 0.06,
E: 0.05,
F: 0.05,
G: 0.06,
H: 0.0625,
I: 0.0275,
J: 0.05,
K: 0.06,
L: 0.05,
M: 0.075,
N: 0.0625,
O: 0.0625,
P: 0.06,
Q: 0.0625,
R: 0.06,
S: 0.06,
T: 0.06,
U: 0.06,
V: 0.06,
W: 0.075,
X: 0.06,
Y: 0.06,
Z: 0.06
};
var symbolMap = {
"!": 0.025,
"@": 0.08,
"#": 0.07,
"$": 0.058,
"%": 0.07,
"^": 0.04,
"&": 0.06,
"*": 0.04,
"(": 0.04,
")": 0.04,
"_": 0.041,
"{": 0.034,
"}": 0.034,
"/": 0.04,
"|": 0.02,
"<": 0.049,
">": 0.049,
"[": 0.0300,
"]": 0.0300,
".": 0.0260,
",": 0.0260,
"?": 0.048,
"~": 0.0610,
"`": 0.0310,
"+": 0.0510,
"=": 0.0510
};
// #endregion
// *************************************
// END MAPS
// *************************************
var _this = null;
function TextHelper(){
_this = this;
this.text = "";
this.textArray = "";
this.lineHeight = 0;
this.totalTextLength = 0;
this.scaler = 1.0;
}
// *************************************
// START UTILITY
// *************************************
// #region UTILITY
// Split the string into a text array to be operated on
function createTextArray(){
_this.textArray = _this.text.split("");
}
// Account for the text length
function adjustForScale(defaultTextLength){
_this.totalTextLength = defaultTextLength * _this.scaler;
}
// #endregion
// *************************************
// END UTILITY
// *************************************
// #endregion
// *************************************
// END name
// *************************************
// *************************************
// START API
// *************************************
// #region API
// Set the text that needs to be calculated on
function setText(newText){
_this.text = newText;
createTextArray();
return _this;
}
// Set the line height which helps calculate the font size
var DEFAULT_LINE_HEIGHT = 0.1;
function setLineHeight(newLineHeight){
_this.lineHeight = newLineHeight;
_this.scaler = _this.lineHeight / DEFAULT_LINE_HEIGHT;
return _this;
}
// Calculate the sign dimensions
var DEFAULT_CHAR_SIZE = 0.025;
var NUMBER = 0.05;
var DIGIT_REGEX = /\d/g;
var WHITE_SPACE_REGEX = /[ ]/g;
var SPACE = 0.018;
function getTotalTextLength(){
// Map the string array to it's sizes
var lengthArray = _this.textArray.map(function(letter){
if (charMap[letter]){
return charMap[letter];
} else if (letter.match(DIGIT_REGEX)){
return NUMBER;
} else if (symbolMap[letter]) {
return symbolMap[letter];
} else if (letter.match(WHITE_SPACE_REGEX)) {
return SPACE;
} else {
return DEFAULT_CHAR_SIZE;
}
});
// add up all the values in the array
var defaultTextLength = lengthArray.reduce(function(prev, curr){
return prev + curr;
}, 0);
adjustForScale(defaultTextLength);
return _this.totalTextLength;
}
// #endregion
// *************************************
// END API
// *************************************
TextHelper.prototype = {
setText: setText,
setLineHeight: setLineHeight,
getTotalTextLength: getTotalTextLength
};
module.exports = TextHelper;
// var text = new TextHelper();
// text.setText("lowbar");
// text.setLineHeight("0.1");
// text.getTotalTextLength();

View file

@ -0,0 +1,96 @@
//
// Simplified Nametag
// Created by Milad Nazeri on 2019-02-16
// Copyright 2019 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
//
// Click on someone to get a nametag for them
//
var PickRayController = Script.require('./resources/modules/pickRayController.js?' + Date.now());
var NameTagListManager = Script.require('./resources/modules/nameTagListManager.js?' + Date.now());
var pickRayController = new PickRayController();
var nameTagListManager = new NameTagListManager();
// Handles avatar being solo'd
pickRayController
.registerEventHandler(selectAvatar)
.setType("avatar")
.setMapName("hifi_simplifiedNametag")
.setShouldDoublePress(true)
.create()
.enable();
function selectAvatar(uuid, intersection) {
nameTagListManager.handleSelect(uuid, intersection);
}
// Handles reset of list if you change domains
function onDomainChange() {
nameTagListManager.reset();
}
// Handles removing an avatar from the list if they leave the domain
function onAvatarRemoved(uuid) {
nameTagListManager.maybeRemove(uuid);
}
// Automatically add an avatar if they come into the domain. Mainly used for alwaysOn mode.
function onAvatarAdded(uuid) {
nameTagListManager.maybeAdd(uuid);
}
// Called on init
var avatarNametagMode;
function create() {
nameTagListManager.create();
handleAvatarNametagMode(Settings.getValue("simplifiedNametag/avatarNametagMode", "on"));
Window.domainChanged.connect(onDomainChange);
AvatarManager.avatarRemovedEvent.connect(onAvatarRemoved);
AvatarManager.avatarAddedEvent.connect(onAvatarAdded);
}
// Called when the script is closing
function destroy() {
nameTagListManager.destroy();
pickRayController.destroy();
Window.domainChanged.disconnect(onDomainChange);
AvatarManager.avatarRemovedEvent.disconnect(onAvatarRemoved);
AvatarManager.avatarAddedEvent.disconnect(onAvatarAdded);
}
// chose which mode you want the nametags in. On, off, or alwaysOn.
function handleAvatarNametagMode(newAvatarNameTagMode) {
avatarNametagMode = newAvatarNameTagMode;
nameTagListManager.handleAvatarNametagMode(avatarNametagMode);
Settings.setValue("simplifiedNametag/avatarNametagMode", avatarNametagMode);
}
// *************************************
// START api
// *************************************
// #region api
module.exports = {
create: create,
destroy: destroy,
handleAvatarNametagMode: handleAvatarNametagMode
};
// #endregion
// *************************************
// END api
// *************************************

View file

@ -0,0 +1,12 @@
<svg width="531" height="95" viewBox="0 0 531 95" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="64" width="353" height="95" rx="10" fill="white"/>
<g clip-path="url(#clip0)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M115.081 28.5049L112.537 31.049C109.183 27.3485 104.442 24.92 99.007 24.92C93.8031 24.92 89.1775 27.2328 85.8239 30.7021L83.2798 28.158C87.2116 23.9949 92.878 21.3351 99.007 21.3351C105.367 21.3351 111.149 24.1105 115.081 28.5049ZM106.639 36.9481L109.184 34.404C106.755 31.513 103.055 29.6628 99.0072 29.6628C95.0754 29.6628 91.6062 31.3974 89.1777 34.0571L91.7218 36.6012C93.5721 34.6353 96.1162 33.2476 99.0072 33.2476C102.129 33.2476 104.905 34.6353 106.639 36.9481ZM103.348 42.2823V41.7164C103.348 39.4525 101.433 37.6414 99.1803 37.6414C96.9273 37.6414 95.0123 39.4525 95.0123 41.7164V49.5267L103.348 42.2823ZM95.8246 58.6522L92.4739 61.5966C94.0083 63.4173 96.4683 64.5816 99.1802 64.5816C103.799 64.5816 107.629 61.1858 107.629 56.9976V51.1116C107.629 49.9796 108.417 49.0741 109.544 49.0741C110.558 49.0741 111.571 49.8664 111.571 50.9984V56.9976C111.571 62.7705 107.066 67.5246 101.208 68.4301V72.2787H106.164C107.291 72.2787 108.192 73.1842 108.192 74.3162C108.192 75.4481 107.291 76.3536 106.164 76.3536H92.3086C91.1821 76.3536 90.281 75.4481 90.281 74.3162C90.281 73.1842 91.1821 72.2787 92.3086 72.2787H97.1525V68.4301C94.0724 68.0229 91.3422 66.4435 89.4655 64.2402L86.1129 67.1863C85.3244 67.8655 84.0852 67.7523 83.4093 66.9599L83.184 66.7335C82.5081 65.9412 82.6208 64.6961 83.4093 64.0169L112.022 38.6616C112.811 37.9825 114.05 38.0957 114.726 38.888L114.951 39.1144C115.627 40.0199 115.514 41.1519 114.838 41.9442L103.348 52.0408V56.2044C103.348 58.4682 101.433 60.2793 99.1803 60.2793C97.7776 60.2793 96.5729 59.6425 95.8246 58.6522ZM88.9292 49.0752C89.943 49.0752 90.7315 49.9808 90.7315 51.1127V53.3766L86.7888 56.8856V50.8863C86.9015 49.8676 87.8027 48.962 88.9292 49.0752Z" fill="#B20012"/>
</g>
<path d="M132.308 77H141.908V33.8L159.268 77H162.708L179.748 33.8V77H190.388V19.8H176.308L161.588 58.84L146.548 19.8H132.308V77ZM225.48 77.8C240.6 77.8 248.68 69.56 248.68 54.6V19.8H237.96V53.72C237.96 65.56 233.8 69.24 225.56 69.24C217.08 69.24 213.72 64.92 213.72 54.44V19.8H203V55.24C203 69.96 211.16 77.8 225.48 77.8ZM272.733 77H283.453V28.2H299.373V19.8H256.813V28.2H272.733V77ZM307.933 77H345.053V68.6H318.573V51.88H338.733V43.88H318.573V28.2H343.693V19.8H307.933V77ZM365.292 68.6V28.2H371.452C384.892 28.2 390.492 35.64 390.492 47.96V48.6C390.492 61.24 384.332 68.6 371.532 68.6H365.292ZM354.652 77H371.852C391.932 77 401.612 65.16 401.612 48.52V47.8C401.612 31.16 391.932 19.8 372.012 19.8H354.652V77Z" fill="#B20012"/>
<defs>
<clipPath id="clip0">
<rect width="55.5084" height="55.5084" fill="white" transform="translate(70.5977 21.3351)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,4 @@
<svg width="553" height="553" viewBox="0 0 553 553" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="276.5" cy="276.5" r="276.5" fill="white"/>
<path d="M292.112 239.537V388.865C292.957 396.799 291.001 404.778 286.583 411.421C282.164 418.064 275.561 422.953 267.916 425.243C263.762 426.761 259.413 427.679 255 427.971C249.454 428.205 243.94 427.025 238.976 424.544C234.011 422.062 229.759 418.359 226.619 413.784C220.979 408.145 212.61 399.415 201.695 387.592C190.779 375.77 182.593 367.039 176.953 361.219C175.486 359.629 173.471 358.654 171.313 358.491H155.304C148.119 358.643 140.935 358.156 133.836 357.035C125.817 355.846 118.507 351.771 113.279 345.577C107.506 339.98 104.172 332.334 104 324.296V220.621C103.989 215.99 105.012 211.415 106.995 207.23C108.978 203.045 111.87 199.355 115.462 196.43C122.88 189.865 132.48 186.298 142.387 186.426H170.949L172.223 185.153C173.774 184.335 175.237 183.36 176.589 182.243C188.778 169.875 205.515 152.414 226.255 129.678C231.222 123.895 237.881 119.818 245.292 118.023C252.702 116.228 260.489 116.806 267.553 119.674C275.013 121.964 281.472 126.722 285.869 133.168C290.266 139.613 292.34 147.362 291.749 155.142L292.112 239.537ZM240.809 169.875L196.783 218.257C195.369 219.895 193.644 221.237 191.708 222.205C189.772 223.173 187.663 223.747 185.504 223.895H142.751V319.203H186.777C189.465 319.135 192.074 320.113 194.054 321.931C199.375 328.283 205.022 334.354 210.973 340.12C218.614 347.759 224.254 353.761 228.074 358.309L240.809 371.223C243.866 375.22 247.21 378.989 250.815 382.499L252.27 383.955V158.598L240.809 169.875ZM452.572 218.257C451.101 216.263 449.182 214.643 446.97 213.527C444.758 212.411 442.315 211.829 439.837 211.829C437.36 211.829 434.916 212.411 432.704 213.527C430.492 214.643 428.574 216.263 427.102 218.257L345.963 299.196C344 300.708 342.41 302.65 341.317 304.874C340.223 307.097 339.654 309.541 339.654 312.019C339.654 314.496 340.223 316.941 341.317 319.164C342.41 321.387 344 323.33 345.963 324.842C347.454 326.836 349.389 328.456 351.616 329.572C353.842 330.687 356.298 331.268 358.789 331.268C361.279 331.268 363.735 330.687 365.962 329.572C368.188 328.456 370.124 326.836 371.615 324.842L452.572 243.903C454.567 242.412 456.187 240.477 457.303 238.251C458.419 236.025 459 233.569 459 231.08C459 228.59 458.419 226.134 457.303 223.908C456.187 221.682 454.567 219.747 452.572 218.257V218.257ZM452.572 324.842C454.567 323.351 456.187 321.416 457.303 319.19C458.419 316.964 459 314.509 459 312.019C459 309.529 458.419 307.073 457.303 304.847C456.187 302.621 454.567 300.686 452.572 299.196L371.615 218.257C370.124 216.262 368.188 214.642 365.962 213.526C363.735 212.411 361.279 211.83 358.789 211.83C356.298 211.83 353.842 212.411 351.616 213.526C349.389 214.642 347.454 216.262 345.963 218.257C344 219.769 342.41 221.711 341.317 223.934C340.223 226.157 339.654 228.602 339.654 231.08C339.654 233.557 340.223 236.002 341.317 238.225C342.41 240.448 344 242.39 345.963 243.903L427.102 324.842C428.574 326.835 430.492 328.455 432.704 329.571C434.916 330.688 437.36 331.269 439.837 331.269C442.315 331.269 444.758 330.688 446.97 329.571C449.182 328.455 451.101 326.835 452.572 324.842V324.842Z" fill="#B20012"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,502 @@
"use strict";
/* jslint vars: true, plusplus: true */
//
// simplifiedUI.js
//
// Authors: Wayne Chen & Zach Fox
// Created on: 5/1/2019
// Copyright 2019 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
//
// START CONFIG OPTIONS
var DOCKED_QML_SUPPORTED = false;
var REMOVE_EXISTING_UI = true;
var TOOLBAR_NAME = "com.highfidelity.interface.toolbar.system";
var DEFAULT_SCRIPTS_PATH_PREFIX = ScriptDiscoveryService.defaultScriptsPath + "/";
// END CONFIG OPTIONS
var DEFAULT_SCRIPTS_SEPARATE = [
DEFAULT_SCRIPTS_PATH_PREFIX + "system/controllers/controllerScripts.js"
];
function loadSeparateDefaults() {
for (var i in DEFAULT_SCRIPTS_SEPARATE) {
Script.load(DEFAULT_SCRIPTS_SEPARATE[i]);
}
}
var DEFAULT_SCRIPTS_COMBINED = [
DEFAULT_SCRIPTS_PATH_PREFIX + "system/request-service.js",
DEFAULT_SCRIPTS_PATH_PREFIX + "system/progress.js",
DEFAULT_SCRIPTS_PATH_PREFIX + "system/away.js"
];
function runDefaultsTogether() {
for (var i in DEFAULT_SCRIPTS_COMBINED) {
Script.include(DEFAULT_SCRIPTS_COMBINED[i]);
}
}
var MENU_NAMES = ["File", "Edit", "Display", "View", "Navigate", "Settings", "Developer", "Help"];
function removeDesktopMenu() {
MENU_NAMES.forEach(function(menu) {
Menu.removeMenu(menu);
});
}
function handleUpdateAvatarThumbnailURL(avatarThumbnailURL) {
if (topBarWindow) {
topBarWindow.sendToQml({
"source": "simplifiedUI.js",
"method": "updateAvatarThumbnailURL",
"data": {
"avatarThumbnailURL": avatarThumbnailURL
}
});
}
}
var AVATAR_APP_MESSAGE_SOURCE = "AvatarApp.qml";
function onMessageFromAvatarApp(message) {
if (message.source !== AVATAR_APP_MESSAGE_SOURCE) {
return;
}
switch (message.method) {
case "updateAvatarThumbnailURL":
handleUpdateAvatarThumbnailURL(message.data.avatarThumbnailURL);
break;
default:
console.log("Unrecognized message from " + AVATAR_APP_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break;
}
}
function onAvatarAppClosed() {
if (avatarAppWindow) {
avatarAppWindow.fromQml.disconnect(onMessageFromAvatarApp);
avatarAppWindow.closed.disconnect(onAvatarAppClosed);
}
avatarAppWindow = false;
}
var AVATAR_APP_QML_PATH = Script.resourcesPath() + "qml/hifi/simplifiedUI/avatarApp/AvatarApp.qml";
var AVATAR_APP_WINDOW_TITLE = "Your Avatars";
var AVATAR_APP_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var AVATAR_APP_WIDTH_PX = 480;
var AVATAR_APP_HEIGHT_PX = 615;
var avatarAppWindow = false;
function toggleAvatarApp() {
if (avatarAppWindow) {
avatarAppWindow.close();
// This really shouldn't be necessary.
// This signal really should automatically be called by the signal handler set up below.
// But fixing that requires an engine change, so this workaround will do.
onAvatarAppClosed();
return;
}
avatarAppWindow = Desktop.createWindow(AVATAR_APP_QML_PATH, {
title: AVATAR_APP_WINDOW_TITLE,
presentationMode: AVATAR_APP_PRESENTATION_MODE,
size: {
x: AVATAR_APP_WIDTH_PX,
y: AVATAR_APP_HEIGHT_PX
}
});
avatarAppWindow.fromQml.connect(onMessageFromAvatarApp);
avatarAppWindow.closed.connect(onAvatarAppClosed);
}
function handleAvatarNametagMode(newAvatarNametagMode) {
simplifiedNametag.handleAvatarNametagMode(newAvatarNametagMode);
}
var SETTINGS_APP_MESSAGE_SOURCE = "SettingsApp.qml";
function onMessageFromSettingsApp(message) {
if (message.source !== SETTINGS_APP_MESSAGE_SOURCE) {
return;
}
switch (message.method) {
case "handleAvatarNametagMode":
handleAvatarNametagMode(message.avatarNametagMode);
break;
default:
console.log("Unrecognized message from " + SETTINGS_APP_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break;
}
}
function onSettingsAppClosed() {
if (settingsAppWindow) {
settingsAppWindow.fromQml.disconnect(onMessageFromSettingsApp);
settingsAppWindow.closed.disconnect(onSettingsAppClosed);
}
settingsAppWindow = false;
}
var SETTINGS_APP_QML_PATH = Script.resourcesPath() + "qml/hifi/simplifiedUI/settingsApp/SettingsApp.qml";
var SETTINGS_APP_WINDOW_TITLE = "Settings";
var SETTINGS_APP_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var SETTINGS_APP_WIDTH_PX = 480;
var SETTINGS_APP_HEIGHT_PX = 615;
var settingsAppWindow = false;
function toggleSettingsApp() {
if (settingsAppWindow) {
settingsAppWindow.close();
// This really shouldn't be necessary.
// This signal really should automatically be called by the signal handler set up below.
// But fixing that requires an engine change, so this workaround will do.
onSettingsAppClosed();
return;
}
settingsAppWindow = Desktop.createWindow(SETTINGS_APP_QML_PATH, {
title: SETTINGS_APP_WINDOW_TITLE,
presentationMode: SETTINGS_APP_PRESENTATION_MODE,
size: {
x: SETTINGS_APP_WIDTH_PX,
y: SETTINGS_APP_HEIGHT_PX
}
});
settingsAppWindow.fromQml.connect(onMessageFromSettingsApp);
settingsAppWindow.closed.connect(onSettingsAppClosed);
}
function maybeDeleteOutputDeviceMutedOverlay() {
if (outputDeviceMutedOverlay) {
Overlays.deleteOverlay(outputDeviceMutedOverlay);
outputDeviceMutedOverlay = false;
}
}
var outputDeviceMutedOverlay = false;
var OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_DIMS_PX = 600;
var OUTPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX = 20;
var OUTPUT_DEVICE_MUTED_MARGIN_LEFT_RIGHT_PX = 20;
function updateOutputDeviceMutedOverlay(isMuted) {
if (isMuted) {
var props = {
imageURL: Script.resolvePath("images/outputDeviceMuted.svg"),
alpha: 0.5
};
var overlayDims = OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_DIMS_PX;
props.x = Window.innerWidth / 2 - overlayDims / 2;
props.y = Window.innerHeight / 2 - overlayDims / 2;
var outputDeviceMutedOverlayBottomY = props.y + overlayDims;
var inputDeviceMutedOverlayTopY = getInputDeviceMutedOverlayTopY();
if (outputDeviceMutedOverlayBottomY + OUTPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX > inputDeviceMutedOverlayTopY) {
overlayDims = 2 * (inputDeviceMutedOverlayTopY - Window.innerHeight / 2 - OUTPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX);
}
if (overlayDims + OUTPUT_DEVICE_MUTED_MARGIN_LEFT_RIGHT_PX > Window.innerWidth) {
overlayDims = Math.min(Window.innerWidth - OUTPUT_DEVICE_MUTED_MARGIN_LEFT_RIGHT_PX, overlayDims);
} else {
overlayDims = Math.min(OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_DIMS_PX, overlayDims);
}
props.width = overlayDims;
props.height = overlayDims;
props.x = Window.innerWidth / 2 - overlayDims / 2;
props.y = Window.innerHeight / 2 - overlayDims / 2;
if (outputDeviceMutedOverlay) {
Overlays.editOverlay(outputDeviceMutedOverlay, props);
} else {
outputDeviceMutedOverlay = Overlays.addOverlay("image", props);
}
} else {
maybeDeleteOutputDeviceMutedOverlay();
}
}
var savedAvatarGain = Audio.getAvatarGain();
var savedInjectorGain = Audio.getInjectorGain();
var savedLocalInjectorGain = Audio.getLocalInjectorGain();
var savedSystemInjectorGain = Audio.getSystemInjectorGain();
function setOutputMuted(outputMuted) {
updateOutputDeviceMutedOverlay(outputMuted);
if (outputMuted) {
savedAvatarGain = Audio.getAvatarGain();
savedInjectorGain = Audio.getInjectorGain();
savedLocalInjectorGain = Audio.getLocalInjectorGain();
savedSystemInjectorGain = Audio.getSystemInjectorGain();
Audio.setAvatarGain(-60);
Audio.setInjectorGain(-60);
Audio.setLocalInjectorGain(-60);
Audio.setSystemInjectorGain(-60);
} else {
if (savedAvatarGain === -60) {
savedAvatarGain = 0;
}
Audio.setAvatarGain(savedAvatarGain);
if (savedInjectorGain === -60) {
savedInjectorGain = 0;
}
Audio.setInjectorGain(savedInjectorGain);
if (savedLocalInjectorGain === -60) {
savedLocalInjectorGain = 0;
}
Audio.setLocalInjectorGain(savedLocalInjectorGain);
if (savedSystemInjectorGain === -60) {
savedSystemInjectorGain = 0;
}
Audio.setSystemInjectorGain(savedSystemInjectorGain);
}
}
var TOP_BAR_MESSAGE_SOURCE = "SimplifiedTopBar.qml";
function onMessageFromTopBar(message) {
if (message.source !== TOP_BAR_MESSAGE_SOURCE) {
return;
}
switch (message.method) {
case "toggleAvatarApp":
toggleAvatarApp();
break;
case "toggleSettingsApp":
toggleSettingsApp();
break;
case "setOutputMuted":
setOutputMuted(message.data.outputMuted);
break;
default:
console.log("Unrecognized message from " + TOP_BAR_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break;
}
}
function onTopBarClosed() {
if (topBarWindow) {
topBarWindow.fromQml.disconnect(onMessageFromTopBar);
topBarWindow.closed.disconnect(onTopBarClosed);
}
topBarWindow = false;
}
function isOutputMuted() {
return Audio.getAvatarGain() === -60 && Audio.getInjectorGain() === -60 && Audio.getLocalInjectorGain() === -60 && Audio.getSystemInjectorGain() === -60;
}
var TOP_BAR_QML_PATH = Script.resourcesPath() + "qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml";
var TOP_BAR_WINDOW_TITLE = "Simplified Top Bar";
var TOP_BAR_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var TOP_BAR_WIDTH_PX = Window.innerWidth;
var TOP_BAR_HEIGHT_PX = 48;
var topBarWindow = false;
function loadSimplifiedTopBar() {
var windowProps = {
title: TOP_BAR_WINDOW_TITLE,
presentationMode: TOP_BAR_PRESENTATION_MODE,
size: {
x: TOP_BAR_WIDTH_PX,
y: TOP_BAR_HEIGHT_PX
}
};
if (DOCKED_QML_SUPPORTED) {
windowProps.presentationWindowInfo = {
dockArea: Desktop.DockArea.TOP
};
} else {
windowProps.position = {
x: Window.x,
y: Window.y
};
}
topBarWindow = Desktop.createWindow(TOP_BAR_QML_PATH, windowProps);
topBarWindow.fromQml.connect(onMessageFromTopBar);
topBarWindow.closed.connect(onTopBarClosed);
topBarWindow.sendToQml({
"source": "simplifiedUI.js",
"method": "updateOutputMuted",
"data": {
"outputMuted": isOutputMuted()
}
})
}
var pausedScriptList = [];
var SCRIPT_NAME_WHITELIST = ["simplifiedUI.js", "statusIndicator.js"];
function pauseCurrentScripts() {
var currentlyRunningScripts = ScriptDiscoveryService.getRunning();
for (var i = 0; i < currentlyRunningScripts.length; i++) {
var currentScriptObject = currentlyRunningScripts[i];
if (SCRIPT_NAME_WHITELIST.indexOf(currentScriptObject.name) === -1) {
ScriptDiscoveryService.stopScript(currentScriptObject.url);
pausedScriptList.push(currentScriptObject.url);
}
}
}
function maybeDeleteInputDeviceMutedOverlay() {
if (inputDeviceMutedOverlay) {
Overlays.deleteOverlay(inputDeviceMutedOverlay);
inputDeviceMutedOverlay = false;
}
}
function getInputDeviceMutedOverlayTopY() {
return (Window.innerHeight - INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_Y_PX - INPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX);
}
var inputDeviceMutedOverlay = false;
var INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_X_PX = 320;
var INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_Y_PX = 60;
var INPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX = 20;
function updateInputDeviceMutedOverlay(isMuted) {
if (isMuted) {
var props = {
imageURL: Script.resolvePath("images/inputDeviceMuted.svg"),
alpha: 0.5
};
props.width = INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_X_PX;
props.height = INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_Y_PX;
props.x = Window.innerWidth / 2 - INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_X_PX / 2;
props.y = getInputDeviceMutedOverlayTopY();
if (inputDeviceMutedOverlay) {
Overlays.editOverlay(inputDeviceMutedOverlay, props);
} else {
inputDeviceMutedOverlay = Overlays.addOverlay("image", props);
}
} else {
maybeDeleteInputDeviceMutedOverlay();
}
}
function onDesktopInputDeviceMutedChanged(isMuted) {
updateInputDeviceMutedOverlay(isMuted);
}
function onGeometryChanged(rect) {
updateInputDeviceMutedOverlay(Audio.muted);
updateOutputDeviceMutedOverlay(isOutputMuted());
if (topBarWindow && !DOCKED_QML_SUPPORTED) {
topBarWindow.size = {
"x": rect.width,
"y": TOP_BAR_HEIGHT_PX
};
topBarWindow.position = {
"x": rect.x,
"y": rect.y
};
}
}
function ensureFirstPersonCameraInHMD(isHMDMode) {
if (isHMDMode) {
Camera.setModeString("first person");
}
}
var simplifiedNametag = Script.require("../simplifiedNametag/simplifiedNametag.js");
function startup() {
if (REMOVE_EXISTING_UI) {
pauseCurrentScripts();
removeDesktopMenu();
runDefaultsTogether();
loadSeparateDefaults();
if (!HMD.active) {
var toolbar = Toolbars.getToolbar(TOOLBAR_NAME);
toolbar.writeProperty("visible", false);
}
}
loadSimplifiedTopBar();
simplifiedNametag.create();
updateInputDeviceMutedOverlay(Audio.muted);
updateOutputDeviceMutedOverlay(isOutputMuted());
Audio.mutedDesktopChanged.connect(onDesktopInputDeviceMutedChanged);
Window.geometryChanged.connect(onGeometryChanged);
HMD.displayModeChanged.connect(ensureFirstPersonCameraInHMD);
}
function restoreScripts() {
pausedScriptList.forEach(function(url) {
ScriptDiscoveryService.loadScript(url);
});
pausedScriptList = [];
}
function shutdown() {
restoreScripts();
if (REMOVE_EXISTING_UI) {
Window.confirm("You'll have to restart Interface to get full functionality back. Clicking yes or no will dismiss this dialog.");
if (!HMD.active) {
var toolbar = Toolbars.getToolbar(TOOLBAR_NAME);
toolbar.writeProperty("visible", true);
}
}
if (topBarWindow) {
topBarWindow.close();
}
if (avatarAppWindow) {
avatarAppWindow.close();
}
if (settingsAppWindow) {
settingsAppWindow.close();
}
maybeDeleteInputDeviceMutedOverlay();
maybeDeleteOutputDeviceMutedOverlay();
simplifiedNametag.destroy();
Audio.mutedDesktopChanged.disconnect(onDesktopInputDeviceMutedChanged);
Window.geometryChanged.disconnect(onGeometryChanged);
HMD.displayModeChanged.disconnect(ensureFirstPersonCameraInHMD);
}
Script.scriptEnding.connect(shutdown);
startup();