Merge branch 'master' of https://github.com/highfidelity/hifi into orange

This commit is contained in:
samcake 2016-02-24 17:30:40 -08:00
commit ae6e625894
96 changed files with 2803 additions and 659 deletions

View file

@ -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
View 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);
}
}
}
});

View file

@ -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) + '}}'
);
};
}

View file

@ -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;

View 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));

View file

@ -9,11 +9,6 @@
"Enabled": {
"enabled": true
}
},
"Antialiasing": {
"Enabled": {
"enabled": true
}
}
}
}

Binary file not shown.

View 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.

Binary file not shown.

View 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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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.

Binary file not shown.

View file

@ -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;

View file

@ -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 {

View 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
}
}
}

View 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
}
}
}
}

View 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
}
}
}

View 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
}

View 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 != ""
}
*/
}

View 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)
}
}
}

View 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
}

View file

@ -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 {
}
}

View file

@ -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;
}
}

View file

@ -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()
}

View file

@ -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

View file

@ -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;

View file

@ -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 { }
}
}
}

View file

@ -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: {

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}
}

View 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.
}

View 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
}

View 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
}

View 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
}

View 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
}
}
}

View 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);
}
}

View 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
}
}
}

View 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
}
}
}
}

View 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{}
}

View 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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -352,7 +352,6 @@ private:
void checkSkeleton();
void initializeAcceptedFiles();
int getRenderAmbientLight() const;
void displaySide(RenderArgs* renderArgs, Camera& whichCamera, bool selfAvatarOnly = false);

View file

@ -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);

View file

@ -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...";

View file

@ -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);
}
*/
}

View file

@ -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;
});

View file

@ -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;

View file

@ -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);

View file

@ -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; };

View file

@ -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

View file

@ -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;
};

View file

@ -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(); };

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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") {

View file

@ -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);
}

View file

@ -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);

View file

@ -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.
}
}
}
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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; }

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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; }

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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:

View file

@ -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);

View file

@ -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;

View file

@ -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++) {

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
});

View file

@ -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
}

View file

@ -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

View file

@ -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];
}

View file

@ -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,

View file

@ -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 {

View file

@ -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 };

View file

@ -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