mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 20:54:25 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into fix/light-intensity
This commit is contained in:
commit
c2ed5e5474
109 changed files with 3032 additions and 714 deletions
|
@ -564,7 +564,7 @@ function MyController(hand) {
|
|||
"additiveBlending": 0,
|
||||
"textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png"
|
||||
}
|
||||
|
||||
|
||||
this.particleBeamObject = Entities.addEntity(particleBeamPropertiesObject);
|
||||
};
|
||||
|
||||
|
@ -1588,7 +1588,9 @@ function MyController(hand) {
|
|||
|
||||
ids.forEach(function(id) {
|
||||
var props = Entities.getEntityProperties(id, ["boundingBox", "name"]);
|
||||
if (props.name === 'pointer') {
|
||||
if (!props ||
|
||||
!props.boundingBox ||
|
||||
props.name === 'pointer') {
|
||||
return;
|
||||
}
|
||||
var entityMinPoint = props.boundingBox.brn;
|
||||
|
|
47
examples/depthReticle.js
Normal file
47
examples/depthReticle.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
// depthReticle.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/23/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// When used in HMD, this script will make the reticle depth track to any clickable item in view.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var APPARENT_2D_OVERLAY_DEPTH = 1.0;
|
||||
var APPARENT_MAXIMUM_DEPTH = 100.0; // this is a depth at which things all seem sufficiently distant
|
||||
var lastDepthCheckTime = 0;
|
||||
|
||||
Script.update.connect(function(deltaTime) {
|
||||
var TIME_BETWEEN_DEPTH_CHECKS = 100;
|
||||
var timeSinceLastDepthCheck = Date.now() - lastDepthCheckTime;
|
||||
if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) {
|
||||
var reticlePosition = Reticle.position;
|
||||
|
||||
// first check the 2D Overlays
|
||||
if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(reticlePosition)) {
|
||||
Reticle.setDepth(APPARENT_2D_OVERLAY_DEPTH);
|
||||
} else {
|
||||
var pickRay = Camera.computePickRay(reticlePosition.x, reticlePosition.y);
|
||||
|
||||
// Then check the 3D overlays
|
||||
var result = Overlays.findRayIntersection(pickRay);
|
||||
|
||||
if (!result.intersects) {
|
||||
// finally check the entities
|
||||
result = Entities.findRayIntersection(pickRay, true);
|
||||
}
|
||||
|
||||
// If either the overlays or entities intersect, then set the reticle depth to
|
||||
// the distance of intersection
|
||||
if (result.intersects) {
|
||||
Reticle.setDepth(result.distance);
|
||||
} else {
|
||||
// if nothing intersects... set the depth to some sufficiently large depth
|
||||
Reticle.setDepth(APPARENT_MAXIMUM_DEPTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
|
@ -75,8 +75,7 @@
|
|||
function createEmitNumberPropertyUpdateFunction(propertyName, decimals) {
|
||||
decimals = decimals == undefined ? 4 : decimals;
|
||||
return function() {
|
||||
var value = +this.value;
|
||||
value = +value.toFixed(decimals);
|
||||
var value = parseFloat(this.value).toFixed(decimals);
|
||||
|
||||
EventBridge.emitWebEvent(
|
||||
'{ "type":"update", "properties":{"' + propertyName + '":' + value + '}}'
|
||||
|
|
|
@ -32,11 +32,9 @@ ParticleExplorerTool = function() {
|
|||
|
||||
that.destroyWebView = function() {
|
||||
if (!that.webView) {
|
||||
print("EBL CAN'ZT CLOSE WEB VIEW- IT DOESNT EXISTS!")
|
||||
return;
|
||||
}
|
||||
|
||||
print("EBL CLOSING WEB VIEW")
|
||||
that.webView.close();
|
||||
that.webView = null;
|
||||
that.activeParticleEntity = 0;
|
||||
|
|
101
examples/tests/particleOrientationTest.js
Normal file
101
examples/tests/particleOrientationTest.js
Normal file
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// particleOrientationTest.js
|
||||
// examples/tests
|
||||
//
|
||||
// Created by Piper.Peppercorn.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var emitterBone = 'Head'
|
||||
var particleEntities = [];
|
||||
|
||||
function emitter(jointName) {
|
||||
var jointID = MyAvatar.jointNames.indexOf(jointName);
|
||||
var newEmitter = Entities.addEntity({
|
||||
name: 'particleEmitter ' + jointName,
|
||||
type: 'ParticleEffect',
|
||||
emitterShouldTrail: true,
|
||||
textures: 'https://dl.dropboxusercontent.com/u/96759331/ParticleTest.png',
|
||||
position: Vec3.sum(MyAvatar.getAbsoluteJointRotationInObjectFrame(jointID), MyAvatar.position),
|
||||
parentJointIndex: jointID,
|
||||
position: MyAvatar.getJointPosition(jointName),
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
isEmitting: 1,
|
||||
maxParticles: 1,
|
||||
lifespan: 2.0
|
||||
,
|
||||
emitRate: 1,
|
||||
emitSpeed: 0.0,
|
||||
speedSpread: 0.0,
|
||||
/*
|
||||
emitOrientation: {
|
||||
x: -0.7035577893257141,
|
||||
y: -0.000015259007341228426,
|
||||
z: -0.000015259007341228426,
|
||||
w: 1.7106381058692932
|
||||
},
|
||||
*/
|
||||
emitOrientation: {
|
||||
x:0,
|
||||
y: 0,
|
||||
z: 0,
|
||||
w: Math.PI
|
||||
},
|
||||
emitRadiusStart: 0,
|
||||
polarStart: 0,
|
||||
polarFinish: 0,
|
||||
azimuthFinish: 3.1415927410125732,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
particleRadius: 2.0,
|
||||
radiusSpread: 1.0,
|
||||
radiusStart: 2.0,
|
||||
radiusFinish: 2.0,
|
||||
colorSpread: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
colorStart: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
alpha: 1,
|
||||
alphaSpread: 0,
|
||||
alphaStart: 1,
|
||||
alphaFinish: 1
|
||||
});
|
||||
return newEmitter;
|
||||
}
|
||||
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
for (var i = 0; i < particleEntities.length; i++) {
|
||||
// Fixes a crash on shutdown:
|
||||
Entities.editEntity(particleEntities[i], { parentID: '' });
|
||||
Entities.deleteEntity(particleEntities[i]);
|
||||
}
|
||||
});
|
||||
|
||||
particleEntities.push(emitter(emitterBone));
|
|
@ -9,11 +9,6 @@
|
|||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"Antialiasing": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
BIN
interface/resources/fonts/AnonymousPro-Regular.ttf
Normal file
BIN
interface/resources/fonts/AnonymousPro-Regular.ttf
Normal file
Binary file not shown.
93
interface/resources/fonts/AnonymousPro.license
Normal file
93
interface/resources/fonts/AnonymousPro.license
Normal file
|
@ -0,0 +1,93 @@
|
|||
Copyright (c) 2009, Mark Simonson (http://www.ms-studio.com, mark@marksimonson.com),
|
||||
with Reserved Font Name Anonymous Pro.
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
interface/resources/fonts/FiraSans-SemiBold.ttf
Normal file
BIN
interface/resources/fonts/FiraSans-SemiBold.ttf
Normal file
Binary file not shown.
94
interface/resources/fonts/FiraSans.license
Normal file
94
interface/resources/fonts/FiraSans.license
Normal file
|
@ -0,0 +1,94 @@
|
|||
Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
|
||||
with Reserved Font Name < Fira >,
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
interface/resources/fonts/Raleway-Bold.ttf
Normal file
BIN
interface/resources/fonts/Raleway-Bold.ttf
Normal file
Binary file not shown.
BIN
interface/resources/fonts/Raleway-Light.ttf
Normal file
BIN
interface/resources/fonts/Raleway-Light.ttf
Normal file
Binary file not shown.
BIN
interface/resources/fonts/Raleway-Regular.ttf
Normal file
BIN
interface/resources/fonts/Raleway-Regular.ttf
Normal file
Binary file not shown.
BIN
interface/resources/fonts/Raleway-SemiBold.ttf
Normal file
BIN
interface/resources/fonts/Raleway-SemiBold.ttf
Normal file
Binary file not shown.
94
interface/resources/fonts/Raleway.license
Normal file
94
interface/resources/fonts/Raleway.license
Normal file
|
@ -0,0 +1,94 @@
|
|||
Copyright (c) 2010, Matt McInerney (matt@pixelspread.com),
|
||||
Copyright (c) 2011, Pablo Impallari (www.impallari.com|impallari@gmail.com),
|
||||
Copyright (c) 2011, Rodrigo Fuenzalida (www.rfuenzalida.com|hello@rfuenzalida.com), with Reserved Font Name Raleway
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
interface/resources/fonts/hifi-glyphs.ttf
Normal file
BIN
interface/resources/fonts/hifi-glyphs.ttf
Normal file
Binary file not shown.
|
@ -5,6 +5,8 @@ import QtQuick.Controls 1.2
|
|||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 300
|
||||
objectName: "StatsItem"
|
||||
|
||||
Hifi.Stats {
|
||||
id: root
|
||||
objectName: "Stats"
|
||||
|
@ -27,6 +29,7 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
Column {
|
||||
|
@ -83,6 +86,7 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
hoverEnabled: true
|
||||
}
|
||||
Column {
|
||||
id: pingCol
|
||||
|
@ -123,6 +127,7 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
hoverEnabled: true
|
||||
}
|
||||
Column {
|
||||
id: geoCol
|
||||
|
@ -172,6 +177,7 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
hoverEnabled: true
|
||||
}
|
||||
Column {
|
||||
id: octreeCol
|
||||
|
@ -186,42 +192,29 @@ Item {
|
|||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
visible: root.expanded;
|
||||
text: "\tItems Rendered Opaque: " + root.opaqueRendered +
|
||||
" / Translucent: " + root.translucentRendered +
|
||||
" / Shadow: " + root.shadowRendered +
|
||||
" / Other: " + root.otherRendered;
|
||||
text: "Items rendered / considered: " +
|
||||
root.itemRendered + " / " + root.itemConsidered;
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
visible: root.expanded;
|
||||
text: "\tOpaque considered: " + root.opaqueConsidered +
|
||||
" / Out of view: " + root.opaqueOutOfView +
|
||||
" / Too small: " + root.opaqueTooSmall;
|
||||
text: " out of view: " + root.itemOutOfView +
|
||||
" too small: " + root.itemTooSmall;
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
visible: root.expanded;
|
||||
text: "\tShadow considered: " + root.shadowConsidered +
|
||||
" / Out of view: " + root.shadowOutOfView +
|
||||
" / Too small: " + root.shadowTooSmall;
|
||||
text: "Shadows rendered / considered: " +
|
||||
root.shadowRendered + " / " + root.shadowConsidered;
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
visible: root.expanded;
|
||||
text: "\tTranslucent considered: " + root.translucentConsidered +
|
||||
" / Out of view: " + root.translucentOutOfView +
|
||||
" / Too small: " + root.translucentTooSmall;
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
visible: root.expanded;
|
||||
text: "\tOther considered: " + root.otherConsidered +
|
||||
" / Out of view: " + root.otherOutOfView +
|
||||
" / Too small: " + root.otherTooSmall;
|
||||
text: " out of view: " + root.shadowOutOfView +
|
||||
" too small: " + root.shadowTooSmall;
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
|
|
|
@ -20,8 +20,10 @@ Windows.Window {
|
|||
property string newTabSource
|
||||
property alias tabView: tabView
|
||||
onParentChanged: {
|
||||
x = 120;
|
||||
y = 120;
|
||||
if (parent) {
|
||||
x = 120;
|
||||
y = 120;
|
||||
}
|
||||
}
|
||||
|
||||
Settings {
|
||||
|
|
54
interface/resources/qml/controls-uit/Button.qml
Normal file
54
interface/resources/qml/controls-uit/Button.qml
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Button.qml
|
||||
//
|
||||
// Created by David Rowe on 16 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
Original.Button {
|
||||
id: button
|
||||
property int color: 0
|
||||
width: 120
|
||||
height: 30
|
||||
|
||||
style: ButtonStyle {
|
||||
|
||||
background: Rectangle {
|
||||
radius: hifi.buttons.radius
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.2
|
||||
color: enabled
|
||||
? (!pressed && button.color != hifi.buttons.black || (!hovered || pressed) && button.color == hifi.buttons.black
|
||||
? hifi.buttons.colorStart[button.color] : hifi.buttons.colorFinish[button.color])
|
||||
: hifi.buttons.colorStart[hifi.buttons.white]
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: enabled
|
||||
? ((!hovered || pressed) && button.color != hifi.buttons.black || !pressed && button.color == hifi.buttons.black
|
||||
? hifi.buttons.colorFinish[button.color] : hifi.buttons.colorStart[button.color])
|
||||
: hifi.buttons.colorFinish[hifi.buttons.white]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label: RalewayBold {
|
||||
font.capitalization: Font.AllUppercase
|
||||
color: enabled ? hifi.buttons.textColor[button.color] : hifi.colors.lightGrayText
|
||||
size: hifi.fontSizes.buttonLabel
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: control.text
|
||||
}
|
||||
}
|
||||
}
|
65
interface/resources/qml/controls-uit/StaticSection.qml
Normal file
65
interface/resources/qml/controls-uit/StaticSection.qml
Normal file
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// StaticSection.qml
|
||||
//
|
||||
// Created by David Rowe on 16 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
Column {
|
||||
property string name: "Static Section"
|
||||
property bool hasSeparator: false
|
||||
|
||||
spacing: hifi.dimensions.contentSpacing.y
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: hifi.dimensions.contentMargin.x
|
||||
right: parent.right
|
||||
rightMargin: hifi.dimensions.contentMargin.x
|
||||
}
|
||||
|
||||
VerticalSpacer { }
|
||||
|
||||
Item {
|
||||
visible: hasSeparator
|
||||
anchors.top: sectionName.top
|
||||
|
||||
Rectangle {
|
||||
width: frame.width
|
||||
height: 1
|
||||
color: hifi.colors.baseGrayShadow
|
||||
x: -hifi.dimensions.contentMargin.x
|
||||
anchors.bottom: highlight.top
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: highlight
|
||||
width: frame.width
|
||||
height: 1
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
x: -hifi.dimensions.contentMargin.x
|
||||
anchors.bottom: parent.top
|
||||
}
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: sectionName
|
||||
text: parent.name
|
||||
size: hifi.fontSizes.sectionName
|
||||
font.capitalization: Font.AllUppercase
|
||||
color: hifi.colors.lightGrayText
|
||||
verticalAlignment: Text.AlignBottom
|
||||
height: {
|
||||
if (hasSeparator) {
|
||||
hifi.dimensions.contentMargin.y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
181
interface/resources/qml/controls-uit/Table.qml
Normal file
181
interface/resources/qml/controls-uit/Table.qml
Normal file
|
@ -0,0 +1,181 @@
|
|||
//
|
||||
// Table.qml
|
||||
//
|
||||
// Created by David Rowe on 18 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
TableView {
|
||||
id: tableView
|
||||
|
||||
property var tableModel: ListModel { }
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
|
||||
|
||||
model: tableModel
|
||||
|
||||
TableViewColumn {
|
||||
role: "name"
|
||||
}
|
||||
|
||||
anchors { left: parent.left; right: parent.right }
|
||||
|
||||
headerVisible: false
|
||||
headerDelegate: Item { } // Fix OSX QML bug that displays scrollbar starting too low.
|
||||
|
||||
// Use rectangle to draw border with rounded corners.
|
||||
frameVisible: false
|
||||
Rectangle {
|
||||
color: "#00000000"
|
||||
anchors { fill: parent; margins: -2 }
|
||||
radius: hifi.dimensions.borderRadius
|
||||
border.color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
|
||||
border.width: 2
|
||||
}
|
||||
anchors.margins: 2 // Shrink TableView to lie within border.
|
||||
|
||||
backgroundVisible: true
|
||||
|
||||
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
|
||||
|
||||
style: TableViewStyle {
|
||||
// Needed in order for rows to keep displaying rows after end of table entries.
|
||||
backgroundColor: parent.isLightColorScheme ? hifi.colors.tableRowLightEven : hifi.colors.tableRowDarkEven
|
||||
alternateBackgroundColor: parent.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
|
||||
|
||||
handle: Item {
|
||||
id: scrollbarHandle
|
||||
implicitWidth: 6
|
||||
Rectangle {
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: 2 // Move it right
|
||||
rightMargin: -2 // ""
|
||||
topMargin: 3 // Shrink vertically
|
||||
bottomMargin: 3 // ""
|
||||
}
|
||||
radius: 3
|
||||
color: hifi.colors.tableScrollHandle
|
||||
}
|
||||
}
|
||||
|
||||
scrollBarBackground: Item {
|
||||
implicitWidth: 10
|
||||
Rectangle {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: -1 // Expand
|
||||
}
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 1 // Shrink
|
||||
}
|
||||
radius: 4
|
||||
color: hifi.colors.tableScrollBackground
|
||||
}
|
||||
}
|
||||
|
||||
incrementControl: Item {
|
||||
visible: false
|
||||
}
|
||||
|
||||
decrementControl: Item {
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
|
||||
rowDelegate: Rectangle {
|
||||
height: (styleData.selected ? 1.8 : 1) * hifi.dimensions.tableRowHeight
|
||||
color: styleData.selected
|
||||
? hifi.colors.primaryHighlight
|
||||
: tableView.isLightColorScheme
|
||||
? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd)
|
||||
: (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd)
|
||||
}
|
||||
|
||||
itemDelegate: Item {
|
||||
anchors {
|
||||
left: parent ? parent.left : undefined
|
||||
leftMargin: hifi.dimensions.tablePadding
|
||||
right: parent ? parent.right : undefined
|
||||
rightMargin: hifi.dimensions.tablePadding
|
||||
}
|
||||
|
||||
FiraSansSemiBold {
|
||||
id: textItem
|
||||
text: styleData.value
|
||||
size: hifi.fontSizes.tableText
|
||||
color: colorScheme == hifi.colorSchemes.light
|
||||
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
|
||||
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
topMargin: 3
|
||||
}
|
||||
|
||||
// FIXME: Put reload item in tableModel passed in from RunningScripts.
|
||||
HiFiGlyphs {
|
||||
id: reloadButton
|
||||
text: hifi.glyphs.reloadSmall
|
||||
color: parent.color
|
||||
anchors {
|
||||
top: parent.top
|
||||
right: stopButton.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
MouseArea {
|
||||
anchors { fill: parent; margins: -2 }
|
||||
onClicked: reloadScript(model.url)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Put stop item in tableModel passed in from RunningScripts.
|
||||
HiFiGlyphs {
|
||||
id: stopButton
|
||||
text: hifi.glyphs.closeSmall
|
||||
color: parent.color
|
||||
anchors {
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
MouseArea {
|
||||
anchors { fill: parent; margins: -2 }
|
||||
onClicked: stopScript(model.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Automatically use aux. information from tableModel
|
||||
FiraSansSemiBold {
|
||||
text: tableModel.get(styleData.row) ? tableModel.get(styleData.row).url : ""
|
||||
elide: Text.ElideMiddle
|
||||
size: hifi.fontSizes.tableText
|
||||
color: colorScheme == hifi.colorSchemes.light
|
||||
? (styleData.selected ? hifi.colors.black : hifi.colors.lightGray)
|
||||
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
|
||||
anchors {
|
||||
top: textItem.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
visible: styleData.selected
|
||||
}
|
||||
}
|
||||
}
|
25
interface/resources/qml/controls-uit/TextEdit.qml
Normal file
25
interface/resources/qml/controls-uit/TextEdit.qml
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// TextEdit.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 24 Apr 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import "../styles-uit"
|
||||
|
||||
TextEdit {
|
||||
|
||||
property real size: 32
|
||||
|
||||
FontLoader { id: ralewaySemibold; source: "../../fonts/Raleway-Semibold.ttf"; }
|
||||
font.family: ralewaySemibold.name
|
||||
font.pointSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
59
interface/resources/qml/controls-uit/TextField.qml
Normal file
59
interface/resources/qml/controls-uit/TextField.qml
Normal file
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// TextField.qml
|
||||
//
|
||||
// Created by David Rowe on 17 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
TextField {
|
||||
id: textField
|
||||
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
property string label: ""
|
||||
|
||||
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
|
||||
font.family: firaSansSemiBold.name
|
||||
font.pixelSize: hifi.fontSizes.textFieldInput
|
||||
height: implicitHeight + 4 // Make surrounding box higher so that highlight is vertically centered.
|
||||
placeholderText: textField.label // Instead of separate label (see below).
|
||||
|
||||
style: TextFieldStyle {
|
||||
textColor: textField.colorScheme == hifi.colorSchemes.light
|
||||
? (textField.focus ? hifi.colors.black : hifi.colors.lightGray)
|
||||
: (textField.focus ? hifi.colors.white : hifi.colors.lightGrayText)
|
||||
background: Rectangle {
|
||||
color: textField.colorScheme == hifi.colorSchemes.light
|
||||
? (textField.focus ? hifi.colors.white : hifi.colors.lightGray)
|
||||
: (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow)
|
||||
border.color: hifi.colors.primaryHighlight
|
||||
border.width: textField.focus ? 1 : 0
|
||||
}
|
||||
placeholderTextColor: hifi.colors.lightGray
|
||||
selectedTextColor: hifi.colors.black
|
||||
selectionColor: hifi.colors.primaryHighlight
|
||||
padding.left: hifi.dimensions.textPadding
|
||||
padding.right: hifi.dimensions.textPadding
|
||||
}
|
||||
|
||||
/*
|
||||
// Separate label instead of placeholderText.
|
||||
RalewaySemibold {
|
||||
text: textField.label
|
||||
size: hifi.fontSizes.inputLabel
|
||||
color: hifi.colors.lightGrayText
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: 4
|
||||
visible: label != ""
|
||||
}
|
||||
*/
|
||||
}
|
147
interface/resources/qml/controls-uit/Tree.qml
Normal file
147
interface/resources/qml/controls-uit/Tree.qml
Normal file
|
@ -0,0 +1,147 @@
|
|||
//
|
||||
// Table.qml
|
||||
//
|
||||
// Created by David Rowe on 17 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
TreeView {
|
||||
id: treeView
|
||||
|
||||
property var treeModel: ListModel { }
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
|
||||
|
||||
model: treeModel
|
||||
|
||||
TableViewColumn {
|
||||
role: "display";
|
||||
}
|
||||
|
||||
anchors { left: parent.left; right: parent.right }
|
||||
|
||||
headerVisible: false
|
||||
headerDelegate: Item { } // Fix OSX QML bug that displays scrollbar starting too low.
|
||||
|
||||
// Use rectangle to draw border with rounded corners.
|
||||
frameVisible: false
|
||||
Rectangle {
|
||||
color: "#00000000"
|
||||
anchors.fill: parent
|
||||
radius: hifi.dimensions.borderRadius
|
||||
border.color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
|
||||
border.width: 2
|
||||
anchors.margins: -2
|
||||
}
|
||||
anchors.margins: 2 // Shrink TreeView to lie within border.
|
||||
|
||||
backgroundVisible: true
|
||||
|
||||
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
|
||||
|
||||
style: TreeViewStyle {
|
||||
// Needed in order for rows to keep displaying rows after end of table entries.
|
||||
backgroundColor: parent.isLightColorScheme ? hifi.colors.tableRowLightEven : hifi.colors.tableRowDarkEven
|
||||
alternateBackgroundColor: parent.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
|
||||
|
||||
branchDelegate: HiFiGlyphs {
|
||||
text: styleData.isExpanded ? hifi.glyphs.disclosureCollapse : hifi.glyphs.disclosureExpand
|
||||
size: hifi.fontSizes.tableText * 2.5 // tableText is in points; proportionately scale to pixels
|
||||
color: colorScheme == hifi.colorSchemes.light
|
||||
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
|
||||
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
|
||||
anchors {
|
||||
left: parent ? parent.left : undefined
|
||||
leftMargin: hifi.dimensions.tablePadding / 2
|
||||
}
|
||||
}
|
||||
|
||||
handle: Item {
|
||||
id: scrollbarHandle
|
||||
implicitWidth: 6
|
||||
Rectangle {
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: 2 // Move it right
|
||||
rightMargin: -2 // ""
|
||||
topMargin: 3 // Shrink vertically
|
||||
bottomMargin: 3 // ""
|
||||
}
|
||||
radius: 3
|
||||
color: hifi.colors.tableScrollHandle
|
||||
}
|
||||
}
|
||||
|
||||
scrollBarBackground: Item {
|
||||
implicitWidth: 10
|
||||
Rectangle {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: -1 // Expand
|
||||
}
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 1 // Shrink
|
||||
}
|
||||
radius: 4
|
||||
color: hifi.colors.tableScrollBackground
|
||||
}
|
||||
}
|
||||
|
||||
incrementControl: Item {
|
||||
visible: false
|
||||
}
|
||||
|
||||
decrementControl: Item {
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
|
||||
rowDelegate: Rectangle {
|
||||
height: hifi.dimensions.tableRowHeight
|
||||
color: styleData.selected
|
||||
? hifi.colors.primaryHighlight
|
||||
: treeView.isLightColorScheme
|
||||
? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd)
|
||||
: (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd)
|
||||
}
|
||||
|
||||
itemDelegate: FiraSansSemiBold {
|
||||
anchors {
|
||||
left: parent ? parent.left : undefined
|
||||
leftMargin: (2 + styleData.depth) * hifi.dimensions.tablePadding
|
||||
right: parent ? parent.right : undefined
|
||||
rightMargin: hifi.dimensions.tablePadding
|
||||
verticalCenter: parent ? parent.verticalCenter : undefined
|
||||
}
|
||||
|
||||
text: styleData.value
|
||||
size: hifi.fontSizes.tableText
|
||||
color: colorScheme == hifi.colorSchemes.light
|
||||
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
|
||||
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
|
||||
}
|
||||
|
||||
onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index)
|
||||
|
||||
onActivated: {
|
||||
var path = scriptsModel.data(index, 0x100)
|
||||
if (path) {
|
||||
loadScript(path)
|
||||
}
|
||||
}
|
||||
}
|
18
interface/resources/qml/controls-uit/VerticalSpacer.qml
Normal file
18
interface/resources/qml/controls-uit/VerticalSpacer.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// VerticalSpacer.qml
|
||||
//
|
||||
// Created by David Rowe on 16 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
width: 1 // Must be non-zero
|
||||
height: hifi.dimensions.contentSpacing.y
|
||||
}
|
|
@ -1,21 +1,33 @@
|
|||
//
|
||||
// Desktop.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 15 Apr 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs;
|
||||
|
||||
import "../dialogs"
|
||||
import "../menus"
|
||||
import "../js/Utils.js" as Utils
|
||||
|
||||
// This is our primary 'desktop' object to which all VR dialogs and
|
||||
// windows will be childed.
|
||||
// This is our primary 'desktop' object to which all VR dialogs and windows are childed.
|
||||
FocusScope {
|
||||
id: desktop
|
||||
anchors.fill: parent;
|
||||
objectName: "desktop"
|
||||
anchors.fill: parent
|
||||
|
||||
onHeightChanged: d.repositionAll();
|
||||
onWidthChanged: d.repositionAll();
|
||||
|
||||
// Controls and windows can trigger this signal to ensure the desktop becomes visible
|
||||
// when they're opened.
|
||||
signal showDesktop();
|
||||
|
||||
// Allows QML/JS to find the desktop through the parent chain
|
||||
property bool desktopRoot: true
|
||||
|
||||
|
@ -148,12 +160,12 @@ FocusScope {
|
|||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged);
|
||||
//offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged);
|
||||
focusHack.start();
|
||||
}
|
||||
|
||||
function onWindowFocusChanged() {
|
||||
console.log("Focus item is " + offscreenWindow.activeFocusItem);
|
||||
//console.log("Focus item is " + offscreenWindow.activeFocusItem);
|
||||
|
||||
// FIXME this needs more testing before it can go into production
|
||||
// and I already cant produce any way to have a modal dialog lose focus
|
||||
|
@ -217,6 +229,8 @@ FocusScope {
|
|||
}
|
||||
|
||||
reposition(targetWindow);
|
||||
|
||||
showDesktop();
|
||||
}
|
||||
|
||||
function reposition(item) {
|
||||
|
@ -304,6 +318,7 @@ FocusScope {
|
|||
|
||||
Rectangle {
|
||||
id: focusDebugger;
|
||||
objectName: "focusDebugger"
|
||||
z: 9999; visible: false; color: "red"
|
||||
ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 }
|
||||
}
|
||||
|
@ -314,8 +329,5 @@ FocusScope {
|
|||
enabled: DebugQML
|
||||
onTriggered: focusDebugger.visible = !focusDebugger.visible
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
//
|
||||
// FocusHack.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 21 Jan 2015
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
objectName: "FocusHack"
|
||||
|
||||
TextInput {
|
||||
id: textInput;
|
||||
|
@ -21,6 +32,3 @@ FocusScope {
|
|||
focusTimer.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,13 +1,23 @@
|
|||
//
|
||||
// Desktop.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 25 Apr 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
|
||||
import "../controls"
|
||||
import "../styles"
|
||||
import "../windows"
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
import "../windows-uit"
|
||||
|
||||
import "messageDialog"
|
||||
|
||||
// FIXME respect default button functionality
|
||||
ModalWindow {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
|
@ -32,96 +42,91 @@ ModalWindow {
|
|||
property alias detailedText: detailedText.text
|
||||
property alias text: mainTextContainer.text
|
||||
property alias informativeText: informativeTextContainer.text
|
||||
onIconChanged: iconHolder.updateIcon();
|
||||
onIconChanged: updateIcon();
|
||||
property int buttons: OriginalDialogs.StandardButton.Ok
|
||||
property int icon: OriginalDialogs.StandardIcon.NoIcon
|
||||
property string iconText: ""
|
||||
property int defaultButton: OriginalDialogs.StandardButton.NoButton;
|
||||
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
|
||||
focus: defaultButton === OriginalDialogs.StandardButton.NoButton
|
||||
|
||||
Rectangle {
|
||||
function updateIcon() {
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
switch (root.icon) {
|
||||
case OriginalDialogs.StandardIcon.Information:
|
||||
iconText = "\uF05A";
|
||||
break;
|
||||
case OriginalDialogs.StandardIcon.Question:
|
||||
iconText = "\uF059"
|
||||
break;
|
||||
case OriginalDialogs.StandardIcon.Warning:
|
||||
iconText = "\uF071"
|
||||
break;
|
||||
case OriginalDialogs.StandardIcon.Critical:
|
||||
iconText = "\uF057"
|
||||
break;
|
||||
default:
|
||||
iconText = ""
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: messageBox
|
||||
clip: true
|
||||
anchors.fill: parent
|
||||
radius: 4
|
||||
color: "white"
|
||||
width: pane.width
|
||||
height: pane.height
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property real spacing: hifi.layout.spacing
|
||||
readonly property real outerSpacing: hifi.layout.spacing * 2
|
||||
readonly property real spacing: hifi.dimensions.contentSpacing.x
|
||||
readonly property real outerSpacing: hifi.dimensions.contentSpacing.y
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWdith: 1280
|
||||
readonly property int minHeight: 160
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = iconHolder.width + mainTextContainer.width + d.spacing * 6
|
||||
var targetHeight = mainTextContainer.implicitHeight + informativeTextContainer.implicitHeight + d.spacing * 8 + buttons.height + details.height
|
||||
var targetWidth = mainTextContainer.width
|
||||
var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y
|
||||
+ (informativeTextContainer.text != "" ? informativeTextContainer.contentHeight + 3 * hifi.dimensions.contentSpacing.y : 0)
|
||||
+ buttons.height
|
||||
+ (content.state === "expanded" ? details.implicitHeight + hifi.dimensions.contentSpacing.y : 0)
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth)
|
||||
root.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)
|
||||
}
|
||||
}
|
||||
|
||||
FontAwesome {
|
||||
id: iconHolder
|
||||
size: 48
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
margins: d.spacing * 2
|
||||
}
|
||||
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
style: Text.Outline; styleColor: "black"
|
||||
Component.onCompleted: updateIcon();
|
||||
function updateIcon() {
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
switch (root.icon) {
|
||||
case OriginalDialogs.StandardIcon.Information:
|
||||
text = "\uF05A";
|
||||
color = "blue";
|
||||
break;
|
||||
|
||||
case OriginalDialogs.StandardIcon.Question:
|
||||
text = "\uF059"
|
||||
color = "blue";
|
||||
break;
|
||||
|
||||
case OriginalDialogs.StandardIcon.Warning:
|
||||
text = "\uF071"
|
||||
color = "yellow";
|
||||
break;
|
||||
|
||||
case OriginalDialogs.StandardIcon.Critical:
|
||||
text = "\uF057"
|
||||
color = "red"
|
||||
break;
|
||||
|
||||
default:
|
||||
text = ""
|
||||
}
|
||||
visible = (text != "");
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
RalewaySemibold {
|
||||
id: mainTextContainer
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
wrapMode: Text.WordWrap
|
||||
font { pointSize: 14; weight: Font.Bold }
|
||||
anchors { left: iconHolder.right; top: parent.top; margins: d.spacing * 2 }
|
||||
size: hifi.fontSizes.menuItem
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
lineHeight: 2
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
}
|
||||
|
||||
Text {
|
||||
RalewaySemibold {
|
||||
id: informativeTextContainer
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
wrapMode: Text.WordWrap
|
||||
font.pointSize: 11
|
||||
anchors { top: mainTextContainer.bottom; right: parent.right; left: iconHolder.right; margins: d.spacing * 2 }
|
||||
size: hifi.fontSizes.menuItem
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 0
|
||||
topMargin: text != "" ? hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
|
@ -130,29 +135,35 @@ ModalWindow {
|
|||
spacing: d.spacing
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
layoutDirection: Qt.RightToLeft
|
||||
anchors { bottom: details.top; right: parent.right; margins: d.spacing * 2; bottomMargin: 0 }
|
||||
MessageDialogButton { dialog: root; text: qsTr("OK"); button: OriginalDialogs.StandardButton.Ok; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Yes"); button: OriginalDialogs.StandardButton.Yes; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("No"); button: OriginalDialogs.StandardButton.No; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Restore Defaults"); button: OriginalDialogs.StandardButton.RestoreDefaults; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Cancel"); button: OriginalDialogs.StandardButton.Cancel; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Abort"); button: OriginalDialogs.StandardButton.Abort; }
|
||||
anchors {
|
||||
top: informativeTextContainer.text == "" ? mainTextContainer.bottom : informativeTextContainer.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
MessageDialogButton { dialog: root; text: qsTr("Close"); button: OriginalDialogs.StandardButton.Close; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Abort"); button: OriginalDialogs.StandardButton.Abort; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Cancel"); button: OriginalDialogs.StandardButton.Cancel; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Restore Defaults"); button: OriginalDialogs.StandardButton.RestoreDefaults; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("No"); button: OriginalDialogs.StandardButton.No; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Yes"); button: OriginalDialogs.StandardButton.Yes; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("OK"); button: OriginalDialogs.StandardButton.Ok; }
|
||||
|
||||
Button {
|
||||
id: moreButton
|
||||
text: qsTr("Show Details...")
|
||||
onClicked: { content.state = (content.state === "" ? "expanded" : "")
|
||||
}
|
||||
width: 160
|
||||
onClicked: { content.state = (content.state === "" ? "expanded" : "") }
|
||||
visible: detailedText && detailedText.length > 0
|
||||
}
|
||||
MessageDialogButton { dialog: root; text: qsTr("Help"); button: OriginalDialogs.StandardButton.Help; }
|
||||
|
@ -161,10 +172,16 @@ ModalWindow {
|
|||
Item {
|
||||
id: details
|
||||
width: parent.width
|
||||
implicitHeight: detailedText.implicitHeight + root.spacing
|
||||
implicitHeight: detailedText.implicitHeight
|
||||
height: 0
|
||||
clip: true
|
||||
anchors { bottom: parent.bottom; left: parent.left; right: parent.right; margins: d.spacing * 2 }
|
||||
anchors {
|
||||
top: buttons.bottom
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
Flickable {
|
||||
id: flickable
|
||||
contentHeight: detailedText.height
|
||||
|
@ -173,10 +190,13 @@ ModalWindow {
|
|||
anchors.bottomMargin: root.outerSpacing
|
||||
TextEdit {
|
||||
id: detailedText
|
||||
size: hifi.fontSizes.menuItem
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
width: details.width
|
||||
wrapMode: Text.WordWrap
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
anchors.margins: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,6 +210,7 @@ ModalWindow {
|
|||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: updateIcon();
|
||||
onStateChanged: d.resize()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,24 @@
|
|||
//
|
||||
// MessageDialogButton.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 29 Jan 2016
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Dialogs 1.2
|
||||
|
||||
import "../../controls-uit"
|
||||
|
||||
Button {
|
||||
property var dialog;
|
||||
property int button: StandardButton.NoButton;
|
||||
|
||||
color: dialog.defaultButton === button ? hifi.buttons.blue : hifi.buttons.white
|
||||
focus: dialog.defaultButton === button
|
||||
onClicked: dialog.click(button)
|
||||
visible: dialog.buttons & button
|
||||
|
|
|
@ -8,6 +8,16 @@ import ".."
|
|||
Desktop {
|
||||
id: desktop
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
propagateComposedEvents: true
|
||||
scrollGestureEnabled: false // we don't need/want these
|
||||
onEntered: ApplicationCompositor.reticleOverDesktop = true
|
||||
onExited: ApplicationCompositor.reticleOverDesktop = false
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
WebEngine.settings.javascriptCanOpenWindows = true;
|
||||
WebEngine.settings.javascriptCanAccessClipboard = false;
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
//
|
||||
// RunningScripts.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 12 Jan 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../../styles" as Hifi
|
||||
import "../../controls" as HifiControls
|
||||
import "../../windows"
|
||||
import "../../styles-uit"
|
||||
import "../../controls-uit" as HifiControls
|
||||
import "../../windows-uit"
|
||||
|
||||
Window {
|
||||
id: root
|
||||
|
@ -15,6 +25,9 @@ Window {
|
|||
destroyOnInvisible: true
|
||||
x: 40; y: 40
|
||||
implicitWidth: 384; implicitHeight: 640
|
||||
minSize: Qt.vector2d(200, 300)
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
property var scripts: ScriptDiscoveryService;
|
||||
property var scriptsModel: scripts.scriptsModelFilter
|
||||
|
@ -33,6 +46,11 @@ Window {
|
|||
|
||||
Component.onCompleted: updateRunningScripts()
|
||||
|
||||
function setDefaultFocus() {
|
||||
// Work around FocusScope of scrollable window.
|
||||
filterEdit.forceActiveFocus();
|
||||
}
|
||||
|
||||
function updateRunningScripts() {
|
||||
var runningScripts = ScriptDiscoveryService.getRunning();
|
||||
runningScriptsModel.clear()
|
||||
|
@ -66,126 +84,50 @@ Window {
|
|||
scripts.stopAllScripts();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: "white"
|
||||
anchors.fill: parent
|
||||
Column {
|
||||
width: pane.contentWidth
|
||||
|
||||
Item {
|
||||
anchors { fill: parent; margins: 8 }
|
||||
Text {
|
||||
id: title
|
||||
font.bold: true
|
||||
font.pointSize: 16
|
||||
color: "#0e7077"
|
||||
text: "Currently Running"
|
||||
}
|
||||
HifiControls.StaticSection {
|
||||
name: "Currently Running"
|
||||
|
||||
Row {
|
||||
id: allButtons
|
||||
anchors.top: title.bottom
|
||||
anchors.topMargin: 8
|
||||
spacing: 8
|
||||
Button { text: "Reload all"; onClicked: reloadAll() }
|
||||
Button { text: "Stop all"; onClicked: stopAll() }
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
||||
ScrollView {
|
||||
onActiveFocusChanged: if (activeFocus && listView.currentItem) { listView.currentItem.forceActiveFocus(); }
|
||||
anchors {
|
||||
top: allButtons.bottom;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
topMargin: 8
|
||||
bottom: row1.top
|
||||
bottomMargin: 8
|
||||
HifiControls.Button {
|
||||
text: "Reload all"
|
||||
color: hifi.buttons.black
|
||||
onClicked: reloadAll()
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
clip: true
|
||||
anchors { fill: parent; margins: 0 }
|
||||
model: runningScriptsModel
|
||||
delegate: FocusScope {
|
||||
id: scope
|
||||
anchors { left: parent.left; right: parent.right }
|
||||
height: scriptName.height + 12 + (ListView.isCurrentItem ? scriptName.height + 6 : 0)
|
||||
Keys.onDownPressed: listView.incrementCurrentIndex()
|
||||
Keys.onUpPressed: listView.decrementCurrentIndex()
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
radius: 3
|
||||
color: scope.ListView.isCurrentItem ? "#79f" :
|
||||
index % 2 ? "#ddd" : "#eee"
|
||||
|
||||
Text {
|
||||
id: scriptName
|
||||
anchors { left: parent.left; leftMargin: 4; top: parent.top; topMargin:6 }
|
||||
text: name
|
||||
}
|
||||
|
||||
Text {
|
||||
id: scriptUrl
|
||||
anchors { left: scriptName.left; right: parent.right; rightMargin: 4; top: scriptName.bottom; topMargin: 6 }
|
||||
text: url
|
||||
elide: Text.ElideMiddle
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { listView.currentIndex = index; scope.forceActiveFocus(); }
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.verticalCenter: scriptName.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 4
|
||||
spacing: 4
|
||||
HifiControls.FontAwesome {
|
||||
text: "\uf021"; size: scriptName.height;
|
||||
MouseArea {
|
||||
anchors { fill: parent; margins: -2; }
|
||||
onClicked: reloadScript(model.url)
|
||||
}
|
||||
}
|
||||
HifiControls.FontAwesome {
|
||||
size: scriptName.height; text: "\uf00d"
|
||||
MouseArea {
|
||||
anchors { fill: parent; margins: -2; }
|
||||
onClicked: stopScript(model.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
HifiControls.Button {
|
||||
text: "Stop all"
|
||||
color: hifi.buttons.red
|
||||
onClicked: stopAll()
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: loadLabel
|
||||
text: "Load Scripts"
|
||||
font.bold: true
|
||||
font.pointSize: 16
|
||||
color: "#0e7077"
|
||||
|
||||
HifiControls.Table {
|
||||
tableModel: runningScriptsModel
|
||||
height: 185
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.bottom: filterEdit.top
|
||||
anchors.bottomMargin: 8
|
||||
anchors.right: parent.right
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.StaticSection {
|
||||
name: "Load Scripts"
|
||||
hasSeparator: true
|
||||
|
||||
Row {
|
||||
id: row1
|
||||
spacing: 8
|
||||
anchors.bottom: filterEdit.top
|
||||
anchors.bottomMargin: 8
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
anchors.right: parent.right
|
||||
|
||||
|
||||
Button {
|
||||
text: "from URL";
|
||||
onClicked: fromUrlTimer.running = true;
|
||||
HifiControls.Button {
|
||||
text: "from URL"
|
||||
color: hifi.buttons.black
|
||||
height: 26
|
||||
onClicked: fromUrlTimer.running = true
|
||||
|
||||
// For some reason trigginer an API that enters
|
||||
// an internal event loop directly from the button clicked
|
||||
|
@ -203,9 +145,11 @@ Window {
|
|||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
HifiControls.Button {
|
||||
text: "from Disk"
|
||||
onClicked: fromDiskTimer.running = true;
|
||||
color: hifi.buttons.black
|
||||
height: 26
|
||||
onClicked: fromDiskTimer.running = true
|
||||
|
||||
Timer {
|
||||
id: fromDiskTimer
|
||||
|
@ -221,66 +165,32 @@ Window {
|
|||
id: filterEdit
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: treeView.top
|
||||
anchors.bottomMargin: 8
|
||||
placeholderText: "filter"
|
||||
focus: true
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
//placeholderText: "filter"
|
||||
label: "Filter"
|
||||
onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i")
|
||||
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
|
||||
}
|
||||
|
||||
TreeView {
|
||||
HifiControls.Tree {
|
||||
id: treeView
|
||||
height: 128
|
||||
anchors.bottom: loadButton.top
|
||||
anchors.bottomMargin: 8
|
||||
height: 155
|
||||
treeModel: scriptsModel
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
headerVisible: false
|
||||
// FIXME doesn't work?
|
||||
onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index)
|
||||
// FIXME not triggered by double click?
|
||||
onActivated: {
|
||||
var path = scriptsModel.data(index, 0x100)
|
||||
if (path) {
|
||||
loadScript(path)
|
||||
}
|
||||
}
|
||||
model: scriptsModel
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
onClicked: treeView.foo();
|
||||
}
|
||||
|
||||
function foo() {
|
||||
var localRect = Qt.rect(0, 0, width, height);
|
||||
var rect = desktop.mapFromItem(treeView, 0, 0, width, height)
|
||||
console.log("Local Rect " + localRect)
|
||||
console.log("Rect " + rect)
|
||||
console.log("Desktop size " + Qt.size(desktop.width, desktop.height));
|
||||
}
|
||||
|
||||
TableViewColumn {
|
||||
title: "Name";
|
||||
role: "display";
|
||||
// delegate: Text {
|
||||
// text: styleData.value
|
||||
// renderType: Text.QtRendering
|
||||
// elite: styleData.elideMode
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.TextField {
|
||||
id: selectedScript
|
||||
readOnly: true
|
||||
anchors.left: parent.left
|
||||
anchors.right: loadButton.left
|
||||
anchors.rightMargin: 8
|
||||
anchors.bottom: loadButton.bottom
|
||||
anchors.top: loadButton.top
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: loadButton.width + hifi.dimensions.contentSpacing.x
|
||||
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
readOnly: true
|
||||
|
||||
Connections {
|
||||
target: treeView
|
||||
onCurrentIndexChanged: {
|
||||
|
@ -290,19 +200,28 @@ Window {
|
|||
} else {
|
||||
selectedScript.text = ""
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: loadButton
|
||||
anchors.bottom: parent.bottom
|
||||
Item {
|
||||
// Take the loadButton out of the column flow.
|
||||
id: loadButtonContainer
|
||||
anchors.top: selectedScript.top
|
||||
anchors.right: parent.right
|
||||
text: "Load"
|
||||
enabled: selectedScript.text != ""
|
||||
onClicked: root.loadScript(selectedScript.text)
|
||||
|
||||
HifiControls.Button {
|
||||
id: loadButton
|
||||
anchors.right: parent.right
|
||||
|
||||
text: "Load"
|
||||
color: hifi.buttons.blue
|
||||
enabled: selectedScript.text != ""
|
||||
onClicked: root.loadScript(selectedScript.text)
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.VerticalSpacer { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,11 @@ import "."
|
|||
Item {
|
||||
id: root
|
||||
anchors.fill: parent
|
||||
objectName: "MouseMenuHandlerItem"
|
||||
|
||||
MouseArea {
|
||||
id: menuRoot;
|
||||
objectName: "MouseMenuHandlerMouseArea"
|
||||
anchors.fill: parent
|
||||
enabled: d.topMenu !== null
|
||||
onClicked: {
|
||||
|
|
23
interface/resources/qml/styles-uit/AnonymousProRegular.qml
Normal file
23
interface/resources/qml/styles-uit/AnonymousProRegular.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// AnonymousProRegular.qml
|
||||
//
|
||||
// Created by David Rowe on 12 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Text {
|
||||
id: root
|
||||
FontLoader { id: anonymousProRegular; source: "../../fonts/AnonymousPro-Regular.ttf"; }
|
||||
property real size: 32
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: anonymousProRegular.name
|
||||
}
|
23
interface/resources/qml/styles-uit/FiraSansSemiBold.qml
Normal file
23
interface/resources/qml/styles-uit/FiraSansSemiBold.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// FiraSansSemiBold.qml
|
||||
//
|
||||
// Created by David Rowe on 12 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Text {
|
||||
id: root
|
||||
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
|
||||
property real size: 32
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: firaSansSemiBold.name
|
||||
}
|
26
interface/resources/qml/styles-uit/FontAwesome.qml
Normal file
26
interface/resources/qml/styles-uit/FontAwesome.qml
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// FontAwesome.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 24 Apr 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Text {
|
||||
id: root
|
||||
FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; }
|
||||
property int size: 32
|
||||
width: size
|
||||
height: size
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: iconFont.name
|
||||
}
|
||||
|
25
interface/resources/qml/styles-uit/HiFiGlyphs.qml
Normal file
25
interface/resources/qml/styles-uit/HiFiGlyphs.qml
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// HiFiGlyphs.qml
|
||||
//
|
||||
// Created by David Rowe on 12 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Text {
|
||||
id: root
|
||||
FontLoader { id: hiFiGlyphs; source: "../../fonts/hifi-glyphs.ttf"; }
|
||||
property int size: 32
|
||||
font.pixelSize: size
|
||||
width: size
|
||||
height: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: hiFiGlyphs.name
|
||||
}
|
134
interface/resources/qml/styles-uit/HifiConstants.qml
Normal file
134
interface/resources/qml/styles-uit/HifiConstants.qml
Normal file
|
@ -0,0 +1,134 @@
|
|||
//
|
||||
// HiFiConstants.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 28 Apr 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Window 2.2
|
||||
|
||||
Item {
|
||||
readonly property alias colors: colors
|
||||
readonly property alias colorSchemes: colorSchemes
|
||||
readonly property alias dimensions: dimensions
|
||||
readonly property alias fontSizes: fontSizes
|
||||
readonly property alias glyphs: glyphs
|
||||
readonly property alias buttons: buttons
|
||||
readonly property alias effects: effects
|
||||
|
||||
Item {
|
||||
id: colors
|
||||
|
||||
// Base colors
|
||||
readonly property color baseGray: "#404040"
|
||||
readonly property color darkGray: "#121212"
|
||||
readonly property color baseGrayShadow: "#252525"
|
||||
readonly property color baseGrayHighlight: "#575757"
|
||||
readonly property color lightGray: "#6a6a6a"
|
||||
readonly property color lightGrayText: "#afafaf"
|
||||
readonly property color faintGray: "#e3e3e3"
|
||||
readonly property color primaryHighlight: "#00b4ef"
|
||||
readonly property color blueAccent: "#1080b8"
|
||||
readonly property color redHighlight: "#e2334d"
|
||||
readonly property color redAccent: "#b70a37"
|
||||
readonly property color greenHighlight: "#1ac567"
|
||||
readonly property color greenShadow: "#2c8e72"
|
||||
// Semitransparent
|
||||
readonly property color darkGray30: "#4d121212"
|
||||
readonly property color darkGray0: "#00121212"
|
||||
readonly property color baseGrayShadow60: "#99252525"
|
||||
readonly property color baseGrayHighlight40: "#66575757"
|
||||
readonly property color baseGrayHighlight15: "#26575757"
|
||||
readonly property color lightGrayText80: "#ccafafaf"
|
||||
readonly property color faintGray50: "#80e3e3e3"
|
||||
|
||||
// Other colors
|
||||
readonly property color white: "#ffffff"
|
||||
readonly property color black: "#000000"
|
||||
// Semitransparent
|
||||
readonly property color white50: "#80ffffff"
|
||||
readonly property color white30: "#4dffffff"
|
||||
readonly property color white25: "#40ffffff"
|
||||
|
||||
// Control specific colors
|
||||
readonly property color tableRowLightOdd: white50
|
||||
readonly property color tableRowLightEven: "#1a575757"
|
||||
readonly property color tableRowDarkOdd: "#80393939"
|
||||
readonly property color tableRowDarkEven: "#a6181818"
|
||||
readonly property color tableScrollHandle: "#707070"
|
||||
readonly property color tableScrollBackground: "#323232"
|
||||
}
|
||||
|
||||
Item {
|
||||
id: colorSchemes
|
||||
readonly property int light: 0
|
||||
readonly property int dark: 1
|
||||
}
|
||||
|
||||
Item {
|
||||
id: dimensions
|
||||
readonly property bool largeScreen: Screen.width >= 1920 && Screen.height >= 1080
|
||||
readonly property real borderRadius: largeScreen ? 7.5 : 5.0
|
||||
readonly property real borderWidth: largeScreen ? 2 : 1
|
||||
readonly property vector2d contentMargin: Qt.vector2d(12, 24)
|
||||
readonly property vector2d contentSpacing: Qt.vector2d(8, 12)
|
||||
readonly property real textPadding: 8
|
||||
readonly property real tablePadding: 12
|
||||
readonly property real tableRowHeight: largeScreen ? 26 : 23
|
||||
readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30)
|
||||
readonly property real modalDialogTitleHeight: 40
|
||||
}
|
||||
|
||||
Item {
|
||||
id: fontSizes // In pixels
|
||||
readonly property real overlayTitle: dimensions.largeScreen? 18 : 14
|
||||
readonly property real tabName: dimensions.largeScreen? 12 : 10
|
||||
readonly property real sectionName: dimensions.largeScreen? 12 : 10
|
||||
readonly property real inputLabel: dimensions.largeScreen? 14 : 10
|
||||
readonly property real textFieldInput: dimensions.largeScreen? 15 : 12
|
||||
readonly property real tableText: dimensions.largeScreen? 15 : 12
|
||||
readonly property real buttonLabel: dimensions.largeScreen? 13 : 9
|
||||
readonly property real iconButton: dimensions.largeScreen? 13 : 9
|
||||
readonly property real listItem: dimensions.largeScreen? 15 : 11
|
||||
readonly property real tabularData: dimensions.largeScreen? 15 : 11
|
||||
readonly property real logs: dimensions.largeScreen? 16 : 12
|
||||
readonly property real code: dimensions.largeScreen? 16 : 12
|
||||
readonly property real rootMenu: dimensions.largeScreen? 15 : 11
|
||||
readonly property real menuItem: dimensions.largeScreen? 15 : 11
|
||||
readonly property real shortcutText: dimensions.largeScreen? 13 : 9
|
||||
}
|
||||
|
||||
Item {
|
||||
id: glyphs
|
||||
readonly property string close: "w"
|
||||
readonly property string closeInverted: "x"
|
||||
readonly property string closeSmall: "C"
|
||||
readonly property string disclosureCollapse: "Z"
|
||||
readonly property string disclosureExpand: "B"
|
||||
readonly property string pin: "y"
|
||||
readonly property string pinInverted: "z"
|
||||
readonly property string reloadSmall: "a"
|
||||
readonly property string resizeHandle: "A"
|
||||
}
|
||||
|
||||
Item {
|
||||
id: buttons
|
||||
readonly property int white: 0
|
||||
readonly property int blue: 1
|
||||
readonly property int red: 2
|
||||
readonly property int black: 3
|
||||
readonly property var textColor: [ colors.darkGray, colors.white, colors.white, colors.white ]
|
||||
readonly property var colorStart: [ "#ffffff", "#00b4ef", "#d42043", "#343434" ]
|
||||
readonly property var colorFinish: [ "#afafaf", "#1080b8", "#94132e", "#000000" ]
|
||||
readonly property int radius: 5
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: effects
|
||||
readonly property int fadeInDuration: 300
|
||||
}
|
||||
}
|
24
interface/resources/qml/styles-uit/RalewayBold.qml
Normal file
24
interface/resources/qml/styles-uit/RalewayBold.qml
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// RalewayBold.qml
|
||||
//
|
||||
// Created by David Rowe on 12 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Text {
|
||||
id: root
|
||||
FontLoader { id: ralewayBold; source: "../../fonts/Raleway-Bold.ttf"; }
|
||||
property real size: 32
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: ralewayBold.name
|
||||
font.bold: true // Font seems to need this in order to display bold.
|
||||
}
|
23
interface/resources/qml/styles-uit/RalewayLight.qml
Normal file
23
interface/resources/qml/styles-uit/RalewayLight.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// RalewayLight.qml
|
||||
//
|
||||
// Created by David Rowe on 12 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Text {
|
||||
id: root
|
||||
FontLoader { id: ralewayLight; source: "../../fonts/Raleway-Light.ttf"; }
|
||||
property real size: 32
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: ralewayLight.name
|
||||
}
|
23
interface/resources/qml/styles-uit/RalewayRegular.qml
Normal file
23
interface/resources/qml/styles-uit/RalewayRegular.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// RalewayRegular.qml
|
||||
//
|
||||
// Created by David Rowe on 12 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Text {
|
||||
id: root
|
||||
FontLoader { id: ralewayRegular; source: "../../fonts/Raleway-Regular.ttf"; }
|
||||
property real size: 32
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: ralewayRegular.name
|
||||
}
|
23
interface/resources/qml/styles-uit/RalewaySemibold.qml
Normal file
23
interface/resources/qml/styles-uit/RalewaySemibold.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// RalewaySemibold.qml
|
||||
//
|
||||
// Created by David Rowe on 12 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Text {
|
||||
id: root
|
||||
FontLoader { id: ralewaySemibold; source: "../../fonts/Raleway-Semibold.ttf"; }
|
||||
property real size: 32
|
||||
font.pixelSize: size
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: ralewaySemibold.name
|
||||
}
|
111
interface/resources/qml/windows-uit/DefaultFrame.qml
Normal file
111
interface/resources/qml/windows-uit/DefaultFrame.qml
Normal file
|
@ -0,0 +1,111 @@
|
|||
//
|
||||
// DefaultFrame.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 12 Jan 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "."
|
||||
import "../styles-uit"
|
||||
|
||||
Frame {
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
Rectangle {
|
||||
// Dialog frame
|
||||
id: frameContent
|
||||
anchors {
|
||||
topMargin: -frameMarginTop
|
||||
leftMargin: -frameMarginLeft
|
||||
rightMargin: -frameMarginRight
|
||||
bottomMargin: -frameMarginBottom
|
||||
}
|
||||
anchors.fill: parent
|
||||
color: hifi.colors.baseGrayHighlight40
|
||||
border {
|
||||
width: hifi.dimensions.borderWidth
|
||||
color: hifi.colors.faintGray50
|
||||
}
|
||||
radius: hifi.dimensions.borderRadius
|
||||
|
||||
// Allow dragging of the window
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
drag.target: window
|
||||
}
|
||||
|
||||
Row {
|
||||
id: controlsRow
|
||||
anchors {
|
||||
right: parent.right;
|
||||
top: parent.top;
|
||||
topMargin: frameMargin + 1 // Move down a little to visually align with the title
|
||||
rightMargin: frameMarginRight;
|
||||
}
|
||||
spacing: iconSize / 4
|
||||
|
||||
HiFiGlyphs {
|
||||
// "Pin" button
|
||||
visible: false
|
||||
text: (frame.pinned && !pinClickArea.containsMouse) || (!frame.pinned && pinClickArea.containsMouse) ? hifi.glyphs.pinInverted : hifi.glyphs.pin
|
||||
color: pinClickArea.containsMouse && !pinClickArea.pressed ? hifi.colors.redHighlight : hifi.colors.white
|
||||
size: iconSize
|
||||
MouseArea {
|
||||
id: pinClickArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
propagateComposedEvents: true
|
||||
onClicked: { frame.pin(); mouse.accepted = false; }
|
||||
}
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
// "Close" button
|
||||
visible: window ? window.closable : false
|
||||
text: closeClickArea.containsPress ? hifi.glyphs.closeInverted : hifi.glyphs.close
|
||||
color: closeClickArea.containsMouse ? hifi.colors.redHighlight : hifi.colors.white
|
||||
size: iconSize
|
||||
MouseArea {
|
||||
id: closeClickArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: window.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
// Title
|
||||
id: titleText
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: frameMarginLeft + hifi.dimensions.contentMargin.x
|
||||
right: controlsRow.left
|
||||
rightMargin: iconSize
|
||||
top: parent.top
|
||||
topMargin: frameMargin
|
||||
}
|
||||
text: window ? window.title : ""
|
||||
color: hifi.colors.white
|
||||
size: hifi.fontSizes.overlayTitle
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
source: titleText
|
||||
anchors.fill: titleText
|
||||
horizontalOffset: 1
|
||||
verticalOffset: 1
|
||||
samples: 2
|
||||
color: hifi.colors.baseGrayShadow60
|
||||
visible: (window && window.focus)
|
||||
cached: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
60
interface/resources/qml/windows-uit/Fadable.qml
Normal file
60
interface/resources/qml/windows-uit/Fadable.qml
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Fadable.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 15 Jan 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
// Enable window visibility transitions
|
||||
FocusScope {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
Component.onCompleted: {
|
||||
fadeTargetProperty = visible ? 1.0 : 0.0
|
||||
}
|
||||
|
||||
// The target property to animate, usually scale or opacity
|
||||
property alias fadeTargetProperty: root.opacity
|
||||
// always start the property at 0 to enable fade in on creation
|
||||
fadeTargetProperty: 0
|
||||
// DO NOT set visible to false or when derived types override it it
|
||||
// will short circuit the fade in on initial visibility
|
||||
// visible: false <--- NO
|
||||
|
||||
// Some dialogs should be destroyed when they become
|
||||
// invisible, so handle that
|
||||
onVisibleChanged: {
|
||||
// If someone directly set the visibility to false
|
||||
// toggle it back on and use the targetVisible flag to transition
|
||||
// via fading.
|
||||
if ((!visible && fadeTargetProperty != 0.0) || (visible && fadeTargetProperty == 0.0)) {
|
||||
var target = visible;
|
||||
visible = !visible;
|
||||
fadeTargetProperty = target ? 1.0 : 0.0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The actual animator
|
||||
Behavior on fadeTargetProperty {
|
||||
NumberAnimation {
|
||||
duration: hifi.effects.fadeInDuration
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
|
||||
// Once we're transparent, disable the dialog's visibility
|
||||
onFadeTargetPropertyChanged: {
|
||||
visible = (fadeTargetProperty != 0.0);
|
||||
}
|
||||
}
|
133
interface/resources/qml/windows-uit/Frame.qml
Normal file
133
interface/resources/qml/windows-uit/Frame.qml
Normal file
|
@ -0,0 +1,133 @@
|
|||
//
|
||||
// Frame.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 12 Jan 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "../styles-uit"
|
||||
import "../js/Utils.js" as Utils
|
||||
|
||||
Item {
|
||||
id: frame
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
default property var decoration
|
||||
|
||||
readonly property int iconSize: 22
|
||||
readonly property int frameMargin: 9
|
||||
readonly property int frameMarginLeft: frameMargin
|
||||
readonly property int frameMarginRight: frameMargin
|
||||
readonly property int frameMarginTop: 2 * frameMargin + iconSize
|
||||
readonly property int frameMarginBottom: iconSize + 11
|
||||
|
||||
// Frames always fill their parents, but their decorations may extend
|
||||
// beyond the window via negative margin sizes
|
||||
anchors.fill: parent
|
||||
|
||||
children: [
|
||||
focusShadow,
|
||||
decoration,
|
||||
sizeOutline,
|
||||
debugZ,
|
||||
sizeDrag
|
||||
]
|
||||
|
||||
Text {
|
||||
id: debugZ
|
||||
visible: DebugQML
|
||||
text: window ? "Z: " + window.z : ""
|
||||
y: window ? window.height + 4 : 0
|
||||
}
|
||||
|
||||
function deltaSize(dx, dy) {
|
||||
var newSize = Qt.vector2d(window.width + dx, window.height + dy);
|
||||
newSize = Utils.clampVector(newSize, window.minSize, window.maxSize);
|
||||
window.width = newSize.x
|
||||
window.height = newSize.y
|
||||
}
|
||||
|
||||
RadialGradient {
|
||||
id: focusShadow
|
||||
width: 1.66 * window.width
|
||||
height: 1.66 * window.height
|
||||
x: (window.width - width) / 2
|
||||
y: window.height / 2 - 0.375 * height
|
||||
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX.
|
||||
// Check again when have a later version of QtQuick.
|
||||
visible: window && window.focus && pane.visible && Qt.platform.os != "osx"
|
||||
gradient: Gradient {
|
||||
// GradientStop position 0.5 is at full circumference of circle that fits inside the square.
|
||||
GradientStop { position: 0.0; color: "#ff000000" } // black, 100% opacity
|
||||
GradientStop { position: 0.333; color: "#1f000000" } // black, 12% opacity
|
||||
GradientStop { position: 0.5; color: "#00000000" } // black, 0% opacity
|
||||
GradientStop { position: 1.0; color: "#00000000" }
|
||||
}
|
||||
cached: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: sizeOutline
|
||||
x: -frameMarginLeft
|
||||
y: -frameMarginTop
|
||||
width: window ? window.width + frameMarginLeft + frameMarginRight : 0
|
||||
height: window ? window.height + frameMarginTop + frameMarginBottom : 0
|
||||
color: hifi.colors.baseGrayHighlight15
|
||||
border.width: 3
|
||||
border.color: hifi.colors.white50
|
||||
radius: hifi.dimensions.borderRadius
|
||||
visible: window ? !pane.visible : false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
// Resize handle
|
||||
id: sizeDrag
|
||||
width: iconSize
|
||||
height: iconSize
|
||||
enabled: window ? window.resizable : false
|
||||
hoverEnabled: true
|
||||
x: window ? window.width + frameMarginRight - iconSize : 0
|
||||
y: window ? window.height + 4 : 0
|
||||
property vector2d pressOrigin
|
||||
property vector2d sizeOrigin
|
||||
property bool hid: false
|
||||
onPressed: {
|
||||
//console.log("Pressed on size")
|
||||
pressOrigin = Qt.vector2d(mouseX, mouseY)
|
||||
sizeOrigin = Qt.vector2d(window.content.width, window.content.height)
|
||||
hid = false;
|
||||
}
|
||||
onReleased: {
|
||||
if (hid) {
|
||||
pane.visible = true
|
||||
frameContent.visible = true
|
||||
hid = false;
|
||||
}
|
||||
}
|
||||
onPositionChanged: {
|
||||
if (pressed) {
|
||||
if (pane.visible) {
|
||||
pane.visible = false;
|
||||
frameContent.visible = false
|
||||
hid = true;
|
||||
}
|
||||
var delta = Qt.vector2d(mouseX, mouseY).minus(pressOrigin);
|
||||
frame.deltaSize(delta.x, delta.y)
|
||||
}
|
||||
}
|
||||
HiFiGlyphs {
|
||||
visible: sizeDrag.enabled
|
||||
x: -11 // Move a little to visually align
|
||||
y: -4 // ""
|
||||
text: hifi.glyphs.resizeHandle
|
||||
size: iconSize + 10
|
||||
color: sizeDrag.containsMouse || sizeDrag.pressed ? hifi.colors.white : hifi.colors.white50
|
||||
}
|
||||
}
|
||||
}
|
81
interface/resources/qml/windows-uit/ModalFrame.qml
Normal file
81
interface/resources/qml/windows-uit/ModalFrame.qml
Normal file
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// ModalFrame.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 15 Jan 2016
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
import "."
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Frame {
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
Rectangle {
|
||||
id: modalFrame
|
||||
|
||||
readonly property bool hasTitle: window.title != ""
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
topMargin: -hifi.dimensions.modalDialogMargin.y - (modalFrame.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0)
|
||||
leftMargin: -hifi.dimensions.modalDialogMargin.x
|
||||
rightMargin: -hifi.dimensions.modalDialogMargin.x
|
||||
bottomMargin: -hifi.dimensions.modalDialogMargin.y
|
||||
}
|
||||
|
||||
border {
|
||||
width: hifi.dimensions.borderWidth
|
||||
color: hifi.colors.lightGrayText80
|
||||
}
|
||||
radius: hifi.dimensions.borderRadius
|
||||
color: hifi.colors.faintGray
|
||||
|
||||
Item {
|
||||
visible: modalFrame.hasTitle
|
||||
anchors.fill: parent
|
||||
anchors {
|
||||
topMargin: -parent.anchors.topMargin
|
||||
leftMargin: -parent.anchors.leftMargin
|
||||
rightMargin: -parent.anchors.rightMargin
|
||||
}
|
||||
|
||||
Item {
|
||||
width: title.width + (window.iconText !== "" ? icon.width + hifi.dimensions.contentSpacing.x : 0)
|
||||
x: (parent.width - width) / 2
|
||||
|
||||
FontAwesome {
|
||||
id: icon
|
||||
text: window.iconText
|
||||
size: 30
|
||||
color: hifi.colors.lightGrayText
|
||||
visible: text != ""
|
||||
y: -hifi.dimensions.modalDialogTitleHeight - 5
|
||||
anchors.left: parent.left
|
||||
}
|
||||
RalewayRegular {
|
||||
id: title
|
||||
text: window.title
|
||||
elide: Text.ElideRight
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
size: hifi.fontSizes.overlayTitle
|
||||
y: -hifi.dimensions.modalDialogTitleHeight
|
||||
anchors.right: parent.right
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: hifi.colors.lightGray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
interface/resources/qml/windows-uit/ModalWindow.qml
Normal file
22
interface/resources/qml/windows-uit/ModalWindow.qml
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// ModalWindow.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 22 Jan 2016
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
|
||||
import "."
|
||||
|
||||
Window {
|
||||
id: window
|
||||
anchors.centerIn: parent
|
||||
modality: Qt.ApplicationModal
|
||||
destroyOnCloseButton: true
|
||||
destroyOnInvisible: true
|
||||
frame: ModalFrame{}
|
||||
}
|
281
interface/resources/qml/windows-uit/Window.qml
Normal file
281
interface/resources/qml/windows-uit/Window.qml
Normal file
|
@ -0,0 +1,281 @@
|
|||
//
|
||||
// Window.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 12 Jan 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "."
|
||||
import "../styles-uit"
|
||||
|
||||
// FIXME how do I set the initial position of a window without
|
||||
// overriding places where the a individual client of the window
|
||||
// might be setting the position with a Settings{} element?
|
||||
|
||||
// FIXME how to I enable dragging without allowing the window to lay outside
|
||||
// of the desktop? How do I ensure when the desktop resizes all the windows
|
||||
// are still at least partially visible?
|
||||
Fadable {
|
||||
id: window
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
// The Window size is the size of the content, while the frame
|
||||
// decorations can extend outside it.
|
||||
implicitHeight: content ? content.height : 0
|
||||
implicitWidth: content ? content.width : 0
|
||||
x: -1; y: -1
|
||||
enabled: visible
|
||||
|
||||
signal windowDestroyed();
|
||||
|
||||
property int modality: Qt.NonModal
|
||||
readonly property bool topLevelWindow: true
|
||||
property string title
|
||||
// Should the window be closable control?
|
||||
property bool closable: true
|
||||
// Should the window try to remain on top of other windows?
|
||||
property bool alwaysOnTop: false
|
||||
// Should hitting the close button hide or destroy the window?
|
||||
property bool destroyOnCloseButton: true
|
||||
// Should hiding the window destroy it or just hide it?
|
||||
property bool destroyOnInvisible: false
|
||||
// FIXME support for pinned / unpinned pending full design
|
||||
// property bool pinnable: false
|
||||
// property bool pinned: false
|
||||
property bool resizable: false
|
||||
|
||||
property vector2d minSize: Qt.vector2d(100, 100)
|
||||
property vector2d maxSize: Qt.vector2d(1280, 720)
|
||||
|
||||
// The content to place inside the window, determined by the client
|
||||
default property var content
|
||||
|
||||
function setDefaultFocus() {} // Default function; can be overridden by dialogs.
|
||||
|
||||
property var rectifier: Timer {
|
||||
property bool executing: false;
|
||||
interval: 100
|
||||
repeat: false
|
||||
running: false
|
||||
|
||||
onTriggered: {
|
||||
executing = true;
|
||||
x = Math.floor(x);
|
||||
y = Math.floor(y);
|
||||
executing = false;
|
||||
}
|
||||
|
||||
function begin() {
|
||||
if (!executing) {
|
||||
restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
onXChanged: rectifier.begin();
|
||||
onYChanged: rectifier.begin();
|
||||
|
||||
// This mouse area serves to raise the window. To function, it must live
|
||||
// in the window and have a higher Z-order than the content, but follow
|
||||
// the position and size of frame decoration
|
||||
property var activator: MouseArea {
|
||||
width: frame.decoration.width
|
||||
height: frame.decoration.height
|
||||
x: frame.decoration.anchors.leftMargin
|
||||
y: frame.decoration.anchors.topMargin
|
||||
propagateComposedEvents: true
|
||||
acceptedButtons: Qt.AllButtons
|
||||
enabled: window.visible
|
||||
onPressed: {
|
||||
//console.log("Pressed on activator area");
|
||||
window.raise();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
// This mouse area serves to swallow mouse events while the mouse is over the window
|
||||
// to prevent things like mouse wheel events from reaching the application and changing
|
||||
// the camera if the user is scrolling through a list and gets to the end.
|
||||
property var swallower: MouseArea {
|
||||
width: frame.decoration.width
|
||||
height: frame.decoration.height
|
||||
x: frame.decoration.anchors.leftMargin
|
||||
y: frame.decoration.anchors.topMargin
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.AllButtons
|
||||
enabled: window.visible
|
||||
onClicked: {}
|
||||
onDoubleClicked: {}
|
||||
onPressAndHold: {}
|
||||
onReleased: {}
|
||||
onWheel: {}
|
||||
}
|
||||
|
||||
// Default to a standard frame. Can be overriden to provide custom
|
||||
// frame styles, like a full desktop frame to simulate a modal window
|
||||
property var frame: DefaultFrame { }
|
||||
|
||||
// Scrollable window content.
|
||||
property var pane: Item {
|
||||
property bool isScrolling: scrollView.height < scrollView.contentItem.height
|
||||
property int contentWidth: scrollView.width - (isScrolling ? 11 : 0)
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: isScrolling ? 11 : 0
|
||||
|
||||
Rectangle {
|
||||
id: contentBackground
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: parent.isScrolling ? 11 : 0
|
||||
color: hifi.colors.baseGray
|
||||
visible: modality != Qt.ApplicationModal
|
||||
}
|
||||
|
||||
LinearGradient {
|
||||
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX.
|
||||
// Check again when have a later version of QtQuick.
|
||||
visible: modality != Qt.ApplicationModal && Qt.platform.os != "osx"
|
||||
anchors.top: contentBackground.bottom
|
||||
anchors.left: contentBackground.left
|
||||
width: contentBackground.width - 1
|
||||
height: 4
|
||||
start: Qt.point(0, 0)
|
||||
end: Qt.point(0, 4)
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: hifi.colors.darkGray }
|
||||
GradientStop { position: 1.0; color: hifi.colors.darkGray0 }
|
||||
}
|
||||
cached: true
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
contentItem: content
|
||||
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: parent.isScrolling ? 1 : 0
|
||||
|
||||
style: ScrollViewStyle {
|
||||
|
||||
padding.right: -7 // Move to right away from content.
|
||||
|
||||
handle: Item {
|
||||
implicitWidth: 8
|
||||
Rectangle {
|
||||
radius: 4
|
||||
color: hifi.colors.white30
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: 2 // Finesse size and position.
|
||||
topMargin: 1
|
||||
bottomMargin: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scrollBarBackground: Item {
|
||||
implicitWidth: 10
|
||||
Rectangle {
|
||||
color: hifi.colors.darkGray30
|
||||
radius: 4
|
||||
anchors {
|
||||
fill: parent
|
||||
topMargin: -1 // Finesse size
|
||||
bottomMargin: -2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
incrementControl: Item {
|
||||
visible: false
|
||||
}
|
||||
|
||||
decrementControl: Item {
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
children: [ swallower, frame, pane, activator ]
|
||||
|
||||
Component.onCompleted: { raise(); setDefaultFocus(); }
|
||||
Component.onDestruction: windowDestroyed();
|
||||
onParentChanged: raise();
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible && destroyOnInvisible) {
|
||||
destroy();
|
||||
return;
|
||||
}
|
||||
if (visible) {
|
||||
raise();
|
||||
}
|
||||
enabled = visible
|
||||
}
|
||||
|
||||
function raise() {
|
||||
if (visible && parent) {
|
||||
desktop.raise(window)
|
||||
}
|
||||
}
|
||||
|
||||
function pin() {
|
||||
// pinned = ! pinned
|
||||
}
|
||||
|
||||
// our close function performs the same way as the OffscreenUI class:
|
||||
// don't do anything but manipulate the targetVisible flag and let the other
|
||||
// mechanisms decide if the window should be destroyed after the close
|
||||
// animation completes
|
||||
// FIXME using this close function messes up the visibility signals received by the
|
||||
// type and it's derived types
|
||||
// function close() {
|
||||
// console.log("Closing " + window)
|
||||
// if (destroyOnCloseButton) {
|
||||
// destroyOnInvisible = true
|
||||
// }
|
||||
// visible = false;
|
||||
// }
|
||||
|
||||
function framedRect() {
|
||||
if (!frame || !frame.decoration) {
|
||||
return Qt.rect(0, 0, window.width, window.height)
|
||||
}
|
||||
return Qt.rect(frame.decoration.anchors.leftMargin, frame.decoration.anchors.topMargin,
|
||||
window.width - frame.decoration.anchors.leftMargin - frame.decoration.anchors.rightMargin,
|
||||
window.height - frame.decoration.anchors.topMargin - frame.decoration.anchors.bottomMargin)
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch(event.key) {
|
||||
case Qt.Key_Control:
|
||||
case Qt.Key_Shift:
|
||||
case Qt.Key_Meta:
|
||||
case Qt.Key_Alt:
|
||||
break;
|
||||
|
||||
case Qt.Key_W:
|
||||
if (window.closable && (event.modifiers === Qt.ControlModifier)) {
|
||||
visible = false
|
||||
event.accepted = true
|
||||
}
|
||||
// fall through
|
||||
|
||||
default:
|
||||
// Consume unmodified keyboard entries while the window is focused, to prevent them
|
||||
// from propagating to the application
|
||||
if (event.modifiers === Qt.NoModifier) {
|
||||
event.accepted = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1198,7 +1198,8 @@ void Application::initializeUi() {
|
|||
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
|
||||
// support the window management and scripting proxies for VR use
|
||||
offscreenUi->createDesktop(QString("hifi/Desktop.qml"));
|
||||
|
||||
connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
|
||||
|
||||
// FIXME either expose so that dialogs can set this themselves or
|
||||
// do better detection in the offscreen UI of what has focus
|
||||
offscreenUi->setNavigationFocused(false);
|
||||
|
@ -1259,6 +1260,8 @@ void Application::initializeUi() {
|
|||
rootContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
|
||||
rootContext->setContextProperty("Reticle", _compositor.getReticleInterface());
|
||||
|
||||
rootContext->setContextProperty("ApplicationCompositor", &_compositor);
|
||||
|
||||
_glWidget->installEventFilter(offscreenUi.data());
|
||||
offscreenUi->setMouseTranslator([=](const QPointF& pt) {
|
||||
QPointF result = pt;
|
||||
|
@ -3772,8 +3775,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
// The pending changes collecting the changes here
|
||||
render::PendingChanges pendingChanges;
|
||||
|
||||
// FIXME: Move this out of here!, Background / skybox should be driven by the enityt content just like the other entities
|
||||
// Background rendering decision
|
||||
if (BackgroundRenderData::_item == 0) {
|
||||
if (!render::Item::isValidID(BackgroundRenderData::_item)) {
|
||||
auto backgroundRenderData = make_shared<BackgroundRenderData>();
|
||||
auto backgroundRenderPayload = make_shared<BackgroundRenderData::Payload>(backgroundRenderData);
|
||||
BackgroundRenderData::_item = _main3DScene->allocateID();
|
||||
|
@ -3798,8 +3802,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Move this out of here!, WorldBox should be driven by the entity content just like the other entities
|
||||
// Make sure the WorldBox is in the scene
|
||||
if (WorldBoxRenderData::_item == 0) {
|
||||
if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
|
||||
auto worldBoxRenderData = make_shared<WorldBoxRenderData>();
|
||||
auto worldBoxRenderPayload = make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
|
||||
|
||||
|
@ -3814,9 +3819,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
}
|
||||
|
||||
// Setup the current Zone Entity lighting and skybox
|
||||
// Fixme: We need a better soution through an actual render item !!!
|
||||
{
|
||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||
// FIXME: Use a zone setting to determine the ambient light mode
|
||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(-1);
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity(), skyStage->getSunLight()->getAmbientIntensity());
|
||||
|
||||
|
@ -4307,7 +4312,7 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
|||
case FSTReader::HEAD_AND_BODY_MODEL:
|
||||
ok = QMessageBox::Ok == OffscreenUi::question("Set Avatar",
|
||||
"Would you like to use '" + modelName + "' for your avatar?",
|
||||
QMessageBox::Ok | QMessageBox::Cancel);
|
||||
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -4627,34 +4632,6 @@ float Application::getRenderResolutionScale() const {
|
|||
}
|
||||
}
|
||||
|
||||
int Application::getRenderAmbientLight() const {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLightGlobal)) {
|
||||
return -1;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight0)) {
|
||||
return 0;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight1)) {
|
||||
return 1;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight2)) {
|
||||
return 2;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight3)) {
|
||||
return 3;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight4)) {
|
||||
return 4;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight5)) {
|
||||
return 5;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight6)) {
|
||||
return 6;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight7)) {
|
||||
return 7;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight8)) {
|
||||
return 8;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight9)) {
|
||||
return 9;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Application::notifyPacketVersionMismatch() {
|
||||
if (!_notifiedPacketVersionMismatchThisDomain) {
|
||||
_notifiedPacketVersionMismatchThisDomain = true;
|
||||
|
@ -5036,27 +5013,11 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de
|
|||
// controller pose is in Avatar frame.
|
||||
glm::vec3 position = pose.getTranslation();
|
||||
glm::quat rotation = pose.getRotation();
|
||||
glm::vec3 rawVelocity = pose.getVelocity();
|
||||
glm::vec3 angularVelocity = pose.getAngularVelocity();
|
||||
|
||||
// Compute current velocity from position change
|
||||
glm::vec3 rawVelocity;
|
||||
if (deltaTime > 0.0f) {
|
||||
rawVelocity = (position - palm.getRawPosition()) / deltaTime;
|
||||
} else {
|
||||
rawVelocity = glm::vec3(0.0f);
|
||||
}
|
||||
palm.setRawVelocity(rawVelocity); // meters/sec
|
||||
|
||||
// Angular Velocity of Palm
|
||||
glm::quat deltaRotation = rotation * glm::inverse(palm.getRawRotation());
|
||||
glm::vec3 angularVelocity(0.0f);
|
||||
float rotationAngle = glm::angle(deltaRotation);
|
||||
if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) {
|
||||
angularVelocity = glm::normalize(glm::axis(deltaRotation));
|
||||
angularVelocity *= (rotationAngle / deltaTime);
|
||||
palm.setRawAngularVelocity(angularVelocity);
|
||||
} else {
|
||||
palm.setRawAngularVelocity(glm::vec3(0.0f));
|
||||
}
|
||||
palm.setRawVelocity(rawVelocity);
|
||||
palm.setRawAngularVelocity(angularVelocity);
|
||||
|
||||
if (controller::InputDevice::getLowVelocityFilter()) {
|
||||
// Use a velocity sensitive filter to damp small motions and preserve large ones with
|
||||
|
@ -5128,3 +5089,9 @@ void Application::readArgumentsFromLocalSocket() {
|
|||
qApp->openUrl(QString::fromUtf8(message));
|
||||
}
|
||||
}
|
||||
|
||||
void Application::showDesktop() {
|
||||
if (!_overlayConductor.getEnabled()) {
|
||||
_overlayConductor.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -280,6 +280,7 @@ public slots:
|
|||
void runTests();
|
||||
|
||||
private slots:
|
||||
void showDesktop();
|
||||
void clearDomainOctreeDetails();
|
||||
void idle(uint64_t now);
|
||||
void aboutToQuit();
|
||||
|
@ -351,7 +352,6 @@ private:
|
|||
void checkSkeleton();
|
||||
|
||||
void initializeAcceptedFiles();
|
||||
int getRenderAmbientLight() const;
|
||||
|
||||
void displaySide(RenderArgs* renderArgs, Camera& whichCamera, bool selfAvatarOnly = false);
|
||||
|
||||
|
|
|
@ -312,12 +312,6 @@ Menu::Menu() {
|
|||
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/AudioPreferencesDialog.qml"), "AudioPreferencesDialog");
|
||||
});
|
||||
|
||||
// Settings > Graphics...
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Graphics...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), "GraphicsPreferencesDialog");
|
||||
});
|
||||
|
||||
// Settings > LOD...-- FIXME: needs implementation
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "LOD...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
|
@ -345,27 +339,17 @@ Menu::Menu() {
|
|||
// Developer menu ----------------------------------
|
||||
MenuWrapper* developerMenu = addMenu("Developer", "Developer");
|
||||
|
||||
// Developer > Graphics...
|
||||
action = addActionToQMenuAndActionHash(developerMenu, "Graphics...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), "GraphicsPreferencesDialog");
|
||||
});
|
||||
|
||||
// Developer > Render >>>
|
||||
MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render");
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::WorldAxes);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, 0, true);
|
||||
|
||||
// Developer > Render > Ambient Light
|
||||
MenuWrapper* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight);
|
||||
QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu);
|
||||
ambientLightGroup->setExclusive(true);
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLightGlobal, 0, true));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight0, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight1, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight2, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight3, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight4, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight5, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight6, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight7, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false));
|
||||
|
||||
// Developer > Render > Throttle FPS If Not Focus
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, true);
|
||||
|
||||
|
|
|
@ -266,18 +266,6 @@ namespace MenuOption {
|
|||
const QString RenderResolutionHalf = "1/2";
|
||||
const QString RenderResolutionThird = "1/3";
|
||||
const QString RenderResolutionQuarter = "1/4";
|
||||
const QString RenderAmbientLight = "Ambient Light";
|
||||
const QString RenderAmbientLightGlobal = "Global";
|
||||
const QString RenderAmbientLight0 = "OLD_TOWN_SQUARE";
|
||||
const QString RenderAmbientLight1 = "GRACE_CATHEDRAL";
|
||||
const QString RenderAmbientLight2 = "EUCALYPTUS_GROVE";
|
||||
const QString RenderAmbientLight3 = "ST_PETERS_BASILICA";
|
||||
const QString RenderAmbientLight4 = "UFFIZI_GALLERY";
|
||||
const QString RenderAmbientLight5 = "GALILEOS_TOMB";
|
||||
const QString RenderAmbientLight6 = "VINE_STREET_KITCHEN";
|
||||
const QString RenderAmbientLight7 = "BREEZEWAY";
|
||||
const QString RenderAmbientLight8 = "CAMPUS_SUNSET";
|
||||
const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET";
|
||||
const QString ResetAvatarSize = "Reset Avatar Size";
|
||||
const QString ResetSensors = "Reset Sensors";
|
||||
const QString RunningScripts = "Running Scripts...";
|
||||
|
|
|
@ -315,6 +315,7 @@ bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene>
|
|||
|
||||
void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_renderItemID);
|
||||
render::Item::clearID(_renderItemID);
|
||||
_skeletonModel.removeFromScene(scene, pendingChanges);
|
||||
getHead()->getFaceModel().removeFromScene(scene, pendingChanges);
|
||||
for (auto& attachmentModel : _attachmentModels) {
|
||||
|
@ -323,7 +324,7 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::S
|
|||
}
|
||||
|
||||
void Avatar::updateRenderItem(render::PendingChanges& pendingChanges) {
|
||||
if (_renderItemID != render::Item::INVALID_ITEM_ID) {
|
||||
if (render::Item::isValidID(_renderItemID)) {
|
||||
pendingChanges.updateItem<render::Payload<AvatarData>>(_renderItemID, [](render::Payload<AvatarData>& p) {});
|
||||
}
|
||||
}
|
||||
|
@ -930,35 +931,6 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
|||
}
|
||||
_attachmentModels[i]->setURL(attachmentData[i].modelURL);
|
||||
}
|
||||
|
||||
// AJT: TODO REMOVE
|
||||
/*
|
||||
// make sure we have as many models as attachments
|
||||
while (_attachmentModels.size() < attachmentData.size()) {
|
||||
Model* model = nullptr;
|
||||
if (_unusedAttachments.size() > 0) {
|
||||
model = _unusedAttachments.takeFirst();
|
||||
} else {
|
||||
model = new Model(std::make_shared<Rig>(), this);
|
||||
}
|
||||
model->init();
|
||||
_attachmentModels.append(model);
|
||||
}
|
||||
while (_attachmentModels.size() > attachmentData.size()) {
|
||||
auto attachmentModel = _attachmentModels.back();
|
||||
_attachmentModels.pop_back();
|
||||
_attachmentsToRemove.push_back(attachmentModel);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// update the urls
|
||||
for (int i = 0; i < attachmentData.size(); i++) {
|
||||
_attachmentModels[i]->setURL(attachmentData.at(i).modelURL);
|
||||
_attachmentModels[i]->setSnapModelToCenter(true);
|
||||
_attachmentModels[i]->setScaleToFit(true, getUniformScale() * _attachmentData.at(i).scale);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -93,7 +93,8 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
|
|||
activateBody(true);
|
||||
}
|
||||
|
||||
std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) {
|
||||
std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position,
|
||||
glm::vec3& linearVelocity, glm::vec3& angularVelocity) {
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
auto holdingAvatar = std::static_pointer_cast<Avatar>(avatarManager->getAvatarBySessionID(_holderID));
|
||||
|
||||
|
@ -103,19 +104,22 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::ve
|
|||
|
||||
withReadLock([&]{
|
||||
bool isRightHand = (_hand == "right");
|
||||
glm::vec3 palmPosition { Vectors::ZERO };
|
||||
glm::quat palmRotation { Quaternions::IDENTITY };
|
||||
glm::vec3 palmPosition;
|
||||
glm::quat palmRotation;
|
||||
glm::vec3 palmLinearVelocity;
|
||||
glm::vec3 palmAngularVelocity;
|
||||
|
||||
PalmData palmData = holdingAvatar->getHand()->getCopyOfPalmData(isRightHand ? HandData::RightHand : HandData::LeftHand);
|
||||
|
||||
// TODO: adjust according to _relativePosition and _relativeRotation?
|
||||
linearVelocity = palmData.getVelocity();
|
||||
angularVelocity = palmData.getAngularVelocity();
|
||||
|
||||
if (_ignoreIK && holdingAvatar->isMyAvatar()) {
|
||||
// We cannot ignore other avatars IK and this is not the point of this option
|
||||
// This is meant to make the grabbing behavior more reactive.
|
||||
if (isRightHand) {
|
||||
palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition();
|
||||
palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation();
|
||||
} else {
|
||||
palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition();
|
||||
palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation();
|
||||
}
|
||||
palmPosition = palmData.getPosition();
|
||||
palmRotation = palmData.getRotation();
|
||||
} else if (holdingAvatar->isMyAvatar()) {
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
glm::quat avatarRigidBodyRotation;
|
||||
|
@ -153,14 +157,19 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::ve
|
|||
|
||||
rotation = palmRotation * _relativeRotation;
|
||||
position = palmPosition + rotation * _relativePosition;
|
||||
|
||||
// update linearVelocity based on offset via _relativePosition;
|
||||
linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition);
|
||||
});
|
||||
|
||||
return holdingAvatar;
|
||||
}
|
||||
|
||||
void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
|
||||
glm::quat rotation { Quaternions::IDENTITY };
|
||||
glm::vec3 position { Vectors::ZERO };
|
||||
glm::quat rotation;
|
||||
glm::vec3 position;
|
||||
glm::vec3 linearVelocity;
|
||||
glm::vec3 angularVelocity;
|
||||
bool valid = false;
|
||||
int holdCount = 0;
|
||||
|
||||
|
@ -173,7 +182,8 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
|
|||
std::shared_ptr<AvatarActionHold> holdAction = std::static_pointer_cast<AvatarActionHold>(action);
|
||||
glm::quat rotationForAction;
|
||||
glm::vec3 positionForAction;
|
||||
std::shared_ptr<Avatar> holdingAvatar = holdAction->getTarget(rotationForAction, positionForAction);
|
||||
glm::vec3 linearVelocityForAction, angularVelocityForAction;
|
||||
std::shared_ptr<Avatar> holdingAvatar = holdAction->getTarget(rotationForAction, positionForAction, linearVelocityForAction, angularVelocityForAction);
|
||||
if (holdingAvatar) {
|
||||
holdCount ++;
|
||||
if (holdAction.get() == this) {
|
||||
|
@ -183,15 +193,21 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
|
|||
}
|
||||
|
||||
position += positionForAction;
|
||||
linearVelocity += linearVelocityForAction;
|
||||
angularVelocity += angularVelocityForAction;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid && holdCount > 0) {
|
||||
position /= holdCount;
|
||||
linearVelocity /= holdCount;
|
||||
angularVelocity /= holdCount;
|
||||
|
||||
withWriteLock([&]{
|
||||
_positionalTarget = position;
|
||||
_rotationalTarget = rotation;
|
||||
_linearVelocityTarget = linearVelocity;
|
||||
_angularVelocityTarget = angularVelocity;
|
||||
_positionalTargetSet = true;
|
||||
_rotationalTargetSet = true;
|
||||
_active = true;
|
||||
|
@ -225,15 +241,8 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
|||
|
||||
withWriteLock([&]{
|
||||
if (_kinematicSetVelocity) {
|
||||
if (_previousSet) {
|
||||
// smooth velocity over 2 frames
|
||||
glm::vec3 positionalDelta = _positionalTarget - _previousPositionalTarget;
|
||||
glm::vec3 positionalVelocity =
|
||||
(positionalDelta + _previousPositionalDelta) / (deltaTimeStep + _previousDeltaTimeStep);
|
||||
rigidBody->setLinearVelocity(glmToBullet(positionalVelocity));
|
||||
_previousPositionalDelta = positionalDelta;
|
||||
_previousDeltaTimeStep = deltaTimeStep;
|
||||
}
|
||||
rigidBody->setLinearVelocity(glmToBullet(_linearVelocityTarget));
|
||||
rigidBody->setAngularVelocity(glmToBullet(_angularVelocityTarget));
|
||||
}
|
||||
|
||||
btTransform worldTrans = rigidBody->getWorldTransform();
|
||||
|
|
|
@ -36,7 +36,8 @@ public:
|
|||
virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); }
|
||||
|
||||
bool getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
|
||||
std::shared_ptr<Avatar> getTarget(glm::quat& rotation, glm::vec3& position);
|
||||
std::shared_ptr<Avatar> getTarget(glm::quat& rotation, glm::vec3& position,
|
||||
glm::vec3& linearVelocity, glm::vec3& angularVelocity);
|
||||
|
||||
virtual void prepareForPhysicsSimulation() override;
|
||||
|
||||
|
@ -50,6 +51,9 @@ private:
|
|||
QString _hand { "right" };
|
||||
QUuid _holderID;
|
||||
|
||||
glm::vec3 _linearVelocityTarget;
|
||||
glm::vec3 _angularVelocityTarget;
|
||||
|
||||
bool _kinematic { false };
|
||||
bool _kinematicSetVelocity { false };
|
||||
bool _previousSet { false };
|
||||
|
@ -57,7 +61,6 @@ private:
|
|||
glm::vec3 _previousPositionalTarget;
|
||||
glm::quat _previousRotationalTarget;
|
||||
|
||||
float _previousDeltaTimeStep = 0.0f;
|
||||
glm::vec3 _previousPositionalDelta;
|
||||
|
||||
glm::vec3 _palmOffsetFromRigidBody;
|
||||
|
|
|
@ -123,8 +123,11 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
|||
}
|
||||
|
||||
// connect to AddressManager signal for location jumps
|
||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||
this, &MyAvatar::goToLocation);
|
||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||
[=](const glm::vec3& newPosition, bool hasOrientation, const glm::quat& newOrientation, bool shouldFaceLocation){
|
||||
goToLocation(newPosition, hasOrientation, newOrientation, shouldFaceLocation);
|
||||
});
|
||||
|
||||
_characterController.setEnabled(true);
|
||||
|
||||
_bodySensorMatrix = deriveBodyFromHMDSensor();
|
||||
|
@ -1666,6 +1669,41 @@ void MyAvatar::resetSize() {
|
|||
qCDebug(interfaceapp, "Reset scale to %f", (double)_targetScale);
|
||||
}
|
||||
|
||||
|
||||
void MyAvatar::goToLocation(const QVariant& propertiesVar) {
|
||||
qCDebug(interfaceapp, "MyAvatar QML goToLocation");
|
||||
auto properties = propertiesVar.toMap();
|
||||
if (!properties.contains("position")) {
|
||||
qCWarning(interfaceapp, "goToLocation called without a position variable");
|
||||
return;
|
||||
}
|
||||
|
||||
bool validPosition;
|
||||
glm::vec3 v = vec3FromVariant(properties["position"], validPosition);
|
||||
if (!validPosition) {
|
||||
qCWarning(interfaceapp, "goToLocation called with invalid position variable");
|
||||
return;
|
||||
}
|
||||
bool validOrientation = false;
|
||||
glm::quat q;
|
||||
if (properties.contains("orientation")) {
|
||||
q = quatFromVariant(properties["orientation"], validOrientation);
|
||||
if (!validOrientation) {
|
||||
glm::vec3 eulerOrientation = vec3FromVariant(properties["orientation"], validOrientation);
|
||||
q = glm::quat(eulerOrientation);
|
||||
if (!validOrientation) {
|
||||
qCWarning(interfaceapp, "goToLocation called with invalid orientation variable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validOrientation) {
|
||||
goToLocation(v, true, q);
|
||||
} else {
|
||||
goToLocation(v);
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
||||
bool hasOrientation, const glm::quat& newOrientation,
|
||||
bool shouldFaceLocation) {
|
||||
|
@ -1873,7 +1911,7 @@ bool MyAvatar::FollowHelper::shouldActivate(const MyAvatar& myAvatar, const glm:
|
|||
const float CYLINDER_RADIUS = 0.15f;
|
||||
|
||||
glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);
|
||||
glm::vec3 radialOffset(offset.x, 0.0f, offset.y);
|
||||
glm::vec3 radialOffset(offset.x, 0.0f, offset.z);
|
||||
float radialDistance = glm::length(radialOffset);
|
||||
|
||||
return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM) || (radialDistance > CYLINDER_RADIUS);
|
||||
|
|
|
@ -253,6 +253,7 @@ public slots:
|
|||
void goToLocation(const glm::vec3& newPosition,
|
||||
bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(),
|
||||
bool shouldFaceLocation = false);
|
||||
void goToLocation(const QVariant& properties);
|
||||
|
||||
// Set/Get update the thrust that will move the avatar around
|
||||
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
||||
|
|
|
@ -283,16 +283,43 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
|
|||
|
||||
//Mouse Pointer
|
||||
if (getReticleVisible()) {
|
||||
glm::mat4 overlayXfm;
|
||||
_modelTransform.getMatrix(overlayXfm);
|
||||
if (getReticleDepth() != 1.0f) {
|
||||
// calculate the "apparent location" based on the depth and the current ray
|
||||
glm::vec3 origin, direction;
|
||||
auto reticlePosition = getReticlePosition();
|
||||
computeHmdPickRay(reticlePosition, origin, direction);
|
||||
auto apparentPosition = origin + (direction * getReticleDepth());
|
||||
|
||||
auto reticlePosition = getReticlePosition();
|
||||
glm::vec2 projection = overlayToSpherical(reticlePosition);
|
||||
float cursorDepth = getReticleDepth();
|
||||
mat4 pointerXfm = glm::scale(mat4(), vec3(cursorDepth)) * glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
|
||||
mat4 reticleXfm = overlayXfm * pointerXfm;
|
||||
reticleXfm = glm::scale(reticleXfm, reticleScale);
|
||||
batch.setModelTransform(reticleXfm);
|
||||
// same code as used to render for apparent location
|
||||
auto myCamera = qApp->getCamera();
|
||||
mat4 cameraMat = myCamera->getTransform();
|
||||
auto UITransform = cameraMat * glm::inverse(headPose);
|
||||
auto relativePosition4 = glm::inverse(UITransform) * vec4(apparentPosition, 1);
|
||||
auto relativePosition = vec3(relativePosition4) / relativePosition4.w;
|
||||
auto relativeDistance = glm::length(relativePosition);
|
||||
|
||||
// look at borrowed from overlays
|
||||
float elevation = -asinf(relativePosition.y / glm::length(relativePosition));
|
||||
float azimuth = atan2f(relativePosition.x, relativePosition.z);
|
||||
glm::quat faceCamera = glm::quat(glm::vec3(elevation, azimuth, 0)) * quat(vec3(0, 0, -1)); // this extra *quat(vec3(0,0,-1)) was required to get the quad to flip this seems like we could optimize
|
||||
|
||||
Transform transform;
|
||||
transform.setTranslation(relativePosition);
|
||||
transform.setScale(reticleScale);
|
||||
transform.postScale(relativeDistance); // scale not quite working, distant things too large
|
||||
transform.setRotation(faceCamera);
|
||||
batch.setModelTransform(transform);
|
||||
} else {
|
||||
glm::mat4 overlayXfm;
|
||||
_modelTransform.getMatrix(overlayXfm);
|
||||
|
||||
auto reticlePosition = getReticlePosition();
|
||||
glm::vec2 projection = overlayToSpherical(reticlePosition);
|
||||
mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
|
||||
mat4 reticleXfm = overlayXfm * pointerXfm;
|
||||
reticleXfm = glm::scale(reticleXfm, reticleScale);
|
||||
batch.setModelTransform(reticleXfm);
|
||||
}
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
|
||||
}
|
||||
});
|
||||
|
@ -300,7 +327,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
|
|||
|
||||
QPointF ApplicationCompositor::getMouseEventPosition(QMouseEvent* event) {
|
||||
if (qApp->isHMDMode()) {
|
||||
QMutexLocker locker(&_reticlePositionInHMDLock);
|
||||
QMutexLocker locker(&_reticleLock);
|
||||
return QPointF(_reticlePositionInHMD.x, _reticlePositionInHMD.y);
|
||||
}
|
||||
return event->localPos();
|
||||
|
@ -354,7 +381,7 @@ bool ApplicationCompositor::handleRealMouseMoveEvent(bool sendFakeEvent) {
|
|||
|
||||
// If we're in HMD mode
|
||||
if (shouldCaptureMouse()) {
|
||||
QMutexLocker locker(&_reticlePositionInHMDLock);
|
||||
QMutexLocker locker(&_reticleLock);
|
||||
auto newPosition = QCursor::pos();
|
||||
auto changeInRealMouse = newPosition - _lastKnownRealMouse;
|
||||
auto newReticlePosition = _reticlePositionInHMD + toGlm(changeInRealMouse);
|
||||
|
@ -368,9 +395,9 @@ bool ApplicationCompositor::handleRealMouseMoveEvent(bool sendFakeEvent) {
|
|||
return false; // let the caller know to process the event
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationCompositor::getReticlePosition() {
|
||||
glm::vec2 ApplicationCompositor::getReticlePosition() const {
|
||||
if (qApp->isHMDMode()) {
|
||||
QMutexLocker locker(&_reticlePositionInHMDLock);
|
||||
QMutexLocker locker(&_reticleLock);
|
||||
return _reticlePositionInHMD;
|
||||
}
|
||||
return toGlm(QCursor::pos());
|
||||
|
@ -378,7 +405,7 @@ glm::vec2 ApplicationCompositor::getReticlePosition() {
|
|||
|
||||
void ApplicationCompositor::setReticlePosition(glm::vec2 position, bool sendFakeEvent) {
|
||||
if (qApp->isHMDMode()) {
|
||||
QMutexLocker locker(&_reticlePositionInHMDLock);
|
||||
QMutexLocker locker(&_reticleLock);
|
||||
const float MOUSE_EXTENTS_VERT_ANGULAR_SIZE = 170.0f; // 5deg from poles
|
||||
const float MOUSE_EXTENTS_VERT_PIXELS = VIRTUAL_SCREEN_SIZE_Y * (MOUSE_EXTENTS_VERT_ANGULAR_SIZE / DEFAULT_HMD_UI_VERT_ANGULAR_SIZE);
|
||||
const float MOUSE_EXTENTS_HORZ_ANGULAR_SIZE = 360.0f; // full sphere
|
||||
|
|
|
@ -29,6 +29,7 @@ class RenderArgs;
|
|||
class ReticleInterface;
|
||||
|
||||
|
||||
const float DEFAULT_RETICLE_DEPTH = 1.0f; // FIXME - probably should be based on UI radius
|
||||
|
||||
const float MAGNIFY_WIDTH = 220.0f;
|
||||
const float MAGNIFY_HEIGHT = 100.0f;
|
||||
|
@ -46,6 +47,7 @@ class ApplicationCompositor : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(float alpha READ getAlpha WRITE setAlpha)
|
||||
Q_PROPERTY(bool reticleOverDesktop READ getReticleOverDesktop WRITE setReticleOverDesktop)
|
||||
public:
|
||||
ApplicationCompositor();
|
||||
~ApplicationCompositor();
|
||||
|
@ -83,13 +85,14 @@ public:
|
|||
float getAlpha() const { return _alpha; }
|
||||
void setAlpha(float alpha) { _alpha = alpha; }
|
||||
|
||||
bool getReticleVisible() { return _reticleVisible; }
|
||||
bool getReticleVisible() const { return _reticleVisible; }
|
||||
void setReticleVisible(bool visible) { _reticleVisible = visible; }
|
||||
|
||||
float getReticleDepth() { return _reticleDepth; }
|
||||
float getReticleDepth() const { return _reticleDepth; }
|
||||
void setReticleDepth(float depth) { _reticleDepth = depth; }
|
||||
void resetReticleDepth() { _reticleDepth = DEFAULT_RETICLE_DEPTH; }
|
||||
|
||||
glm::vec2 getReticlePosition();
|
||||
glm::vec2 getReticlePosition() const;
|
||||
void setReticlePosition(glm::vec2 position, bool sendFakeEvent = true);
|
||||
|
||||
glm::vec2 getReticleMaximumPosition() const;
|
||||
|
@ -103,7 +106,12 @@ public:
|
|||
|
||||
bool shouldCaptureMouse() const;
|
||||
|
||||
/// if the reticle is pointing to a system overlay (a dialog box for example) then the function returns true otherwise false
|
||||
bool getReticleOverDesktop() const { return _isOverDesktop; }
|
||||
void setReticleOverDesktop(bool value) { _isOverDesktop = value; }
|
||||
|
||||
private:
|
||||
bool _isOverDesktop { true };
|
||||
|
||||
void displayOverlayTextureStereo(RenderArgs* renderArgs, float aspectRatio, float fov);
|
||||
void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
|
||||
|
@ -147,11 +155,13 @@ private:
|
|||
// application specific position, when it's in desktop mode, the reticle position will simply move
|
||||
// the system mouse.
|
||||
glm::vec2 _reticlePositionInHMD { 0.0f, 0.0f };
|
||||
mutable QMutex _reticlePositionInHMDLock{ QMutex::Recursive };
|
||||
mutable QMutex _reticleLock { QMutex::Recursive };
|
||||
|
||||
QPointF _lastKnownRealMouse;
|
||||
bool _ignoreMouseMove { false };
|
||||
|
||||
bool _reticleOverQml { false };
|
||||
|
||||
ReticleInterface* _reticleInterface;
|
||||
};
|
||||
|
||||
|
@ -163,11 +173,13 @@ class ReticleInterface : public QObject {
|
|||
Q_PROPERTY(float depth READ getDepth WRITE setDepth)
|
||||
Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition)
|
||||
Q_PROPERTY(bool mouseCaptured READ isMouseCaptured)
|
||||
Q_PROPERTY(bool pointingAtSystemOverlay READ isPointingAtSystemOverlay)
|
||||
|
||||
public:
|
||||
ReticleInterface(ApplicationCompositor* outer) : QObject(outer), _compositor(outer) {}
|
||||
|
||||
Q_INVOKABLE bool isMouseCaptured() { return _compositor->shouldCaptureMouse(); }
|
||||
Q_INVOKABLE bool isPointingAtSystemOverlay() { return !_compositor->getReticleOverDesktop(); }
|
||||
|
||||
Q_INVOKABLE bool getVisible() { return _compositor->getReticleVisible(); }
|
||||
Q_INVOKABLE void setVisible(bool visible) { _compositor->setReticleVisible(visible); }
|
||||
|
@ -179,6 +191,7 @@ public:
|
|||
Q_INVOKABLE void setPosition(glm::vec2 position) { _compositor->setReticlePosition(position); }
|
||||
|
||||
Q_INVOKABLE glm::vec2 getMaximumPosition() { return _compositor->getReticleMaximumPosition(); }
|
||||
|
||||
private:
|
||||
ApplicationCompositor* _compositor;
|
||||
};
|
||||
|
|
|
@ -330,15 +330,6 @@ void setupPreferences() {
|
|||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
auto antialiasingConfig = renderConfig->getConfig<Antialiasing>();
|
||||
{
|
||||
auto getter = [antialiasingConfig]()->QString { return antialiasingConfig->getPreset(); };
|
||||
auto setter = [antialiasingConfig](QString preset) { antialiasingConfig->setPreset(preset); };
|
||||
auto preference = new ComboBoxPreference(RENDER, "Antialiasing", getter, setter);
|
||||
preference->setItems(antialiasingConfig->getPresetList());
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
auto shadowConfig = renderConfig->getConfig<RenderShadowTask>();
|
||||
{
|
||||
auto getter = [shadowConfig]()->QString { return shadowConfig->getPreset(); };
|
||||
|
|
|
@ -342,22 +342,14 @@ void Stats::setRenderDetails(const RenderDetails& details) {
|
|||
STAT_UPDATE(triangles, details._trianglesRendered);
|
||||
STAT_UPDATE(materialSwitches, details._materialSwitches);
|
||||
if (_expanded) {
|
||||
STAT_UPDATE(opaqueConsidered, (int)details._opaque._considered);
|
||||
STAT_UPDATE(opaqueOutOfView, details._opaque._outOfView);
|
||||
STAT_UPDATE(opaqueTooSmall, details._opaque._tooSmall);
|
||||
STAT_UPDATE(opaqueRendered, (int)details._opaque._rendered);
|
||||
STAT_UPDATE(shadowConsidered, (int)details._shadow._considered);
|
||||
STAT_UPDATE(itemConsidered, details._item._considered);
|
||||
STAT_UPDATE(itemOutOfView, details._item._outOfView);
|
||||
STAT_UPDATE(itemTooSmall, details._item._tooSmall);
|
||||
STAT_UPDATE(itemRendered, details._item._rendered);
|
||||
STAT_UPDATE(shadowConsidered, details._shadow._considered);
|
||||
STAT_UPDATE(shadowOutOfView, details._shadow._outOfView);
|
||||
STAT_UPDATE(shadowTooSmall, details._shadow._tooSmall);
|
||||
STAT_UPDATE(shadowRendered, (int)details._shadow._rendered);
|
||||
STAT_UPDATE(translucentConsidered, (int)details._translucent._considered);
|
||||
STAT_UPDATE(translucentOutOfView, details._translucent._outOfView);
|
||||
STAT_UPDATE(translucentTooSmall, details._translucent._tooSmall);
|
||||
STAT_UPDATE(translucentRendered, (int)details._translucent._rendered);
|
||||
STAT_UPDATE(otherConsidered, (int)details._other._considered);
|
||||
STAT_UPDATE(otherOutOfView, details._other._outOfView);
|
||||
STAT_UPDATE(otherTooSmall, details._other._tooSmall);
|
||||
STAT_UPDATE(otherRendered, (int)details._other._rendered);
|
||||
STAT_UPDATE(shadowRendered, details._shadow._rendered);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,22 +59,14 @@ class Stats : public QQuickItem {
|
|||
STATS_PROPERTY(int, triangles, 0)
|
||||
STATS_PROPERTY(int, quads, 0)
|
||||
STATS_PROPERTY(int, materialSwitches, 0)
|
||||
STATS_PROPERTY(int, opaqueConsidered, 0)
|
||||
STATS_PROPERTY(int, opaqueOutOfView, 0)
|
||||
STATS_PROPERTY(int, opaqueTooSmall, 0)
|
||||
STATS_PROPERTY(int, opaqueRendered, 0)
|
||||
STATS_PROPERTY(int, itemConsidered, 0)
|
||||
STATS_PROPERTY(int, itemOutOfView, 0)
|
||||
STATS_PROPERTY(int, itemTooSmall, 0)
|
||||
STATS_PROPERTY(int, itemRendered, 0)
|
||||
STATS_PROPERTY(int, shadowConsidered, 0)
|
||||
STATS_PROPERTY(int, shadowOutOfView, 0)
|
||||
STATS_PROPERTY(int, shadowTooSmall, 0)
|
||||
STATS_PROPERTY(int, shadowRendered, 0)
|
||||
STATS_PROPERTY(int, translucentConsidered, 0)
|
||||
STATS_PROPERTY(int, translucentOutOfView, 0)
|
||||
STATS_PROPERTY(int, translucentTooSmall, 0)
|
||||
STATS_PROPERTY(int, translucentRendered, 0)
|
||||
STATS_PROPERTY(int, otherConsidered, 0)
|
||||
STATS_PROPERTY(int, otherOutOfView, 0)
|
||||
STATS_PROPERTY(int, otherTooSmall, 0)
|
||||
STATS_PROPERTY(int, otherRendered, 0)
|
||||
STATS_PROPERTY(QString, sendingMode, QString())
|
||||
STATS_PROPERTY(QString, packetStats, QString())
|
||||
STATS_PROPERTY(QString, lodStatus, QString())
|
||||
|
@ -145,22 +137,14 @@ signals:
|
|||
void trianglesChanged();
|
||||
void quadsChanged();
|
||||
void materialSwitchesChanged();
|
||||
void opaqueConsideredChanged();
|
||||
void opaqueOutOfViewChanged();
|
||||
void opaqueTooSmallChanged();
|
||||
void opaqueRenderedChanged();
|
||||
void itemConsideredChanged();
|
||||
void itemOutOfViewChanged();
|
||||
void itemTooSmallChanged();
|
||||
void itemRenderedChanged();
|
||||
void shadowConsideredChanged();
|
||||
void shadowOutOfViewChanged();
|
||||
void shadowTooSmallChanged();
|
||||
void shadowRenderedChanged();
|
||||
void translucentConsideredChanged();
|
||||
void translucentOutOfViewChanged();
|
||||
void translucentTooSmallChanged();
|
||||
void translucentRenderedChanged();
|
||||
void otherConsideredChanged();
|
||||
void otherOutOfViewChanged();
|
||||
void otherTooSmallChanged();
|
||||
void otherRenderedChanged();
|
||||
void sendingModeChanged();
|
||||
void packetStatsChanged();
|
||||
void lodStatusChanged();
|
||||
|
|
|
@ -45,7 +45,7 @@ void ModelOverlay::update(float deltatime) {
|
|||
_updateModel = false;
|
||||
|
||||
_model.setSnapModelToCenter(true);
|
||||
_model.setScale(getScale());
|
||||
_model.setScale(getDimensions());
|
||||
_model.setRotation(getRotation());
|
||||
_model.setTranslation(getPosition());
|
||||
_model.setURL(_url);
|
||||
|
@ -82,22 +82,6 @@ void ModelOverlay::render(RenderArgs* args) {
|
|||
if (!_visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
if (_model.isActive()) {
|
||||
if (_model.isRenderable()) {
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
_model.render(args, getAlpha());
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void ModelOverlay::setProperties(const QScriptValue &properties) {
|
||||
|
@ -107,10 +91,19 @@ void ModelOverlay::setProperties(const QScriptValue &properties) {
|
|||
|
||||
Volume3DOverlay::setProperties(properties);
|
||||
|
||||
if (position != getPosition() || rotation != getRotation() || scale != getDimensions()) {
|
||||
_model.setScaleToFit(true, getScale());
|
||||
if (position != getPosition() || rotation != getRotation()) {
|
||||
_updateModel = true;
|
||||
}
|
||||
|
||||
if (scale != getDimensions()) {
|
||||
auto newScale = getDimensions();
|
||||
if (newScale.x <= 0 || newScale.y <= 0 || newScale.z <= 0) {
|
||||
setDimensions(scale);
|
||||
} else {
|
||||
_model.setScaleToFit(true, getDimensions());
|
||||
_updateModel = true;
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue urlValue = properties.property("url");
|
||||
if (urlValue.isValid() && urlValue.isString()) {
|
||||
|
@ -140,7 +133,7 @@ QScriptValue ModelOverlay::getProperty(const QString& property) {
|
|||
if (property == "url") {
|
||||
return _url.toString();
|
||||
}
|
||||
if (property == "dimensions") {
|
||||
if (property == "dimensions" || property == "scale" || property == "size") {
|
||||
return vec3toScriptValue(_scriptEngine, _model.getScaleToFitDimensions());
|
||||
}
|
||||
if (property == "textures") {
|
||||
|
|
|
@ -229,6 +229,6 @@ bool Overlay::addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene
|
|||
|
||||
void Overlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_renderItemID);
|
||||
_renderItemID = render::Item::INVALID_ITEM_ID;
|
||||
render::Item::clearID(_renderItemID);
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ void Overlays::cleanupOverlaysToDelete() {
|
|||
Overlay::Pointer overlay = _overlaysToDelete.takeLast();
|
||||
|
||||
auto itemID = overlay->getRenderItemID();
|
||||
if (itemID != render::Item::INVALID_ITEM_ID) {
|
||||
if (render::Item::isValidID(itemID)) {
|
||||
overlay->removeFromScene(overlay, scene, pendingChanges);
|
||||
}
|
||||
} while (!_overlaysToDelete.isEmpty());
|
||||
|
@ -241,7 +241,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
|||
render::ItemKey itemKey = render::payloadGetKey(thisOverlay);
|
||||
if (itemKey != oldItemKey) {
|
||||
auto itemID = thisOverlay->getRenderItemID();
|
||||
if (itemID != render::Item::INVALID_ITEM_ID) {
|
||||
if (render::Item::isValidID(itemID)) {
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
pendingChanges.resortItem(itemID, oldItemKey, itemKey);
|
||||
|
|
|
@ -104,7 +104,9 @@ void AudioInjector::restart() {
|
|||
|
||||
// reset state to start sending from beginning again
|
||||
_nextFrame = 0;
|
||||
_frameTimer->invalidate();
|
||||
if (_frameTimer) {
|
||||
_frameTimer->invalidate();
|
||||
}
|
||||
_hasSentFirstFrame = false;
|
||||
|
||||
// check our state to decide if we need extra handling for the restart request
|
||||
|
@ -122,7 +124,9 @@ void AudioInjector::restart() {
|
|||
injectLocally();
|
||||
} else {
|
||||
// wake the AudioInjectorManager back up if it's stuck waiting
|
||||
injectorManager->restartFinishedInjector(this);
|
||||
if (!injectorManager->restartFinishedInjector(this)) {
|
||||
_state = State::Finished; // we're not playing, so reset the state used by isPlaying.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,15 @@ void AudioInjectorManager::run() {
|
|||
|
||||
static const int MAX_INJECTORS_PER_THREAD = 40; // calculated based on AudioInjector time to send frame, with sufficient padding
|
||||
|
||||
bool AudioInjectorManager::wouldExceedLimits() { // Should be called inside of a lock.
|
||||
if (_injectors.size() >= MAX_INJECTORS_PER_THREAD) {
|
||||
qDebug() << "AudioInjectorManager::threadInjector could not thread AudioInjector - at max of"
|
||||
<< MAX_INJECTORS_PER_THREAD << "current audio injectors.";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AudioInjectorManager::threadInjector(AudioInjector* injector) {
|
||||
if (_shouldStop) {
|
||||
qDebug() << "AudioInjectorManager::threadInjector asked to thread injector but is shutting down.";
|
||||
|
@ -138,8 +147,9 @@ bool AudioInjectorManager::threadInjector(AudioInjector* injector) {
|
|||
// guard the injectors vector with a mutex
|
||||
Lock lock(_injectorsMutex);
|
||||
|
||||
// check if we'll be able to thread this injector (do we have < max concurrent injectors)
|
||||
if (_injectors.size() < MAX_INJECTORS_PER_THREAD) {
|
||||
if (wouldExceedLimits()) {
|
||||
return false;
|
||||
} else {
|
||||
if (!_thread) {
|
||||
createThread();
|
||||
}
|
||||
|
@ -156,23 +166,22 @@ bool AudioInjectorManager::threadInjector(AudioInjector* injector) {
|
|||
_injectorReady.notify_one();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// unable to thread this injector, at the max
|
||||
qDebug() << "AudioInjectorManager::threadInjector could not thread AudioInjector - at max of"
|
||||
<< MAX_INJECTORS_PER_THREAD << "current audio injectors.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioInjectorManager::restartFinishedInjector(AudioInjector* injector) {
|
||||
bool AudioInjectorManager::restartFinishedInjector(AudioInjector* injector) {
|
||||
if (!_shouldStop) {
|
||||
// guard the injectors vector with a mutex
|
||||
Lock lock(_injectorsMutex);
|
||||
|
||||
if (wouldExceedLimits()) {
|
||||
return false;
|
||||
}
|
||||
// add the injector to the queue with a send timestamp of now
|
||||
_injectors.emplace(usecTimestampNow(), InjectorQPointer { injector });
|
||||
|
||||
// notify our wait condition so we can inject two frames for this injector immediately
|
||||
_injectorReady.notify_one();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -50,8 +50,9 @@ private:
|
|||
using Lock = std::unique_lock<Mutex>;
|
||||
|
||||
bool threadInjector(AudioInjector* injector);
|
||||
void restartFinishedInjector(AudioInjector* injector);
|
||||
bool restartFinishedInjector(AudioInjector* injector);
|
||||
void notifyInjectorReadyCondition() { _injectorReady.notify_one(); }
|
||||
bool wouldExceedLimits();
|
||||
|
||||
AudioInjectorManager() {};
|
||||
AudioInjectorManager(const AudioInjectorManager&) = delete;
|
||||
|
|
|
@ -93,6 +93,7 @@ public:
|
|||
PalmData(HandData* owningHandData = nullptr, HandData::Hand hand = HandData::UnknownHand);
|
||||
glm::vec3 getPosition() const { return _owningHandData->localToWorldPosition(_rawPosition); }
|
||||
glm::vec3 getVelocity() const { return _owningHandData->localToWorldDirection(_rawVelocity); }
|
||||
glm::vec3 getAngularVelocity() const { return _owningHandData->localToWorldDirection(_rawAngularVelocity); }
|
||||
|
||||
const glm::vec3& getRawPosition() const { return _rawPosition; }
|
||||
bool isActive() const { return _isActive; }
|
||||
|
|
|
@ -66,10 +66,11 @@ public:
|
|||
|
||||
void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_myItem);
|
||||
render::Item::clearID(_myItem);
|
||||
}
|
||||
|
||||
void notifyChanged() {
|
||||
if (_myItem == render::Item::INVALID_ITEM_ID) {
|
||||
if (!render::Item::isValidID(_myItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -251,6 +251,7 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p
|
|||
void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_myMetaItem);
|
||||
render::Item::clearID(_myMetaItem);
|
||||
if (_model) {
|
||||
_model->removeFromScene(scene, pendingChanges);
|
||||
}
|
||||
|
|
|
@ -179,6 +179,7 @@ void RenderableParticleEffectEntityItem::removeFromScene(EntityItemPointer self,
|
|||
render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_renderItemId);
|
||||
_scene = nullptr;
|
||||
render::Item::clearID(_renderItemId);
|
||||
};
|
||||
|
||||
void RenderableParticleEffectEntityItem::update(const quint64& now) {
|
||||
|
@ -199,7 +200,8 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) {
|
|||
}
|
||||
|
||||
void RenderableParticleEffectEntityItem::updateRenderItem() {
|
||||
if (!_scene) {
|
||||
// this 2 tests are synonyms for this class, but we would like to get rid of the _scene pointer ultimately
|
||||
if (!_scene || !render::Item::isValidID(_renderItemId)) {
|
||||
return;
|
||||
}
|
||||
if (!getVisible()) {
|
||||
|
@ -312,7 +314,7 @@ void RenderableParticleEffectEntityItem::createPipelines() {
|
|||
}
|
||||
|
||||
void RenderableParticleEffectEntityItem::notifyBoundChanged() {
|
||||
if (_renderItemId == render::Item::INVALID_ITEM_ID) {
|
||||
if (!render::Item::isValidID(_renderItemId)) {
|
||||
return;
|
||||
}
|
||||
render::PendingChanges pendingChanges;
|
||||
|
|
|
@ -572,6 +572,7 @@ void RenderablePolyVoxEntityItem::removeFromScene(EntityItemPointer self,
|
|||
std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_myItem);
|
||||
render::Item::clearID(_myItem);
|
||||
}
|
||||
|
||||
namespace render {
|
||||
|
|
|
@ -230,6 +230,7 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_pt
|
|||
void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_myMetaItem);
|
||||
render::Item::clearID(_myMetaItem);
|
||||
if (_model) {
|
||||
_model->removeFromScene(scene, pendingChanges);
|
||||
}
|
||||
|
@ -237,7 +238,7 @@ void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, std::shar
|
|||
|
||||
|
||||
void RenderableZoneEntityItem::notifyBoundChanged() {
|
||||
if (_myMetaItem == render::Item::INVALID_ITEM_ID) {
|
||||
if (!render::Item::isValidID(_myMetaItem)) {
|
||||
return;
|
||||
}
|
||||
render::PendingChanges pendingChanges;
|
||||
|
|
|
@ -44,11 +44,12 @@ out vec4 varColor;
|
|||
out vec2 varTexcoord;
|
||||
|
||||
const int NUM_VERTICES_PER_PARTICLE = 4;
|
||||
// This ordering ensures that un-rotated particles render upright in the wiewer.
|
||||
const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE](
|
||||
vec4(-1.0, -1.0, 0.0, 0.0),
|
||||
vec4(1.0, -1.0, 0.0, 0.0),
|
||||
vec4(-1.0, 1.0, 0.0, 0.0),
|
||||
vec4(1.0, 1.0, 0.0, 0.0)
|
||||
vec4(-1.0, -1.0, 0.0, 0.0),
|
||||
vec4(1.0, 1.0, 0.0, 0.0),
|
||||
vec4(1.0, -1.0, 0.0, 0.0)
|
||||
);
|
||||
|
||||
float bezierInterpolate(float y1, float y2, float y3, float u) {
|
||||
|
@ -115,7 +116,8 @@ void main(void) {
|
|||
float seed = inColor.y;
|
||||
|
||||
// Pass the texcoord and the z texcoord is representing the texture icon
|
||||
varTexcoord = vec2((UNIT_QUAD[twoTriID].xy + 1.0) * 0.5);
|
||||
// Offset for corrected vertex ordering.
|
||||
varTexcoord = vec2((UNIT_QUAD[twoTriID].xy -1.0) * vec2(0.5, -0.5));
|
||||
varColor = interpolate3Vec4(particle.color.start, particle.color.middle, particle.color.finish, age);
|
||||
|
||||
// anchor point in eye space
|
||||
|
|
|
@ -260,10 +260,22 @@ QNetworkReply* OBJReader::request(QUrl& url, bool isTest) {
|
|||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest netRequest(url);
|
||||
QNetworkReply* netReply = isTest ? networkAccessManager.head(netRequest) : networkAccessManager.get(netRequest);
|
||||
if (!qApp) {
|
||||
return netReply;
|
||||
}
|
||||
QEventLoop loop; // Create an event loop that will quit when we get the finished signal
|
||||
QObject::connect(netReply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
loop.exec(); // Nothing is going to happen on this whole run thread until we get this
|
||||
netReply->waitForReadyRead(-1); // so we might as well block this thread waiting for the response, rather than
|
||||
|
||||
bool aboutToQuit { false };
|
||||
auto connection = QObject::connect(qApp, &QCoreApplication::aboutToQuit, [&] {
|
||||
aboutToQuit = true;
|
||||
});
|
||||
static const int WAIT_TIMEOUT_MS = 500;
|
||||
while (qApp && !aboutToQuit && !netReply->isReadable()) {
|
||||
netReply->waitForReadyRead(WAIT_TIMEOUT_MS); // so we might as well block this thread waiting for the response, rather than
|
||||
}
|
||||
QObject::disconnect(connection);
|
||||
return netReply; // trying to sync later on.
|
||||
}
|
||||
|
||||
|
|
|
@ -315,6 +315,8 @@ OffscreenQmlSurface::OffscreenQmlSurface() {
|
|||
}
|
||||
|
||||
OffscreenQmlSurface::~OffscreenQmlSurface() {
|
||||
QObject::disconnect(&_updateTimer);
|
||||
QObject::disconnect(qApp);
|
||||
_renderer->stop();
|
||||
delete _rootItem;
|
||||
delete _renderer;
|
||||
|
@ -322,6 +324,10 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
|
|||
delete _qmlEngine;
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::onAboutToQuit() {
|
||||
QObject::disconnect(&_updateTimer);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
||||
_renderer = new OffscreenQmlRenderer(this, shareContext);
|
||||
_renderer->_renderControl->_renderWindow = _proxyWindow;
|
||||
|
@ -334,12 +340,9 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
|||
// When Quick says there is a need to render, we will not render immediately. Instead,
|
||||
// a timer with a small interval is used to get better performance.
|
||||
_updateTimer.setInterval(MIN_TIMER_MS);
|
||||
connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
|
||||
QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this]{
|
||||
disconnect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
|
||||
});
|
||||
QObject::connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
|
||||
QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &OffscreenQmlSurface::onAboutToQuit);
|
||||
_updateTimer.start();
|
||||
|
||||
_qmlComponent = new QQmlComponent(_qmlEngine);
|
||||
_qmlEngine->rootContext()->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ signals:
|
|||
public slots:
|
||||
void requestUpdate();
|
||||
void requestRender();
|
||||
void onAboutToQuit();
|
||||
|
||||
private:
|
||||
QObject* finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f);
|
||||
|
|
|
@ -21,6 +21,17 @@
|
|||
class NLPacket : public udt::Packet {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Packet Type | Packet Version |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Node UUID | Hash (only if verified) | Optional (only if sourced)
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// NLPacket Header Format
|
||||
|
||||
// this is used by the Octree classes - must be known at compile time
|
||||
static const int MAX_PACKET_HEADER_SIZE =
|
||||
sizeof(udt::Packet::SequenceNumberAndBitField) + sizeof(udt::Packet::MessageNumberAndBitField) +
|
||||
|
|
|
@ -26,10 +26,65 @@ namespace udt {
|
|||
static const int UDP_SEND_BUFFER_SIZE_BYTES = 1048576;
|
||||
static const int UDP_RECEIVE_BUFFER_SIZE_BYTES = 1048576;
|
||||
static const int DEFAULT_SYN_INTERVAL_USECS = 10 * 1000;
|
||||
static const int SEQUENCE_NUMBER_BITS = sizeof(SequenceNumber) * 8;
|
||||
static const int MESSAGE_LINE_NUMBER_BITS = 32;
|
||||
static const int MESSAGE_NUMBER_BITS = 30;
|
||||
static const uint32_t CONTROL_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 1);
|
||||
|
||||
|
||||
// Header constants
|
||||
|
||||
// Bit sizes (in order)
|
||||
static const int CONTROL_BIT_SIZE = 1;
|
||||
static const int RELIABILITY_BIT_SIZE = 1;
|
||||
static const int MESSAGE_BIT_SIZE = 1;
|
||||
static const int OBFUSCATION_LEVEL_SIZE = 2;
|
||||
static const int SEQUENCE_NUMBER_SIZE= 27;
|
||||
|
||||
static const int PACKET_POSITION_SIZE = 2;
|
||||
static const int MESSAGE_NUMBER_SIZE = 30;
|
||||
|
||||
static const int MESSAGE_PART_NUMBER_SIZE = 32;
|
||||
|
||||
// Offsets
|
||||
static const int SEQUENCE_NUMBER_OFFSET = 0;
|
||||
static const int OBFUSCATION_LEVEL_OFFSET = SEQUENCE_NUMBER_OFFSET + SEQUENCE_NUMBER_SIZE;
|
||||
static const int MESSAGE_BIT_OFFSET = OBFUSCATION_LEVEL_OFFSET + OBFUSCATION_LEVEL_SIZE;
|
||||
static const int RELIABILITY_BIT_OFFSET = MESSAGE_BIT_OFFSET + MESSAGE_BIT_SIZE;
|
||||
static const int CONTROL_BIT_OFFSET = RELIABILITY_BIT_OFFSET + RELIABILITY_BIT_SIZE;
|
||||
|
||||
static const int MESSAGE_NUMBER_OFFSET = 0;
|
||||
static const int PACKET_POSITION_OFFSET = MESSAGE_NUMBER_OFFSET + MESSAGE_NUMBER_SIZE;
|
||||
|
||||
static const int MESSAGE_PART_NUMBER_OFFSET = 0;
|
||||
|
||||
// Masks
|
||||
static const uint32_t CONTROL_BIT_MASK = uint32_t(1) << CONTROL_BIT_OFFSET;
|
||||
static const uint32_t RELIABILITY_BIT_MASK = uint32_t(1) << RELIABILITY_BIT_OFFSET;
|
||||
static const uint32_t MESSAGE_BIT_MASK = uint32_t(1) << MESSAGE_BIT_OFFSET;
|
||||
static const uint32_t OBFUSCATION_LEVEL_MASK = uint32_t(3) << OBFUSCATION_LEVEL_OFFSET;
|
||||
static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK | OBFUSCATION_LEVEL_MASK;
|
||||
static const uint32_t SEQUENCE_NUMBER_MASK = ~BIT_FIELD_MASK;
|
||||
|
||||
static const uint32_t PACKET_POSITION_MASK = uint32_t(3) << PACKET_POSITION_OFFSET;
|
||||
static const uint32_t MESSAGE_NUMBER_MASK = ~PACKET_POSITION_MASK;
|
||||
|
||||
static const uint32_t MESSAGE_PART_NUMBER_MASK = ~uint32_t(0);
|
||||
|
||||
|
||||
// Static checks
|
||||
static_assert(CONTROL_BIT_SIZE + RELIABILITY_BIT_SIZE + MESSAGE_BIT_SIZE +
|
||||
OBFUSCATION_LEVEL_SIZE + SEQUENCE_NUMBER_SIZE == 32, "Sequence number line size incorrect");
|
||||
static_assert(PACKET_POSITION_SIZE + MESSAGE_NUMBER_SIZE == 32, "Message number line size incorrect");
|
||||
static_assert(MESSAGE_PART_NUMBER_SIZE == 32, "Message part number line size incorrect");
|
||||
|
||||
static_assert(CONTROL_BIT_MASK == 0x80000000, "CONTROL_BIT_MASK incorrect");
|
||||
static_assert(RELIABILITY_BIT_MASK == 0x40000000, "RELIABILITY_BIT_MASK incorrect");
|
||||
static_assert(MESSAGE_BIT_MASK == 0x20000000, "MESSAGE_BIT_MASK incorrect");
|
||||
static_assert(OBFUSCATION_LEVEL_MASK == 0x18000000, "OBFUSCATION_LEVEL_MASK incorrect");
|
||||
static_assert(BIT_FIELD_MASK == 0xF8000000, "BIT_FIELD_MASK incorrect");
|
||||
static_assert(SEQUENCE_NUMBER_MASK == 0x07FFFFFF, "SEQUENCE_NUMBER_MASK incorrect");
|
||||
|
||||
static_assert(PACKET_POSITION_MASK == 0xC0000000, "PACKET_POSITION_MASK incorrect");
|
||||
static_assert(MESSAGE_NUMBER_MASK == 0x3FFFFFFF, "MESSAGE_NUMBER_MASK incorrect");
|
||||
|
||||
static_assert(MESSAGE_PART_NUMBER_MASK == 0xFFFFFFFF, "MESSAGE_PART_NUMBER_MASK incorrect");
|
||||
}
|
||||
|
||||
#endif // hifi_udt_Constants_h
|
||||
|
|
|
@ -11,10 +11,35 @@
|
|||
|
||||
#include "Packet.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <LogHandler.h>
|
||||
|
||||
using namespace udt;
|
||||
|
||||
static int packetMetaTypeId = qRegisterMetaType<Packet*>("Packet*");
|
||||
|
||||
using Key = uint64_t;
|
||||
static const std::array<Key, 4> KEYS {{
|
||||
0x0,
|
||||
0x6362726973736574,
|
||||
0x7362697261726461,
|
||||
0x72687566666d616e,
|
||||
}};
|
||||
|
||||
void xorHelper(char* start, int size, Key key) {
|
||||
const auto end = start + size;
|
||||
|
||||
auto p = start;
|
||||
for (; p + sizeof(Key) < end; p += sizeof(Key)) {
|
||||
*reinterpret_cast<Key*>(p) ^= key;
|
||||
}
|
||||
|
||||
for (int i = 0; p < end; ++p || ++i) {
|
||||
*p ^= *(reinterpret_cast<const char*>(&key) + i);
|
||||
}
|
||||
}
|
||||
|
||||
int Packet::localHeaderSize(bool isPartOfMessage) {
|
||||
return sizeof(Packet::SequenceNumberAndBitField) +
|
||||
(isPartOfMessage ? sizeof(Packet::MessageNumberAndBitField) + sizeof(MessagePartNumber) : 0);
|
||||
|
@ -69,44 +94,48 @@ Packet::Packet(std::unique_ptr<char[]> data, qint64 size, const HifiSockAddr& se
|
|||
readHeader();
|
||||
|
||||
adjustPayloadStartAndCapacity(Packet::localHeaderSize(_isPartOfMessage), _payloadSize > 0);
|
||||
|
||||
if (getObfuscationLevel() != Packet::NoObfuscation) {
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
QString debugString = "Unobfuscating packet %1 with level %2";
|
||||
debugString = debugString.arg(QString::number((uint32_t)getSequenceNumber()),
|
||||
QString::number(getObfuscationLevel()));
|
||||
|
||||
if (isPartOfMessage()) {
|
||||
debugString += "\n";
|
||||
debugString += " Message Number: %1, Part Number: %2.";
|
||||
debugString = debugString.arg(QString::number(getMessageNumber()),
|
||||
QString::number(getMessagePartNumber()));
|
||||
}
|
||||
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("^Unobfuscating packet .*");
|
||||
qDebug() << qPrintable(debugString);
|
||||
#endif
|
||||
|
||||
obfuscate(NoObfuscation); // Undo obfuscation
|
||||
}
|
||||
}
|
||||
|
||||
Packet::Packet(const Packet& other) :
|
||||
BasePacket(other)
|
||||
{
|
||||
_isReliable = other._isReliable;
|
||||
_isPartOfMessage = other._isPartOfMessage;
|
||||
_sequenceNumber = other._sequenceNumber;
|
||||
Packet::Packet(const Packet& other) : BasePacket(other) {
|
||||
copyMembers(other);
|
||||
}
|
||||
|
||||
Packet& Packet::operator=(const Packet& other) {
|
||||
BasePacket::operator=(other);
|
||||
|
||||
_isReliable = other._isReliable;
|
||||
_isPartOfMessage = other._isPartOfMessage;
|
||||
_sequenceNumber = other._sequenceNumber;
|
||||
|
||||
copyMembers(other);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Packet::Packet(Packet&& other) :
|
||||
BasePacket(std::move(other))
|
||||
{
|
||||
_isReliable = other._isReliable;
|
||||
_isPartOfMessage = other._isPartOfMessage;
|
||||
_sequenceNumber = other._sequenceNumber;
|
||||
_packetPosition = other._packetPosition;
|
||||
_messageNumber = other._messageNumber;
|
||||
Packet::Packet(Packet&& other) : BasePacket(std::move(other)) {
|
||||
copyMembers(other);
|
||||
}
|
||||
|
||||
Packet& Packet::operator=(Packet&& other) {
|
||||
BasePacket::operator=(std::move(other));
|
||||
|
||||
_isReliable = other._isReliable;
|
||||
_isPartOfMessage = other._isPartOfMessage;
|
||||
_sequenceNumber = other._sequenceNumber;
|
||||
_packetPosition = other._packetPosition;
|
||||
_messageNumber = other._messageNumber;
|
||||
|
||||
copyMembers(other);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -124,13 +153,27 @@ void Packet::writeSequenceNumber(SequenceNumber sequenceNumber) const {
|
|||
writeHeader();
|
||||
}
|
||||
|
||||
static const uint32_t RELIABILITY_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 2);
|
||||
static const uint32_t MESSAGE_BIT_MASK = uint32_t(1) << (SEQUENCE_NUMBER_BITS - 3);
|
||||
static const uint32_t BIT_FIELD_MASK = CONTROL_BIT_MASK | RELIABILITY_BIT_MASK | MESSAGE_BIT_MASK;
|
||||
void Packet::obfuscate(ObfuscationLevel level) {
|
||||
auto obfuscationKey = KEYS[getObfuscationLevel()] ^ KEYS[level]; // Undo old and apply new one.
|
||||
if (obfuscationKey != 0) {
|
||||
xorHelper(getData() + localHeaderSize(isPartOfMessage()),
|
||||
getDataSize() - localHeaderSize(isPartOfMessage()), obfuscationKey);
|
||||
|
||||
static const uint8_t PACKET_POSITION_OFFSET = 30;
|
||||
static const uint32_t PACKET_POSITION_MASK = uint32_t(0x03) << PACKET_POSITION_OFFSET;
|
||||
static const uint32_t MESSAGE_NUMBER_MASK = ~PACKET_POSITION_MASK;
|
||||
// Update members and header
|
||||
_obfuscationLevel = level;
|
||||
writeHeader();
|
||||
}
|
||||
}
|
||||
|
||||
void Packet::copyMembers(const Packet& other) {
|
||||
_isReliable = other._isReliable;
|
||||
_isPartOfMessage = other._isPartOfMessage;
|
||||
_obfuscationLevel = other._obfuscationLevel;
|
||||
_sequenceNumber = other._sequenceNumber;
|
||||
_packetPosition = other._packetPosition;
|
||||
_messageNumber = other._messageNumber;
|
||||
_messagePartNumber = other._messagePartNumber;
|
||||
}
|
||||
|
||||
void Packet::readHeader() const {
|
||||
SequenceNumberAndBitField* seqNumBitField = reinterpret_cast<SequenceNumberAndBitField*>(_packet.get());
|
||||
|
@ -139,10 +182,12 @@ void Packet::readHeader() const {
|
|||
|
||||
_isReliable = (bool) (*seqNumBitField & RELIABILITY_BIT_MASK); // Only keep reliability bit
|
||||
_isPartOfMessage = (bool) (*seqNumBitField & MESSAGE_BIT_MASK); // Only keep message bit
|
||||
_sequenceNumber = SequenceNumber{ *seqNumBitField & ~BIT_FIELD_MASK }; // Remove the bit field
|
||||
_obfuscationLevel = (ObfuscationLevel)((*seqNumBitField & OBFUSCATION_LEVEL_MASK) >> OBFUSCATION_LEVEL_OFFSET);
|
||||
_sequenceNumber = SequenceNumber{ *seqNumBitField & SEQUENCE_NUMBER_MASK }; // Remove the bit field
|
||||
|
||||
if (_isPartOfMessage) {
|
||||
MessageNumberAndBitField* messageNumberAndBitField = seqNumBitField + 1;
|
||||
|
||||
_messageNumber = *messageNumberAndBitField & MESSAGE_NUMBER_MASK;
|
||||
_packetPosition = static_cast<PacketPosition>(*messageNumberAndBitField >> PACKET_POSITION_OFFSET);
|
||||
|
||||
|
@ -163,6 +208,10 @@ void Packet::writeHeader() const {
|
|||
if (_isReliable) {
|
||||
*seqNumBitField |= RELIABILITY_BIT_MASK;
|
||||
}
|
||||
|
||||
if (_obfuscationLevel != NoObfuscation) {
|
||||
*seqNumBitField |= (_obfuscationLevel << OBFUSCATION_LEVEL_OFFSET);
|
||||
}
|
||||
|
||||
if (_isPartOfMessage) {
|
||||
*seqNumBitField |= MESSAGE_BIT_MASK;
|
||||
|
|
|
@ -25,6 +25,25 @@ namespace udt {
|
|||
class Packet : public BasePacket {
|
||||
Q_OBJECT
|
||||
public:
|
||||
// Packet Header Format
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |C|R|M| O | Sequence Number |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | P | Message Number | Optional (only if M = 1)
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Message Part Number | Optional (only if M = 1)
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// C: Control bit
|
||||
// R: Reliable bit
|
||||
// M: Message bit
|
||||
// O: Obfuscation level
|
||||
// P: Position bits
|
||||
|
||||
|
||||
// NOTE: The SequenceNumber is only actually 29 bits to leave room for a bit field
|
||||
using SequenceNumberAndBitField = uint32_t;
|
||||
|
||||
|
@ -35,12 +54,20 @@ public:
|
|||
|
||||
// Use same size as MessageNumberAndBitField so we can use the enum with bitwise operations
|
||||
enum PacketPosition : MessageNumberAndBitField {
|
||||
ONLY = 0x0,
|
||||
FIRST = 0x2,
|
||||
MIDDLE = 0x3,
|
||||
LAST = 0x1
|
||||
ONLY = 0x0, // 00
|
||||
FIRST = 0x2, // 10
|
||||
MIDDLE = 0x3, // 11
|
||||
LAST = 0x1 // 01
|
||||
};
|
||||
|
||||
|
||||
// Use same size as SequenceNumberAndBitField so we can use the enum with bitwise operations
|
||||
enum ObfuscationLevel : SequenceNumberAndBitField {
|
||||
NoObfuscation = 0x0, // 00
|
||||
ObfuscationL1 = 0x1, // 01
|
||||
ObfuscationL2 = 0x2, // 10
|
||||
ObfuscationL3 = 0x3, // 11
|
||||
};
|
||||
|
||||
static std::unique_ptr<Packet> create(qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false);
|
||||
static std::unique_ptr<Packet> fromReceivedPacket(std::unique_ptr<char[]> data, qint64 size, const HifiSockAddr& senderSockAddr);
|
||||
|
||||
|
@ -56,7 +83,8 @@ public:
|
|||
|
||||
bool isPartOfMessage() const { return _isPartOfMessage; }
|
||||
bool isReliable() const { return _isReliable; }
|
||||
|
||||
|
||||
ObfuscationLevel getObfuscationLevel() const { return _obfuscationLevel; }
|
||||
SequenceNumber getSequenceNumber() const { return _sequenceNumber; }
|
||||
MessageNumber getMessageNumber() const { return _messageNumber; }
|
||||
PacketPosition getPacketPosition() const { return _packetPosition; }
|
||||
|
@ -64,6 +92,7 @@ public:
|
|||
|
||||
void writeMessageNumber(MessageNumber messageNumber, PacketPosition position, MessagePartNumber messagePartNumber);
|
||||
void writeSequenceNumber(SequenceNumber sequenceNumber) const;
|
||||
void obfuscate(ObfuscationLevel level);
|
||||
|
||||
protected:
|
||||
Packet(qint64 size, bool isReliable = false, bool isPartOfMessage = false);
|
||||
|
@ -76,6 +105,8 @@ protected:
|
|||
Packet& operator=(Packet&& other);
|
||||
|
||||
private:
|
||||
void copyMembers(const Packet& other);
|
||||
|
||||
// Header readers - these read data to member variables after pulling packet off wire
|
||||
void readHeader() const;
|
||||
void writeHeader() const;
|
||||
|
@ -83,6 +114,7 @@ private:
|
|||
// Simple holders to prevent multiple reading and bitwise ops
|
||||
mutable bool _isReliable { false };
|
||||
mutable bool _isPartOfMessage { false };
|
||||
mutable ObfuscationLevel _obfuscationLevel { NoObfuscation };
|
||||
mutable SequenceNumber _sequenceNumber { 0 };
|
||||
mutable MessageNumber _messageNumber { 0 };
|
||||
mutable PacketPosition _packetPosition { PacketPosition::ONLY };
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
using namespace udt;
|
||||
|
||||
MessageNumber PacketQueue::getNextMessageNumber() {
|
||||
static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << MESSAGE_NUMBER_BITS;
|
||||
static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << MESSAGE_NUMBER_SIZE;
|
||||
_currentMessageNumber = (_currentMessageNumber + 1) % MAX_MESSAGE_NUMBER;
|
||||
return _currentMessageNumber;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <LogHandler.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "../NetworkLogging.h"
|
||||
|
@ -225,7 +226,9 @@ void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr<Packet> newPacket,
|
|||
{
|
||||
// Insert the packet we have just sent in the sent list
|
||||
QWriteLocker locker(&_sentLock);
|
||||
_sentPackets[newPacket->getSequenceNumber()].swap(newPacket);
|
||||
auto& entry = _sentPackets[newPacket->getSequenceNumber()];
|
||||
entry.first = 0; // No resend
|
||||
entry.second.swap(newPacket);
|
||||
}
|
||||
Q_ASSERT_X(!newPacket, "SendQueue::sendNewPacketAndAddToSentList()", "Overriden packet in sent list");
|
||||
|
||||
|
@ -354,14 +357,46 @@ bool SendQueue::maybeResendPacket() {
|
|||
auto it = _sentPackets.find(resendNumber);
|
||||
|
||||
if (it != _sentPackets.end()) {
|
||||
auto& entry = it->second;
|
||||
// we found the packet - grab it
|
||||
auto& resendPacket = *(it->second);
|
||||
|
||||
// send it off
|
||||
sendPacket(resendPacket);
|
||||
|
||||
// unlock the sent packets
|
||||
sentLocker.unlock();
|
||||
auto& resendPacket = *(entry.second);
|
||||
++entry.first; // Add 1 resend
|
||||
|
||||
Packet::ObfuscationLevel level = (Packet::ObfuscationLevel)(entry.first < 2 ? 0 : (entry.first - 2) % 4);
|
||||
|
||||
if (level != Packet::NoObfuscation) {
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
QString debugString = "Obfuscating packet %1 with level %2";
|
||||
debugString = debugString.arg(QString::number((uint32_t)resendPacket.getSequenceNumber()),
|
||||
QString::number(level));
|
||||
if (resendPacket.isPartOfMessage()) {
|
||||
debugString += "\n";
|
||||
debugString += " Message Number: %1, Part Number: %2.";
|
||||
debugString = debugString.arg(QString::number(resendPacket.getMessageNumber()),
|
||||
QString::number(resendPacket.getMessagePartNumber()));
|
||||
}
|
||||
static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("^Obfuscating packet .*");
|
||||
qCritical() << qPrintable(debugString);
|
||||
#endif
|
||||
|
||||
// Create copy of the packet
|
||||
auto packet = Packet::createCopy(resendPacket);
|
||||
|
||||
// unlock the sent packets
|
||||
sentLocker.unlock();
|
||||
|
||||
// Obfuscate packet
|
||||
packet->obfuscate(level);
|
||||
|
||||
// send it off
|
||||
sendPacket(*packet);
|
||||
} else {
|
||||
// send it off
|
||||
sendPacket(resendPacket);
|
||||
|
||||
// unlock the sent packets
|
||||
sentLocker.unlock();
|
||||
}
|
||||
|
||||
emit packetRetransmitted();
|
||||
|
||||
|
|
|
@ -126,7 +126,8 @@ private:
|
|||
LossList _naks; // Sequence numbers of packets to resend
|
||||
|
||||
mutable QReadWriteLock _sentLock; // Protects the sent packet list
|
||||
std::unordered_map<SequenceNumber, std::unique_ptr<Packet>> _sentPackets; // Packets waiting for ACK.
|
||||
using PacketResendPair = std::pair<uint8_t, std::unique_ptr<Packet>>; // Number of resend + packet ptr
|
||||
std::unordered_map<SequenceNumber, PacketResendPair> _sentPackets; // Packets waiting for ACK.
|
||||
|
||||
std::mutex _handshakeMutex; // Protects the handshake ACK condition_variable
|
||||
std::atomic<bool> _hasReceivedHandshakeACK { false }; // flag for receipt of handshake ACK from client
|
||||
|
|
|
@ -24,9 +24,9 @@ public:
|
|||
using Type = int32_t;
|
||||
using UType = uint32_t;
|
||||
|
||||
// Values are for 29 bit SequenceNumber
|
||||
static const Type THRESHOLD = 0x0FFFFFFF; // threshold for comparing sequence numbers
|
||||
static const Type MAX = 0x1FFFFFFF; // maximum sequence number used in UDT
|
||||
// Values are for 27 bit SequenceNumber
|
||||
static const Type THRESHOLD = 0x03FFFFFF; // threshold for comparing sequence numbers
|
||||
static const Type MAX = 0x07FFFFFF; // maximum sequence number used in UDT
|
||||
|
||||
SequenceNumber() = default;
|
||||
SequenceNumber(const SequenceNumber& other) : _value(other._value) {}
|
||||
|
|
|
@ -277,7 +277,7 @@ void Socket::readPendingDatagrams() {
|
|||
if (packet->isReliable()) {
|
||||
// if this was a reliable packet then signal the matching connection with the sequence number
|
||||
auto& connection = findOrCreateConnection(senderSockAddr);
|
||||
|
||||
|
||||
if (!connection.processReceivedSequenceNumber(packet->getSequenceNumber(),
|
||||
packet->getDataSize(),
|
||||
packet->getPayloadSize())) {
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
#include "render/DrawTask.h"
|
||||
|
||||
class AntiAliasingConfig : public render::Job::Config::Persistent {
|
||||
class AntiAliasingConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled)
|
||||
public:
|
||||
AntiAliasingConfig() : render::Job::Config::Persistent("Antialiasing", false) {}
|
||||
AntiAliasingConfig() : render::Job::Config(true) {}
|
||||
};
|
||||
|
||||
class Antialiasing {
|
||||
|
|
|
@ -43,7 +43,7 @@ Model::Model(RigPointer rig, QObject* parent) :
|
|||
_rotation(),
|
||||
_scale(1.0f, 1.0f, 1.0f),
|
||||
_scaleToFit(false),
|
||||
_scaleToFitDimensions(0.0f),
|
||||
_scaleToFitDimensions(1.0f),
|
||||
_scaledToFit(false),
|
||||
_snapModelToRegistrationPoint(false),
|
||||
_snappedToRegistrationPoint(false),
|
||||
|
@ -909,6 +909,14 @@ void Model::setScaleToFit(bool scaleToFit, float largestDimension, bool forceRes
|
|||
}
|
||||
}
|
||||
|
||||
glm::vec3 Model::getScaleToFitDimensions() const {
|
||||
if (_scaleToFitDimensions.y == FAKE_DIMENSION_PLACEHOLDER &&
|
||||
_scaleToFitDimensions.z == FAKE_DIMENSION_PLACEHOLDER) {
|
||||
return glm::vec3(_scaleToFitDimensions.x);
|
||||
}
|
||||
return _scaleToFitDimensions;
|
||||
}
|
||||
|
||||
void Model::scaleToFit() {
|
||||
// If our _scaleToFitDimensions.y/z are FAKE_DIMENSION_PLACEHOLDER then it means our
|
||||
// user asked to scale us in a fixed aspect ratio to a single largest dimension, but
|
||||
|
|
|
@ -197,7 +197,7 @@ public:
|
|||
|
||||
/// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension
|
||||
bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit
|
||||
const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to
|
||||
glm::vec3 getScaleToFitDimensions() const; /// the dimensions model is scaled to, including inferred y/z
|
||||
|
||||
void setCauterizeBones(bool flag) { _cauterizeBones = flag; }
|
||||
bool getCauterizeBones() const { return _cauterizeBones; }
|
||||
|
|
|
@ -56,7 +56,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
|||
// Fetch and cull the items from the scene
|
||||
auto sceneFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
||||
const auto sceneSelection = addJob<FetchSpatialTree>("FetchSceneSelection", sceneFilter);
|
||||
const auto culledSceneSelection = addJob<CullSpatialSelection>("CullSceneSelection", sceneSelection, cullFunctor, RenderDetails::OPAQUE_ITEM, sceneFilter);
|
||||
const auto culledSceneSelection = addJob<CullSpatialSelection>("CullSceneSelection", sceneSelection, cullFunctor, RenderDetails::ITEM, sceneFilter);
|
||||
|
||||
// Multi filter visible items into different buckets
|
||||
const int NUM_FILTERS = 3;
|
||||
|
|
|
@ -108,7 +108,7 @@ RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) : Task(std::make_sha
|
|||
const auto fetchedItems = addJob<FetchItems>("FetchShadowMap");
|
||||
|
||||
// CPU: Cull against KeyLight frustum (nearby viewing camera)
|
||||
const auto culledItems = addJob<CullItems<RenderDetails::SHADOW_ITEM>>("CullShadowMap", fetchedItems, cullFunctor);
|
||||
const auto culledItems = addJob<CullItems<RenderDetails::SHADOW>>("CullShadowMap", fetchedItems, cullFunctor);
|
||||
|
||||
// CPU: Sort by pipeline
|
||||
const auto sortedShapes = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledItems);
|
||||
|
|
|
@ -44,11 +44,11 @@ void main() {
|
|||
// fetch raw RGB values for nearby locations
|
||||
// sampling pattern is "five on a die" (each diagonal direction and the center)
|
||||
// computing the coordinates for these texture reads could be moved to the vertex shader for speed if needed
|
||||
vec3 rgbNW = texture2D(colorTexture, varTexcoord + (vec2(-1.0, -1.0) * texcoordOffset)).xyz;
|
||||
vec3 rgbNE = texture2D(colorTexture, varTexcoord + (vec2(+1.0, -1.0) * texcoordOffset)).xyz;
|
||||
vec3 rgbSW = texture2D(colorTexture, varTexcoord + (vec2(-1.0, +1.0) * texcoordOffset)).xyz;
|
||||
vec3 rgbSE = texture2D(colorTexture, varTexcoord + (vec2(+1.0, +1.0) * texcoordOffset)).xyz;
|
||||
vec3 rgbM = texture2D(colorTexture, varTexcoord).xyz;
|
||||
vec3 rgbNW = texture(colorTexture, varTexcoord + (vec2(-1.0, -1.0) * texcoordOffset)).xyz;
|
||||
vec3 rgbNE = texture(colorTexture, varTexcoord + (vec2(+1.0, -1.0) * texcoordOffset)).xyz;
|
||||
vec3 rgbSW = texture(colorTexture, varTexcoord + (vec2(-1.0, +1.0) * texcoordOffset)).xyz;
|
||||
vec3 rgbSE = texture(colorTexture, varTexcoord + (vec2(+1.0, +1.0) * texcoordOffset)).xyz;
|
||||
vec3 rgbM = texture(colorTexture, varTexcoord).xyz;
|
||||
|
||||
// convert RGB values to luminance
|
||||
vec3 luma = vec3(0.299, 0.587, 0.114);
|
||||
|
@ -76,11 +76,11 @@ void main() {
|
|||
|
||||
// perform additional texture sampling perpendicular to gradient
|
||||
vec3 rgbA = (1.0 / 2.0) * (
|
||||
texture2D(colorTexture, varTexcoord + dir * (1.0 / 3.0 - 0.5)).xyz +
|
||||
texture2D(colorTexture, varTexcoord + dir * (2.0 / 3.0 - 0.5)).xyz);
|
||||
texture(colorTexture, varTexcoord + dir * (1.0 / 3.0 - 0.5)).xyz +
|
||||
texture(colorTexture, varTexcoord + dir * (2.0 / 3.0 - 0.5)).xyz);
|
||||
vec3 rgbB = rgbA * (1.0 / 2.0) + (1.0 / 4.0) * (
|
||||
texture2D(colorTexture, varTexcoord + dir * (0.0 / 3.0 - 0.5)).xyz +
|
||||
texture2D(colorTexture, varTexcoord + dir * (3.0 / 3.0 - 0.5)).xyz);
|
||||
texture(colorTexture, varTexcoord + dir * (0.0 / 3.0 - 0.5)).xyz +
|
||||
texture(colorTexture, varTexcoord + dir * (3.0 / 3.0 - 0.5)).xyz);
|
||||
float lumaB = dot(rgbB, luma);
|
||||
|
||||
// compare luma of new samples to the luma range of the original neighborhood
|
||||
|
|
|
@ -28,7 +28,7 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
|
|||
RenderArgs* args = renderContext->args;
|
||||
ViewFrustum* frustum = args->_viewFrustum;
|
||||
|
||||
details._considered += inItems.size();
|
||||
details._considered += (int)inItems.size();
|
||||
|
||||
// Culling / LOD
|
||||
for (auto item : inItems) {
|
||||
|
@ -59,7 +59,7 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
|
|||
details._outOfView++;
|
||||
}
|
||||
}
|
||||
details._rendered += outItems.size();
|
||||
details._rendered += (int)outItems.size();
|
||||
}
|
||||
|
||||
struct ItemBoundSort {
|
||||
|
@ -202,7 +202,7 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re
|
|||
auto& scene = sceneContext->_scene;
|
||||
|
||||
auto& details = args->_details.edit(_detailType);
|
||||
details._considered += inSelection.numItems();
|
||||
details._considered += (int)inSelection.numItems();
|
||||
|
||||
// Eventually use a frozen frustum
|
||||
auto argFrustum = args->_viewFrustum;
|
||||
|
@ -325,7 +325,7 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re
|
|||
}
|
||||
}
|
||||
|
||||
details._rendered += outItems.size();
|
||||
details._rendered += (int)outItems.size();
|
||||
|
||||
|
||||
// Restore frustum if using the frozen one:
|
||||
|
|
|
@ -138,7 +138,7 @@ namespace render {
|
|||
_cullFunctor{ cullFunctor } {}
|
||||
|
||||
CullFunctor _cullFunctor;
|
||||
RenderDetails::Type _detailType{ RenderDetails::OPAQUE_ITEM };
|
||||
RenderDetails::Type _detailType{ RenderDetails::OTHER };
|
||||
ItemFilter _filter{ ItemFilter::Builder::opaqueShape().withoutLayered() };
|
||||
|
||||
void configure(const Config& config);
|
||||
|
|
|
@ -217,6 +217,10 @@ public:
|
|||
static const ID INVALID_ITEM_ID = 0;
|
||||
static const ItemCell INVALID_CELL = -1;
|
||||
|
||||
// Convenient function to clear an ID or check it s valid
|
||||
static void clearID(ID& id) { id = INVALID_ITEM_ID; }
|
||||
static bool isValidID(const ID id) { return id != INVALID_ITEM_ID; }
|
||||
|
||||
// Bound is the AABBox fully containing this item
|
||||
typedef AABox Bound;
|
||||
|
||||
|
|
|
@ -144,7 +144,12 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
|
|||
ScriptEngine::~ScriptEngine() {
|
||||
qCDebug(scriptengine) << "Script Engine shutting down (destructor) for script:" << getFilename();
|
||||
|
||||
DependencyManager::get<ScriptEngines>()->removeScriptEngine(this);
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
||||
if (scriptEngines) {
|
||||
scriptEngines->removeScriptEngine(this);
|
||||
} else {
|
||||
qCWarning(scriptengine) << "Script destroyed after ScriptEngines!";
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::disconnectNonEssentialSignals() {
|
||||
|
|
|
@ -9,10 +9,13 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QColor>
|
||||
#include <QUrl>
|
||||
#include <QUuid>
|
||||
#include <QRect>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtCore/QRect>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtGui/QColor>
|
||||
#include <QtGui/QVector3D>
|
||||
#include <QtGui/QQuaternion>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include "RegisteredMetaTypes.h"
|
||||
|
@ -91,6 +94,51 @@ QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::
|
|||
return array;
|
||||
}
|
||||
|
||||
glm::vec3 vec3FromVariant(const QVariant &object, bool& valid) {
|
||||
glm::vec3 v;
|
||||
valid = false;
|
||||
if (!object.isValid() || object.isNull()) {
|
||||
return v;
|
||||
} else if (object.canConvert<float>()) {
|
||||
v = glm::vec3(object.toFloat());
|
||||
valid = true;
|
||||
} else if (object.canConvert<QVector3D>()) {
|
||||
auto qvec3 = qvariant_cast<QVector3D>(object);
|
||||
v.x = qvec3.x();
|
||||
v.y = qvec3.y();
|
||||
v.z = qvec3.z();
|
||||
valid = true;
|
||||
} else {
|
||||
auto map = object.toMap();
|
||||
auto x = map["x"];
|
||||
auto y = map["y"];
|
||||
auto z = map["z"];
|
||||
if (!x.isValid()) {
|
||||
x = map["width"];
|
||||
}
|
||||
if (!y.isValid()) {
|
||||
y = map["height"];
|
||||
}
|
||||
if (!y.isValid()) {
|
||||
z = map["depth"];
|
||||
}
|
||||
|
||||
if (x.canConvert<float>() && y.canConvert<float>() && z.canConvert<float>()) {
|
||||
v.x = x.toFloat();
|
||||
v.y = y.toFloat();
|
||||
v.z = z.toFloat();
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
glm::vec3 vec3FromVariant(const QVariant &object) {
|
||||
bool valid = false;
|
||||
return vec3FromVariant(object, valid);
|
||||
}
|
||||
|
||||
|
||||
QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat &quat) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) {
|
||||
|
@ -111,6 +159,42 @@ void quatFromScriptValue(const QScriptValue &object, glm::quat &quat) {
|
|||
quat.w = object.property("w").toVariant().toFloat();
|
||||
}
|
||||
|
||||
glm::quat quatFromVariant(const QVariant &object, bool& isValid) {
|
||||
glm::quat q;
|
||||
if (object.canConvert<QQuaternion>()) {
|
||||
auto qvec3 = qvariant_cast<QQuaternion>(object);
|
||||
q.x = qvec3.x();
|
||||
q.y = qvec3.y();
|
||||
q.z = qvec3.z();
|
||||
q.w = qvec3.scalar();
|
||||
isValid = true;
|
||||
} else {
|
||||
auto map = object.toMap();
|
||||
q.x = map["x"].toFloat(&isValid);
|
||||
if (!isValid) {
|
||||
return glm::quat();
|
||||
}
|
||||
q.y = map["y"].toFloat(&isValid);
|
||||
if (!isValid) {
|
||||
return glm::quat();
|
||||
}
|
||||
q.z = map["z"].toFloat(&isValid);
|
||||
if (!isValid) {
|
||||
return glm::quat();
|
||||
}
|
||||
q.w = map["w"].toFloat(&isValid);
|
||||
if (!isValid) {
|
||||
return glm::quat();
|
||||
}
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
glm::quat quatFromVariant(const QVariant &object) {
|
||||
bool valid = false;
|
||||
return quatFromVariant(object, valid);
|
||||
}
|
||||
|
||||
QScriptValue qVectorQuatToScriptValue(QScriptEngine* engine, const QVector<glm::quat>& vector) {
|
||||
QScriptValue array = engine->newArray();
|
||||
for (int i = 0; i < vector.size(); i++) {
|
||||
|
|
|
@ -41,12 +41,18 @@ void vec4FromScriptValue(const QScriptValue& object, glm::vec4& vec4);
|
|||
QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3);
|
||||
void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3);
|
||||
|
||||
glm::vec3 vec3FromVariant(const QVariant &object, bool& valid);
|
||||
glm::vec3 vec3FromVariant(const QVariant &object);
|
||||
|
||||
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2);
|
||||
void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2);
|
||||
|
||||
QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat& quat);
|
||||
void quatFromScriptValue(const QScriptValue &object, glm::quat& quat);
|
||||
|
||||
glm::quat quatFromVariant(const QVariant &object, bool& isValid);
|
||||
glm::quat quatFromVariant(const QVariant &object);
|
||||
|
||||
QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect);
|
||||
void qRectFromScriptValue(const QScriptValue& object, QRect& rect);
|
||||
|
||||
|
|
|
@ -35,36 +35,31 @@ class ShapePipeline;
|
|||
class RenderDetails {
|
||||
public:
|
||||
enum Type {
|
||||
OPAQUE_ITEM,
|
||||
SHADOW_ITEM,
|
||||
TRANSLUCENT_ITEM,
|
||||
OTHER_ITEM
|
||||
ITEM,
|
||||
SHADOW,
|
||||
OTHER
|
||||
};
|
||||
|
||||
struct Item {
|
||||
size_t _considered = 0;
|
||||
size_t _rendered = 0;
|
||||
int _considered = 0;
|
||||
int _outOfView = 0;
|
||||
int _tooSmall = 0;
|
||||
int _rendered = 0;
|
||||
};
|
||||
|
||||
int _materialSwitches = 0;
|
||||
int _trianglesRendered = 0;
|
||||
|
||||
Item _opaque;
|
||||
Item _item;
|
||||
Item _shadow;
|
||||
Item _translucent;
|
||||
Item _other;
|
||||
|
||||
Item& edit(Type type) {
|
||||
switch (type) {
|
||||
case OPAQUE_ITEM:
|
||||
return _opaque;
|
||||
case SHADOW_ITEM:
|
||||
case SHADOW:
|
||||
return _shadow;
|
||||
case TRANSLUCENT_ITEM:
|
||||
return _translucent;
|
||||
case OTHER_ITEM:
|
||||
case ITEM:
|
||||
return _item;
|
||||
default:
|
||||
return _other;
|
||||
}
|
||||
|
|
|
@ -112,6 +112,7 @@ void OffscreenUi::create(QOpenGLContext* context) {
|
|||
}
|
||||
|
||||
void OffscreenUi::show(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) {
|
||||
emit showDesktop();
|
||||
QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name);
|
||||
// First load?
|
||||
if (!item) {
|
||||
|
@ -127,6 +128,7 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<voi
|
|||
QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name);
|
||||
// Already loaded?
|
||||
if (item) {
|
||||
emit showDesktop();
|
||||
item->setVisible(!item->isVisible());
|
||||
return;
|
||||
}
|
||||
|
@ -134,6 +136,7 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<voi
|
|||
load(url, f);
|
||||
item = getRootItem()->findChild<QQuickItem*>(name);
|
||||
if (item && !item->isVisible()) {
|
||||
emit showDesktop();
|
||||
item->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
@ -251,15 +254,15 @@ QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QS
|
|||
}
|
||||
QMessageBox::StandardButton OffscreenUi::information(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Information, title, text, buttons, defaultButton);
|
||||
}
|
||||
QMessageBox::StandardButton OffscreenUi::question(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Question, title, text, buttons, defaultButton);
|
||||
}
|
||||
QMessageBox::StandardButton OffscreenUi::warning(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Critical, title, text, buttons, defaultButton);
|
||||
return DependencyManager::get<OffscreenUi>()->messageBox(QMessageBox::Icon::Warning, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
|
||||
|
@ -439,6 +442,8 @@ void OffscreenUi::createDesktop(const QUrl& url) {
|
|||
new VrMenu(this);
|
||||
|
||||
new KeyboardFocusHack();
|
||||
|
||||
connect(_desktop, SIGNAL(showDesktop()), this, SLOT(showDesktop()));
|
||||
}
|
||||
|
||||
QQuickItem* OffscreenUi::getDesktop() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue