mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 07:47:30 +02:00
Merge branch 'vive-ui' of https://github.com/highfidelity/hifi into fix-paused-interactions-with-mouse
This commit is contained in:
commit
3138c4041b
45 changed files with 907 additions and 364 deletions
|
@ -9,6 +9,8 @@
|
|||
"to": "Actions.StepYaw",
|
||||
"filters":
|
||||
[
|
||||
{ "type": "deadZone", "min": 0.15 },
|
||||
"constrainToInteger",
|
||||
{ "type": "pulse", "interval": 0.5 },
|
||||
{ "type": "scale", "scale": 22.5 }
|
||||
]
|
||||
|
|
105
interface/resources/icons/hud-01.svg
Normal file
105
interface/resources/icons/hud-01.svg
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.49;}
|
||||
.st1{fill:#1E1E1E;}
|
||||
.st2{opacity:0.5;}
|
||||
.st3{fill:#EAEAEA;}
|
||||
.st4{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g class="st0">
|
||||
<path class="st1" d="M50,146c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V146z"/>
|
||||
</g>
|
||||
<g class="st2">
|
||||
<g>
|
||||
<path class="st3" d="M25.1,109.5c-4.2,0-8,1.8-10.8,4.8c0,0-0.5,0.7,0.2,1.2c0.7,0.6,1.4-0.1,1.4-0.1c2.4-2.4,5.7-3.9,9.2-3.9
|
||||
c3.6,0,6.9,1.5,9.3,4.1c0,0,0.7,0.8,1.5,0.3c0.7-0.4,0.2-1.2,0.2-1.3C33.3,111.4,29.4,109.5,25.1,109.5z"/>
|
||||
<path class="st3" d="M35.4,116.3c-0.2,0-0.4,0-0.5-0.1c-0.2-0.1-0.5-0.3-0.6-0.4l0,0c-2.5-2.6-5.7-4-9.2-4c-3.4,0-6.6,1.4-9.1,3.9
|
||||
l0,0c-0.1,0.1-0.3,0.2-0.4,0.3c-0.5,0.2-0.9,0.2-1.3-0.2c-0.6-0.5-0.4-1.1-0.3-1.4c0-0.1,0.1-0.1,0.1-0.2l0,0
|
||||
c2.9-3.1,6.8-4.9,10.9-4.9c4.2,0,8.2,1.8,11.2,5.1c0.1,0.1,0.3,0.5,0.2,0.9c0,0.3-0.2,0.6-0.5,0.8
|
||||
C35.9,116.2,35.6,116.3,35.4,116.3z M34.7,115.4c0.1,0.1,0.6,0.6,1.1,0.2c0.1-0.1,0.2-0.2,0.2-0.3c0-0.3-0.1-0.5-0.1-0.6
|
||||
c-2.9-3.2-6.7-5-10.8-5c-4,0-7.7,1.7-10.6,4.7c-0.1,0.1-0.3,0.5,0.1,0.9c0.5,0.4,1,0,1.1-0.1c2.6-2.6,5.9-4,9.4-4
|
||||
C28.7,111.2,32.1,112.7,34.7,115.4L34.7,115.4z M36,114.7C36,114.7,36,114.7,36,114.7L36,114.7z M35.9,114.7
|
||||
C35.9,114.7,35.9,114.7,35.9,114.7L35.9,114.7z"/>
|
||||
</g>
|
||||
<path class="st3" d="M27.3,116l-1.5-0.9c-0.3-0.2-0.7-0.2-1,0l-1.5,0.9c-0.3,0.2-0.5,0.5-0.5,0.9l0,1.8c0,0.4,0.2,0.7,0.5,0.9
|
||||
l1.5,0.9c0.2,0.1,0.3,0.1,0.5,0.1c0.2,0,0.4,0,0.5-0.1l1.5-0.9c0.3-0.2,0.5-0.5,0.5-0.9l0-1.8C27.8,116.5,27.6,116.2,27.3,116z"/>
|
||||
<path class="st3" d="M31.2,125l-1.2-1.5c-0.2-0.3-0.5-0.4-0.8-0.4l-7.9,0c0,0,0,0,0,0c-0.3,0-0.6,0.1-0.8,0.4l-1.2,1.5
|
||||
c-0.3,0.4-0.3,0.9,0,1.3l1.2,1.5c0.2,0.3,0.5,0.4,0.8,0.4l7.9,0c0,0,0,0,0,0c0.3,0,0.6-0.1,0.8-0.4l1.2-1.5
|
||||
C31.5,126,31.5,125.4,31.2,125z"/>
|
||||
</g>
|
||||
<g class="st2">
|
||||
<path class="st3" d="M19.2,135.5v6.4H18v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6H18v-2.6H19.2z"/>
|
||||
<path class="st3" d="M25.4,141c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.5-0.5c0.1-0.2,0.2-0.4,0.3-0.7c0.1-0.3,0.1-0.5,0.1-0.8
|
||||
v-3.4h1.3v3.4c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.3,0.7-0.5,1c-0.2,0.3-0.5,0.5-0.9,0.7c-0.4,0.2-0.8,0.3-1.3,0.3
|
||||
c-0.5,0-1-0.1-1.4-0.3c-0.4-0.2-0.7-0.4-0.9-0.7c-0.2-0.3-0.4-0.6-0.5-1c-0.1-0.4-0.2-0.8-0.2-1.2v-3.4h1.3v3.4
|
||||
c0,0.3,0,0.5,0.1,0.8c0.1,0.3,0.1,0.5,0.3,0.7c0.1,0.2,0.3,0.4,0.5,0.5S25.1,141,25.4,141z"/>
|
||||
<path class="st3" d="M31.7,141.9v-6.4H34c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.4,1,0.7c0.3,0.3,0.5,0.6,0.6,1
|
||||
c0.1,0.4,0.2,0.8,0.2,1.2c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.4,0.7-0.6,1c-0.3,0.3-0.6,0.5-1,0.6c-0.4,0.2-0.8,0.2-1.3,0.2H31.7z
|
||||
M35.9,138.7c0-0.3,0-0.6-0.1-0.8c-0.1-0.3-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.6-0.4c-0.2-0.1-0.5-0.2-0.8-0.2h-1.1v4.2H34
|
||||
c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.6-0.4c0.2-0.2,0.3-0.4,0.4-0.7C35.8,139.3,35.9,139,35.9,138.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M50,96c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4V54c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V96z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st3" d="M25.1,59.5c-4.2,0-8,1.8-10.8,4.8c0,0-0.5,0.7,0.2,1.2c0.7,0.6,1.4-0.1,1.4-0.1c2.4-2.4,5.7-3.9,9.2-3.9
|
||||
c3.6,0,6.9,1.5,9.3,4.1c0,0,0.7,0.8,1.5,0.3c0.7-0.4,0.2-1.2,0.2-1.3C33.3,61.5,29.4,59.5,25.1,59.5z"/>
|
||||
<path class="st3" d="M35.4,66.3c-0.2,0-0.4,0-0.5-0.1c-0.2-0.1-0.5-0.3-0.6-0.4l0,0c-2.5-2.6-5.7-4-9.2-4c-3.4,0-6.6,1.4-9.1,3.9
|
||||
l0,0c-0.1,0.1-0.3,0.2-0.4,0.3c-0.5,0.2-0.9,0.2-1.3-0.2c-0.6-0.5-0.4-1.1-0.3-1.4c0-0.1,0.1-0.1,0.1-0.2l0,0
|
||||
c2.9-3.1,6.8-4.9,10.9-4.9c4.2,0,8.2,1.8,11.2,5.1c0.1,0.1,0.3,0.5,0.2,0.9c0,0.3-0.2,0.6-0.5,0.8C35.9,66.2,35.6,66.3,35.4,66.3z
|
||||
M34.7,65.5c0.1,0.1,0.6,0.6,1.1,0.2c0.1-0.1,0.2-0.2,0.2-0.3c0-0.3-0.1-0.5-0.1-0.6c-2.9-3.2-6.7-5-10.8-5c-4,0-7.7,1.7-10.6,4.7
|
||||
c-0.1,0.1-0.3,0.5,0.1,0.9c0.5,0.4,1,0,1.1-0.1c2.6-2.6,5.9-4,9.4-4C28.7,61.3,32.1,62.7,34.7,65.5L34.7,65.5z M36,64.7
|
||||
C36,64.7,36,64.7,36,64.7L36,64.7z M35.9,64.7C35.9,64.7,35.9,64.7,35.9,64.7L35.9,64.7z"/>
|
||||
</g>
|
||||
<path class="st3" d="M27.3,66l-1.5-0.9c-0.3-0.2-0.7-0.2-1,0L23.2,66c-0.3,0.2-0.5,0.5-0.5,0.9l0,1.8c0,0.4,0.2,0.7,0.5,0.9
|
||||
l1.5,0.9c0.2,0.1,0.3,0.1,0.5,0.1c0.2,0,0.4,0,0.5-0.1l1.5-0.9c0.3-0.2,0.5-0.5,0.5-0.9l0-1.8C27.8,66.5,27.6,66.2,27.3,66z"/>
|
||||
<path class="st3" d="M31.2,75.1L30,73.5c-0.2-0.3-0.5-0.4-0.8-0.4l-7.9,0c0,0,0,0,0,0c-0.3,0-0.6,0.1-0.8,0.4l-1.2,1.5
|
||||
c-0.3,0.4-0.3,0.9,0,1.3l1.2,1.5c0.2,0.3,0.5,0.4,0.8,0.4l7.9,0c0,0,0,0,0,0c0.3,0,0.6-0.1,0.8-0.4l1.2-1.5
|
||||
C31.5,76,31.5,75.5,31.2,75.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M19.2,85.5v6.4H18v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6H18v-2.6H19.2z"/>
|
||||
<path class="st3" d="M25.4,91c0.3,0,0.6-0.1,0.8-0.2s0.4-0.3,0.5-0.5c0.1-0.2,0.2-0.4,0.3-0.7s0.1-0.5,0.1-0.8v-3.4h1.3v3.4
|
||||
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.3,0.7-0.5,1c-0.2,0.3-0.5,0.5-0.9,0.7c-0.4,0.2-0.8,0.3-1.3,0.3c-0.5,0-1-0.1-1.4-0.3
|
||||
c-0.4-0.2-0.7-0.4-0.9-0.7c-0.2-0.3-0.4-0.6-0.5-1c-0.1-0.4-0.2-0.8-0.2-1.2v-3.4h1.3v3.4c0,0.3,0,0.5,0.1,0.8
|
||||
c0.1,0.3,0.1,0.5,0.3,0.7c0.1,0.2,0.3,0.4,0.5,0.5S25.1,91,25.4,91z"/>
|
||||
<path class="st3" d="M31.7,91.9v-6.4H34c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.4,1,0.7c0.3,0.3,0.5,0.6,0.6,1c0.1,0.4,0.2,0.8,0.2,1.2
|
||||
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.4,0.7-0.6,1c-0.3,0.3-0.6,0.5-1,0.6c-0.4,0.2-0.8,0.2-1.3,0.2H31.7z M35.9,88.7
|
||||
c0-0.3,0-0.6-0.1-0.8c-0.1-0.3-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.6-0.4c-0.2-0.1-0.5-0.2-0.8-0.2h-1.1v4.2H34
|
||||
c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.6-0.4c0.2-0.2,0.3-0.4,0.4-0.7C35.8,89.3,35.9,89,35.9,88.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st4" d="M50,46.1c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V46.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M25.1,9.6c-4.2,0-8,1.8-10.8,4.8c0,0-0.5,0.7,0.2,1.2c0.7,0.6,1.4-0.1,1.4-0.1c2.4-2.4,5.7-3.9,9.2-3.9
|
||||
c3.6,0,6.9,1.5,9.3,4.1c0,0,0.7,0.8,1.5,0.3c0.7-0.4,0.2-1.2,0.2-1.3C33.3,11.5,29.4,9.6,25.1,9.6z"/>
|
||||
<path d="M35.4,16.3c-0.2,0-0.4,0-0.5-0.1c-0.2-0.1-0.5-0.3-0.6-0.4l0,0c-2.5-2.6-5.7-4-9.2-4c-3.4,0-6.6,1.4-9.1,3.9l0,0
|
||||
c-0.1,0.1-0.3,0.2-0.4,0.3c-0.5,0.2-0.9,0.2-1.3-0.2c-0.6-0.5-0.4-1.1-0.3-1.4c0-0.1,0.1-0.1,0.1-0.2l0,0
|
||||
c2.9-3.1,6.8-4.9,10.9-4.9c4.2,0,8.2,1.8,11.2,5.1c0.1,0.1,0.3,0.5,0.2,0.9c0,0.3-0.2,0.6-0.5,0.8C35.9,16.3,35.6,16.3,35.4,16.3z
|
||||
M34.7,15.5c0.1,0.1,0.6,0.6,1.1,0.2c0.1-0.1,0.2-0.2,0.2-0.3c0-0.3-0.1-0.5-0.1-0.6c-2.9-3.2-6.7-5-10.8-5c-4,0-7.7,1.7-10.6,4.7
|
||||
c-0.1,0.1-0.3,0.5,0.1,0.9c0.5,0.4,1,0,1.1-0.1c2.6-2.6,5.9-4,9.4-4C28.7,11.3,32.1,12.8,34.7,15.5L34.7,15.5z M36,14.8
|
||||
C36,14.8,36,14.8,36,14.8L36,14.8z M35.9,14.8C35.9,14.8,35.9,14.8,35.9,14.8L35.9,14.8z"/>
|
||||
</g>
|
||||
<path d="M27.3,16l-1.5-0.9c-0.3-0.2-0.7-0.2-1,0L23.2,16c-0.3,0.2-0.5,0.5-0.5,0.9l0,1.8c0,0.4,0.2,0.7,0.5,0.9l1.5,0.9
|
||||
c0.2,0.1,0.3,0.1,0.5,0.1c0.2,0,0.4,0,0.5-0.1l1.5-0.9c0.3-0.2,0.5-0.5,0.5-0.9l0-1.8C27.8,16.6,27.6,16.2,27.3,16z"/>
|
||||
<path d="M31.2,25.1L30,23.6c-0.2-0.3-0.5-0.4-0.8-0.4l-7.9,0c0,0,0,0,0,0c-0.3,0-0.6,0.1-0.8,0.4l-1.2,1.5c-0.3,0.4-0.3,0.9,0,1.3
|
||||
l1.2,1.5c0.2,0.3,0.5,0.4,0.8,0.4l7.9,0c0,0,0,0,0,0c0.3,0,0.6-0.1,0.8-0.4l1.2-1.5C31.5,26,31.5,25.5,31.2,25.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M19.2,35.6V42H18v-2.7h-2.9V42h-1.2v-6.4h1.2v2.6H18v-2.6H19.2z"/>
|
||||
<path d="M25.4,41c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.5-0.5c0.1-0.2,0.2-0.4,0.3-0.7c0.1-0.3,0.1-0.5,0.1-0.8v-3.4h1.3v3.4
|
||||
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.3,0.7-0.5,1c-0.2,0.3-0.5,0.5-0.9,0.7c-0.4,0.2-0.8,0.3-1.3,0.3c-0.5,0-1-0.1-1.4-0.3
|
||||
c-0.4-0.2-0.7-0.4-0.9-0.7c-0.2-0.3-0.4-0.6-0.5-1c-0.1-0.4-0.2-0.8-0.2-1.2v-3.4h1.3v3.4c0,0.3,0,0.5,0.1,0.8
|
||||
c0.1,0.3,0.1,0.5,0.3,0.7c0.1,0.2,0.3,0.4,0.5,0.5C24.9,41,25.1,41,25.4,41z"/>
|
||||
<path d="M31.7,42v-6.4H34c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.4,1,0.7c0.3,0.3,0.5,0.6,0.6,1c0.1,0.4,0.2,0.8,0.2,1.2
|
||||
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.4,0.7-0.6,1c-0.3,0.3-0.6,0.5-1,0.6C34.9,41.9,34.5,42,34,42H31.7z M35.9,38.8
|
||||
c0-0.3,0-0.6-0.1-0.8c-0.1-0.3-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.6-0.4c-0.2-0.1-0.5-0.2-0.8-0.2h-1.1v4.2H34
|
||||
c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.6-0.4c0.2-0.2,0.3-0.4,0.4-0.7C35.8,39.3,35.9,39.1,35.9,38.8z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8 KiB |
|
@ -299,7 +299,7 @@ FocusScope {
|
|||
if (pinned) {
|
||||
// recalculate our non-pinned children
|
||||
hiddenChildren = d.findMatchingChildren(desktop, function(child){
|
||||
return !d.isTopLevelWindow(child) && child.visible;
|
||||
return !d.isTopLevelWindow(child) && child.visible && !child.pinned;
|
||||
});
|
||||
|
||||
hiddenChildren.forEach(function(child){
|
||||
|
|
|
@ -4,11 +4,13 @@ import QtWebEngine 1.1;
|
|||
|
||||
import "../desktop"
|
||||
import ".."
|
||||
import "."
|
||||
|
||||
Desktop {
|
||||
id: desktop
|
||||
|
||||
MouseArea {
|
||||
id: hoverWatch
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
propagateComposedEvents: true
|
||||
|
@ -47,7 +49,12 @@ Desktop {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
ToggleHudButton {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 32
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
36
interface/resources/qml/hifi/ToggleHudButton.qml
Normal file
36
interface/resources/qml/hifi/ToggleHudButton.qml
Normal file
|
@ -0,0 +1,36 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
import "../windows"
|
||||
|
||||
Window {
|
||||
//frame: HiddenFrame {}
|
||||
hideBackground: true
|
||||
resizable: false
|
||||
destroyOnCloseButton: false
|
||||
destroyOnHidden: false
|
||||
closable: false
|
||||
shown: true
|
||||
pinned: true
|
||||
width: 50
|
||||
height: 50
|
||||
clip: true
|
||||
visible: true
|
||||
|
||||
Item {
|
||||
width: 50
|
||||
height: 50
|
||||
Image {
|
||||
y: desktop.pinned ? -50 : 0
|
||||
id: hudToggleImage
|
||||
source: "../../icons/hud-01.svg"
|
||||
}
|
||||
MouseArea {
|
||||
readonly property string overlayMenuItem: "Overlays"
|
||||
anchors.fill: parent
|
||||
onClicked: MenuInterface.setIsOptionChecked(overlayMenuItem, !MenuInterface.isOptionChecked(overlayMenuItem))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -23,9 +23,9 @@ Window {
|
|||
title: "Running Scripts"
|
||||
resizable: true
|
||||
destroyOnHidden: true
|
||||
implicitWidth: 400
|
||||
implicitWidth: 424
|
||||
implicitHeight: isHMD ? 695 : 728
|
||||
minSize: Qt.vector2d(200, 300)
|
||||
minSize: Qt.vector2d(424, 300)
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
|
@ -86,6 +86,11 @@ Window {
|
|||
scripts.reloadAllScripts();
|
||||
}
|
||||
|
||||
function loadDefaults() {
|
||||
console.log("Load default scripts");
|
||||
scripts.loadOneScript(scripts.defaultScriptsPath + "/defaultScripts.js");
|
||||
}
|
||||
|
||||
function stopAll() {
|
||||
console.log("Stop all scripts");
|
||||
scripts.stopAllScripts();
|
||||
|
@ -104,13 +109,13 @@ Window {
|
|||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
||||
HifiControls.Button {
|
||||
text: "Reload all"
|
||||
text: "Reload All"
|
||||
color: hifi.buttons.black
|
||||
onClicked: reloadAll()
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
text: "Stop all"
|
||||
text: "Remove All"
|
||||
color: hifi.buttons.red
|
||||
onClicked: stopAll()
|
||||
}
|
||||
|
@ -218,7 +223,6 @@ Window {
|
|||
|
||||
Row {
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
anchors.right: parent.right
|
||||
|
||||
HifiControls.Button {
|
||||
text: "from URL"
|
||||
|
@ -256,6 +260,12 @@ Window {
|
|||
onTriggered: ApplicationInterface.loadDialog();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
text: "Load Defaults"
|
||||
color: hifi.buttons.black
|
||||
onClicked: loadDefaults()
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.VerticalSpacer {}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <QtCore/QAbstractNativeEventFilter>
|
||||
#include <QtCore/QCommandLineParser>
|
||||
#include <QtCore/QMimeData>
|
||||
#include <QtCore/QThreadPool>
|
||||
|
||||
|
@ -197,7 +198,6 @@ static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check f
|
|||
|
||||
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
|
||||
static const QString INPUT_DEVICE_MENU_PREFIX = "Device: ";
|
||||
Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS);
|
||||
|
||||
const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
|
||||
|
@ -999,7 +999,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get());
|
||||
if (webEntity) {
|
||||
webEntity->setProxyWindow(_window->windowHandle());
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->pluginFocusOutEvent();
|
||||
}
|
||||
_keyboardFocusedItem = entityItemID;
|
||||
|
@ -1152,9 +1152,7 @@ void Application::aboutToQuit() {
|
|||
emit beforeAboutToQuit();
|
||||
|
||||
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
|
||||
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
|
||||
QAction* action = Menu::getInstance()->getActionForOption(name);
|
||||
if (action->isChecked()) {
|
||||
if (inputPlugin->isActive()) {
|
||||
inputPlugin->deactivate();
|
||||
}
|
||||
}
|
||||
|
@ -1418,7 +1416,7 @@ void Application::initializeUi() {
|
|||
|
||||
rootContext->setContextProperty("Overlays", &_overlays);
|
||||
rootContext->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
||||
rootContext->setContextProperty("Menu", MenuScriptingInterface::getInstance());
|
||||
rootContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
||||
rootContext->setContextProperty("Stats", Stats::getInstance());
|
||||
rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||
rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
||||
|
@ -1476,7 +1474,6 @@ void Application::initializeUi() {
|
|||
}
|
||||
}
|
||||
_window->setMenuBar(new Menu());
|
||||
updateInputModes();
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, [=] {
|
||||
|
@ -2024,7 +2021,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
|
||||
if (hasFocus()) {
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->keyPressEvent(event);
|
||||
}
|
||||
|
||||
|
@ -2359,7 +2356,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->keyReleaseEvent(event);
|
||||
}
|
||||
|
||||
|
@ -2391,9 +2388,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
|
|||
void Application::focusOutEvent(QFocusEvent* event) {
|
||||
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
|
||||
foreach(auto inputPlugin, inputPlugins) {
|
||||
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
|
||||
QAction* action = Menu::getInstance()->getActionForOption(name);
|
||||
if (action && action->isChecked()) {
|
||||
if (inputPlugin->isActive()) {
|
||||
inputPlugin->pluginFocusOutEvent();
|
||||
}
|
||||
}
|
||||
|
@ -2478,7 +2473,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
|
@ -2515,7 +2510,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
|||
|
||||
|
||||
if (hasFocus()) {
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->mousePressEvent(event);
|
||||
}
|
||||
|
||||
|
@ -2560,7 +2555,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
|
|||
}
|
||||
|
||||
if (hasFocus()) {
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
|
@ -2587,7 +2582,7 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->touchUpdateEvent(event);
|
||||
}
|
||||
}
|
||||
|
@ -2605,7 +2600,7 @@ void Application::touchBeginEvent(QTouchEvent* event) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->touchBeginEvent(event);
|
||||
}
|
||||
|
||||
|
@ -2622,7 +2617,7 @@ void Application::touchEndEvent(QTouchEvent* event) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->touchEndEvent(event);
|
||||
}
|
||||
|
||||
|
@ -2638,7 +2633,7 @@ void Application::wheelEvent(QWheelEvent* event) const {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
|
||||
if (_keyboardMouseDevice->isActive()) {
|
||||
_keyboardMouseDevice->wheelEvent(event);
|
||||
}
|
||||
}
|
||||
|
@ -2771,9 +2766,7 @@ void Application::idle(float nsecsElapsed) {
|
|||
getActiveDisplayPlugin()->idle();
|
||||
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
|
||||
foreach(auto inputPlugin, inputPlugins) {
|
||||
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
|
||||
QAction* action = Menu::getInstance()->getActionForOption(name);
|
||||
if (action && action->isChecked()) {
|
||||
if (inputPlugin->isActive()) {
|
||||
inputPlugin->idle();
|
||||
}
|
||||
}
|
||||
|
@ -2957,6 +2950,27 @@ void Application::loadSettings() {
|
|||
//DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false);
|
||||
|
||||
Menu::getInstance()->loadSettings();
|
||||
|
||||
// If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.
|
||||
auto pluginManager = PluginManager::getInstance();
|
||||
auto plugins = pluginManager->getPreferredDisplayPlugins();
|
||||
for (auto plugin : plugins) {
|
||||
auto menu = Menu::getInstance();
|
||||
if (auto action = menu->getActionForOption(plugin->getName())) {
|
||||
action->setChecked(true);
|
||||
action->trigger();
|
||||
// Find and activated highest priority plugin, bail for the rest
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto inputs = pluginManager->getInputPlugins();
|
||||
for (auto plugin : inputs) {
|
||||
if (!plugin->isActive()) {
|
||||
plugin->activate();
|
||||
}
|
||||
}
|
||||
|
||||
getMyAvatar()->loadData();
|
||||
|
||||
_settingsLoaded = true;
|
||||
|
@ -4937,7 +4951,34 @@ void Application::postLambdaEvent(std::function<void()> f) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::initPlugins() {
|
||||
void Application::initPlugins(const QStringList& arguments) {
|
||||
QCommandLineOption display("display", "Preferred displays", "displays");
|
||||
QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays");
|
||||
QCommandLineOption disableInputs("disable-inputs", "Inputs to disable", "inputs");
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addOption(display);
|
||||
parser.addOption(disableDisplays);
|
||||
parser.addOption(disableInputs);
|
||||
parser.parse(arguments);
|
||||
|
||||
if (parser.isSet(display)) {
|
||||
auto preferredDisplays = parser.value(display).split(',', QString::SkipEmptyParts);
|
||||
qInfo() << "Setting prefered display plugins:" << preferredDisplays;
|
||||
PluginManager::getInstance()->setPreferredDisplayPlugins(preferredDisplays);
|
||||
}
|
||||
|
||||
if (parser.isSet(disableDisplays)) {
|
||||
auto disabledDisplays = parser.value(disableDisplays).split(',', QString::SkipEmptyParts);
|
||||
qInfo() << "Disabling following display plugins:" << disabledDisplays;
|
||||
PluginManager::getInstance()->disableDisplays(disabledDisplays);
|
||||
}
|
||||
|
||||
if (parser.isSet(disableInputs)) {
|
||||
auto disabledInputs = parser.value(disableInputs).split(',', QString::SkipEmptyParts);
|
||||
qInfo() << "Disabling following input plugins:" << disabledInputs;
|
||||
PluginManager::getInstance()->disableInputs(disabledInputs);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::shutdownPlugins() {
|
||||
|
@ -5207,81 +5248,6 @@ void Application::updateDisplayMode() {
|
|||
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
|
||||
}
|
||||
|
||||
static void addInputPluginToMenu(InputPluginPointer inputPlugin) {
|
||||
auto menu = Menu::getInstance();
|
||||
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
|
||||
Q_ASSERT(!menu->menuItemExists(MenuOption::InputMenu, name));
|
||||
|
||||
static QActionGroup* inputPluginGroup = nullptr;
|
||||
if (!inputPluginGroup) {
|
||||
inputPluginGroup = new QActionGroup(menu);
|
||||
inputPluginGroup->setExclusive(false);
|
||||
}
|
||||
|
||||
auto parent = menu->getMenu(MenuOption::InputMenu);
|
||||
auto action = menu->addCheckableActionToQMenuAndActionHash(parent,
|
||||
name, 0, true, qApp,
|
||||
SLOT(updateInputModes()));
|
||||
|
||||
inputPluginGroup->addAction(action);
|
||||
Q_ASSERT(menu->menuItemExists(MenuOption::InputMenu, name));
|
||||
}
|
||||
|
||||
|
||||
void Application::updateInputModes() {
|
||||
auto menu = Menu::getInstance();
|
||||
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
foreach(auto inputPlugin, inputPlugins) {
|
||||
addInputPluginToMenu(inputPlugin);
|
||||
}
|
||||
});
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
|
||||
InputPluginList newInputPlugins;
|
||||
InputPluginList removedInputPlugins;
|
||||
foreach(auto inputPlugin, inputPlugins) {
|
||||
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
|
||||
QAction* action = menu->getActionForOption(name);
|
||||
|
||||
auto it = std::find(std::begin(_activeInputPlugins), std::end(_activeInputPlugins), inputPlugin);
|
||||
if (action->isChecked() && it == std::end(_activeInputPlugins)) {
|
||||
_activeInputPlugins.push_back(inputPlugin);
|
||||
newInputPlugins.push_back(inputPlugin);
|
||||
} else if (!action->isChecked() && it != std::end(_activeInputPlugins)) {
|
||||
_activeInputPlugins.erase(it);
|
||||
removedInputPlugins.push_back(inputPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
// A plugin was checked
|
||||
if (newInputPlugins.size() > 0) {
|
||||
foreach(auto newInputPlugin, newInputPlugins) {
|
||||
newInputPlugin->activate();
|
||||
//newInputPlugin->installEventFilter(qApp);
|
||||
//newInputPlugin->installEventFilter(offscreenUi.data());
|
||||
}
|
||||
}
|
||||
if (removedInputPlugins.size() > 0) { // A plugin was unchecked
|
||||
foreach(auto removedInputPlugin, removedInputPlugins) {
|
||||
removedInputPlugin->deactivate();
|
||||
//removedInputPlugin->removeEventFilter(qApp);
|
||||
//removedInputPlugin->removeEventFilter(offscreenUi.data());
|
||||
}
|
||||
}
|
||||
|
||||
//if (newInputPlugins.size() > 0 || removedInputPlugins.size() > 0) {
|
||||
// if (!_currentInputPluginActions.isEmpty()) {
|
||||
// auto menu = Menu::getInstance();
|
||||
// foreach(auto itemInfo, _currentInputPluginActions) {
|
||||
// menu->removeMenuItem(itemInfo.first, itemInfo.second);
|
||||
// }
|
||||
// _currentInputPluginActions.clear();
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
mat4 Application::getEyeProjection(int eye) const {
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
if (isHMDMode()) {
|
||||
|
|
|
@ -101,7 +101,7 @@ public:
|
|||
};
|
||||
|
||||
// FIXME? Empty methods, do we still need them?
|
||||
static void initPlugins();
|
||||
static void initPlugins(const QStringList& arguments);
|
||||
static void shutdownPlugins();
|
||||
|
||||
Application(int& argc, char** argv, QElapsedTimer& startup_time);
|
||||
|
@ -327,7 +327,6 @@ private slots:
|
|||
void nodeKilled(SharedNodePointer node);
|
||||
static void packetSent(quint64 length);
|
||||
void updateDisplayMode();
|
||||
void updateInputModes();
|
||||
void domainConnectionRefused(const QString& reasonMessage, int reason);
|
||||
|
||||
private:
|
||||
|
|
|
@ -403,12 +403,6 @@ Menu::Menu() {
|
|||
// Developer > Avatar >>>
|
||||
MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar");
|
||||
|
||||
// Settings > Input Devices
|
||||
MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu, "Advanced");
|
||||
QActionGroup* inputModeGroup = new QActionGroup(inputModeMenu);
|
||||
inputModeGroup->setExclusive(false);
|
||||
|
||||
|
||||
// Developer > Avatar > Face Tracking
|
||||
MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking");
|
||||
{
|
||||
|
|
|
@ -113,7 +113,6 @@ namespace MenuOption {
|
|||
const QString Help = "Help...";
|
||||
const QString IncreaseAvatarSize = "Increase Avatar Size";
|
||||
const QString IndependentMode = "Independent Mode";
|
||||
const QString InputMenu = "Developer>Avatar>Input Devices";
|
||||
const QString ActionMotorControl = "Enable Default Motor Control";
|
||||
const QString LeapMotionOnHMD = "Leap Motion on HMD";
|
||||
const QString LoadScript = "Open and Run Script File...";
|
||||
|
|
|
@ -1214,7 +1214,10 @@ void MyAvatar::updateMotors() {
|
|||
if (_characterController.getState() == CharacterController::State::Hover) {
|
||||
motorRotation = getHead()->getCameraOrientation();
|
||||
} else {
|
||||
motorRotation = getOrientation();
|
||||
// non-hovering = walking: follow camera twist about vertical but not lift
|
||||
// so we decompose camera's rotation and store the twist part in motorRotation
|
||||
glm::quat liftRotation;
|
||||
swingTwistDecomposition(getHead()->getCameraOrientation(), _worldUpDirection, liftRotation, motorRotation);
|
||||
}
|
||||
const float DEFAULT_MOTOR_TIMESCALE = 0.2f;
|
||||
const float INVALID_MOTOR_TIMESCALE = 1.0e6f;
|
||||
|
|
|
@ -46,6 +46,12 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
bool instanceMightBeRunning = true;
|
||||
|
||||
QStringList arguments;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
arguments << argv[i];
|
||||
}
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// Try to create a shared memory block - if it can't be created, there is an instance of
|
||||
// interface already running. We only do this on Windows for now because of the potential
|
||||
|
@ -64,12 +70,6 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
// Try to connect - if we can't connect, interface has probably just gone down
|
||||
if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) {
|
||||
|
||||
QStringList arguments;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
arguments << argv[i];
|
||||
}
|
||||
|
||||
QCommandLineParser parser;
|
||||
QCommandLineOption urlOption("url", "", "value");
|
||||
parser.addOption(urlOption);
|
||||
|
@ -135,7 +135,7 @@ int main(int argc, const char* argv[]) {
|
|||
// Oculus initialization MUST PRECEDE OpenGL context creation.
|
||||
// The nature of the Application constructor means this has to be either here,
|
||||
// or in the main window ctor, before GL startup.
|
||||
Application::initPlugins();
|
||||
Application::initPlugins(arguments);
|
||||
|
||||
int exitCode;
|
||||
{
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
ClipboardScriptingInterface::ClipboardScriptingInterface() {
|
||||
}
|
||||
|
||||
glm::vec3 ClipboardScriptingInterface::getContentsDimensions() {
|
||||
return qApp->getEntityClipboard()->getContentsDimensions();
|
||||
}
|
||||
|
||||
float ClipboardScriptingInterface::getClipboardContentsLargestDimension() {
|
||||
return qApp->getEntityClipboard()->getContentsLargestDimension();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ signals:
|
|||
void readyToImport();
|
||||
|
||||
public slots:
|
||||
glm::vec3 getContentsDimensions(); /// returns the overall dimensions of everything on the blipboard
|
||||
float getClipboardContentsLargestDimension(); /// returns the largest dimension of everything on the clipboard
|
||||
bool importEntities(const QString& filename);
|
||||
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs);
|
||||
|
|
|
@ -632,13 +632,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
#endif
|
||||
|
||||
int numBytesRead = sourceBuffer - startPosition;
|
||||
|
||||
if (numBytesRead != buffer.size()) {
|
||||
if (shouldLogError(now)) {
|
||||
qCWarning(avatars) << "AvatarData packet size mismatch: expected " << numBytesRead << " received " << buffer.size();
|
||||
}
|
||||
}
|
||||
|
||||
_averageBytesReceived.updateAverage(numBytesRead);
|
||||
return numBytesRead;
|
||||
}
|
||||
|
@ -1270,6 +1263,10 @@ static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
|
|||
static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments");
|
||||
static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities");
|
||||
static const QString JSON_AVATAR_SCALE = QStringLiteral("scale");
|
||||
static const QString JSON_AVATAR_VERSION = QStringLiteral("version");
|
||||
|
||||
static const int JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION = 0;
|
||||
static const int JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION = 1;
|
||||
|
||||
QJsonValue toJsonValue(const JointData& joint) {
|
||||
QJsonArray result;
|
||||
|
@ -1293,6 +1290,8 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
|
|||
QJsonObject AvatarData::toJson() const {
|
||||
QJsonObject root;
|
||||
|
||||
root[JSON_AVATAR_VERSION] = JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION;
|
||||
|
||||
if (!getSkeletonModelURL().isEmpty()) {
|
||||
root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString();
|
||||
}
|
||||
|
@ -1359,6 +1358,15 @@ QJsonObject AvatarData::toJson() const {
|
|||
}
|
||||
|
||||
void AvatarData::fromJson(const QJsonObject& json) {
|
||||
|
||||
int version;
|
||||
if (json.contains(JSON_AVATAR_VERSION)) {
|
||||
version = json[JSON_AVATAR_VERSION].toInt();
|
||||
} else {
|
||||
// initial data did not have a version field.
|
||||
version = JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION;
|
||||
}
|
||||
|
||||
// The head setOrientation likes to overwrite the avatar orientation,
|
||||
// so lets do the head first
|
||||
// Most head data is relative to the avatar, and needs no basis correction,
|
||||
|
@ -1424,20 +1432,28 @@ void AvatarData::fromJson(const QJsonObject& json) {
|
|||
// }
|
||||
// }
|
||||
|
||||
// Joint rotations are relative to the avatar, so they require no basis correction
|
||||
if (json.contains(JSON_AVATAR_JOINT_ARRAY)) {
|
||||
QVector<JointData> jointArray;
|
||||
QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray();
|
||||
jointArray.reserve(jointArrayJson.size());
|
||||
int i = 0;
|
||||
for (const auto& jointJson : jointArrayJson) {
|
||||
auto joint = jointDataFromJsonValue(jointJson);
|
||||
jointArray.push_back(joint);
|
||||
setJointData(i, joint.rotation, joint.translation);
|
||||
_jointData[i].rotationSet = true; // Have to do that to broadcast the avatar new pose
|
||||
i++;
|
||||
if (version == JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION) {
|
||||
// because we don't have the full joint hierarchy skeleton of the model,
|
||||
// we can't properly convert from relative rotations into absolute rotations.
|
||||
quint64 now = usecTimestampNow();
|
||||
if (shouldLogError(now)) {
|
||||
qCWarning(avatars) << "Version 0 avatar recordings not supported. using default rotations";
|
||||
}
|
||||
} else {
|
||||
QVector<JointData> jointArray;
|
||||
QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray();
|
||||
jointArray.reserve(jointArrayJson.size());
|
||||
int i = 0;
|
||||
for (const auto& jointJson : jointArrayJson) {
|
||||
auto joint = jointDataFromJsonValue(jointJson);
|
||||
jointArray.push_back(joint);
|
||||
setJointData(i, joint.rotation, joint.translation);
|
||||
_jointData[i].rotationSet = true; // Have to do that to broadcast the avatar new pose
|
||||
i++;
|
||||
}
|
||||
setRawJointData(jointArray);
|
||||
}
|
||||
setRawJointData(jointArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1121,6 +1121,27 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) {
|
|||
return result;
|
||||
}
|
||||
|
||||
QVector<QUuid> EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
|
||||
QVector<QUuid> result;
|
||||
if (!_entityTree) {
|
||||
return result;
|
||||
}
|
||||
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID);
|
||||
if (!entity) {
|
||||
qDebug() << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID;
|
||||
return result;
|
||||
}
|
||||
|
||||
_entityTree->withReadLock([&] {
|
||||
entity->forEachChild([&](SpatiallyNestablePointer child) {
|
||||
result.push_back(child->getID());
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<QUuid> EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) {
|
||||
QVector<QUuid> result;
|
||||
if (!_entityTree) {
|
||||
|
|
|
@ -171,6 +171,7 @@ public slots:
|
|||
|
||||
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
|
||||
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
|
||||
Q_INVOKABLE QVector<QUuid> getChildrenIDs(const QUuid& parentID);
|
||||
Q_INVOKABLE QVector<QUuid> getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex);
|
||||
|
||||
signals:
|
||||
|
|
|
@ -1284,6 +1284,7 @@ class ContentsDimensionOperator : public RecurseOctreeOperator {
|
|||
public:
|
||||
virtual bool preRecursion(OctreeElementPointer element);
|
||||
virtual bool postRecursion(OctreeElementPointer element) { return true; }
|
||||
glm::vec3 getDimensions() const { return _contentExtents.size(); }
|
||||
float getLargestDimension() const { return _contentExtents.largestDimension(); }
|
||||
private:
|
||||
Extents _contentExtents;
|
||||
|
@ -1295,6 +1296,12 @@ bool ContentsDimensionOperator::preRecursion(OctreeElementPointer element) {
|
|||
return true;
|
||||
}
|
||||
|
||||
glm::vec3 EntityTree::getContentsDimensions() {
|
||||
ContentsDimensionOperator theOperator;
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
return theOperator.getDimensions();
|
||||
}
|
||||
|
||||
float EntityTree::getContentsLargestDimension() {
|
||||
ContentsDimensionOperator theOperator;
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
|
|
|
@ -207,6 +207,7 @@ public:
|
|||
bool skipThoseWithBadParents) override;
|
||||
virtual bool readFromMap(QVariantMap& entityDescription) override;
|
||||
|
||||
glm::vec3 getContentsDimensions();
|
||||
float getContentsLargestDimension();
|
||||
|
||||
virtual void resetEditStats() override {
|
||||
|
|
|
@ -55,7 +55,7 @@ void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) cons
|
|||
|
||||
if (extraEncodeData->contains(this)) {
|
||||
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
|
||||
qCDebug(entities) << " encode data:" << entityTreeElementExtraEncodeData;
|
||||
} else {
|
||||
qCDebug(entities) << " encode data: MISSING!!";
|
||||
|
@ -97,7 +97,7 @@ bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamPa
|
|||
|
||||
if (extraEncodeData->contains(this)) {
|
||||
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
|
||||
|
||||
bool childCompleted = entityTreeElementExtraEncodeData->childCompleted[childIndex];
|
||||
|
||||
|
@ -126,7 +126,7 @@ bool EntityTreeElement::alreadyFullyEncoded(EncodeBitstreamParams& params) const
|
|||
|
||||
if (extraEncodeData->contains(this)) {
|
||||
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
|
||||
|
||||
// If we know that ALL subtrees below us have already been recursed, then we don't
|
||||
// need to recurse this child.
|
||||
|
@ -140,7 +140,7 @@ void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppen
|
|||
assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes
|
||||
if (extraEncodeData->contains(this)) {
|
||||
EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
|
||||
|
||||
if (childAppendState == OctreeElement::COMPLETED) {
|
||||
entityTreeElementExtraEncodeData->childCompleted[childIndex] = true;
|
||||
|
@ -165,7 +165,7 @@ void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params) con
|
|||
assert(extraEncodeData->contains(this));
|
||||
|
||||
EntityTreeElementExtraEncodeData* thisExtraEncodeData
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
|
||||
= static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
|
||||
|
||||
// Note: this will be called when OUR element has finished running through encodeTreeBitstreamRecursion()
|
||||
// which means, it's possible that our parent element hasn't finished encoding OUR data... so
|
||||
|
@ -241,7 +241,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
|
|||
bool hadElementExtraData = false;
|
||||
if (extraEncodeData && extraEncodeData->contains(this)) {
|
||||
entityTreeElementExtraEncodeData =
|
||||
static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
|
||||
static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
|
||||
hadElementExtraData = true;
|
||||
} else {
|
||||
// if there wasn't one already, then create one
|
||||
|
@ -268,7 +268,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
|
|||
|
||||
//assert(extraEncodeData);
|
||||
//assert(extraEncodeData->contains(this));
|
||||
//entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>(extraEncodeData->value(this));
|
||||
//entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
|
||||
|
||||
LevelDetails elementLevel = packetData->startLevel();
|
||||
|
||||
|
|
|
@ -396,6 +396,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
|||
|
||||
_renderer->_renderControl->_renderWindow = _proxyWindow;
|
||||
|
||||
connect(_renderer->_quickWindow, &QQuickWindow::focusObjectChanged, this, &OffscreenQmlSurface::onFocusObjectChanged);
|
||||
|
||||
// Create a QML engine.
|
||||
_qmlEngine = new QQmlEngine;
|
||||
if (!_qmlEngine->incubationController()) {
|
||||
|
@ -742,3 +744,21 @@ QVariant OffscreenQmlSurface::returnFromUiThread(std::function<QVariant()> funct
|
|||
|
||||
return function();
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::onFocusObjectChanged(QObject* object) {
|
||||
if (!object) {
|
||||
setFocusText(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QInputMethodQueryEvent query(Qt::ImEnabled);
|
||||
qApp->sendEvent(object, &query);
|
||||
setFocusText(query.value(Qt::ImEnabled).toBool());
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::setFocusText(bool newFocusText) {
|
||||
if (newFocusText != _focusText) {
|
||||
_focusText = newFocusText;
|
||||
emit focusTextChanged(_focusText);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class OffscreenQmlRenderThread;
|
|||
|
||||
class OffscreenQmlSurface : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged)
|
||||
public:
|
||||
OffscreenQmlSurface();
|
||||
virtual ~OffscreenQmlSurface();
|
||||
|
@ -55,6 +55,7 @@ public:
|
|||
_mouseTranslator = mouseTranslator;
|
||||
}
|
||||
|
||||
bool isFocusText() const { return _focusText; }
|
||||
void pause();
|
||||
void resume();
|
||||
bool isPaused() const;
|
||||
|
@ -70,6 +71,8 @@ public:
|
|||
|
||||
signals:
|
||||
void textureUpdated(unsigned int texture);
|
||||
void focusObjectChanged(QObject* newFocus);
|
||||
void focusTextChanged(bool focusText);
|
||||
|
||||
public slots:
|
||||
void requestUpdate();
|
||||
|
@ -78,6 +81,7 @@ public slots:
|
|||
|
||||
protected:
|
||||
bool filterEnabled(QObject* originalDestination, QEvent* event) const;
|
||||
void setFocusText(bool newFocusText);
|
||||
|
||||
private:
|
||||
QObject* finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f);
|
||||
|
@ -85,6 +89,7 @@ private:
|
|||
|
||||
private slots:
|
||||
void updateQuick();
|
||||
void onFocusObjectChanged(QObject* newFocus);
|
||||
|
||||
private:
|
||||
friend class OffscreenQmlRenderThread;
|
||||
|
@ -97,6 +102,7 @@ private:
|
|||
bool _render{ false };
|
||||
bool _polish{ true };
|
||||
bool _paused{ true };
|
||||
bool _focusText { false };
|
||||
uint8_t _maxFps{ 60 };
|
||||
MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p.toPoint(); } };
|
||||
QWindow* _proxyWindow { nullptr };
|
||||
|
|
|
@ -25,7 +25,6 @@ InputPluginList getInputPlugins() {
|
|||
for (int i = 0; PLUGIN_POOL[i]; ++i) {
|
||||
InputPlugin* plugin = PLUGIN_POOL[i];
|
||||
if (plugin->isSupported()) {
|
||||
plugin->init();
|
||||
result.push_back(InputPluginPointer(plugin));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,50 @@ PluginManager* PluginManager::getInstance() {
|
|||
return &_manager;
|
||||
}
|
||||
|
||||
QString getPluginNameFromMetaData(QJsonObject object) {
|
||||
static const char* METADATA_KEY = "MetaData";
|
||||
static const char* NAME_KEY = "name";
|
||||
|
||||
if (!object.contains(METADATA_KEY) || !object[METADATA_KEY].isObject()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
auto metaDataObject = object[METADATA_KEY].toObject();
|
||||
|
||||
if (!metaDataObject.contains(NAME_KEY) || !metaDataObject[NAME_KEY].isString()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return metaDataObject[NAME_KEY].toString();
|
||||
}
|
||||
|
||||
QString getPluginIIDFromMetaData(QJsonObject object) {
|
||||
static const char* IID_KEY = "IID";
|
||||
|
||||
if (!object.contains(IID_KEY) || !object[IID_KEY].isString()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return object[IID_KEY].toString();
|
||||
}
|
||||
|
||||
QStringList preferredDisplayPlugins;
|
||||
QStringList disabledDisplays;
|
||||
QStringList disabledInputs;
|
||||
|
||||
bool isDisabled(QJsonObject metaData) {
|
||||
auto name = getPluginNameFromMetaData(metaData);
|
||||
auto iid = getPluginIIDFromMetaData(metaData);
|
||||
|
||||
if (iid == DisplayProvider_iid) {
|
||||
return disabledDisplays.contains(name);
|
||||
} else if (iid == InputProvider_iid) {
|
||||
return disabledInputs.contains(name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
using Loader = QSharedPointer<QPluginLoader>;
|
||||
using LoaderList = QList<Loader>;
|
||||
|
||||
|
@ -43,11 +87,21 @@ const LoaderList& getLoadedPlugins() {
|
|||
qDebug() << "Loading runtime plugins from " << pluginPath;
|
||||
auto candidates = pluginDir.entryList();
|
||||
for (auto plugin : candidates) {
|
||||
qDebug() << "Attempting plugins " << plugin;
|
||||
qDebug() << "Attempting plugin" << qPrintable(plugin);
|
||||
QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin));
|
||||
|
||||
if (isDisabled(loader->metaData())) {
|
||||
qWarning() << "Plugin" << qPrintable(plugin) << "is disabled";
|
||||
// Skip this one, it's disabled
|
||||
continue;
|
||||
}
|
||||
|
||||
if (loader->load()) {
|
||||
qDebug() << "Plugins " << plugin << " success";
|
||||
qDebug() << "Plugin" << qPrintable(plugin) << "loaded successfully";
|
||||
loadedPlugins.push_back(loader);
|
||||
} else {
|
||||
qDebug() << "Plugin" << qPrintable(plugin) << "failed to load:";
|
||||
qDebug() << " " << qPrintable(loader->errorString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +164,9 @@ const InputPluginList& PluginManager::getInputPlugins() {
|
|||
InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance());
|
||||
if (inputProvider) {
|
||||
for (auto inputPlugin : inputProvider->getInputPlugins()) {
|
||||
inputPlugins.push_back(inputPlugin);
|
||||
if (inputPlugin->isSupported()) {
|
||||
inputPlugins.push_back(inputPlugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +180,40 @@ const InputPluginList& PluginManager::getInputPlugins() {
|
|||
return inputPlugins;
|
||||
}
|
||||
|
||||
void PluginManager::setPreferredDisplayPlugins(const QStringList& displays) {
|
||||
preferredDisplayPlugins = displays;
|
||||
}
|
||||
|
||||
DisplayPluginList PluginManager::getPreferredDisplayPlugins() {
|
||||
static DisplayPluginList displayPlugins;
|
||||
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
// Grab the built in plugins
|
||||
auto plugins = getDisplayPlugins();
|
||||
|
||||
for (auto pluginName : preferredDisplayPlugins) {
|
||||
auto it = std::find_if(plugins.begin(), plugins.end(), [&](DisplayPluginPointer plugin) {
|
||||
return plugin->getName() == pluginName;
|
||||
});
|
||||
if (it != plugins.end()) {
|
||||
displayPlugins.push_back(*it);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return displayPlugins;
|
||||
}
|
||||
|
||||
|
||||
void PluginManager::disableDisplays(const QStringList& displays) {
|
||||
disabledDisplays << displays;
|
||||
}
|
||||
|
||||
void PluginManager::disableInputs(const QStringList& inputs) {
|
||||
disabledInputs << inputs;
|
||||
}
|
||||
|
||||
void PluginManager::saveSettings() {
|
||||
saveInputPluginSettings(getInputPlugins());
|
||||
}
|
||||
|
|
|
@ -13,11 +13,17 @@
|
|||
|
||||
class PluginManager : public QObject {
|
||||
public:
|
||||
static PluginManager* getInstance();
|
||||
PluginManager();
|
||||
static PluginManager* getInstance();
|
||||
PluginManager();
|
||||
|
||||
const DisplayPluginList& getDisplayPlugins();
|
||||
void disableDisplayPlugin(const QString& name);
|
||||
const InputPluginList& getInputPlugins();
|
||||
void saveSettings();
|
||||
const DisplayPluginList& getDisplayPlugins();
|
||||
const InputPluginList& getInputPlugins();
|
||||
|
||||
DisplayPluginList getPreferredDisplayPlugins();
|
||||
void setPreferredDisplayPlugins(const QStringList& displays);
|
||||
|
||||
void disableDisplayPlugin(const QString& name);
|
||||
void disableDisplays(const QStringList& displays);
|
||||
void disableInputs(const QStringList& inputs);
|
||||
void saveSettings();
|
||||
};
|
||||
|
|
|
@ -28,7 +28,9 @@ Settings::~Settings() {
|
|||
}
|
||||
|
||||
void Settings::remove(const QString& key) {
|
||||
_manager->remove(key);
|
||||
if (key == "" || _manager->contains(key)) {
|
||||
_manager->remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList Settings::childGroups() const {
|
||||
|
@ -72,7 +74,9 @@ void Settings::endGroup() {
|
|||
}
|
||||
|
||||
void Settings::setValue(const QString& name, const QVariant& value) {
|
||||
_manager->setValue(name, value);
|
||||
if (_manager->value(name) != value) {
|
||||
_manager->setValue(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant Settings::value(const QString& name, const QVariant& defaultValue) const {
|
||||
|
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{"name":"Neuron"}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{"name":"SDL2"}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{"name":"Sixense"}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{"name":"Spacemouse"}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{"name":"Oculus Rift"}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
using namespace oglplus;
|
||||
|
||||
const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift (0.5) (Legacy)");
|
||||
const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift");
|
||||
|
||||
OculusLegacyDisplayPlugin::OculusLegacyDisplayPlugin() {
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{"name":"Oculus Rift"}
|
||||
|
|
|
@ -36,12 +36,14 @@ 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 } };
|
||||
bool _openVrDisplayActive { false };
|
||||
|
||||
bool OpenVrDisplayPlugin::isSupported() const {
|
||||
return openVrSupported();
|
||||
}
|
||||
|
||||
bool OpenVrDisplayPlugin::internalActivate() {
|
||||
_openVrDisplayActive = true;
|
||||
_container->setIsOptionChecked(StandingHMDSensorMode, true);
|
||||
|
||||
if (!_system) {
|
||||
|
@ -94,6 +96,7 @@ bool OpenVrDisplayPlugin::internalActivate() {
|
|||
|
||||
void OpenVrDisplayPlugin::internalDeactivate() {
|
||||
Parent::internalDeactivate();
|
||||
_openVrDisplayActive = false;
|
||||
_container->setIsOptionChecked(StandingHMDSensorMode, false);
|
||||
if (_system) {
|
||||
// Invalidate poses. It's fine if someone else sets these shared values, but we're about to stop updating them, and
|
||||
|
|
|
@ -14,9 +14,13 @@
|
|||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
#include <QtGui/QInputMethodEvent>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(displayplugins)
|
||||
Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display")
|
||||
|
||||
|
@ -90,6 +94,121 @@ void releaseOpenVrSystem() {
|
|||
}
|
||||
}
|
||||
|
||||
static char textArray[8192];
|
||||
|
||||
static QMetaObject::Connection _focusConnection, _focusTextConnection;
|
||||
extern bool _openVrDisplayActive;
|
||||
static vr::IVROverlay* _overlay { nullptr };
|
||||
static QObject* _keyboardFocusObject { nullptr };
|
||||
static QString _existingText;
|
||||
static Qt::InputMethodHints _currentHints;
|
||||
extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
|
||||
static bool _keyboardShown { false };
|
||||
static const uint32_t SHOW_KEYBOARD_DELAY_MS = 100;
|
||||
|
||||
void showOpenVrKeyboard(bool show = true) {
|
||||
if (!_overlay) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (show) {
|
||||
// To avoid flickering the keyboard when a text element is only briefly selected,
|
||||
// show the keyboard asynchrnously after a very short delay, but only after we check
|
||||
// that the current focus object is still one that is text enabled
|
||||
QTimer::singleShot(SHOW_KEYBOARD_DELAY_MS, [] {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto currentFocus = offscreenUi->getWindow()->focusObject();
|
||||
QInputMethodQueryEvent query(Qt::ImEnabled | Qt::ImQueryInput | Qt::ImHints);
|
||||
qApp->sendEvent(currentFocus, &query);
|
||||
// Current focus isn't text enabled, bail early.
|
||||
if (!query.value(Qt::ImEnabled).toBool()) {
|
||||
return;
|
||||
}
|
||||
// We're going to show the keyboard now...
|
||||
_keyboardFocusObject = currentFocus;
|
||||
_currentHints = Qt::InputMethodHints(query.value(Qt::ImHints).toUInt());
|
||||
vr::EGamepadTextInputMode inputMode = vr::k_EGamepadTextInputModeNormal;
|
||||
if (_currentHints & Qt::ImhHiddenText) {
|
||||
inputMode = vr::k_EGamepadTextInputModePassword;
|
||||
}
|
||||
vr::EGamepadTextInputLineMode lineMode = vr::k_EGamepadTextInputLineModeSingleLine;
|
||||
if (_currentHints & Qt::ImhMultiLine) {
|
||||
lineMode = vr::k_EGamepadTextInputLineModeMultipleLines;
|
||||
}
|
||||
_existingText = query.value(Qt::ImSurroundingText).toString();
|
||||
|
||||
auto showKeyboardResult = _overlay->ShowKeyboard(inputMode, lineMode, "Keyboard", 1024,
|
||||
_existingText.toLocal8Bit().toStdString().c_str(), false, 0);
|
||||
|
||||
if (vr::VROverlayError_None == showKeyboardResult) {
|
||||
_keyboardShown = true;
|
||||
// Try to position the keyboard slightly below where the user is looking.
|
||||
mat4 headPose = toGlm(_trackedDevicePose[0].mDeviceToAbsoluteTracking);
|
||||
mat4 keyboardTransform = glm::translate(headPose, vec3(0, -0.5, -1));
|
||||
keyboardTransform = keyboardTransform * glm::rotate(mat4(), 3.14159f / 4.0f, vec3(-1, 0, 0));
|
||||
auto keyboardTransformVr = toOpenVr(keyboardTransform);
|
||||
_overlay->SetKeyboardTransformAbsolute(vr::ETrackingUniverseOrigin::TrackingUniverseStanding, &keyboardTransformVr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
_keyboardFocusObject = nullptr;
|
||||
if (_keyboardShown) {
|
||||
_overlay->HideKeyboard();
|
||||
_keyboardShown = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void finishOpenVrKeyboardInput() {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto chars = _overlay->GetKeyboardText(textArray, 8192);
|
||||
auto newText = QString(QByteArray(textArray, chars));
|
||||
// TODO modify the new text to match the possible input hints:
|
||||
// ImhDigitsOnly ImhFormattedNumbersOnly ImhUppercaseOnly ImhLowercaseOnly
|
||||
// ImhDialableCharactersOnly ImhEmailCharactersOnly ImhUrlCharactersOnly ImhLatinOnly
|
||||
QInputMethodEvent event(_existingText, QList<QInputMethodEvent::Attribute>());
|
||||
event.setCommitString(newText, 0, _existingText.size());
|
||||
qApp->sendEvent(_keyboardFocusObject, &event);
|
||||
// Simulate an enter press on the top level window to trigger the action
|
||||
if (0 == (_currentHints & Qt::ImhMultiLine)) {
|
||||
qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n")));
|
||||
qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers()));
|
||||
}
|
||||
}
|
||||
|
||||
static const QString DEBUG_FLAG("HIFI_DISABLE_STEAM_VR_KEYBOARD");
|
||||
bool disableSteamVrKeyboard = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
|
||||
void enableOpenVrKeyboard() {
|
||||
if (disableSteamVrKeyboard) {
|
||||
return;
|
||||
}
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
_overlay = vr::VROverlay();
|
||||
|
||||
_focusConnection = QObject::connect(offscreenUi->getWindow(), &QQuickWindow::focusObjectChanged, [](QObject* object) {
|
||||
if (object != _keyboardFocusObject) {
|
||||
showOpenVrKeyboard(false);
|
||||
}
|
||||
});
|
||||
|
||||
_focusTextConnection = QObject::connect(offscreenUi.data(), &OffscreenUi::focusTextChanged, [](bool focusText) {
|
||||
if (_openVrDisplayActive) {
|
||||
showOpenVrKeyboard(focusText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void disableOpenVrKeyboard() {
|
||||
if (disableSteamVrKeyboard) {
|
||||
return;
|
||||
}
|
||||
QObject::disconnect(_focusTextConnection);
|
||||
QObject::disconnect(_focusConnection);
|
||||
}
|
||||
|
||||
|
||||
void handleOpenVrEvents() {
|
||||
if (!activeHmd) {
|
||||
return;
|
||||
|
@ -107,6 +226,10 @@ void handleOpenVrEvents() {
|
|||
activeHmd->AcknowledgeQuit_Exiting();
|
||||
break;
|
||||
|
||||
case vr::VREvent_KeyboardDone:
|
||||
finishOpenVrKeyboardInput();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -114,3 +237,4 @@ void handleOpenVrEvents() {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ vr::IVRSystem* acquireOpenVrSystem();
|
|||
void releaseOpenVrSystem();
|
||||
void handleOpenVrEvents();
|
||||
bool openVrQuitRequested();
|
||||
void enableOpenVrKeyboard();
|
||||
void disableOpenVrKeyboard();
|
||||
|
||||
|
||||
template<typename F>
|
||||
void openvr_for_each_eye(F f) {
|
||||
|
@ -41,3 +44,13 @@ inline mat4 toGlm(const vr::HmdMatrix34_t& m) {
|
|||
m.m[0][3], m.m[1][3], m.m[2][3], 1.0f);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline vr::HmdMatrix34_t toOpenVr(const mat4& m) {
|
||||
vr::HmdMatrix34_t result;
|
||||
for (uint8_t i = 0; i < 3; ++i) {
|
||||
for (uint8_t j = 0; j < 4; ++j) {
|
||||
result.m[i][j] = m[j][i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
#include "ViveControllerManager.h"
|
||||
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <PathUtils.h>
|
||||
#include <GeometryCache.h>
|
||||
|
@ -22,6 +20,7 @@
|
|||
#include <NumericalConstants.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
#include <controllers/UserInputMapper.h>
|
||||
|
||||
|
@ -68,6 +67,8 @@ bool ViveControllerManager::activate() {
|
|||
}
|
||||
Q_ASSERT(_system);
|
||||
|
||||
enableOpenVrKeyboard();
|
||||
|
||||
// OpenVR provides 3d mesh representations of the controllers
|
||||
// Disabled controller rendering code
|
||||
/*
|
||||
|
@ -132,6 +133,8 @@ bool ViveControllerManager::activate() {
|
|||
void ViveControllerManager::deactivate() {
|
||||
InputPlugin::deactivate();
|
||||
|
||||
disableOpenVrKeyboard();
|
||||
|
||||
_container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
|
||||
_container->removeMenu(MENU_PATH);
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{"name":"OpenVR (Vive)"}
|
||||
|
|
|
@ -4,99 +4,121 @@
|
|||
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.49;}
|
||||
.st1{fill:#1E1E1E;}
|
||||
.st2{opacity:0.9;}
|
||||
.st1{opacity:0.9;}
|
||||
.st2{fill:#1E1E1E;}
|
||||
.st3{fill:#FFFFFF;}
|
||||
.st4{fill:#333333;}
|
||||
.st5{fill:#CBCBCB;}
|
||||
.st6{enable-background:new ;}
|
||||
.st7{fill:#CBCBCB;stroke:#CBCBCB;stroke-width:0.2978;stroke-linecap:square;stroke-miterlimit:10;}
|
||||
.st8{fill:#CBCBCB;stroke:#CBCBCB;stroke-width:9.574610e-03;stroke-linejoin:round;stroke-miterlimit:10;}
|
||||
.st9{fill:#EAEAEA;}
|
||||
.st10{opacity:0.47;}
|
||||
.st11{opacity:0.49;fill:#EAEAEA;}
|
||||
.st12{opacity:0.47;enable-background:new ;}
|
||||
.st13{opacity:0.5;}
|
||||
.st4{fill:#EAEAEA;}
|
||||
.st5{opacity:0.49;fill:#EAEAEA;}
|
||||
</style>
|
||||
<g>
|
||||
<g class="st2">
|
||||
<path class="st3" d="M50,46.3c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V46.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g class="st2">
|
||||
<path class="st1" d="M50,96.3c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V96.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path d="M21.6,21.5c-1.4,1.4-2.8,2.8-4.2,4.2c-0.3-0.3-0.7-0.7-1-1c1.4-1.4,2.8-2.8,4.2-4.2l-1.1-1.1c-1.6,1.6-3.2,3.2-4.9,4.8
|
||||
c-0.3,0.3-0.5,0.7-0.6,1.2c-0.2,1.3-0.4,2.6-0.6,4c0.1,0,0.2,0,0.3,0c1.3-0.3,2.5-0.5,3.8-0.8c0.2-0.1,0.5-0.2,0.7-0.4
|
||||
c1.7-1.7,3.4-3.4,5.1-5.1L21.6,21.5z"/>
|
||||
<path d="M28.2,10.6c0.5-0.5,1.1-1.1,1.7-1.7c0.2-0.2,0.5-0.2,0.7,0c1,1,2,2,3,3c0.2,0.2,0.2,0.5,0,0.8c-0.6,0.6-1.2,1.2-1.7,1.7
|
||||
C30.7,13.2,29.4,11.9,28.2,10.6z"/>
|
||||
<path d="M29.4,19.1c-0.3,0.1-0.4,0-0.6-0.2c-0.4-0.4-0.8-0.8-1.2-1.2c1-1,1.9-1.9,2.9-2.9c0.1-0.1,0.2-0.2,0.2-0.2
|
||||
c-1.3-1.3-2.5-2.5-3.8-3.9c-0.1,0.1-0.1,0.2-0.2,0.3c-1,1-1.9,1.9-2.9,2.9c-1.8-1.8-3.5-3.5-5.3-5.3c-0.1-0.1-0.3-0.3-0.4-0.4
|
||||
c-1-0.7-2.2-0.6-3,0.3c-0.8,0.9-0.7,2.2,0.1,3c2.6,2.6,5.3,5.3,7.9,7.9c0.9,0.9,1.7,1.7,2.6,2.6c0.1,0.1,0.2,0.2,0.1,0.4
|
||||
c-0.1,0.4-0.2,0.8-0.2,1.2c-0.2,2.5,1.4,4.7,3.9,5.4c1,0.3,2,0.2,3.1-0.2c-0.1-0.1-0.2-0.2-0.3-0.2c-0.7-0.7-1.5-1.5-2.2-2.2
|
||||
c-0.5-0.5-0.6-1.4-0.1-1.9c0.4-0.4,0.8-0.8,1.2-1.2c0.6-0.5,1.3-0.5,1.8,0c0.1,0.1,0.2,0.2,0.3,0.3c0.7,0.7,1.5,1.5,2.2,2.2
|
||||
c0,0,0.1,0,0.1,0c0.1-0.4,0.2-0.8,0.2-1.3C36.3,20.9,32.9,18.1,29.4,19.1z M16.7,10.6c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.8,0.7-0.8
|
||||
c0.4,0,0.8,0.4,0.8,0.7C17.4,10.3,17.1,10.6,16.7,10.6z M27.1,13c0.3,0.3,0.6,0.7,1,1c-0.7,0.7-1.4,1.4-2.1,2.1
|
||||
c-0.3-0.3-0.7-0.7-1-1C25.7,14.4,26.4,13.7,27.1,13z"/>
|
||||
<g>
|
||||
<path d="M18.2,41.3v1.1h-4.4V36h4.4v1.1H15v1.5h2.7v1H15v1.7H18.2z"/>
|
||||
<path d="M19.4,42.4V36h2.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.4,1,0.7c0.3,0.3,0.5,0.6,0.6,1c0.1,0.4,0.2,0.8,0.2,1.2
|
||||
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.4,0.7-0.6,1c-0.3,0.3-0.6,0.5-1,0.6c-0.4,0.2-0.8,0.2-1.3,0.2H19.4z M23.6,39.2
|
||||
c0-0.3,0-0.6-0.1-0.8c-0.1-0.3-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.6-0.4c-0.2-0.1-0.5-0.2-0.8-0.2h-1.1v4.2h1.1
|
||||
c0.3,0,0.6-0.1,0.8-0.2c0.2-0.1,0.4-0.3,0.6-0.4c0.2-0.2,0.3-0.4,0.4-0.7C23.6,39.8,23.6,39.5,23.6,39.2z"/>
|
||||
<path d="M26.1,42.4V36h1.2v6.4H26.1z"/>
|
||||
<path d="M33.6,37.1h-2v5.3h-1.2v-5.3h-2V36h5.3V37.1z"/>
|
||||
</g>
|
||||
<path class="st9" d="M21.9,71.5c-1.4,1.4-2.8,2.8-4.2,4.2c-0.3-0.3-0.7-0.7-1-1c1.4-1.4,2.8-2.8,4.2-4.2l-1.1-1.1
|
||||
c-1.6,1.6-3.2,3.2-4.9,4.8c-0.3,0.3-0.5,0.7-0.6,1.2c-0.2,1.3-0.4,2.6-0.6,4c0.1,0,0.2,0,0.3,0c1.3-0.3,2.5-0.5,3.8-0.8
|
||||
c0.2-0.1,0.5-0.2,0.7-0.4c1.7-1.7,3.4-3.4,5.1-5.1L21.9,71.5z"/>
|
||||
<path class="st9" d="M28.5,60.6c0.5-0.5,1.1-1.1,1.7-1.7c0.2-0.2,0.5-0.2,0.7,0c1,1,2,2,3,3c0.2,0.2,0.2,0.5,0,0.8
|
||||
c-0.6,0.6-1.2,1.2-1.7,1.7C31,63.2,29.8,61.9,28.5,60.6z"/>
|
||||
<path class="st9" d="M29.7,69.1c-0.3,0.1-0.4,0-0.6-0.2c-0.4-0.4-0.8-0.8-1.2-1.2c1-1,1.9-1.9,2.9-2.9c0.1-0.1,0.2-0.2,0.2-0.2
|
||||
c-1.3-1.3-2.5-2.5-3.8-3.9c-0.1,0.1-0.1,0.2-0.2,0.3c-1,1-1.9,1.9-2.9,2.9c-1.8-1.8-3.5-3.5-5.3-5.3c-0.1-0.1-0.3-0.3-0.4-0.4
|
||||
c-1-0.7-2.2-0.6-3,0.3c-0.8,0.9-0.7,2.2,0.1,3c2.6,2.6,5.3,5.3,7.9,7.9c0.9,0.9,1.7,1.7,2.6,2.6c0.1,0.1,0.2,0.2,0.1,0.4
|
||||
c-0.1,0.4-0.2,0.8-0.2,1.2c-0.2,2.5,1.4,4.7,3.9,5.4c1,0.3,2,0.2,3.1-0.2c-0.1-0.1-0.2-0.2-0.3-0.2c-0.7-0.7-1.5-1.5-2.2-2.2
|
||||
c-0.5-0.5-0.6-1.4-0.1-1.9c0.4-0.4,0.8-0.8,1.2-1.2c0.6-0.5,1.3-0.5,1.8,0c0.1,0.1,0.2,0.2,0.3,0.3c0.7,0.7,1.5,1.5,2.2,2.2
|
||||
c0,0,0.1,0,0.1,0c0.1-0.4,0.2-0.8,0.2-1.3C36.6,70.9,33.2,68.1,29.7,69.1z M17,60.6c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.8,0.7-0.8
|
||||
c0.4,0,0.8,0.4,0.8,0.7C17.7,60.3,17.4,60.6,17,60.6z M27.4,63c0.3,0.3,0.6,0.7,1,1c-0.7,0.7-1.4,1.4-2.1,2.1c-0.3-0.3-0.7-0.7-1-1
|
||||
C26,64.4,26.7,63.7,27.4,63z"/>
|
||||
<g>
|
||||
<path class="st9" d="M18.5,91.4v1.1H14v-6.4h4.4v1.1h-3.1v1.5H18v1h-2.7v1.7H18.5z"/>
|
||||
<path class="st9" d="M19.7,92.4v-6.4H22c0.5,0,1,0.1,1.4,0.3s0.7,0.4,1,0.7c0.3,0.3,0.5,0.6,0.6,1c0.1,0.4,0.2,0.8,0.2,1.2
|
||||
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.4,0.7-0.6,1c-0.3,0.3-0.6,0.5-1,0.6c-0.4,0.2-0.8,0.2-1.3,0.2H19.7z M23.9,89.2
|
||||
c0-0.3,0-0.6-0.1-0.8s-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.6-0.4c-0.2-0.1-0.5-0.2-0.8-0.2H21v4.2H22c0.3,0,0.6-0.1,0.8-0.2
|
||||
c0.2-0.1,0.4-0.3,0.6-0.4s0.3-0.4,0.4-0.7C23.9,89.8,23.9,89.5,23.9,89.2z"/>
|
||||
<path class="st9" d="M26.4,92.4v-6.4h1.2v6.4H26.4z"/>
|
||||
<path class="st9" d="M34,87.1h-2v5.3h-1.2v-5.3h-2v-1.1H34V87.1z"/>
|
||||
</g>
|
||||
<g class="st0">
|
||||
<g class="st2">
|
||||
<path class="st1" d="M50,146.3c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V146.3z"/>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M50,146.4c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V146.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st11" d="M21.9,121.5c-1.4,1.4-2.8,2.8-4.2,4.2c-0.3-0.3-0.7-0.7-1-1c1.4-1.4,2.8-2.8,4.2-4.2l-1.1-1.1
|
||||
c-1.6,1.6-3.2,3.2-4.9,4.8c-0.3,0.3-0.5,0.7-0.6,1.2c-0.2,1.3-0.4,2.6-0.6,4c0.1,0,0.2,0,0.3,0c1.3-0.3,2.5-0.5,3.8-0.8
|
||||
c0.2-0.1,0.5-0.2,0.7-0.4c1.7-1.7,3.4-3.4,5.1-5.1L21.9,121.5z"/>
|
||||
<path class="st11" d="M28.5,110.6c0.5-0.5,1.1-1.1,1.7-1.7c0.2-0.2,0.5-0.2,0.7,0c1,1,2,2,3,3c0.2,0.2,0.2,0.5,0,0.8
|
||||
c-0.6,0.6-1.2,1.2-1.7,1.7C31,113.2,29.8,111.9,28.5,110.6z"/>
|
||||
<path class="st11" d="M29.7,119.1c-0.3,0.1-0.4,0-0.6-0.2c-0.4-0.4-0.8-0.8-1.2-1.2c1-1,1.9-1.9,2.9-2.9c0.1-0.1,0.2-0.2,0.2-0.2
|
||||
c-1.3-1.3-2.5-2.5-3.8-3.9c-0.1,0.1-0.1,0.2-0.2,0.3c-1,1-1.9,1.9-2.9,2.9c-1.8-1.8-3.5-3.5-5.3-5.3c-0.1-0.1-0.3-0.3-0.4-0.4
|
||||
c-1-0.7-2.2-0.6-3,0.3c-0.8,0.9-0.7,2.2,0.1,3c2.6,2.6,5.3,5.3,7.9,7.9c0.9,0.9,1.7,1.7,2.6,2.6c0.1,0.1,0.2,0.2,0.1,0.4
|
||||
c-0.1,0.4-0.2,0.8-0.2,1.2c-0.2,2.5,1.4,4.7,3.9,5.4c1,0.3,2,0.2,3.1-0.2c-0.1-0.1-0.2-0.2-0.3-0.2c-0.7-0.7-1.5-1.5-2.2-2.2
|
||||
c-0.5-0.5-0.6-1.4-0.1-1.9c0.4-0.4,0.8-0.8,1.2-1.2c0.6-0.5,1.3-0.5,1.8,0c0.1,0.1,0.2,0.2,0.3,0.3c0.7,0.7,1.5,1.5,2.2,2.2
|
||||
c0,0,0.1,0,0.1,0c0.1-0.4,0.2-0.8,0.2-1.3C36.6,120.9,33.2,118.1,29.7,119.1z M17,110.6c-0.4,0-0.7-0.3-0.7-0.7
|
||||
c0-0.4,0.3-0.8,0.7-0.8c0.4,0,0.8,0.4,0.8,0.7C17.7,110.3,17.4,110.6,17,110.6z M27.4,113c0.3,0.3,0.6,0.7,1,1
|
||||
c-0.7,0.7-1.4,1.4-2.1,2.1c-0.3-0.3-0.7-0.7-1-1C26,114.4,26.7,113.7,27.4,113z"/>
|
||||
<g class="st1">
|
||||
<path class="st3" d="M50,46.6c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V46.6z"/>
|
||||
</g>
|
||||
<path d="M27.3,21.1v3.5c0,0.6-0.5,1.1-1.1,1.1H13c-0.6,0-1.1-0.5-1.1-1.1v-6.5c0-0.6,0.5-1.1,1.1-1.1h3.8c-0.1-0.4-0.3-0.9-0.3-1.3
|
||||
H13c-1.4,0-2.4,1.1-2.4,2.4v6.5c0,1.4,1.1,2.4,2.4,2.4h5.9v1.2h-3.4c-0.3,0-0.6,0.3-0.6,0.7c0,0.3,0.3,0.7,0.6,0.7h8.5
|
||||
c0.3,0,0.6-0.3,0.6-0.7c0-0.3-0.3-0.7-0.6-0.7h-3.7V27c-0.1,0-0.2,0-0.4,0h6.3c1.4,0,2.4-1.1,2.4-2.4v-4.4
|
||||
C28.2,20.5,27.8,20.8,27.3,21.1z"/>
|
||||
<path d="M35.7,19.8h-3.7c-0.9,0-1.6-0.9-2.1-1.7c-0.2-0.3-0.6-0.8-0.8-1c-0.2,0.1-0.6,0.6-0.8,0.9c-0.6,0.8-1.2,1.8-2.2,1.8h-3.5
|
||||
c-2.8,0-5-2.2-5-5v-2.3c0-2.8,2.3-5,5-5h13.1c2.8,0,5,2.2,5,5v2.3C40.8,17.6,38.5,19.8,35.7,19.8z M29.2,15.8c0.8,0,1.4,0.8,1.9,1.6
|
||||
c0.2,0.4,0.8,1.1,1,1.1h3.7c2,0,3.7-1.6,3.7-3.7v-2.3c0-2-1.7-3.7-3.7-3.7H22.7c-2,0-3.7,1.6-3.7,3.7v2.3c0,2,1.7,3.7,3.7,3.7h3.5
|
||||
c0.3,0,0.8-0.7,1.1-1.2C27.8,16.5,28.4,15.8,29.2,15.8C29.2,15.8,29.2,15.8,29.2,15.8z"/>
|
||||
<path d="M36.9,21.6c-0.2-0.1-0.4,0-0.6,0.1l-1.8,1.8l0.7,0.7l0.9-0.9c0,0,0.3,1.3-0.7,2.4c-1,1-2.3,0.6-2.3,0.6l0.8-0.8l-0.8-0.8
|
||||
l-1.7,1.7l0,0c0,0-0.1,0.1-0.1,0.2c-0.1,0.2,0,0.4,0.1,0.6l1.8,1.8l0.8-0.8l-0.9-0.9c0,0,1.7,0.3,3.1-1.1c1.3-1.3,1-3.1,1-3.1
|
||||
l0.8,0.8l0.8-0.8l-1.6-1.6C37.2,21.8,37,21.7,36.9,21.6z"/>
|
||||
<g>
|
||||
<path d="M10.3,37.9c0,0-0.1-0.1-0.2-0.2c-0.1-0.1-0.2-0.1-0.4-0.2c-0.2-0.1-0.3-0.1-0.5-0.2c-0.2,0-0.4-0.1-0.6-0.1
|
||||
c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.2,0.3,0.2s0.3,0.1,0.5,0.2
|
||||
c0.2,0.1,0.4,0.1,0.6,0.2c0.3,0.1,0.6,0.2,0.9,0.3c0.3,0.1,0.5,0.2,0.6,0.4c0.2,0.1,0.3,0.3,0.4,0.5c0.1,0.2,0.1,0.4,0.1,0.7
|
||||
c0,0.3-0.1,0.6-0.2,0.9c-0.1,0.2-0.3,0.4-0.5,0.6s-0.5,0.3-0.8,0.3c-0.3,0.1-0.6,0.1-0.9,0.1c-0.5,0-1-0.1-1.4-0.2S6.4,42.2,6,41.9
|
||||
l0.5-1.1c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0.1,0.3,0.2,0.5,0.3s0.4,0.2,0.6,0.2c0.2,0.1,0.5,0.1,0.7,0.1c0.7,0,1-0.2,1-0.7
|
||||
c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.3-0.1-0.5-0.2c-0.2-0.1-0.4-0.1-0.7-0.2c-0.3-0.1-0.6-0.2-0.8-0.3
|
||||
s-0.4-0.2-0.6-0.3c-0.2-0.1-0.3-0.3-0.3-0.5c-0.1-0.2-0.1-0.4-0.1-0.6c0-0.3,0.1-0.6,0.2-0.9c0.1-0.3,0.3-0.5,0.5-0.6
|
||||
s0.5-0.3,0.7-0.4c0.3-0.1,0.6-0.1,0.9-0.1c0.5,0,0.9,0.1,1.2,0.2c0.4,0.1,0.7,0.3,1,0.5L10.3,37.9z"/>
|
||||
<path d="M14.3,36.3h1.1l0.7,2.1l0.7-2.1H18L17,39.2l0.8,2l1.8-5h1.4l-2.6,6.4h-1L16.2,40l-1.1,2.7h-1l-2.6-6.4h1.3l1.8,5l0.8-2
|
||||
L14.3,36.3z"/>
|
||||
<path d="M21.8,42.6v-6.4h1.2v6.4H21.8z"/>
|
||||
<path d="M29.4,37.3h-2v5.3h-1.2v-5.3h-2v-1.1h5.3V37.3z"/>
|
||||
<path d="M30,39.4c0-0.4,0.1-0.8,0.2-1.2c0.1-0.4,0.3-0.7,0.6-1c0.3-0.3,0.6-0.5,1-0.7s0.8-0.3,1.3-0.3c0.6,0,1.1,0.1,1.5,0.4
|
||||
c0.4,0.3,0.7,0.6,0.9,1l-1,0.7c-0.1-0.2-0.2-0.3-0.3-0.5c-0.1-0.1-0.2-0.2-0.4-0.3c-0.1-0.1-0.3-0.1-0.4-0.2c-0.1,0-0.3,0-0.4,0
|
||||
c-0.3,0-0.6,0.1-0.8,0.2s-0.4,0.3-0.6,0.5c-0.1,0.2-0.3,0.4-0.3,0.7s-0.1,0.5-0.1,0.8c0,0.3,0,0.6,0.1,0.8c0.1,0.3,0.2,0.5,0.4,0.7
|
||||
c0.2,0.2,0.3,0.4,0.6,0.5c0.2,0.1,0.5,0.2,0.7,0.2c0.1,0,0.3,0,0.4-0.1c0.1,0,0.3-0.1,0.4-0.2c0.1-0.1,0.3-0.2,0.4-0.3
|
||||
c0.1-0.1,0.2-0.3,0.3-0.4l1,0.6c-0.1,0.2-0.2,0.5-0.4,0.6c-0.2,0.2-0.4,0.3-0.6,0.5c-0.2,0.1-0.5,0.2-0.7,0.3
|
||||
c-0.3,0.1-0.5,0.1-0.8,0.1c-0.4,0-0.9-0.1-1.2-0.3c-0.4-0.2-0.7-0.4-1-0.8c-0.3-0.3-0.5-0.7-0.6-1.1C30.1,40.2,30,39.8,30,39.4z"/>
|
||||
<path d="M42,36.3v6.4h-1.2v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6h2.9v-2.6H42z"/>
|
||||
</g>
|
||||
<g class="st1">
|
||||
<path class="st2" d="M50,96.6c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V96.6z"/>
|
||||
</g>
|
||||
<path class="st4" d="M27.3,71.1v3.5c0,0.6-0.5,1.1-1.1,1.1H13c-0.6,0-1.1-0.5-1.1-1.1v-6.5c0-0.6,0.5-1.1,1.1-1.1h3.8
|
||||
c-0.1-0.4-0.3-0.9-0.3-1.3H13c-1.4,0-2.4,1.1-2.4,2.4v6.5c0,1.4,1.1,2.4,2.4,2.4h5.9v1.2h-3.4c-0.3,0-0.6,0.3-0.6,0.7
|
||||
c0,0.3,0.3,0.7,0.6,0.7h8.5c0.3,0,0.6-0.3,0.6-0.7c0-0.3-0.3-0.7-0.6-0.7h-3.7V77c-0.1,0-0.2,0-0.4,0h6.3c1.4,0,2.4-1.1,2.4-2.4
|
||||
v-4.4C28.2,70.5,27.8,70.8,27.3,71.1z"/>
|
||||
<path class="st4" d="M35.7,69.8h-3.7c-0.9,0-1.6-0.9-2.1-1.7c-0.2-0.3-0.6-0.8-0.8-1c-0.2,0.1-0.6,0.6-0.8,0.9
|
||||
c-0.6,0.8-1.2,1.8-2.2,1.8h-3.5c-2.8,0-5-2.2-5-5v-2.3c0-2.8,2.3-5,5-5h13.1c2.8,0,5,2.2,5,5v2.3C40.8,67.6,38.5,69.8,35.7,69.8z
|
||||
M29.2,65.8c0.8,0,1.4,0.8,1.9,1.6c0.2,0.4,0.8,1.1,1,1.1h3.7c2,0,3.7-1.6,3.7-3.7v-2.3c0-2-1.7-3.7-3.7-3.7H22.7
|
||||
c-2,0-3.7,1.6-3.7,3.7v2.3c0,2,1.7,3.7,3.7,3.7h3.5c0.3,0,0.8-0.7,1.1-1.2C27.8,66.5,28.4,65.8,29.2,65.8
|
||||
C29.2,65.8,29.2,65.8,29.2,65.8z"/>
|
||||
<path class="st4" d="M36.9,71.6c-0.2-0.1-0.4,0-0.6,0.1l-1.8,1.8l0.7,0.7l0.9-0.9c0,0,0.3,1.3-0.7,2.4c-1,1-2.3,0.6-2.3,0.6l0.8-0.8
|
||||
l-0.8-0.8l-1.7,1.7l0,0c0,0-0.1,0.1-0.1,0.2c-0.1,0.2,0,0.4,0.1,0.6l1.8,1.8l0.8-0.8l-0.9-0.9c0,0,1.7,0.3,3.1-1.1
|
||||
c1.3-1.3,1-3.1,1-3.1l0.8,0.8l0.8-0.8l-1.6-1.6C37.2,71.8,37,71.7,36.9,71.6z"/>
|
||||
<g>
|
||||
<path class="st4" d="M10.3,87.9c0,0-0.1-0.1-0.2-0.2c-0.1-0.1-0.2-0.1-0.4-0.2s-0.3-0.1-0.5-0.2c-0.2,0-0.4-0.1-0.6-0.1
|
||||
c-0.3,0-0.6,0.1-0.8,0.2S7.6,87.8,7.6,88c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.2,0.3,0.2c0.1,0.1,0.3,0.1,0.5,0.2
|
||||
c0.2,0.1,0.4,0.1,0.6,0.2c0.3,0.1,0.6,0.2,0.9,0.3s0.5,0.2,0.6,0.4c0.2,0.1,0.3,0.3,0.4,0.5c0.1,0.2,0.1,0.4,0.1,0.7
|
||||
c0,0.3-0.1,0.6-0.2,0.9c-0.1,0.2-0.3,0.4-0.5,0.6c-0.2,0.2-0.5,0.3-0.8,0.3c-0.3,0.1-0.6,0.1-0.9,0.1c-0.5,0-1-0.1-1.4-0.2
|
||||
c-0.5-0.1-0.9-0.3-1.3-0.6l0.5-1.1c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0.1,0.3,0.2,0.5,0.3s0.4,0.2,0.6,0.2c0.2,0.1,0.5,0.1,0.7,0.1
|
||||
c0.7,0,1-0.2,1-0.7c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.3-0.1-0.5-0.2c-0.2-0.1-0.4-0.1-0.7-0.2
|
||||
c-0.3-0.1-0.6-0.2-0.8-0.3c-0.2-0.1-0.4-0.2-0.6-0.3S6.5,89,6.4,88.8c-0.1-0.2-0.1-0.4-0.1-0.6c0-0.3,0.1-0.6,0.2-0.9
|
||||
c0.1-0.3,0.3-0.5,0.5-0.6s0.5-0.3,0.7-0.4s0.6-0.1,0.9-0.1c0.5,0,0.9,0.1,1.2,0.2s0.7,0.3,1,0.5L10.3,87.9z"/>
|
||||
<path class="st4" d="M14.3,86.3h1.1l0.7,2.1l0.7-2.1H18L17,89.2l0.8,2l1.8-5h1.4l-2.6,6.4h-1L16.2,90l-1.1,2.7h-1l-2.6-6.4h1.3
|
||||
l1.8,5l0.8-2L14.3,86.3z"/>
|
||||
<path class="st4" d="M21.8,92.6v-6.4h1.2v6.4H21.8z"/>
|
||||
<path class="st4" d="M29.4,87.3h-2v5.3h-1.2v-5.3h-2v-1.1h5.3V87.3z"/>
|
||||
<path class="st4" d="M30,89.4c0-0.4,0.1-0.8,0.2-1.2c0.1-0.4,0.3-0.7,0.6-1c0.3-0.3,0.6-0.5,1-0.7c0.4-0.2,0.8-0.3,1.3-0.3
|
||||
c0.6,0,1.1,0.1,1.5,0.4s0.7,0.6,0.9,1l-1,0.7c-0.1-0.2-0.2-0.3-0.3-0.5c-0.1-0.1-0.2-0.2-0.4-0.3s-0.3-0.1-0.4-0.2
|
||||
c-0.1,0-0.3,0-0.4,0c-0.3,0-0.6,0.1-0.8,0.2s-0.4,0.3-0.6,0.5c-0.1,0.2-0.3,0.4-0.3,0.7s-0.1,0.5-0.1,0.8c0,0.3,0,0.6,0.1,0.8
|
||||
c0.1,0.3,0.2,0.5,0.4,0.7c0.2,0.2,0.3,0.4,0.6,0.5c0.2,0.1,0.5,0.2,0.7,0.2c0.1,0,0.3,0,0.4-0.1c0.1,0,0.3-0.1,0.4-0.2
|
||||
c0.1-0.1,0.3-0.2,0.4-0.3c0.1-0.1,0.2-0.3,0.3-0.4l1,0.6c-0.1,0.2-0.2,0.5-0.4,0.6c-0.2,0.2-0.4,0.3-0.6,0.5
|
||||
c-0.2,0.1-0.5,0.2-0.7,0.3c-0.3,0.1-0.5,0.1-0.8,0.1c-0.4,0-0.9-0.1-1.2-0.3c-0.4-0.2-0.7-0.4-1-0.8c-0.3-0.3-0.5-0.7-0.6-1.1
|
||||
C30.1,90.2,30,89.8,30,89.4z"/>
|
||||
<path class="st4" d="M42,86.2v6.4h-1.2v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6h2.9v-2.6H42z"/>
|
||||
</g>
|
||||
<path class="st5" d="M27.3,121.1v3.5c0,0.6-0.5,1.1-1.1,1.1H13c-0.6,0-1.1-0.5-1.1-1.1v-6.5c0-0.6,0.5-1.1,1.1-1.1h3.8
|
||||
c-0.1-0.4-0.3-0.9-0.3-1.3H13c-1.4,0-2.4,1.1-2.4,2.4v6.5c0,1.4,1.1,2.4,2.4,2.4h5.9v1.2h-3.4c-0.3,0-0.6,0.3-0.6,0.7
|
||||
c0,0.3,0.3,0.7,0.6,0.7h8.5c0.3,0,0.6-0.3,0.6-0.7c0-0.3-0.3-0.7-0.6-0.7h-3.7V127c-0.1,0-0.2,0-0.4,0h6.3c1.4,0,2.4-1.1,2.4-2.4
|
||||
v-4.4C28.2,120.5,27.8,120.8,27.3,121.1z"/>
|
||||
<path class="st5" d="M35.7,119.8h-3.7c-0.9,0-1.6-0.9-2.1-1.7c-0.2-0.3-0.6-0.8-0.8-1c-0.2,0.1-0.6,0.6-0.8,0.9
|
||||
c-0.6,0.8-1.2,1.8-2.2,1.8h-3.5c-2.8,0-5-2.2-5-5v-2.3c0-2.8,2.3-5,5-5h13.1c2.8,0,5,2.2,5,5v2.3C40.8,117.6,38.5,119.8,35.7,119.8z
|
||||
M29.2,115.8c0.8,0,1.4,0.8,1.9,1.6c0.2,0.4,0.8,1.1,1,1.1h3.7c2,0,3.7-1.6,3.7-3.7v-2.3c0-2-1.7-3.7-3.7-3.7H22.7
|
||||
c-2,0-3.7,1.6-3.7,3.7v2.3c0,2,1.7,3.7,3.7,3.7h3.5c0.3,0,0.8-0.7,1.1-1.2C27.8,116.5,28.4,115.8,29.2,115.8
|
||||
C29.2,115.8,29.2,115.8,29.2,115.8z"/>
|
||||
<path class="st5" d="M36.9,121.6c-0.2-0.1-0.4,0-0.6,0.1l-1.8,1.8l0.7,0.7l0.9-0.9c0,0,0.3,1.3-0.7,2.4c-1,1-2.3,0.6-2.3,0.6
|
||||
l0.8-0.8l-0.8-0.8l-1.7,1.7l0,0c0,0-0.1,0.1-0.1,0.2c-0.1,0.2,0,0.4,0.1,0.6l1.8,1.8l0.8-0.8l-0.9-0.9c0,0,1.7,0.3,3.1-1.1
|
||||
c1.3-1.3,1-3.1,1-3.1l0.8,0.8l0.8-0.8l-1.6-1.6C37.2,121.8,37,121.7,36.9,121.6z"/>
|
||||
<g class="st0">
|
||||
<path class="st9" d="M18.5,141.4v1.1H14v-6.4h4.4v1.1h-3.1v1.5H18v1h-2.7v1.7H18.5z"/>
|
||||
<path class="st9" d="M19.7,142.4v-6.4H22c0.5,0,1,0.1,1.4,0.3s0.7,0.4,1,0.7c0.3,0.3,0.5,0.6,0.6,1c0.1,0.4,0.2,0.8,0.2,1.2
|
||||
c0,0.5-0.1,0.9-0.2,1.3c-0.1,0.4-0.4,0.7-0.6,1c-0.3,0.3-0.6,0.5-1,0.6c-0.4,0.2-0.8,0.2-1.3,0.2H19.7z M23.9,139.2
|
||||
c0-0.3,0-0.6-0.1-0.8s-0.2-0.5-0.4-0.7c-0.2-0.2-0.4-0.3-0.6-0.4c-0.2-0.1-0.5-0.2-0.8-0.2H21v4.2H22c0.3,0,0.6-0.1,0.8-0.2
|
||||
c0.2-0.1,0.4-0.3,0.6-0.4s0.3-0.4,0.4-0.7C23.9,139.8,23.9,139.5,23.9,139.2z"/>
|
||||
<path class="st9" d="M26.4,142.4v-6.4h1.2v6.4H26.4z"/>
|
||||
<path class="st9" d="M34,137.1h-2v5.3h-1.2v-5.3h-2v-1.1H34V137.1z"/>
|
||||
<path class="st4" d="M10.3,137.9c0,0-0.1-0.1-0.2-0.2c-0.1-0.1-0.2-0.1-0.4-0.2s-0.3-0.1-0.5-0.2c-0.2,0-0.4-0.1-0.6-0.1
|
||||
c-0.3,0-0.6,0.1-0.8,0.2s-0.3,0.3-0.3,0.5c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.2,0.3,0.2c0.1,0.1,0.3,0.1,0.5,0.2
|
||||
c0.2,0.1,0.4,0.1,0.6,0.2c0.3,0.1,0.6,0.2,0.9,0.3s0.5,0.2,0.6,0.4c0.2,0.1,0.3,0.3,0.4,0.5c0.1,0.2,0.1,0.4,0.1,0.7
|
||||
c0,0.3-0.1,0.6-0.2,0.9c-0.1,0.2-0.3,0.4-0.5,0.6c-0.2,0.2-0.5,0.3-0.8,0.3c-0.3,0.1-0.6,0.1-0.9,0.1c-0.5,0-1-0.1-1.4-0.2
|
||||
c-0.5-0.1-0.9-0.3-1.3-0.6l0.5-1.1c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0.1,0.3,0.2,0.5,0.3s0.4,0.2,0.6,0.2c0.2,0.1,0.5,0.1,0.7,0.1
|
||||
c0.7,0,1-0.2,1-0.7c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.3-0.1-0.5-0.2c-0.2-0.1-0.4-0.1-0.7-0.2
|
||||
c-0.3-0.1-0.6-0.2-0.8-0.3c-0.2-0.1-0.4-0.2-0.6-0.3s-0.3-0.3-0.3-0.5c-0.1-0.2-0.1-0.4-0.1-0.6c0-0.3,0.1-0.6,0.2-0.9
|
||||
c0.1-0.3,0.3-0.5,0.5-0.6s0.5-0.3,0.7-0.4s0.6-0.1,0.9-0.1c0.5,0,0.9,0.1,1.2,0.2s0.7,0.3,1,0.5L10.3,137.9z"/>
|
||||
<path class="st4" d="M14.3,136.3h1.1l0.7,2.1l0.7-2.1H18l-1.1,2.9l0.8,2l1.8-5h1.4l-2.6,6.4h-1l-1.1-2.7l-1.1,2.7h-1l-2.6-6.4h1.3
|
||||
l1.8,5l0.8-2L14.3,136.3z"/>
|
||||
<path class="st4" d="M21.8,142.6v-6.4h1.2v6.4H21.8z"/>
|
||||
<path class="st4" d="M29.4,137.3h-2v5.3h-1.2v-5.3h-2v-1.1h5.3V137.3z"/>
|
||||
<path class="st4" d="M30,139.4c0-0.4,0.1-0.8,0.2-1.2c0.1-0.4,0.3-0.7,0.6-1c0.3-0.3,0.6-0.5,1-0.7c0.4-0.2,0.8-0.3,1.3-0.3
|
||||
c0.6,0,1.1,0.1,1.5,0.4s0.7,0.6,0.9,1l-1,0.7c-0.1-0.2-0.2-0.3-0.3-0.5c-0.1-0.1-0.2-0.2-0.4-0.3s-0.3-0.1-0.4-0.2
|
||||
c-0.1,0-0.3,0-0.4,0c-0.3,0-0.6,0.1-0.8,0.2s-0.4,0.3-0.6,0.5c-0.1,0.2-0.3,0.4-0.3,0.7s-0.1,0.5-0.1,0.8c0,0.3,0,0.6,0.1,0.8
|
||||
c0.1,0.3,0.2,0.5,0.4,0.7c0.2,0.2,0.3,0.4,0.6,0.5c0.2,0.1,0.5,0.2,0.7,0.2c0.1,0,0.3,0,0.4-0.1c0.1,0,0.3-0.1,0.4-0.2
|
||||
c0.1-0.1,0.3-0.2,0.4-0.3c0.1-0.1,0.2-0.3,0.3-0.4l1,0.6c-0.1,0.2-0.2,0.5-0.4,0.6c-0.2,0.2-0.4,0.3-0.6,0.5
|
||||
c-0.2,0.1-0.5,0.2-0.7,0.3c-0.3,0.1-0.5,0.1-0.8,0.1c-0.4,0-0.9-0.1-1.2-0.3c-0.4-0.2-0.7-0.4-1-0.8c-0.3-0.3-0.5-0.7-0.6-1.1
|
||||
C30.1,140.2,30,139.8,30,139.4z"/>
|
||||
<path class="st4" d="M42,136.2v6.4h-1.2v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6h2.9v-2.6H42z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 10 KiB |
|
@ -92,6 +92,7 @@ var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new posit
|
|||
// other constants
|
||||
//
|
||||
|
||||
var HOTSPOT_DRAW_DISTANCE = 10;
|
||||
var RIGHT_HAND = 1;
|
||||
var LEFT_HAND = 0;
|
||||
|
||||
|
@ -179,47 +180,85 @@ var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic";
|
|||
var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC;
|
||||
var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC;
|
||||
|
||||
function stateToName(state) {
|
||||
switch (state) {
|
||||
case STATE_OFF:
|
||||
return "off";
|
||||
case STATE_SEARCHING:
|
||||
return "searching";
|
||||
case STATE_HOLD_SEARCHING:
|
||||
return "hold_searching";
|
||||
case STATE_DISTANCE_HOLDING:
|
||||
return "distance_holding";
|
||||
case STATE_CONTINUE_DISTANCE_HOLDING:
|
||||
return "continue_distance_holding";
|
||||
case STATE_NEAR_GRABBING:
|
||||
return "near_grabbing";
|
||||
case STATE_CONTINUE_NEAR_GRABBING:
|
||||
return "continue_near_grabbing";
|
||||
case STATE_NEAR_TRIGGER:
|
||||
return "near_trigger";
|
||||
case STATE_CONTINUE_NEAR_TRIGGER:
|
||||
return "continue_near_trigger";
|
||||
case STATE_FAR_TRIGGER:
|
||||
return "far_trigger";
|
||||
case STATE_CONTINUE_FAR_TRIGGER:
|
||||
return "continue_far_trigger";
|
||||
case STATE_RELEASE:
|
||||
return "release";
|
||||
case STATE_EQUIP:
|
||||
return "equip";
|
||||
case STATE_HOLD:
|
||||
return "hold";
|
||||
case STATE_CONTINUE_HOLD:
|
||||
return "continue_hold";
|
||||
case STATE_CONTINUE_EQUIP:
|
||||
return "continue_equip";
|
||||
case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE:
|
||||
return "waiting_for_equip_thumb_release";
|
||||
case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE:
|
||||
return "waiting_for_release_thumb_release";
|
||||
}
|
||||
var CONTROLLER_STATE_MACHINE = {};
|
||||
|
||||
return "unknown";
|
||||
CONTROLLER_STATE_MACHINE[STATE_OFF] = {
|
||||
name: "off",
|
||||
updateMethod: "off"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_SEARCHING] = {
|
||||
name: "searching",
|
||||
updateMethod: "search",
|
||||
enterMethod: "searchEnter",
|
||||
exitMethod: "searchExit"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_HOLD_SEARCHING] = {
|
||||
name: "hold_searching",
|
||||
updateMethod: "search"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_DISTANCE_HOLDING] = {
|
||||
name: "distance_holding",
|
||||
updateMethod: "distanceHolding"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_DISTANCE_HOLDING] = {
|
||||
name: "continue_distance_holding",
|
||||
updateMethod: "continueDistanceHolding"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_NEAR_GRABBING] = {
|
||||
name: "near_grabbing",
|
||||
updateMethod: "nearGrabbing"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_EQUIP] = {
|
||||
name: "equip",
|
||||
updateMethod: "nearGrabbing"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_HOLD] = {
|
||||
name: "hold",
|
||||
updateMethod: "nearGrabbing"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_NEAR_GRABBING] = {
|
||||
name: "continue_near_grabbing",
|
||||
updateMethod: "continueNearGrabbing"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_HOLD] = {
|
||||
name: "continue_hold",
|
||||
updateMethod: "continueNearGrabbing"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_EQUIP] = {
|
||||
name: "continue_equip",
|
||||
updateMethod: "continueNearGrabbing"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_NEAR_TRIGGER] = {
|
||||
name: "near_trigger",
|
||||
updateMethod: "nearTrigger"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_NEAR_TRIGGER] = {
|
||||
name: "continue_near_trigger",
|
||||
updateMethod: "continueNearTrigger"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_FAR_TRIGGER] = {
|
||||
name: "far_trigger",
|
||||
updateMethod: "farTrigger"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_CONTINUE_FAR_TRIGGER] = {
|
||||
name: "continue_far_trigger",
|
||||
updateMethod: "continueFarTrigger"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_RELEASE] = {
|
||||
name: "release",
|
||||
updateMethod: "release"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_WAITING_FOR_EQUIP_THUMB_RELEASE] = {
|
||||
name: "waiting_for_equip_thumb_release",
|
||||
updateMethod: "waitingForEquipThumbRelease"
|
||||
};
|
||||
CONTROLLER_STATE_MACHINE[STATE_WAITING_FOR_RELEASE_THUMB_RELEASE] = {
|
||||
name: "waiting_for_release_thumb_release",
|
||||
updateMethod: "waitingForReleaseThumbRelease"
|
||||
};
|
||||
|
||||
function stateToName(state) {
|
||||
return CONTROLLER_STATE_MACHINE[state] ? CONTROLLER_STATE_MACHINE[state].name : "???";
|
||||
}
|
||||
|
||||
function getTag() {
|
||||
|
@ -249,6 +288,14 @@ function entityIsGrabbedByOther(entityID) {
|
|||
return false;
|
||||
}
|
||||
|
||||
function propsArePhysical(props) {
|
||||
if (!props.dynamic) {
|
||||
return false;
|
||||
}
|
||||
var isPhysical = (props.shapeType && props.shapeType != 'none');
|
||||
return isPhysical;
|
||||
}
|
||||
|
||||
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
|
||||
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
|
||||
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
|
||||
|
@ -314,55 +361,22 @@ function MyController(hand) {
|
|||
this.update = function() {
|
||||
|
||||
this.updateSmoothedTrigger();
|
||||
|
||||
if (isIn2DMode()) {
|
||||
_this.turnOffVisualizations();
|
||||
return;
|
||||
}
|
||||
switch (this.state) {
|
||||
case STATE_OFF:
|
||||
this.off();
|
||||
break;
|
||||
case STATE_SEARCHING:
|
||||
case STATE_HOLD_SEARCHING:
|
||||
this.search();
|
||||
break;
|
||||
case STATE_DISTANCE_HOLDING:
|
||||
this.distanceHolding();
|
||||
break;
|
||||
case STATE_CONTINUE_DISTANCE_HOLDING:
|
||||
this.continueDistanceHolding();
|
||||
break;
|
||||
case STATE_NEAR_GRABBING:
|
||||
case STATE_EQUIP:
|
||||
case STATE_HOLD:
|
||||
this.nearGrabbing();
|
||||
break;
|
||||
case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE:
|
||||
this.waitingForEquipThumbRelease();
|
||||
break;
|
||||
case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE:
|
||||
this.waitingForReleaseThumbRelease();
|
||||
break;
|
||||
case STATE_CONTINUE_NEAR_GRABBING:
|
||||
case STATE_CONTINUE_HOLD:
|
||||
case STATE_CONTINUE_EQUIP:
|
||||
this.continueNearGrabbing();
|
||||
break;
|
||||
case STATE_NEAR_TRIGGER:
|
||||
this.nearTrigger();
|
||||
break;
|
||||
case STATE_CONTINUE_NEAR_TRIGGER:
|
||||
this.continueNearTrigger();
|
||||
break;
|
||||
case STATE_FAR_TRIGGER:
|
||||
this.farTrigger();
|
||||
break;
|
||||
case STATE_CONTINUE_FAR_TRIGGER:
|
||||
this.continueFarTrigger();
|
||||
break;
|
||||
case STATE_RELEASE:
|
||||
this.release();
|
||||
break;
|
||||
|
||||
if (CONTROLLER_STATE_MACHINE[this.state]) {
|
||||
var updateMethodName = CONTROLLER_STATE_MACHINE[this.state].updateMethod;
|
||||
var updateMethod = this[updateMethodName];
|
||||
if (updateMethod) {
|
||||
updateMethod.call(this);
|
||||
} else {
|
||||
print("WARNING: could not find updateMethod for state " + stateToName(this.state));
|
||||
}
|
||||
} else {
|
||||
print("WARNING: could not find state " + this.state + " in state machine");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -374,9 +388,33 @@ function MyController(hand) {
|
|||
this.setState = function(newState) {
|
||||
this.grabSphereOff();
|
||||
if (WANT_DEBUG || WANT_DEBUG_STATE) {
|
||||
print("STATE (" + this.hand + "): " + stateToName(this.state) + " --> " +
|
||||
stateToName(newState) + ", hand: " + this.hand);
|
||||
var oldStateName = stateToName(this.state);
|
||||
var newStateName = stateToName(newState);
|
||||
print("STATE (" + this.hand + "): " + newStateName + " <-- " + oldStateName);
|
||||
}
|
||||
|
||||
// exit the old state
|
||||
if (CONTROLLER_STATE_MACHINE[this.state]) {
|
||||
var exitMethodName = CONTROLLER_STATE_MACHINE[this.state].exitMethod;
|
||||
var exitMethod = this[exitMethodName];
|
||||
if (exitMethod) {
|
||||
exitMethod.call(this);
|
||||
}
|
||||
} else {
|
||||
print("WARNING: could not find state " + this.state + " in state machine");
|
||||
}
|
||||
|
||||
// enter the new state
|
||||
if (CONTROLLER_STATE_MACHINE[newState]) {
|
||||
var enterMethodName = CONTROLLER_STATE_MACHINE[newState].enterMethod;
|
||||
var enterMethod = this[enterMethodName];
|
||||
if (enterMethod) {
|
||||
enterMethod.call(this);
|
||||
}
|
||||
} else {
|
||||
print("WARNING: could not find newState " + newState + " in state machine");
|
||||
}
|
||||
|
||||
this.state = newState;
|
||||
};
|
||||
|
||||
|
@ -759,14 +797,6 @@ function MyController(hand) {
|
|||
}
|
||||
};
|
||||
|
||||
this.propsArePhysical = function(props) {
|
||||
if (!props.dynamic) {
|
||||
return false;
|
||||
}
|
||||
var isPhysical = (props.shapeType && props.shapeType != 'none');
|
||||
return isPhysical;
|
||||
}
|
||||
|
||||
this.turnOffVisualizations = function() {
|
||||
if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) {
|
||||
this.lineOff();
|
||||
|
@ -852,6 +882,56 @@ function MyController(hand) {
|
|||
}
|
||||
};
|
||||
|
||||
this.searchEnter = function() {
|
||||
this.equipHotspotOverlays = [];
|
||||
|
||||
// find entities near the avatar that might be equipable.
|
||||
var entities = Entities.findEntities(MyAvatar.position, HOTSPOT_DRAW_DISTANCE);
|
||||
var i, l = entities.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
|
||||
// is this entity equipable?
|
||||
var grabData = getEntityCustomData(GRABBABLE_DATA_KEY, entities[i], undefined);
|
||||
var grabProps = Entities.getEntityProperties(entities[i], GRABBABLE_PROPERTIES);
|
||||
if (grabData) {
|
||||
|
||||
var hotspotPos = grabProps.position;
|
||||
|
||||
// does this entity have an attach point?
|
||||
var wearableData = getEntityCustomData("wearable", entities[i], undefined);
|
||||
if (wearableData) {
|
||||
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
|
||||
if (wearableData[handJointName]) {
|
||||
// draw the hotspot around the attach point.
|
||||
hotspotPos = wearableData[handJointName][0];
|
||||
}
|
||||
}
|
||||
|
||||
// draw a hotspot!
|
||||
this.equipHotspotOverlays.push(Overlays.addOverlay("sphere", {
|
||||
position: hotspotPos,
|
||||
size: 0.2,
|
||||
color: { red: 90, green: 255, blue: 90 },
|
||||
alpha: 0.7,
|
||||
solid: true,
|
||||
visible: true,
|
||||
ignoreRayIntersection: false,
|
||||
drawInFront: false
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.searchExit = function() {
|
||||
|
||||
// delete all equip hotspots
|
||||
var i, l = this.equipHotspotOverlays.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
Overlays.deleteOverlay(this.equipHotspotOverlays[i]);
|
||||
}
|
||||
this.equipHotspotOverlays = [];
|
||||
};
|
||||
|
||||
this.search = function() {
|
||||
this.grabbedEntity = null;
|
||||
this.isInitialGrab = false;
|
||||
|
@ -863,6 +943,7 @@ function MyController(hand) {
|
|||
this.setState(STATE_RELEASE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state == STATE_HOLD_SEARCHING && this.bumperReleased()) {
|
||||
this.setState(STATE_RELEASE);
|
||||
return;
|
||||
|
@ -951,7 +1032,7 @@ function MyController(hand) {
|
|||
var propsForCandidate = Entities.getEntityProperties(candidateEntities[i], GRABBABLE_PROPERTIES);
|
||||
var near = (nearPickedCandidateEntities.indexOf(candidateEntities[i]) >= 0);
|
||||
|
||||
var isPhysical = this.propsArePhysical(propsForCandidate);
|
||||
var isPhysical = propsArePhysical(propsForCandidate);
|
||||
var grabbable;
|
||||
if (isPhysical) {
|
||||
// physical things default to grabbable
|
||||
|
@ -1030,7 +1111,7 @@ function MyController(hand) {
|
|||
if ((this.grabbedEntity !== null) && (this.triggerSmoothedGrab() || this.bumperSqueezed())) {
|
||||
// We are squeezing enough to grab, and we've found an entity that we'll try to do something with.
|
||||
var near = (nearPickedCandidateEntities.indexOf(this.grabbedEntity) >= 0) || minDistance <= NEAR_PICK_MAX_DISTANCE;
|
||||
var isPhysical = this.propsArePhysical(props);
|
||||
var isPhysical = propsArePhysical(props);
|
||||
|
||||
// near or far trigger
|
||||
if (grabbableData.wantsTrigger) {
|
||||
|
@ -1462,7 +1543,7 @@ function MyController(hand) {
|
|||
}
|
||||
}
|
||||
|
||||
var isPhysical = this.propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity);
|
||||
var isPhysical = propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity);
|
||||
if (isPhysical && this.state == STATE_NEAR_GRABBING) {
|
||||
// grab entity via action
|
||||
if (!this.setupHoldAction()) {
|
||||
|
@ -1879,7 +1960,7 @@ function MyController(hand) {
|
|||
var forceVelocity = false;
|
||||
|
||||
var doSetVelocity = false;
|
||||
if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && this.propsArePhysical(props)) {
|
||||
if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && propsArePhysical(props)) {
|
||||
// TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up
|
||||
// props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that
|
||||
// is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab
|
||||
|
|
|
@ -181,7 +181,7 @@ var toolBar = (function() {
|
|||
function initialize() {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.edit.toolbar", function(windowDimensions, toolbar) {
|
||||
return {
|
||||
x: windowDimensions.x / 2,
|
||||
x: (windowDimensions.x / 2) + (Tool.IMAGE_WIDTH * 2),
|
||||
y: windowDimensions.y
|
||||
};
|
||||
}, {
|
||||
|
|
|
@ -60,7 +60,7 @@ var toolBar = (function() {
|
|||
function initialize() {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.examples.toolbar", function(windowDimensions, toolbar) {
|
||||
return {
|
||||
x: windowDimensions.x / 2,
|
||||
x: (windowDimensions.x / 2) + (Tool.IMAGE_WIDTH * 2),
|
||||
y: windowDimensions.y
|
||||
};
|
||||
}, {
|
||||
|
@ -135,4 +135,4 @@ var toolBar = (function() {
|
|||
}());
|
||||
|
||||
Controller.mousePressEvent.connect(toolBar.mousePressEvent)
|
||||
Script.scriptEnding.connect(toolBar.cleanup);
|
||||
Script.scriptEnding.connect(toolBar.cleanup);
|
||||
|
|
|
@ -13,7 +13,7 @@ Script.include("libraries/toolBars.js");
|
|||
|
||||
function initialPosition(windowDimensions, toolbar) {
|
||||
return {
|
||||
x: windowDimensions.x / 2 - Tool.IMAGE_WIDTH,
|
||||
x: (windowDimensions.x / 2) - (Tool.IMAGE_WIDTH * 1),
|
||||
y: windowDimensions.y
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ var desktopMenuItemName = "Desktop";
|
|||
|
||||
function initialPosition(windowDimensions, toolbar) {
|
||||
return {
|
||||
x: windowDimensions.x / 2 + (2 * Tool.IMAGE_WIDTH),
|
||||
x: (windowDimensions.x / 2) - (Tool.IMAGE_WIDTH * 2.5),
|
||||
y: windowDimensions.y
|
||||
};
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ ApplicationWindow {
|
|||
|
||||
Button {
|
||||
text: "toggle desktop"
|
||||
onClicked: desktop.toggleVisible()
|
||||
onClicked: desktop.togglePinned()
|
||||
}
|
||||
|
||||
// Error alerts
|
||||
|
|
Loading…
Reference in a new issue