mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 04:04:38 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into orange
This commit is contained in:
commit
ae6e625894
96 changed files with 2803 additions and 659 deletions
|
@ -73,9 +73,7 @@ var PICK_MAX_DISTANCE = 500; // max length of pick-ray
|
|||
|
||||
var GRAB_RADIUS = 0.06; // if the ray misses but an object is this close, it will still be selected
|
||||
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
|
||||
var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable.
|
||||
var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected
|
||||
var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
|
||||
var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object
|
||||
var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed
|
||||
var SHOW_GRAB_SPHERE = false; // draw a green sphere to show the grab search position and size
|
||||
|
@ -173,6 +171,10 @@ var STATE_WAITING_FOR_BUMPER_RELEASE = 15;
|
|||
var COLLIDES_WITH_WHILE_GRABBED = "dynamic,otherAvatar";
|
||||
var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic";
|
||||
|
||||
var HEART_BEAT_INTERVAL = 5; // seconds
|
||||
var HEART_BEAT_TIMEOUT = 15;
|
||||
|
||||
|
||||
function stateToName(state) {
|
||||
switch (state) {
|
||||
case STATE_OFF:
|
||||
|
@ -1103,6 +1105,8 @@ function MyController(hand) {
|
|||
return;
|
||||
}
|
||||
|
||||
this.heartBeat(this.grabbedEntity);
|
||||
|
||||
var handPosition = this.getHandPosition();
|
||||
var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
|
||||
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
|
@ -1438,6 +1442,8 @@ function MyController(hand) {
|
|||
return;
|
||||
}
|
||||
|
||||
this.heartBeat(this.grabbedEntity);
|
||||
|
||||
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]);
|
||||
if (props.parentID == MyAvatar.sessionUUID &&
|
||||
Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) {
|
||||
|
@ -1644,7 +1650,7 @@ function MyController(hand) {
|
|||
// this next line allowed both:
|
||||
// (1) far-grab, pull to self, near grab, then throw
|
||||
// (2) equip something physical and adjust it with a other-hand grab without the thing drifting
|
||||
(!this.isInitialGrab && grabData.refCount > 1)) {
|
||||
grabData.refCount > 1) {
|
||||
noVelocity = true;
|
||||
}
|
||||
}
|
||||
|
@ -1670,19 +1676,39 @@ function MyController(hand) {
|
|||
Entities.deleteEntity(this.pointLight);
|
||||
};
|
||||
|
||||
this.heartBeat = function(entityID) {
|
||||
var now = Date.now();
|
||||
if (now - this.lastHeartBeat > HEART_BEAT_INTERVAL) {
|
||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||
data["heartBeat"] = now;
|
||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
||||
this.lastHeartBeat = now;
|
||||
}
|
||||
};
|
||||
|
||||
this.resetAbandonedGrab = function(entityID) {
|
||||
print("cleaning up abandoned grab on " + entityID);
|
||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||
data["refCount"] = 1;
|
||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
||||
this.deactivateEntity(entityID, false);
|
||||
};
|
||||
|
||||
this.activateEntity = function(entityID, grabbedProperties, wasLoaded) {
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA);
|
||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||
data["activated"] = true;
|
||||
data["avatarId"] = MyAvatar.sessionUUID;
|
||||
var now = Date.now();
|
||||
|
||||
if (wasLoaded) {
|
||||
data["refCount"] = 1;
|
||||
data["avatarId"] = MyAvatar.sessionUUID;
|
||||
} else {
|
||||
data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1;
|
||||
|
||||
// zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done
|
||||
if (data["refCount"] == 1) {
|
||||
data["heartBeat"] = now;
|
||||
this.lastHeartBeat = now;
|
||||
|
||||
this.isInitialGrab = true;
|
||||
data["gravity"] = grabbedProperties.gravity;
|
||||
data["collidesWith"] = grabbedProperties.collidesWith;
|
||||
|
@ -1698,12 +1724,21 @@ function MyController(hand) {
|
|||
z: 0
|
||||
},
|
||||
// bummer, it isn't easy to do bitwise collisionMask operations like this:
|
||||
//"collisionMask": COLLISION_MASK_WHILE_GRABBED | grabbedProperties.collisionMask
|
||||
// "collisionMask": COLLISION_MASK_WHILE_GRABBED | grabbedProperties.collisionMask
|
||||
// when using string values
|
||||
"collidesWith": COLLIDES_WITH_WHILE_GRABBED
|
||||
};
|
||||
Entities.editEntity(entityID, whileHeldProperties);
|
||||
} else if (data["refCount"] > 1) {
|
||||
if (data["heartBeat"] === undefined ||
|
||||
now - data["heartBeat"] > HEART_BEAT_TIMEOUT) {
|
||||
// this entity has userData suggesting it is grabbed, but nobody is updating the hearbeat.
|
||||
// deactivate it before grabbing.
|
||||
this.resetAbandonedGrab(entityID);
|
||||
grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||
return this.activateEntity(entityID, grabbedProperties, wasLoaded);
|
||||
}
|
||||
|
||||
this.isInitialGrab = false;
|
||||
// if an object is being grabbed by more than one person (or the same person twice, but nevermind), switch
|
||||
// the collision groups so that it wont collide with "other" avatars. This avoids a situation where two
|
||||
|
|
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,7 +75,7 @@
|
|||
function createEmitNumberPropertyUpdateFunction(propertyName) {
|
||||
return function() {
|
||||
EventBridge.emitWebEvent(
|
||||
'{ "type":"update", "properties":{"' + propertyName + '":' + Number(this.value.toFixed(4)) + '}}'
|
||||
'{ "type":"update", "properties":{"' + propertyName + '":' + parseFloat(this.value).toFixed(4) + '}}'
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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,20 +1,25 @@
|
|||
//
|
||||
// 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
|
||||
objectName: "desktop"
|
||||
|
||||
// Allow the scale of the desktop to be changed without screwing up the size relative to the parent.
|
||||
height: parent.height / scale
|
||||
width: parent.width / scale
|
||||
anchors.fill: parent
|
||||
|
||||
onHeightChanged: d.repositionAll();
|
||||
onWidthChanged: d.repositionAll();
|
||||
|
@ -155,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
|
||||
|
@ -313,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 }
|
||||
}
|
||||
|
@ -325,6 +331,3 @@ FocusScope {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1260,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;
|
||||
|
@ -3773,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();
|
||||
|
@ -3799,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);
|
||||
|
||||
|
@ -3815,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());
|
||||
|
||||
|
@ -4308,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:
|
||||
|
@ -4628,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;
|
||||
|
@ -5037,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
|
||||
|
@ -5134,4 +5094,4 @@ void Application::showDesktop() {
|
|||
if (!_overlayConductor.getEnabled()) {
|
||||
_overlayConductor.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -352,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) {});
|
||||
}
|
||||
}
|
||||
|
@ -929,35 +930,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(float deltaTimeStep, 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;
|
||||
|
||||
if (_ignoreIK && holdingAvatar->isMyAvatar()) {
|
||||
PalmData palmData = holdingAvatar->getHand()->getCopyOfPalmData(isRightHand ? HandData::RightHand : HandData::LeftHand);
|
||||
|
||||
if (palmData.isValid()) {
|
||||
// TODO: adjust according to _relativePosition and _relativeRotation?
|
||||
linearVelocity = palmData.getVelocity();
|
||||
angularVelocity = palmData.getAngularVelocity();
|
||||
}
|
||||
|
||||
if (_ignoreIK && holdingAvatar->isMyAvatar() && palmData.isValid()) {
|
||||
// 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;
|
||||
|
@ -149,18 +153,42 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::ve
|
|||
palmPosition = holdingAvatar->getLeftPalmPosition();
|
||||
palmRotation = holdingAvatar->getLeftPalmRotation();
|
||||
}
|
||||
|
||||
// In this case we are simulating the grab of another avatar.
|
||||
// Because the hand controller velocity for their palms is not transmitted over the
|
||||
// network, we have to synthesize our own.
|
||||
|
||||
if (_previousSet) {
|
||||
// smooth linear velocity over two frames
|
||||
glm::vec3 positionalDelta = palmPosition - _previousPositionalTarget;
|
||||
linearVelocity = (positionalDelta + _previousPositionalDelta) / (deltaTimeStep + _previousDeltaTimeStep);
|
||||
glm::quat deltaRotation = palmRotation * glm::inverse(_previousRotationalTarget);
|
||||
float rotationAngle = glm::angle(deltaRotation);
|
||||
if (rotationAngle > EPSILON) {
|
||||
angularVelocity = glm::normalize(glm::axis(deltaRotation));
|
||||
angularVelocity *= (rotationAngle / deltaTimeStep);
|
||||
}
|
||||
|
||||
_previousPositionalDelta = positionalDelta;
|
||||
_previousDeltaTimeStep = deltaTimeStep;
|
||||
}
|
||||
}
|
||||
|
||||
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 +201,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(deltaTimeStep, rotationForAction, positionForAction, linearVelocityForAction, angularVelocityForAction);
|
||||
if (holdingAvatar) {
|
||||
holdCount ++;
|
||||
if (holdAction.get() == this) {
|
||||
|
@ -183,15 +212,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 +260,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();
|
||||
|
@ -245,6 +273,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
|||
|
||||
_previousPositionalTarget = _positionalTarget;
|
||||
_previousRotationalTarget = _rotationalTarget;
|
||||
_previousDeltaTimeStep = deltaTimeStep;
|
||||
_previousSet = true;
|
||||
});
|
||||
|
||||
|
|
|
@ -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(float deltaTimeStep, 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,7 @@ private:
|
|||
glm::vec3 _previousPositionalTarget;
|
||||
glm::quat _previousRotationalTarget;
|
||||
|
||||
float _previousDeltaTimeStep = 0.0f;
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -254,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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
}
|
||||
/// Same design as QMessageBox::question(), will block, returns result
|
||||
static QMessageBox::StandardButton question(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) {
|
||||
return question(title, text, buttons, defaultButton);
|
||||
}
|
||||
|
|
|
@ -124,18 +124,25 @@ void VrMenu::addMenu(QMenu* menu) {
|
|||
new MenuUserData(menu, result);
|
||||
auto menuAction = menu->menuAction();
|
||||
updateQmlItemFromAction(result, menuAction);
|
||||
QObject::connect(menuAction, &QAction::changed, [=] {
|
||||
auto connection = QObject::connect(menuAction, &QAction::changed, [=] {
|
||||
updateQmlItemFromAction(result, menuAction);
|
||||
});
|
||||
QObject::connect(qApp, &QCoreApplication::aboutToQuit, [=] {
|
||||
QObject::disconnect(connection);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void bindActionToQmlAction(QObject* qmlAction, QAction* action) {
|
||||
new MenuUserData(action, qmlAction);
|
||||
updateQmlItemFromAction(qmlAction, action);
|
||||
QObject::connect(action, &QAction::changed, [=] {
|
||||
auto connection = QObject::connect(action, &QAction::changed, [=] {
|
||||
updateQmlItemFromAction(qmlAction, action);
|
||||
});
|
||||
QObject::connect(qApp, &QCoreApplication::aboutToQuit, [=] {
|
||||
QObject::disconnect(connection);
|
||||
});
|
||||
|
||||
QObject::connect(action, &QAction::toggled, [=](bool checked) {
|
||||
qmlAction->setProperty("checked", checked);
|
||||
});
|
||||
|
|
|
@ -113,7 +113,6 @@ void SixenseManager::deactivate() {
|
|||
_container->removeMenu(MENU_PATH);
|
||||
|
||||
_inputDevice->_poseStateMap.clear();
|
||||
_inputDevice->_collectedSamples.clear();
|
||||
|
||||
if (_inputDevice->_deviceID != controller::Input::INVALID_DEVICE) {
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
|
@ -158,7 +157,6 @@ void SixenseManager::InputDevice::update(float deltaTime, const controller::Inpu
|
|||
_axisStateMap.clear();
|
||||
_buttonPressedMap.clear();
|
||||
_poseStateMap.clear();
|
||||
_collectedSamples.clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -209,13 +207,10 @@ void SixenseManager::InputDevice::update(float deltaTime, const controller::Inpu
|
|||
rawPoses[i] = controller::Pose(position, rotation, Vectors::ZERO, Vectors::ZERO);
|
||||
} else {
|
||||
_poseStateMap.clear();
|
||||
_collectedSamples.clear();
|
||||
}
|
||||
} else {
|
||||
auto hand = left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND;
|
||||
_poseStateMap[hand] = controller::Pose();
|
||||
_collectedSamples[hand].first.clear();
|
||||
_collectedSamples[hand].second.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,29 +476,24 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, const control
|
|||
glm::vec3 velocity(0.0f);
|
||||
glm::vec3 angularVelocity(0.0f);
|
||||
|
||||
if (prevPose.isValid() && deltaTime > std::numeric_limits<float>::epsilon()) {
|
||||
auto& samples = _collectedSamples[hand];
|
||||
|
||||
velocity = (pos - prevPose.getTranslation()) / deltaTime;
|
||||
samples.first.addSample(velocity);
|
||||
velocity = samples.first.average;
|
||||
|
||||
auto deltaRot = glm::normalize(rot * glm::conjugate(prevPose.getRotation()));
|
||||
auto axis = glm::axis(deltaRot);
|
||||
auto speed = glm::angle(deltaRot) / deltaTime;
|
||||
assert(!glm::isnan(speed));
|
||||
angularVelocity = speed * axis;
|
||||
samples.second.addSample(angularVelocity);
|
||||
angularVelocity = samples.second.average;
|
||||
} else if (!prevPose.isValid()) {
|
||||
_collectedSamples[hand].first.clear();
|
||||
_collectedSamples[hand].second.clear();
|
||||
}
|
||||
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
|
||||
|
||||
// transform pose into avatar frame.
|
||||
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
|
||||
auto avatarPose = controller::Pose(pos, rot, velocity, angularVelocity).transform(controllerToAvatar);
|
||||
_poseStateMap[hand] = avatarPose;
|
||||
auto nextPose = controller::Pose(pos, rot, velocity, angularVelocity).transform(controllerToAvatar);
|
||||
|
||||
if (prevPose.isValid() && (deltaTime > std::numeric_limits<float>::epsilon())) {
|
||||
nextPose.velocity = (nextPose.getTranslation() - prevPose.getTranslation()) / deltaTime;
|
||||
|
||||
glm::quat deltaRotation = nextPose.getRotation() * glm::inverse(prevPose.getRotation());
|
||||
float rotationAngle = glm::angle(deltaRotation);
|
||||
if (rotationAngle > EPSILON) {
|
||||
nextPose.angularVelocity = glm::normalize(glm::axis(deltaRotation));
|
||||
nextPose.angularVelocity *= (rotationAngle / deltaTime);
|
||||
}
|
||||
|
||||
}
|
||||
_poseStateMap[hand] = nextPose;
|
||||
|
||||
#endif // HAVE_SIXENSE
|
||||
}
|
||||
|
||||
|
|
|
@ -52,11 +52,6 @@ private:
|
|||
static const glm::vec3 DEFAULT_AVATAR_POSITION;
|
||||
static const float CONTROLLER_THRESHOLD;
|
||||
|
||||
template<typename T>
|
||||
using SampleAverage = MovingAverage<T, MAX_NUM_AVERAGING_SAMPLES>;
|
||||
using Samples = std::pair<SampleAverage<glm::vec3>, SampleAverage<glm::vec3>>;
|
||||
using MovingAverageMap = std::map<int, Samples>;
|
||||
|
||||
class InputDevice : public controller::InputDevice {
|
||||
public:
|
||||
InputDevice() : controller::InputDevice("Hydra") {}
|
||||
|
@ -75,8 +70,6 @@ private:
|
|||
|
||||
friend class SixenseManager;
|
||||
|
||||
MovingAverageMap _collectedSamples;
|
||||
|
||||
int _calibrationState { CALIBRATION_STATE_IDLE };
|
||||
// these are calibration results
|
||||
glm::vec3 _avatarPosition { DEFAULT_AVATAR_POSITION }; // in hydra-frame
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <PerfStat.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "OpenVrHelpers.h"
|
||||
|
||||
|
@ -32,6 +33,8 @@ const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probab
|
|||
static vr::IVRCompositor* _compositor{ nullptr };
|
||||
vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
|
||||
mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
|
||||
vec3 _trackedDeviceLinearVelocities[vr::k_unMaxTrackedDeviceCount];
|
||||
vec3 _trackedDeviceAngularVelocities[vr::k_unMaxTrackedDeviceCount];
|
||||
static mat4 _sensorResetMat;
|
||||
static std::array<vr::Hmd_Eye, 2> VR_EYES { { vr::Eye_Left, vr::Eye_Right } };
|
||||
|
||||
|
@ -119,6 +122,8 @@ glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
|
|||
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
|
||||
_trackedDevicePose[i] = predictedTrackedDevicePose[i];
|
||||
_trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking);
|
||||
_trackedDeviceLinearVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vVelocity));
|
||||
_trackedDeviceAngularVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vAngularVelocity));
|
||||
}
|
||||
return _trackedDevicePoseMat4[0];
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
vr::IVRSystem* acquireOpenVrSystem();
|
||||
void releaseOpenVrSystem();
|
||||
void releaseOpenVrSystem();
|
||||
|
||||
template<typename F>
|
||||
void openvr_for_each_eye(F f) {
|
||||
|
@ -25,6 +25,10 @@ inline mat4 toGlm(const vr::HmdMatrix44_t& m) {
|
|||
return glm::transpose(glm::make_mat4(&m.m[0][0]));
|
||||
}
|
||||
|
||||
inline vec3 toGlm(const vr::HmdVector3_t& v) {
|
||||
return vec3(v.v[0], v.v[1], v.v[2]);
|
||||
}
|
||||
|
||||
inline mat4 toGlm(const vr::HmdMatrix34_t& m) {
|
||||
mat4 result = mat4(
|
||||
m.m[0][0], m.m[1][0], m.m[2][0], 0.0,
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
|
||||
extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
|
||||
extern vec3 _trackedDeviceLinearVelocities[vr::k_unMaxTrackedDeviceCount];
|
||||
extern vec3 _trackedDeviceAngularVelocities[vr::k_unMaxTrackedDeviceCount];
|
||||
|
||||
vr::IVRSystem* acquireOpenVrSystem();
|
||||
void releaseOpenVrSystem();
|
||||
|
@ -249,10 +251,11 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle
|
|||
numTrackedControllers++;
|
||||
bool left = numTrackedControllers == 2;
|
||||
|
||||
const mat4& mat = _trackedDevicePoseMat4[device];
|
||||
|
||||
if (!jointsCaptured) {
|
||||
handlePoseEvent(inputCalibrationData, mat, numTrackedControllers - 1);
|
||||
const mat4& mat = _trackedDevicePoseMat4[device];
|
||||
const vec3 linearVelocity = _trackedDeviceLinearVelocities[device];
|
||||
const vec3 angularVelocity = _trackedDeviceAngularVelocities[device];
|
||||
handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, numTrackedControllers - 1);
|
||||
}
|
||||
|
||||
// handle inputs
|
||||
|
@ -314,7 +317,9 @@ void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool
|
|||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, bool left) {
|
||||
void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData,
|
||||
const mat4& mat, const vec3& linearVelocity,
|
||||
const vec3& angularVelocity, bool left) {
|
||||
// When the sensor-to-world rotation is identity the coordinate axes look like this:
|
||||
//
|
||||
// user
|
||||
|
@ -379,16 +384,22 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input
|
|||
static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET;
|
||||
static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET;
|
||||
|
||||
glm::vec3 position = extractTranslation(mat);
|
||||
glm::quat rotation = glm::quat_cast(mat);
|
||||
auto translationOffset = (left ? leftTranslationOffset : rightTranslationOffset);
|
||||
auto rotationOffset = (left ? leftRotationOffset : rightRotationOffset);
|
||||
|
||||
position += rotation * (left ? leftTranslationOffset : rightTranslationOffset);
|
||||
rotation = rotation * (left ? leftRotationOffset : rightRotationOffset);
|
||||
glm::vec3 position = extractTranslation(mat);
|
||||
glm::quat rotation = glm::normalize(glm::quat_cast(mat));
|
||||
|
||||
position += rotation * translationOffset;
|
||||
rotation = rotation * rotationOffset;
|
||||
|
||||
// transform into avatar frame
|
||||
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
|
||||
auto avatarPose = controller::Pose(position, rotation).transform(controllerToAvatar);
|
||||
_poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose;
|
||||
auto avatarPose = controller::Pose(position, rotation);
|
||||
// handle change in velocity due to translationOffset
|
||||
avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat));
|
||||
avatarPose.angularVelocity = angularVelocity;
|
||||
_poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar);
|
||||
}
|
||||
|
||||
controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const {
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
void updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges);
|
||||
|
||||
void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; }
|
||||
|
||||
|
||||
private:
|
||||
class InputDevice : public controller::InputDevice {
|
||||
public:
|
||||
|
@ -60,7 +60,8 @@ private:
|
|||
|
||||
void handleButtonEvent(uint32_t button, bool pressed, bool left);
|
||||
void handleAxisEvent(uint32_t axis, float x, float y, bool left);
|
||||
void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, bool left);
|
||||
void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
|
||||
const vec3& linearVelocity, const vec3& angularVelocity, bool left);
|
||||
|
||||
int _trackedControllers { 0 };
|
||||
vr::IVRSystem*& _hmd;
|
||||
|
@ -68,8 +69,8 @@ private:
|
|||
};
|
||||
|
||||
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool _registeredWithInputMapper { false };
|
||||
bool _modelLoaded { false };
|
||||
|
|
|
@ -4,7 +4,8 @@ import QtQuick.Dialogs 1.2 as OriginalDialogs
|
|||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../../../interface/resources/qml"
|
||||
import "../../../interface/resources/qml/windows"
|
||||
//import "../../../interface/resources/qml/windows"
|
||||
import "../../../interface/resources/qml/windows-uit"
|
||||
import "../../../interface/resources/qml/dialogs"
|
||||
import "../../../interface/resources/qml/hifi"
|
||||
import "../../../interface/resources/qml/hifi/dialogs"
|
||||
|
@ -13,14 +14,14 @@ ApplicationWindow {
|
|||
id: appWindow
|
||||
visible: true
|
||||
width: 1280
|
||||
height: 720
|
||||
height: 800
|
||||
title: qsTr("Scratch App")
|
||||
|
||||
Desktop {
|
||||
id: desktop
|
||||
anchors.fill: parent
|
||||
rootMenu: StubMenu { id: rootMenu }
|
||||
Component.onCompleted: offscreenWindow = appWindow
|
||||
//Component.onCompleted: offscreenWindow = appWindow
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
@ -36,6 +37,27 @@ ApplicationWindow {
|
|||
|
||||
property var tabs: [];
|
||||
property var urls: [];
|
||||
|
||||
Button {
|
||||
text: "Running Scripts"
|
||||
property var builder: Component {
|
||||
RunningScripts { }
|
||||
}
|
||||
onClicked: {
|
||||
var runningScripts = builder.createObject(desktop);
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Attachments"
|
||||
property var builder: Component {
|
||||
AttachmentsDialog { }
|
||||
}
|
||||
onClicked: {
|
||||
var attachmentsDialog = builder.createObject(desktop);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Button {
|
||||
text: "restore all"
|
||||
|
@ -59,17 +81,27 @@ ApplicationWindow {
|
|||
}
|
||||
*/
|
||||
Button {
|
||||
text: "Show Long Error"
|
||||
// Replicates message box that pops up after selecting new avatar. Includes title.
|
||||
text: "Confirm Avatar"
|
||||
onClicked: {
|
||||
desktop.messageBox({
|
||||
informativeText: "Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds ",
|
||||
text: "Baloney",
|
||||
icon: OriginalDialogs.StandardIcon.Warning,
|
||||
detailedText: "sakjd;laskj dksa;dl jka;lsd j;lkjas ;dlkaj s;dlakjd ;alkjda; slkjda; lkjda;lksjd ;alksjd; alksjd ;alksjd; alksjd; alksdjas;ldkjas;lkdja ;kj ;lkasjd; lkj as;dlka jsd;lka jsd;laksjd a"
|
||||
var messageBox = desktop.messageBox({
|
||||
title: "Set Avatar",
|
||||
text: "Would you like to use 'Albert' for your avatar?",
|
||||
icon: OriginalDialogs.StandardIcon.Question, // Test question icon
|
||||
//icon: OriginalDialogs.StandardIcon.Information, // Test informaton icon
|
||||
//icon: OriginalDialogs.StandardIcon.Warning, // Test warning icon
|
||||
//icon: OriginalDialogs.StandardIcon.Critical, // Test critical icon
|
||||
//icon: OriginalDialogs.StandardIcon.NoIcon, // Test no icon
|
||||
buttons: OriginalDialogs.StandardButton.Ok + OriginalDialogs.StandardButton.Cancel,
|
||||
defaultButton: OriginalDialogs.StandardButton.Ok
|
||||
});
|
||||
messageBox.selected.connect(function(button) {
|
||||
console.log("You clicked " + button)
|
||||
})
|
||||
}
|
||||
}
|
||||
Button {
|
||||
// Message without title.
|
||||
text: "Show Error"
|
||||
onClicked: {
|
||||
var messageBox = desktop.messageBox({
|
||||
|
@ -81,6 +113,20 @@ ApplicationWindow {
|
|||
})
|
||||
}
|
||||
}
|
||||
Button {
|
||||
// detailedText is not currently used anywhere in Interface but it is easier to leave in and style good enough.
|
||||
text: "Show Long Error"
|
||||
onClicked: {
|
||||
desktop.messageBox({
|
||||
informativeText: "Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds ",
|
||||
text: "Baloney",
|
||||
icon: OriginalDialogs.StandardIcon.Warning,
|
||||
detailedText: "sakjd;laskj dksa;dl jka;lsd j;lkjas ;dlkaj s;dlakjd ;alkjda; slkjda; lkjda;lksjd ;alksjd; alksjd ;alksjd; alksjd; alksdjas;ldkjas;lkdja ;kj ;lkasjd; lkj as;dlka jsd;lka jsd;laksjd a"
|
||||
});
|
||||
}
|
||||
}
|
||||
/*
|
||||
// There is no such desktop.queryBox() function; may need to update test to cover QueryDialog.qml?
|
||||
Button {
|
||||
text: "Show Query"
|
||||
onClicked: {
|
||||
|
@ -98,6 +144,7 @@ ApplicationWindow {
|
|||
})
|
||||
}
|
||||
}
|
||||
*/
|
||||
Button {
|
||||
text: "Open Directory"
|
||||
property var builder: Component {
|
||||
|
@ -150,6 +197,7 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Window {
|
||||
id: blue
|
||||
closable: true
|
||||
|
@ -174,6 +222,7 @@ ApplicationWindow {
|
|||
Component.onDestruction: console.log("Blue destroyed")
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
Window {
|
||||
id: green
|
||||
|
|
Loading…
Reference in a new issue