mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-23 15:24:07 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into avatarBandwidthBudgetImprovements
This commit is contained in:
commit
598e79f697
34 changed files with 1500 additions and 553 deletions
|
@ -40,6 +40,7 @@ module.exports = {
|
||||||
"Settings": false,
|
"Settings": false,
|
||||||
"SoundCache": false,
|
"SoundCache": false,
|
||||||
"Stats": false,
|
"Stats": false,
|
||||||
|
"Tablet": false,
|
||||||
"TextureCache": false,
|
"TextureCache": false,
|
||||||
"Toolbars": false,
|
"Toolbars": false,
|
||||||
"Uuid": false,
|
"Uuid": false,
|
||||||
|
@ -61,7 +62,7 @@ module.exports = {
|
||||||
"eqeqeq": ["error", "always"],
|
"eqeqeq": ["error", "always"],
|
||||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||||
"keyword-spacing": ["error", { "before": true, "after": true }],
|
"keyword-spacing": ["error", { "before": true, "after": true }],
|
||||||
"max-len": ["error", 128, 4],
|
"max-len": ["error", 192, 4],
|
||||||
"new-cap": ["error"],
|
"new-cap": ["error"],
|
||||||
"no-floating-decimal": ["error"],
|
"no-floating-decimal": ["error"],
|
||||||
//"no-magic-numbers": ["error", { "ignore": [0, 1], "ignoreArrayIndexes": true }],
|
//"no-magic-numbers": ["error", { "ignore": [0, 1], "ignoreArrayIndexes": true }],
|
||||||
|
|
48
interface/resources/icons/tablet-icons/blank.svg
Normal file
48
interface/resources/icons/tablet-icons/blank.svg
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 50 50"
|
||||||
|
style="enable-background:new 0 0 50 50;"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg2"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="blank.svg"><metadata
|
||||||
|
id="metadata36"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs34" /><sodipodi:namedview
|
||||||
|
pagecolor="#ff4900"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1149"
|
||||||
|
inkscape:window-height="801"
|
||||||
|
id="namedview32"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="4.72"
|
||||||
|
inkscape:cx="25"
|
||||||
|
inkscape:cy="25"
|
||||||
|
inkscape:window-x="1336"
|
||||||
|
inkscape:window-y="519"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg2" /><style
|
||||||
|
type="text/css"
|
||||||
|
id="style4">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style><g
|
||||||
|
id="Layer_2" /></svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,81 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 50 200.1"
|
||||||
|
style="enable-background:new 0 0 50 200.1;"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="empty-toolbar-button.svg"><metadata
|
||||||
|
id="metadata116"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs114" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1574"
|
||||||
|
inkscape:window-height="1234"
|
||||||
|
id="namedview112"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="4.717641"
|
||||||
|
inkscape:cx="-13.634838"
|
||||||
|
inkscape:cy="131.18797"
|
||||||
|
inkscape:window-x="152"
|
||||||
|
inkscape:window-y="117"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="Layer_1" /><style
|
||||||
|
type="text/css"
|
||||||
|
id="style3">
|
||||||
|
.st0{fill:#414042;}
|
||||||
|
.st1{fill:#FFFFFF;}
|
||||||
|
.st2{fill:#1E1E1E;}
|
||||||
|
.st3{fill:#333333;}
|
||||||
|
</style><g
|
||||||
|
id="g6"
|
||||||
|
style="fill:#ffffff;fill-opacity:1"><g
|
||||||
|
id="g8"
|
||||||
|
style="fill:#ffffff;fill-opacity:1"><path
|
||||||
|
style="fill:#ffffff;fill-opacity:1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path10"
|
||||||
|
d="m 50.1,146.1 c 0,2.2 -1.8,4 -4,4 l -42,0 c -2.2,0 -4,-1.8 -4,-4 l 0,-42 c 0,-2.2 1.8,-4 4,-4 l 42,0 c 2.2,0 4,1.8 4,4 l 0,42 z"
|
||||||
|
class="st0" /></g></g><g
|
||||||
|
id="g12"><g
|
||||||
|
id="g14"><path
|
||||||
|
style="fill:#414042"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path16"
|
||||||
|
d="m 50,196.1 c 0,2.2 -1.8,4 -4,4 l -42,0 c -2.2,0 -4,-1.8 -4,-4 l 0,-42 c 0,-2.2 1.8,-4 4,-4 l 42,0 c 2.2,0 4,1.8 4,4 l 0,42 z"
|
||||||
|
class="st0" /></g></g><g
|
||||||
|
id="g18"
|
||||||
|
style="fill:#f0f0f0;fill-opacity:1"><g
|
||||||
|
id="g20"
|
||||||
|
style="fill:#f0f0f0;fill-opacity:1"><path
|
||||||
|
style="fill:#f0f0f0;fill-opacity:1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path22"
|
||||||
|
d="m 50,46 c 0,2.2 -1.8,4 -4,4 L 4,50 C 1.8,50 0,48.2 0,46 L 0,4 C 0,1.8 1.8,0 4,0 l 42,0 c 2.2,0 4,1.8 4,4 l 0,42 z"
|
||||||
|
class="st1" /></g></g><g
|
||||||
|
id="g24"><path
|
||||||
|
style="fill:#1e1e1e"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path26"
|
||||||
|
d="m 50,96.1 c 0,2.2 -1.8,4 -4,4 l -42,0 c -2.2,0 -4,-1.8 -4,-4 l 0,-42 c 0,-2.2 1.8,-4 4,-4 l 42,0 c 2.2,0 4,1.8 4,4 l 0,42 z"
|
||||||
|
class="st2" /></g></svg>
|
After Width: | Height: | Size: 3 KiB |
66
interface/resources/icons/tablet-icons/finger-paint-a.svg
Normal file
66
interface/resources/icons/tablet-icons/finger-paint-a.svg
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 50 50"
|
||||||
|
style="enable-background:new 0 0 50 50;"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="finger-paint-a.svg"
|
||||||
|
inkscape:version="0.92.0 r15299"><metadata
|
||||||
|
id="metadata28"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs26" /><sodipodi:namedview
|
||||||
|
pagecolor="#ff0000"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1054"
|
||||||
|
inkscape:window-height="851"
|
||||||
|
id="namedview24"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="8.88"
|
||||||
|
inkscape:cx="6.7004505"
|
||||||
|
inkscape:cy="25"
|
||||||
|
inkscape:window-x="120"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="Layer_1" /><style
|
||||||
|
type="text/css"
|
||||||
|
id="style10">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style><g
|
||||||
|
id="Layer_2" /><g
|
||||||
|
id="g15"
|
||||||
|
style="fill:#000000;fill-opacity:1"><path
|
||||||
|
class="st0"
|
||||||
|
d="M18.3,19.6c0.7,0.1,1.2,0.5,1.4,1.1c0.4,1.3,2,5.6,2.4,6.9c2.2,0,7.9,0.1,9.9,0.1c0.2,0,0.6,0,0.8,0.1 c0.5,0.1,0.8,0.4,1.1,0.9c0.1,0.2,0.2,0.4,0.2,0.6c0.8,2.9,0.7,2,1.5,4.9c0.8,3,0.1,5.7-2.3,7.7c-1.9,1.6-3.6,2.3-5.7,1.9 c-0.6-0.1-1.2-0.3-1.8-0.5c-3.6-1.5-7.3-2.9-10.9-4.3c-0.9-0.4-1.4-1.2-1.3-2c0.1-0.9,0.9-1.5,1.8-1.6c0.1,0,0.3,0,0.4,0 c0.2,0,0.4,0.1,0.7,0.2c1.6,0.6,2.6,1.4,4.2,2c0,0,0,0,0,0c0,0,0.1,0,0.2,0c-0.1-0.2-0.1-0.4-0.2-0.6c-1.4-4.9-2.9-9.8-4.3-14.7 c-0.2-0.7-0.3-1.4,0.2-2c0.4-0.6,1-0.8,1.7-0.8C18.2,19.5,18.2,19.5,18.3,19.6 M18.9,16.3c-0.1,0-0.3,0-0.4-0.1 c-1.9-0.2-3.6,0.6-4.7,2.1c-1.5,2-0.9,4.1-0.7,4.8c0.9,3,1.8,6,2.6,9c-0.1,0-0.3,0-0.4,0c-2.5,0-4.6,1.9-5,4.3 c-0.2,1.2,0.1,2.4,0.7,3.4c0.6,1,1.5,1.7,2.7,2.2c1.2,0.5,2.4,0.9,3.6,1.4c2.4,0.9,4.9,1.9,7.3,2.9c0.9,0.4,1.7,0.6,2.5,0.7 c3.9,0.7,6.7-1.2,8.5-2.7c3.4-2.8,4.6-6.7,3.4-11.1c-0.5-1.7-0.6-2.1-0.8-2.7c-0.1-0.4-0.3-1-0.7-2.2c-0.1-0.4-0.2-0.7-0.4-1.1 c-0.7-1.5-1.8-2.5-3.4-2.7c-0.6-0.1-1.2-0.1-1.8-0.1c-1.2,0-3.4,0-5.4,0c-0.6,0-1.3-0.1-1.9-0.1c-0.2-0.6-0.5-1.3-0.7-2 c-0.4-1.1-0.7-2.1-0.9-2.6C22.3,17.9,20.8,16.7,18.9,16.3L18.9,16.3z"
|
||||||
|
id="path13"
|
||||||
|
style="fill:#000000;fill-opacity:1" /></g><path
|
||||||
|
class="st0"
|
||||||
|
d="M35.1,4.3c0.5,0,1,0,1.5,0c0.6,0,1.3-0.4,1.3-1.1c0-0.6-0.5-1.2-1.2-1.2c-0.5,0-1,0-1.5,0 c-0.6,0-1.3,0.4-1.3,1.1C33.9,3.6,34.4,4.3,35.1,4.3L35.1,4.3z"
|
||||||
|
id="path17"
|
||||||
|
style="fill:#000000;fill-opacity:1" /><path
|
||||||
|
class="st0"
|
||||||
|
d="M32,7.7c-1.2-0.8-0.9-2.1,0.1-3c1.2-1-0.6-2.6-1.7-1.6c-1,0.8-1.6,2-1.6,3.2c0,1.4,0.8,2.5,2,3.2 c0.5,0.3,1.4,0.1,1.7-0.4C32.8,8.7,32.5,8.1,32,7.7L32,7.7z"
|
||||||
|
id="path19"
|
||||||
|
style="fill:#000000;fill-opacity:1" /><path
|
||||||
|
class="st0"
|
||||||
|
d="M35.4,9.6c-1.4-0.7-2.6,1.3-1.2,1.9c1,0.5,1.8,1.2,2,2.1c0,0,0,0.2,0,0.2c0,0.1,0,0.2,0,0.3c0,0,0,0.2-0.1,0.2 c0,0,0,0,0,0.1c0,0-0.1,0.1-0.1,0.1c-0.2,0.3-0.6,0.6-1,0.8c-1.3,0.5-2.8,0.2-4.1-0.2c-1.4-0.5-2.7-1.1-4.1-1.7 c-3.2-1.3-6.6-2.6-10.1-2.5c-2.8,0.1-6.1,1.1-7.4,3.5c-1.1,2.1-0.4,4.5,1.4,5.8c0-0.8,0.4-1.7,0.9-2.3c-0.7-0.9-0.7-2.2,0.3-3.1 c1.9-1.9,5.3-1.9,7.8-1.4c3.1,0.6,5.9,2,8.8,3.2c2.8,1.1,6.5,2.1,9-0.2C39.9,14.2,38,10.8,35.4,9.6z"
|
||||||
|
id="path21"
|
||||||
|
style="fill:#000000;fill-opacity:1" /></svg>
|
After Width: | Height: | Size: 3.9 KiB |
30
interface/resources/icons/tablet-icons/finger-paint-i.svg
Normal file
30
interface/resources/icons/tablet-icons/finger-paint-i.svg
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?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 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2">
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M18.3,19.6c0.7,0.1,1.2,0.5,1.4,1.1c0.4,1.3,2,5.6,2.4,6.9c2.2,0,7.9,0.1,9.9,0.1c0.2,0,0.6,0,0.8,0.1
|
||||||
|
c0.5,0.1,0.8,0.4,1.1,0.9c0.1,0.2,0.2,0.4,0.2,0.6c0.8,2.9,0.7,2,1.5,4.9c0.8,3,0.1,5.7-2.3,7.7c-1.9,1.6-3.6,2.3-5.7,1.9
|
||||||
|
c-0.6-0.1-1.2-0.3-1.8-0.5c-3.6-1.5-7.3-2.9-10.9-4.3c-0.9-0.4-1.4-1.2-1.3-2c0.1-0.9,0.9-1.5,1.8-1.6c0.1,0,0.3,0,0.4,0
|
||||||
|
c0.2,0,0.4,0.1,0.7,0.2c1.6,0.6,2.6,1.4,4.2,2c0,0,0,0,0,0c0,0,0.1,0,0.2,0c-0.1-0.2-0.1-0.4-0.2-0.6c-1.4-4.9-2.9-9.8-4.3-14.7
|
||||||
|
c-0.2-0.7-0.3-1.4,0.2-2c0.4-0.6,1-0.8,1.7-0.8C18.2,19.5,18.2,19.5,18.3,19.6 M18.9,16.3c-0.1,0-0.3,0-0.4-0.1
|
||||||
|
c-1.9-0.2-3.6,0.6-4.7,2.1c-1.5,2-0.9,4.1-0.7,4.8c0.9,3,1.8,6,2.6,9c-0.1,0-0.3,0-0.4,0c-2.5,0-4.6,1.9-5,4.3
|
||||||
|
c-0.2,1.2,0.1,2.4,0.7,3.4c0.6,1,1.5,1.7,2.7,2.2c1.2,0.5,2.4,0.9,3.6,1.4c2.4,0.9,4.9,1.9,7.3,2.9c0.9,0.4,1.7,0.6,2.5,0.7
|
||||||
|
c3.9,0.7,6.7-1.2,8.5-2.7c3.4-2.8,4.6-6.7,3.4-11.1c-0.5-1.7-0.6-2.1-0.8-2.7c-0.1-0.4-0.3-1-0.7-2.2c-0.1-0.4-0.2-0.7-0.4-1.1
|
||||||
|
c-0.7-1.5-1.8-2.5-3.4-2.7c-0.6-0.1-1.2-0.1-1.8-0.1c-1.2,0-3.4,0-5.4,0c-0.6,0-1.3-0.1-1.9-0.1c-0.2-0.6-0.5-1.3-0.7-2
|
||||||
|
c-0.4-1.1-0.7-2.1-0.9-2.6C22.3,17.9,20.8,16.7,18.9,16.3L18.9,16.3z"/>
|
||||||
|
</g>
|
||||||
|
<path class="st0" d="M35.1,4.3c0.5,0,1,0,1.5,0c0.6,0,1.3-0.4,1.3-1.1c0-0.6-0.5-1.2-1.2-1.2c-0.5,0-1,0-1.5,0
|
||||||
|
c-0.6,0-1.3,0.4-1.3,1.1C33.9,3.6,34.4,4.3,35.1,4.3L35.1,4.3z"/>
|
||||||
|
<path class="st0" d="M32,7.7c-1.2-0.8-0.9-2.1,0.1-3c1.2-1-0.6-2.6-1.7-1.6c-1,0.8-1.6,2-1.6,3.2c0,1.4,0.8,2.5,2,3.2
|
||||||
|
c0.5,0.3,1.4,0.1,1.7-0.4C32.8,8.7,32.5,8.1,32,7.7L32,7.7z"/>
|
||||||
|
<path class="st0" d="M35.4,9.6c-1.4-0.7-2.6,1.3-1.2,1.9c1,0.5,1.8,1.2,2,2.1c0,0,0,0.2,0,0.2c0,0.1,0,0.2,0,0.3c0,0,0,0.2-0.1,0.2
|
||||||
|
c0,0,0,0,0,0.1c0,0-0.1,0.1-0.1,0.1c-0.2,0.3-0.6,0.6-1,0.8c-1.3,0.5-2.8,0.2-4.1-0.2c-1.4-0.5-2.7-1.1-4.1-1.7
|
||||||
|
c-3.2-1.3-6.6-2.6-10.1-2.5c-2.8,0.1-6.1,1.1-7.4,3.5c-1.1,2.1-0.4,4.5,1.4,5.8c0-0.8,0.4-1.7,0.9-2.3c-0.7-0.9-0.7-2.2,0.3-3.1
|
||||||
|
c1.9-1.9,5.3-1.9,7.8-1.4c3.1,0.6,5.9,2,8.8,3.2c2.8,1.1,6.5,2.1,9-0.2C39.9,14.2,38,10.8,35.4,9.6z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -48,6 +48,15 @@ OriginalDesktop.Desktop {
|
||||||
// This used to create sysToolbar dynamically with a call to getToolbar() within onCompleted.
|
// This used to create sysToolbar dynamically with a call to getToolbar() within onCompleted.
|
||||||
// Beginning with QT 5.6, this stopped working, as anything added to toolbars too early got
|
// Beginning with QT 5.6, this stopped working, as anything added to toolbars too early got
|
||||||
// wiped during startup.
|
// wiped during startup.
|
||||||
|
Toolbar {
|
||||||
|
id: sysToolbar;
|
||||||
|
objectName: "com.highfidelity.interface.toolbar.system";
|
||||||
|
anchors.horizontalCenter: settings.constrainToolbarToCenterX ? desktop.horizontalCenter : undefined;
|
||||||
|
// Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained.
|
||||||
|
x: sysToolbar.x
|
||||||
|
y: 50
|
||||||
|
shown: false
|
||||||
|
}
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
id: settings;
|
id: settings;
|
||||||
|
@ -58,8 +67,9 @@ OriginalDesktop.Desktop {
|
||||||
settings.constrainToolbarToCenterX = constrain;
|
settings.constrainToolbarToCenterX = constrain;
|
||||||
}
|
}
|
||||||
property var toolbars: (function (map) { // answer dictionary preloaded with sysToolbar
|
property var toolbars: (function (map) { // answer dictionary preloaded with sysToolbar
|
||||||
return map; })({});
|
map[sysToolbar.objectName] = sysToolbar;
|
||||||
|
return map;
|
||||||
|
})({});
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
WebEngine.settings.javascriptCanOpenWindows = true;
|
WebEngine.settings.javascriptCanOpenWindows = true;
|
||||||
|
|
|
@ -97,10 +97,12 @@ FocusScope {
|
||||||
menuPopperUpper.closeLastMenu();
|
menuPopperUpper.closeLastMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setRootMenu(menu) {
|
function setRootMenu(rootMenu, subMenu) {
|
||||||
tabletMenu.rootMenu = menu
|
tabletMenu.subMenu = subMenu;
|
||||||
|
tabletMenu.rootMenu = rootMenu;
|
||||||
buildMenu()
|
buildMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildMenu() {
|
function buildMenu() {
|
||||||
// Build submenu if specified.
|
// Build submenu if specified.
|
||||||
if (subMenu !== "") {
|
if (subMenu !== "") {
|
||||||
|
|
|
@ -83,7 +83,7 @@ FocusScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
function recalcSize() {
|
function recalcSize() {
|
||||||
if (model.count !== count || !visible) {
|
if (!model || model.count !== count || !visible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,9 @@ Item {
|
||||||
objectName: "tabletRoot"
|
objectName: "tabletRoot"
|
||||||
property string username: "Unknown user"
|
property string username: "Unknown user"
|
||||||
property var eventBridge;
|
property var eventBridge;
|
||||||
property string option: ""
|
|
||||||
|
property var rootMenu;
|
||||||
|
property string subMenu: ""
|
||||||
|
|
||||||
signal showDesktop();
|
signal showDesktop();
|
||||||
|
|
||||||
|
@ -14,7 +16,13 @@ Item {
|
||||||
option = value;
|
option = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setMenuProperties(rootMenu, subMenu) {
|
||||||
|
tabletRoot.rootMenu = rootMenu;
|
||||||
|
tabletRoot.subMenu = subMenu;
|
||||||
|
}
|
||||||
|
|
||||||
function loadSource(url) {
|
function loadSource(url) {
|
||||||
|
loader.source = ""; // make sure we load the qml fresh each time.
|
||||||
loader.source = url;
|
loader.source = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,13 +85,15 @@ Item {
|
||||||
if (loader.item.hasOwnProperty("sendToScript")) {
|
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||||
}
|
}
|
||||||
if (loader.item.hasOwnProperty("subMenu")) {
|
if (loader.item.hasOwnProperty("setRootMenu")) {
|
||||||
loader.item.subMenu = option;
|
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
||||||
}
|
}
|
||||||
loader.item.forceActiveFocus();
|
loader.item.forceActiveFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
width: 480
|
width: 480
|
||||||
height: 720
|
height: 706
|
||||||
|
|
||||||
|
function setShown(value) {}
|
||||||
}
|
}
|
||||||
|
|
111
interface/resources/qml/hifi/tablet/WindowRoot.qml
Normal file
111
interface/resources/qml/hifi/tablet/WindowRoot.qml
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
//
|
||||||
|
// WindowRoot.qml
|
||||||
|
//
|
||||||
|
// Created by Anthony Thibault on 14 Feb 2017
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// This qml is used when tablet content is shown on the 2d overlay ui
|
||||||
|
// TODO: FIXME: this is practically identical to TabletRoot.qml
|
||||||
|
|
||||||
|
import "../../windows" as Windows
|
||||||
|
import QtQuick 2.0
|
||||||
|
import Hifi 1.0
|
||||||
|
|
||||||
|
Windows.ScrollingWindow {
|
||||||
|
id: tabletRoot
|
||||||
|
objectName: "tabletRoot"
|
||||||
|
property string username: "Unknown user"
|
||||||
|
property var eventBridge;
|
||||||
|
|
||||||
|
property var rootMenu;
|
||||||
|
property string subMenu: ""
|
||||||
|
|
||||||
|
shown: false
|
||||||
|
resizable: false
|
||||||
|
|
||||||
|
signal showDesktop();
|
||||||
|
|
||||||
|
function setMenuProperties(rootMenu, subMenu) {
|
||||||
|
tabletRoot.rootMenu = rootMenu;
|
||||||
|
tabletRoot.subMenu = subMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSource(url) {
|
||||||
|
loader.source = ""; // make sure we load the qml fresh each time.
|
||||||
|
loader.source = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadWebUrl(url, injectedJavaScriptUrl) {
|
||||||
|
loader.item.url = url;
|
||||||
|
loader.item.scriptURL = injectedJavaScriptUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// used to send a message from qml to interface script.
|
||||||
|
signal sendToScript(var message);
|
||||||
|
|
||||||
|
// used to receive messages from interface script
|
||||||
|
function fromScript(message) {
|
||||||
|
if (loader.item.hasOwnProperty("fromScript")) {
|
||||||
|
loader.item.fromScript(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundEffect {
|
||||||
|
id: buttonClickSound
|
||||||
|
volume: 0.1
|
||||||
|
source: "../../../sounds/Gamemaster-Audio-button-click.wav"
|
||||||
|
}
|
||||||
|
|
||||||
|
function playButtonClickSound() {
|
||||||
|
// Because of the asynchronous nature of initalization, it is possible for this function to be
|
||||||
|
// called before the C++ has set the globalPosition context variable.
|
||||||
|
if (typeof globalPosition !== 'undefined') {
|
||||||
|
buttonClickSound.play(globalPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMicEnabled() {
|
||||||
|
ApplicationInterface.toggleMuteAudio();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUsername(newUsername) {
|
||||||
|
username = newUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: loader
|
||||||
|
objectName: "loader"
|
||||||
|
asynchronous: false
|
||||||
|
|
||||||
|
height: pane.scrollHeight
|
||||||
|
width: pane.contentWidth
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
|
||||||
|
onLoaded: {
|
||||||
|
if (loader.item.hasOwnProperty("eventBridge")) {
|
||||||
|
loader.item.eventBridge = eventBridge;
|
||||||
|
|
||||||
|
// Hook up callback for clara.io download from the marketplace.
|
||||||
|
eventBridge.webEventReceived.connect(function (event) {
|
||||||
|
if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||||
|
ApplicationInterface.addAssetToWorldFromURL(event.slice(18));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||||
|
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||||
|
}
|
||||||
|
if (loader.item.hasOwnProperty("setRootMenu")) {
|
||||||
|
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
||||||
|
}
|
||||||
|
loader.item.forceActiveFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: 480
|
||||||
|
implicitHeight: 706
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ Item {
|
||||||
id: image
|
id: image
|
||||||
y: -parent.yOffset;
|
y: -parent.yOffset;
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
source: "../../../icons/tablet-icons/empty-toolbar-button.svg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ Window {
|
||||||
id: content
|
id: content
|
||||||
implicitHeight: horizontal ? row.height : column.height
|
implicitHeight: horizontal ? row.height : column.height
|
||||||
implicitWidth: horizontal ? row.width : column.width
|
implicitWidth: horizontal ? row.width : column.width
|
||||||
|
property bool wasVisibleBeforeBeingPinned: false
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: row
|
id: row
|
||||||
|
@ -65,19 +66,11 @@ Window {
|
||||||
Connections {
|
Connections {
|
||||||
target: desktop
|
target: desktop
|
||||||
onPinnedChanged: {
|
onPinnedChanged: {
|
||||||
if (!window.pinned) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var newPinned = desktop.pinned;
|
|
||||||
for (var i in buttons) {
|
|
||||||
var child = buttons[i];
|
|
||||||
if (desktop.pinned) {
|
if (desktop.pinned) {
|
||||||
if (!child.pinned) {
|
content.wasVisibleBeforeBeingPinned = window.visible;
|
||||||
child.visible = false;
|
window.visible = false;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
child.visible = true;
|
window.visible = content.wasVisibleBeforeBeingPinned;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,6 +99,24 @@ Window {
|
||||||
return buttons[index];
|
return buttons[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sortButtons() {
|
||||||
|
var children = [];
|
||||||
|
for (var i = 0; i < container.children.length; i++) {
|
||||||
|
children[i] = container.children[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
children.sort(function (a, b) {
|
||||||
|
if (a.sortOrder === b.sortOrder) {
|
||||||
|
// subsort by stableOrder, because JS sort is not stable in qml.
|
||||||
|
return a.stableOrder - b.stableOrder;
|
||||||
|
} else {
|
||||||
|
return a.sortOrder - b.sortOrder;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
container.children = children;
|
||||||
|
}
|
||||||
|
|
||||||
function addButton(properties) {
|
function addButton(properties) {
|
||||||
properties = properties || {}
|
properties = properties || {}
|
||||||
|
|
||||||
|
@ -123,8 +134,12 @@ Window {
|
||||||
properties.opacity = 0;
|
properties.opacity = 0;
|
||||||
result = toolbarButtonBuilder.createObject(container, properties);
|
result = toolbarButtonBuilder.createObject(container, properties);
|
||||||
buttons.push(result);
|
buttons.push(result);
|
||||||
|
|
||||||
result.opacity = 1;
|
result.opacity = 1;
|
||||||
updatePinned();
|
updatePinned();
|
||||||
|
|
||||||
|
sortButtons();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +152,10 @@ Window {
|
||||||
buttons[index].destroy();
|
buttons[index].destroy();
|
||||||
buttons.splice(index, 1);
|
buttons.splice(index, 1);
|
||||||
updatePinned();
|
updatePinned();
|
||||||
|
|
||||||
|
if (buttons.length === 0) {
|
||||||
|
visible = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePinned() {
|
function updatePinned() {
|
||||||
|
|
|
@ -11,12 +11,33 @@ StateImage {
|
||||||
property int imageOnOut: 0
|
property int imageOnOut: 0
|
||||||
property int imageOnIn: 2
|
property int imageOnIn: 2
|
||||||
|
|
||||||
|
property string text: ""
|
||||||
|
property string hoverText: button.text
|
||||||
|
property string activeText: button.text
|
||||||
|
property string activeHoverText: button.activeText
|
||||||
|
|
||||||
|
property string icon: "icons/tablet-icons/blank.svg"
|
||||||
|
property string hoverIcon: button.icon
|
||||||
|
property string activeIcon: button.icon
|
||||||
|
property string activeHoverIcon: button.activeIcon
|
||||||
|
|
||||||
|
property int sortOrder: 100
|
||||||
|
property int stableSortOrder: 0
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
function changeProperty(key, value) {
|
function changeProperty(key, value) {
|
||||||
button[key] = value;
|
button[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function urlHelper(src) {
|
||||||
|
if (src.match(/\bhttp/)) {
|
||||||
|
return src;
|
||||||
|
} else {
|
||||||
|
return "../../../" + src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateState() {
|
function updateState() {
|
||||||
if (!button.isEntered && !button.isActive) {
|
if (!button.isEntered && !button.isActive) {
|
||||||
buttonState = imageOffOut;
|
buttonState = imageOffOut;
|
||||||
|
@ -53,5 +74,28 @@ StateImage {
|
||||||
updateState();
|
updateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: icon
|
||||||
|
width: 28
|
||||||
|
height: 28
|
||||||
|
anchors.bottom: caption.top
|
||||||
|
anchors.bottomMargin: 0
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
source: urlHelper(button.isActive ? (button.isEntered ? button.activeHoverIcon : button.activeIcon) : (button.isEntered ? button.hoverIcon : button.icon))
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: caption
|
||||||
|
color: button.isActive ? "#000000" : "#ffffff"
|
||||||
|
text: button.isActive ? (button.isEntered ? button.activeHoverText : button.activeText) : (button.isEntered ? button.hoverText : button.text)
|
||||||
|
font.bold: false
|
||||||
|
font.pixelSize: 9
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 5
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,10 @@ Fadable {
|
||||||
|
|
||||||
function setDefaultFocus() {} // Default function; can be overridden by dialogs.
|
function setDefaultFocus() {} // Default function; can be overridden by dialogs.
|
||||||
|
|
||||||
|
function setShown(value) {
|
||||||
|
window.shown = value;
|
||||||
|
}
|
||||||
|
|
||||||
property var rectifier: Timer {
|
property var rectifier: Timer {
|
||||||
property bool executing: false;
|
property bool executing: false;
|
||||||
interval: 100
|
interval: 100
|
||||||
|
|
|
@ -545,6 +545,8 @@ Setting::Handle<int> sessionRunTime{ "sessionRunTime", 0 };
|
||||||
|
|
||||||
const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 100.0f;
|
const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 100.0f;
|
||||||
const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
|
const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f;
|
||||||
|
const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true;
|
||||||
|
const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false;
|
||||||
|
|
||||||
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) :
|
Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) :
|
||||||
QApplication(argc, argv),
|
QApplication(argc, argv),
|
||||||
|
@ -565,6 +567,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||||
_hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT),
|
_hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT),
|
||||||
_desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT),
|
_desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT),
|
||||||
|
_desktopTabletBecomesToolbarSetting("desktopTabletBecomesToolbar", DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR),
|
||||||
|
_hmdTabletBecomesToolbarSetting("hmdTabletBecomesToolbar", DEFAULT_HMD_TABLET_BECOMES_TOOLBAR),
|
||||||
_constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true),
|
_constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true),
|
||||||
_scaleMirror(1.0f),
|
_scaleMirror(1.0f),
|
||||||
_rotateMirror(0.0f),
|
_rotateMirror(0.0f),
|
||||||
|
@ -831,6 +835,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress);
|
connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress);
|
||||||
|
|
||||||
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount);
|
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount);
|
||||||
|
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode);
|
||||||
|
|
||||||
// Save avatar location immediately after a teleport.
|
// Save avatar location immediately after a teleport.
|
||||||
connect(myAvatar.get(), &MyAvatar::positionGoneTo,
|
connect(myAvatar.get(), &MyAvatar::positionGoneTo,
|
||||||
|
@ -1537,6 +1542,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
|
|
||||||
connect(this, &QCoreApplication::aboutToQuit, this, &Application::addAssetToWorldMessageClose);
|
connect(this, &QCoreApplication::aboutToQuit, this, &Application::addAssetToWorldMessageClose);
|
||||||
connect(&domainHandler, &DomainHandler::hostnameChanged, this, &Application::addAssetToWorldMessageClose);
|
connect(&domainHandler, &DomainHandler::hostnameChanged, this, &Application::addAssetToWorldMessageClose);
|
||||||
|
|
||||||
|
updateSystemTabletMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
|
void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
|
||||||
|
@ -2330,6 +2337,16 @@ void Application::setDesktopTabletScale(float desktopTabletScale) {
|
||||||
_desktopTabletScale.set(desktopTabletScale);
|
_desktopTabletScale.set(desktopTabletScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::setDesktopTabletBecomesToolbarSetting(bool value) {
|
||||||
|
_desktopTabletBecomesToolbarSetting.set(value);
|
||||||
|
updateSystemTabletMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::setHmdTabletBecomesToolbarSetting(bool value) {
|
||||||
|
_hmdTabletBecomesToolbarSetting.set(value);
|
||||||
|
updateSystemTabletMode();
|
||||||
|
}
|
||||||
|
|
||||||
void Application::setSettingConstrainToolbarPosition(bool setting) {
|
void Application::setSettingConstrainToolbarPosition(bool setting) {
|
||||||
_constrainToolbarPosition.set(setting);
|
_constrainToolbarPosition.set(setting);
|
||||||
DependencyManager::get<OffscreenUi>()->setConstrainToolbarToCenterX(setting);
|
DependencyManager::get<OffscreenUi>()->setConstrainToolbarToCenterX(setting);
|
||||||
|
@ -5462,6 +5479,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
||||||
scriptEngine->registerGlobalObject("Desktop", DependencyManager::get<DesktopScriptingInterface>().data());
|
scriptEngine->registerGlobalObject("Desktop", DependencyManager::get<DesktopScriptingInterface>().data());
|
||||||
scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
|
scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
|
||||||
|
|
||||||
|
DependencyManager::get<TabletScriptingInterface>().data()->setToolbarScriptingInterface(DependencyManager::get<ToolbarScriptingInterface>().data());
|
||||||
|
|
||||||
scriptEngine->registerGlobalObject("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
scriptEngine->registerGlobalObject("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
||||||
qScriptRegisterMetaType(scriptEngine, CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue);
|
qScriptRegisterMetaType(scriptEngine, CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue);
|
||||||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||||
|
@ -6680,6 +6699,12 @@ void Application::updateDisplayMode() {
|
||||||
|
|
||||||
emit activeDisplayPluginChanged();
|
emit activeDisplayPluginChanged();
|
||||||
|
|
||||||
|
if (_displayPlugin->isHmd()) {
|
||||||
|
qCDebug(interfaceapp) << "Entering into HMD Mode";
|
||||||
|
} else {
|
||||||
|
qCDebug(interfaceapp) << "Entering into Desktop Mode";
|
||||||
|
}
|
||||||
|
|
||||||
// reset the avatar, to set head and hand palms back to a reasonable default pose.
|
// reset the avatar, to set head and hand palms back to a reasonable default pose.
|
||||||
getMyAvatar()->reset(false);
|
getMyAvatar()->reset(false);
|
||||||
|
|
||||||
|
@ -6854,6 +6879,14 @@ void Application::updateThreadPoolCount() const {
|
||||||
QThreadPool::globalInstance()->setMaxThreadCount(threadPoolSize);
|
QThreadPool::globalInstance()->setMaxThreadCount(threadPoolSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::updateSystemTabletMode() {
|
||||||
|
if (isHMDMode()) {
|
||||||
|
DependencyManager::get<TabletScriptingInterface>()->setToolbarMode(getHmdTabletBecomesToolbarSetting());
|
||||||
|
} else {
|
||||||
|
DependencyManager::get<TabletScriptingInterface>()->setToolbarMode(getDesktopTabletBecomesToolbarSetting());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::toggleMuteAudio() {
|
void Application::toggleMuteAudio() {
|
||||||
auto menu = Menu::getInstance();
|
auto menu = Menu::getInstance();
|
||||||
menu->setIsOptionChecked(MenuOption::MuteAudio, !menu->isOptionChecked(MenuOption::MuteAudio));
|
menu->setIsOptionChecked(MenuOption::MuteAudio, !menu->isOptionChecked(MenuOption::MuteAudio));
|
||||||
|
|
|
@ -214,6 +214,11 @@ public:
|
||||||
float getDesktopTabletScale() { return _desktopTabletScale.get(); }
|
float getDesktopTabletScale() { return _desktopTabletScale.get(); }
|
||||||
void setDesktopTabletScale(float desktopTabletScale);
|
void setDesktopTabletScale(float desktopTabletScale);
|
||||||
|
|
||||||
|
bool getDesktopTabletBecomesToolbarSetting() { return _desktopTabletBecomesToolbarSetting.get(); }
|
||||||
|
void setDesktopTabletBecomesToolbarSetting(bool value);
|
||||||
|
bool getHmdTabletBecomesToolbarSetting() { return _hmdTabletBecomesToolbarSetting.get(); }
|
||||||
|
void setHmdTabletBecomesToolbarSetting(bool value);
|
||||||
|
|
||||||
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
||||||
void setSettingConstrainToolbarPosition(bool setting);
|
void setSettingConstrainToolbarPosition(bool setting);
|
||||||
|
|
||||||
|
@ -310,6 +315,7 @@ public slots:
|
||||||
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
|
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
|
||||||
bool importEntities(const QString& url);
|
bool importEntities(const QString& url);
|
||||||
void updateThreadPoolCount() const;
|
void updateThreadPoolCount() const;
|
||||||
|
void updateSystemTabletMode();
|
||||||
|
|
||||||
static void setLowVelocityFilter(bool lowVelocityFilter);
|
static void setLowVelocityFilter(bool lowVelocityFilter);
|
||||||
Q_INVOKABLE void loadDialog();
|
Q_INVOKABLE void loadDialog();
|
||||||
|
@ -550,6 +556,8 @@ private:
|
||||||
Setting::Handle<float> _fieldOfView;
|
Setting::Handle<float> _fieldOfView;
|
||||||
Setting::Handle<float> _hmdTabletScale;
|
Setting::Handle<float> _hmdTabletScale;
|
||||||
Setting::Handle<float> _desktopTabletScale;
|
Setting::Handle<float> _desktopTabletScale;
|
||||||
|
Setting::Handle<bool> _desktopTabletBecomesToolbarSetting;
|
||||||
|
Setting::Handle<bool> _hmdTabletBecomesToolbarSetting;
|
||||||
Setting::Handle<bool> _constrainToolbarPosition;
|
Setting::Handle<bool> _constrainToolbarPosition;
|
||||||
|
|
||||||
float _scaleMirror;
|
float _scaleMirror;
|
||||||
|
|
|
@ -92,6 +92,16 @@ void setupPreferences() {
|
||||||
preference->setMax(500);
|
preference->setMax(500);
|
||||||
preferences->addPreference(preference);
|
preferences->addPreference(preference);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
auto getter = []()->bool { return qApp->getDesktopTabletBecomesToolbarSetting(); };
|
||||||
|
auto setter = [](bool value) { qApp->setDesktopTabletBecomesToolbarSetting(value); };
|
||||||
|
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Desktop Tablet Becomes Toolbar", getter, setter));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto getter = []()->bool { return qApp->getHmdTabletBecomesToolbarSetting(); };
|
||||||
|
auto setter = [](bool value) { qApp->setHmdTabletBecomesToolbarSetting(value); };
|
||||||
|
preferences->addPreference(new CheckPreference(UI_CATEGORY, "HMD Tablet Becomes Toolbar", getter, setter));
|
||||||
|
}
|
||||||
|
|
||||||
// Snapshots
|
// Snapshots
|
||||||
static const QString SNAPSHOTS { "Snapshots" };
|
static const QString SNAPSHOTS { "Snapshots" };
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
#include <AudioInjector.h>
|
#include <AudioInjector.h>
|
||||||
|
|
||||||
SoundEffect::~SoundEffect() {
|
SoundEffect::~SoundEffect() {
|
||||||
if (_sound) {
|
|
||||||
_sound->deleteLater();
|
|
||||||
}
|
|
||||||
if (_injector) {
|
if (_injector) {
|
||||||
// stop will cause the AudioInjector to delete itself.
|
// stop will cause the AudioInjector to delete itself.
|
||||||
_injector->stop();
|
_injector->stop();
|
||||||
|
|
|
@ -11,17 +11,36 @@
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
|
#include "DependencyManager.h"
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
|
#include <QmlWindowClass.h>
|
||||||
|
#include <QQmlProperty>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
#include "ScriptEngineLogging.h"
|
#include "ScriptEngineLogging.h"
|
||||||
#include "DependencyManager.h"
|
#include <OffscreenUi.h>
|
||||||
#include "OffscreenUi.h"
|
#include <InfoView.h>
|
||||||
#include "SoundEffect.h"
|
#include "SoundEffect.h"
|
||||||
|
|
||||||
TabletScriptingInterface::TabletScriptingInterface() {
|
TabletScriptingInterface::TabletScriptingInterface() {
|
||||||
qmlRegisterType<SoundEffect>("Hifi", 1, 0, "SoundEffect");
|
qmlRegisterType<SoundEffect>("Hifi", 1, 0, "SoundEffect");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QObject* TabletScriptingInterface::getSystemToolbarProxy() {
|
||||||
|
const QString SYSTEM_TOOLBAR = "com.highfidelity.interface.toolbar.system";
|
||||||
|
Qt::ConnectionType connectionType = Qt::AutoConnection;
|
||||||
|
if (QThread::currentThread() != _toolbarScriptingInterface->thread()) {
|
||||||
|
connectionType = Qt::BlockingQueuedConnection;
|
||||||
|
}
|
||||||
|
QObject* toolbarProxy = nullptr;
|
||||||
|
bool hasResult = QMetaObject::invokeMethod(_toolbarScriptingInterface, "getToolbar", connectionType, Q_RETURN_ARG(QObject*, toolbarProxy), Q_ARG(QString, SYSTEM_TOOLBAR));
|
||||||
|
if (hasResult) {
|
||||||
|
return toolbarProxy;
|
||||||
|
} else {
|
||||||
|
qCWarning(scriptengine) << "ToolbarScriptingInterface getToolbar has no result";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QObject* TabletScriptingInterface::getTablet(const QString& tabletId) {
|
QObject* TabletScriptingInterface::getTablet(const QString& tabletId) {
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(_mutex);
|
std::lock_guard<std::mutex> guard(_mutex);
|
||||||
|
@ -35,10 +54,21 @@ QObject* TabletScriptingInterface::getTablet(const QString& tabletId) {
|
||||||
// allocate a new tablet, add it to the map then return it.
|
// allocate a new tablet, add it to the map then return it.
|
||||||
auto tabletProxy = QSharedPointer<TabletProxy>(new TabletProxy(tabletId));
|
auto tabletProxy = QSharedPointer<TabletProxy>(new TabletProxy(tabletId));
|
||||||
_tabletProxies[tabletId] = tabletProxy;
|
_tabletProxies[tabletId] = tabletProxy;
|
||||||
|
tabletProxy->setToolbarMode(_toolbarMode);
|
||||||
return tabletProxy.data();
|
return tabletProxy.data();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabletScriptingInterface::setToolbarMode(bool toolbarMode) {
|
||||||
|
std::lock_guard<std::mutex> guard(_mutex);
|
||||||
|
|
||||||
|
_toolbarMode = toolbarMode;
|
||||||
|
|
||||||
|
for (auto& iter : _tabletProxies) {
|
||||||
|
iter.second->setToolbarMode(toolbarMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TabletScriptingInterface::setQmlTabletRoot(QString tabletId, QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface) {
|
void TabletScriptingInterface::setQmlTabletRoot(QString tabletId, QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface) {
|
||||||
TabletProxy* tablet = qobject_cast<TabletProxy*>(getTablet(tabletId));
|
TabletProxy* tablet = qobject_cast<TabletProxy*>(getTablet(tabletId));
|
||||||
if (tablet) {
|
if (tablet) {
|
||||||
|
@ -141,8 +171,51 @@ static const char* TABLET_SOURCE_URL = "Tablet.qml";
|
||||||
static const char* WEB_VIEW_SOURCE_URL = "TabletWebView.qml";
|
static const char* WEB_VIEW_SOURCE_URL = "TabletWebView.qml";
|
||||||
static const char* VRMENU_SOURCE_URL = "TabletMenu.qml";
|
static const char* VRMENU_SOURCE_URL = "TabletMenu.qml";
|
||||||
|
|
||||||
|
class TabletRootWindow : public QmlWindowClass {
|
||||||
|
virtual QString qmlSource() const { return "hifi/tablet/WindowRoot.qml"; }
|
||||||
|
};
|
||||||
|
|
||||||
TabletProxy::TabletProxy(QString name) : _name(name) {
|
TabletProxy::TabletProxy(QString name) : _name(name) {
|
||||||
;
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabletProxy::setToolbarMode(bool toolbarMode) {
|
||||||
|
if (toolbarMode == _toolbarMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_toolbarMode = toolbarMode;
|
||||||
|
|
||||||
|
if (toolbarMode) {
|
||||||
|
removeButtonsFromHomeScreen();
|
||||||
|
addButtonsToToolbar();
|
||||||
|
|
||||||
|
// create new desktop window
|
||||||
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
|
offscreenUi->executeOnUiThread([=] {
|
||||||
|
auto tabletRootWindow = new TabletRootWindow();
|
||||||
|
tabletRootWindow->initQml(QVariantMap());
|
||||||
|
auto quickItem = tabletRootWindow->asQuickItem();
|
||||||
|
_desktopWindow = tabletRootWindow;
|
||||||
|
QMetaObject::invokeMethod(quickItem, "setShown", Q_ARG(const QVariant&, QVariant(false)));
|
||||||
|
|
||||||
|
QObject::connect(quickItem, SIGNAL(windowClosed()), this, SLOT(desktopWindowClosed()));
|
||||||
|
|
||||||
|
QObject::connect(tabletRootWindow, SIGNAL(webEventReceived(QVariant)), this, SIGNAL(webEventReceived(QVariant)));
|
||||||
|
|
||||||
|
// forward qml surface events to interface js
|
||||||
|
connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
removeButtonsFromToolbar();
|
||||||
|
addButtonsToHomeScreen();
|
||||||
|
|
||||||
|
// destroy desktop window
|
||||||
|
if (_desktopWindow) {
|
||||||
|
_desktopWindow->deleteLater();
|
||||||
|
_desktopWindow = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy* buttonProxy) {
|
static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy* buttonProxy) {
|
||||||
|
@ -195,6 +268,13 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (_toolbarMode) {
|
||||||
|
// if someone creates the tablet in toolbar mode, make sure to display the home screen on the tablet.
|
||||||
|
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
||||||
|
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen()), Qt::DirectConnection);
|
||||||
|
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL)));
|
||||||
|
}
|
||||||
|
|
||||||
gotoHomeScreen();
|
gotoHomeScreen();
|
||||||
|
|
||||||
QMetaObject::invokeMethod(_qmlTabletRoot, "setUsername", Q_ARG(const QVariant&, QVariant(getUsername())));
|
QMetaObject::invokeMethod(_qmlTabletRoot, "setUsername", Q_ARG(const QVariant&, QVariant(getUsername())));
|
||||||
|
@ -214,72 +294,115 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::gotoMenuScreen(const QString& submenu) {
|
void TabletProxy::gotoMenuScreen(const QString& submenu) {
|
||||||
if (_qmlTabletRoot) {
|
|
||||||
if (_state != State::Menu) {
|
QObject* root = nullptr;
|
||||||
|
if (!_toolbarMode && _qmlTabletRoot) {
|
||||||
|
root = _qmlTabletRoot;
|
||||||
|
} else if (_toolbarMode && _desktopWindow) {
|
||||||
|
root = _desktopWindow->asQuickItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root) {
|
||||||
removeButtonsFromHomeScreen();
|
removeButtonsFromHomeScreen();
|
||||||
QMetaObject::invokeMethod(_qmlTabletRoot, "setOption", Q_ARG(const QVariant&, QVariant(submenu)));
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
QObject* menu = offscreenUi->getRootMenu();
|
||||||
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen()), Qt::DirectConnection);
|
QMetaObject::invokeMethod(root, "setMenuProperties", Q_ARG(QVariant, QVariant::fromValue(menu)), Q_ARG(const QVariant&, QVariant(submenu)));
|
||||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL)));
|
QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL)));
|
||||||
_state = State::Menu;
|
_state = State::Menu;
|
||||||
emit screenChanged(QVariant("Menu"), QVariant(VRMENU_SOURCE_URL));
|
emit screenChanged(QVariant("Menu"), QVariant(VRMENU_SOURCE_URL));
|
||||||
}
|
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::loadQMLSource(const QVariant& path) {
|
void TabletProxy::loadQMLSource(const QVariant& path) {
|
||||||
if (_qmlTabletRoot) {
|
|
||||||
|
QObject* root = nullptr;
|
||||||
|
if (!_toolbarMode && _qmlTabletRoot) {
|
||||||
|
root = _qmlTabletRoot;
|
||||||
|
} else if (_toolbarMode && _desktopWindow) {
|
||||||
|
root = _desktopWindow->asQuickItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root) {
|
||||||
if (_state != State::QML) {
|
if (_state != State::QML) {
|
||||||
removeButtonsFromHomeScreen();
|
removeButtonsFromHomeScreen();
|
||||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, path));
|
QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path));
|
||||||
_state = State::QML;
|
_state = State::QML;
|
||||||
emit screenChanged(QVariant("QML"), path);
|
emit screenChanged(QVariant("QML"), path);
|
||||||
|
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::gotoHomeScreen() {
|
void TabletProxy::gotoHomeScreen() {
|
||||||
if (_qmlTabletRoot) {
|
|
||||||
if (_state != State::Home) {
|
if (_state != State::Home) {
|
||||||
|
if (!_toolbarMode && _qmlTabletRoot) {
|
||||||
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
||||||
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen()), Qt::DirectConnection);
|
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen()), Qt::DirectConnection);
|
||||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL)));
|
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL)));
|
||||||
QMetaObject::invokeMethod(_qmlTabletRoot, "playButtonClickSound");
|
QMetaObject::invokeMethod(_qmlTabletRoot, "playButtonClickSound");
|
||||||
|
} else if (_toolbarMode && _desktopWindow) {
|
||||||
|
// close desktop window
|
||||||
|
if (_desktopWindow->asQuickItem()) {
|
||||||
|
QMetaObject::invokeMethod(_desktopWindow->asQuickItem(), "setShown", Q_ARG(const QVariant&, QVariant(false)));
|
||||||
|
}
|
||||||
|
}
|
||||||
_state = State::Home;
|
_state = State::Home;
|
||||||
emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL));
|
emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void TabletProxy::gotoWebScreen(const QString& url) {
|
void TabletProxy::gotoWebScreen(const QString& url) {
|
||||||
gotoWebScreen(url, "");
|
gotoWebScreen(url, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl) {
|
void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl) {
|
||||||
if (_qmlTabletRoot) {
|
|
||||||
if (_state == State::Home) {
|
QObject* root = nullptr;
|
||||||
removeButtonsFromHomeScreen();
|
if (!_toolbarMode && _qmlTabletRoot) {
|
||||||
|
root = _qmlTabletRoot;
|
||||||
|
} else if (_toolbarMode && _desktopWindow) {
|
||||||
|
root = _desktopWindow->asQuickItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root) {
|
||||||
|
QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL)));
|
||||||
|
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||||
|
QMetaObject::invokeMethod(root, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl)));
|
||||||
}
|
}
|
||||||
if (_state != State::Web) {
|
|
||||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL)));
|
|
||||||
_state = State::Web;
|
_state = State::Web;
|
||||||
emit screenChanged(QVariant("Web"), QVariant(url));
|
emit screenChanged(QVariant("Web"), QVariant(url));
|
||||||
}
|
}
|
||||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)),
|
|
||||||
Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QObject* TabletProxy::addButton(const QVariant& properties) {
|
QObject* TabletProxy::addButton(const QVariant& properties) {
|
||||||
auto tabletButtonProxy = QSharedPointer<TabletButtonProxy>(new TabletButtonProxy(properties.toMap()));
|
auto tabletButtonProxy = QSharedPointer<TabletButtonProxy>(new TabletButtonProxy(properties.toMap()));
|
||||||
std::lock_guard<std::mutex> guard(_mutex);
|
std::lock_guard<std::mutex> guard(_mutex);
|
||||||
_tabletButtonProxies.push_back(tabletButtonProxy);
|
_tabletButtonProxies.push_back(tabletButtonProxy);
|
||||||
if (_qmlTabletRoot) {
|
if (!_toolbarMode && _qmlTabletRoot) {
|
||||||
auto tablet = getQmlTablet();
|
auto tablet = getQmlTablet();
|
||||||
if (tablet) {
|
if (tablet) {
|
||||||
addButtonProxyToQmlTablet(tablet, tabletButtonProxy.data());
|
addButtonProxyToQmlTablet(tablet, tabletButtonProxy.data());
|
||||||
} else {
|
} else {
|
||||||
qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
||||||
}
|
}
|
||||||
|
} else if (_toolbarMode) {
|
||||||
|
|
||||||
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
||||||
|
|
||||||
|
Qt::ConnectionType connectionType = Qt::AutoConnection;
|
||||||
|
if (QThread::currentThread() != toolbarProxy->thread()) {
|
||||||
|
connectionType = Qt::BlockingQueuedConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy properties from tablet button proxy to toolbar button proxy.
|
||||||
|
QObject* toolbarButtonProxy = nullptr;
|
||||||
|
bool hasResult = QMetaObject::invokeMethod(toolbarProxy, "addButton", connectionType, Q_RETURN_ARG(QObject*, toolbarButtonProxy), Q_ARG(QVariant, tabletButtonProxy->getProperties()));
|
||||||
|
if (hasResult) {
|
||||||
|
tabletButtonProxy->setToolbarButtonProxy(toolbarButtonProxy);
|
||||||
|
} else {
|
||||||
|
qCWarning(scriptengine) << "ToolbarProxy addButton has no result";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return tabletButtonProxy.data();
|
return tabletButtonProxy.data();
|
||||||
}
|
}
|
||||||
|
@ -298,11 +421,18 @@ void TabletProxy::removeButton(QObject* tabletButtonProxy) {
|
||||||
|
|
||||||
auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy);
|
auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy);
|
||||||
if (iter != _tabletButtonProxies.end()) {
|
if (iter != _tabletButtonProxies.end()) {
|
||||||
if (_qmlTabletRoot) {
|
if (!_toolbarMode && _qmlTabletRoot) {
|
||||||
(*iter)->setQmlButton(nullptr);
|
(*iter)->setQmlButton(nullptr);
|
||||||
if (tablet) {
|
if (tablet) {
|
||||||
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, (*iter)->getProperties()));
|
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, (*iter)->getProperties()));
|
||||||
}
|
}
|
||||||
|
} else if (_toolbarMode) {
|
||||||
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
||||||
|
|
||||||
|
// remove button from toolbarProxy
|
||||||
|
QMetaObject::invokeMethod(toolbarProxy, "removeButton", Qt::AutoConnection, Q_ARG(QVariant, (*iter)->getUuid().toString()));
|
||||||
|
(*iter)->setToolbarButtonProxy(nullptr);
|
||||||
}
|
}
|
||||||
_tabletButtonProxies.erase(iter);
|
_tabletButtonProxies.erase(iter);
|
||||||
} else {
|
} else {
|
||||||
|
@ -329,20 +459,24 @@ void TabletProxy::updateAudioBar(const double micLevel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::emitScriptEvent(QVariant msg) {
|
void TabletProxy::emitScriptEvent(QVariant msg) {
|
||||||
if (_qmlOffscreenSurface) {
|
if (!_toolbarMode && _qmlOffscreenSurface) {
|
||||||
QMetaObject::invokeMethod(_qmlOffscreenSurface, "emitScriptEvent", Qt::AutoConnection, Q_ARG(QVariant, msg));
|
QMetaObject::invokeMethod(_qmlOffscreenSurface, "emitScriptEvent", Qt::AutoConnection, Q_ARG(QVariant, msg));
|
||||||
|
} else if (_toolbarMode && _desktopWindow) {
|
||||||
|
QMetaObject::invokeMethod(_desktopWindow, "emitScriptEvent", Qt::AutoConnection, Q_ARG(QVariant, msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::sendToQml(QVariant msg) {
|
void TabletProxy::sendToQml(QVariant msg) {
|
||||||
if (_qmlOffscreenSurface) {
|
if (!_toolbarMode && _qmlOffscreenSurface) {
|
||||||
QMetaObject::invokeMethod(_qmlOffscreenSurface, "sendToQml", Qt::AutoConnection, Q_ARG(QVariant, msg));
|
QMetaObject::invokeMethod(_qmlOffscreenSurface, "sendToQml", Qt::AutoConnection, Q_ARG(QVariant, msg));
|
||||||
|
} else if (_toolbarMode && _desktopWindow) {
|
||||||
|
QMetaObject::invokeMethod(_desktopWindow, "sendToQml", Qt::AutoConnection, Q_ARG(QVariant, msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::addButtonsToHomeScreen() {
|
void TabletProxy::addButtonsToHomeScreen() {
|
||||||
auto tablet = getQmlTablet();
|
auto tablet = getQmlTablet();
|
||||||
if (!tablet) {
|
if (!tablet || _toolbarMode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,33 +492,54 @@ QObject* TabletProxy::getTabletSurface() {
|
||||||
return _qmlOffscreenSurface;
|
return _qmlOffscreenSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabletProxy::addButtonsToMenuScreen() {
|
|
||||||
if (!_qmlTabletRoot) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
|
||||||
if (!loader) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QQuickItem* VrMenu = loader->findChild<QQuickItem*>("tabletMenu");
|
|
||||||
if (VrMenu) {
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
|
||||||
QObject* menu = offscreenUi->getRootMenu();
|
|
||||||
QMetaObject::invokeMethod(VrMenu, "setRootMenu", Qt::AutoConnection, Q_ARG(QVariant, QVariant::fromValue(menu)));
|
|
||||||
}
|
|
||||||
|
|
||||||
QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TabletProxy::removeButtonsFromHomeScreen() {
|
void TabletProxy::removeButtonsFromHomeScreen() {
|
||||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
auto tablet = getQmlTablet();
|
||||||
for (auto& buttonProxy : _tabletButtonProxies) {
|
for (auto& buttonProxy : _tabletButtonProxies) {
|
||||||
|
if (tablet) {
|
||||||
|
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getProperties()));
|
||||||
|
}
|
||||||
buttonProxy->setQmlButton(nullptr);
|
buttonProxy->setQmlButton(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabletProxy::desktopWindowClosed() {
|
||||||
|
gotoHomeScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabletProxy::addButtonsToToolbar() {
|
||||||
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
||||||
|
|
||||||
|
Qt::ConnectionType connectionType = Qt::AutoConnection;
|
||||||
|
if (QThread::currentThread() != toolbarProxy->thread()) {
|
||||||
|
connectionType = Qt::BlockingQueuedConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& buttonProxy : _tabletButtonProxies) {
|
||||||
|
// copy properties from tablet button proxy to toolbar button proxy.
|
||||||
|
QObject* toolbarButtonProxy = nullptr;
|
||||||
|
bool hasResult = QMetaObject::invokeMethod(toolbarProxy, "addButton", connectionType, Q_RETURN_ARG(QObject*, toolbarButtonProxy), Q_ARG(QVariant, buttonProxy->getProperties()));
|
||||||
|
if (hasResult) {
|
||||||
|
buttonProxy->setToolbarButtonProxy(toolbarButtonProxy);
|
||||||
|
} else {
|
||||||
|
qCWarning(scriptengine) << "ToolbarProxy addButton has no result";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make the toolbar visible
|
||||||
|
QMetaObject::invokeMethod(toolbarProxy, "writeProperty", Qt::AutoConnection, Q_ARG(QString, "visible"), Q_ARG(QVariant, QVariant(true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabletProxy::removeButtonsFromToolbar() {
|
||||||
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
||||||
|
for (auto& buttonProxy : _tabletButtonProxies) {
|
||||||
|
// remove button from toolbarProxy
|
||||||
|
QMetaObject::invokeMethod(toolbarProxy, "removeButton", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getUuid().toString()));
|
||||||
|
buttonProxy->setToolbarButtonProxy(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QQuickItem* TabletProxy::getQmlTablet() const {
|
QQuickItem* TabletProxy::getQmlTablet() const {
|
||||||
if (!_qmlTabletRoot) {
|
if (!_qmlTabletRoot) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -430,12 +585,14 @@ QQuickItem* TabletProxy::getQmlMenu() const {
|
||||||
//
|
//
|
||||||
|
|
||||||
const QString UUID_KEY = "uuid";
|
const QString UUID_KEY = "uuid";
|
||||||
|
const QString OBJECT_NAME_KEY = "objectName";
|
||||||
const QString STABLE_ORDER_KEY = "stableOrder";
|
const QString STABLE_ORDER_KEY = "stableOrder";
|
||||||
static int s_stableOrder = 1;
|
static int s_stableOrder = 1;
|
||||||
|
|
||||||
TabletButtonProxy::TabletButtonProxy(const QVariantMap& properties) : _uuid(QUuid::createUuid()), _stableOrder(++s_stableOrder), _properties(properties) {
|
TabletButtonProxy::TabletButtonProxy(const QVariantMap& properties) : _uuid(QUuid::createUuid()), _stableOrder(++s_stableOrder), _properties(properties) {
|
||||||
// this is used to uniquely identify this button.
|
// this is used to uniquely identify this button.
|
||||||
_properties[UUID_KEY] = _uuid;
|
_properties[UUID_KEY] = _uuid;
|
||||||
|
_properties[OBJECT_NAME_KEY] = _uuid.toString();
|
||||||
_properties[STABLE_ORDER_KEY] = _stableOrder;
|
_properties[STABLE_ORDER_KEY] = _stableOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,6 +601,14 @@ void TabletButtonProxy::setQmlButton(QQuickItem* qmlButton) {
|
||||||
_qmlButton = qmlButton;
|
_qmlButton = qmlButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabletButtonProxy::setToolbarButtonProxy(QObject* toolbarButtonProxy) {
|
||||||
|
std::lock_guard<std::mutex> guard(_mutex);
|
||||||
|
_toolbarButtonProxy = toolbarButtonProxy;
|
||||||
|
if (_toolbarButtonProxy) {
|
||||||
|
QObject::connect(_toolbarButtonProxy, SIGNAL(clicked()), this, SLOT(clickedSlot()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap TabletButtonProxy::getProperties() const {
|
QVariantMap TabletButtonProxy::getProperties() const {
|
||||||
std::lock_guard<std::mutex> guard(_mutex);
|
std::lock_guard<std::mutex> guard(_mutex);
|
||||||
return _properties;
|
return _properties;
|
||||||
|
@ -451,6 +616,7 @@ QVariantMap TabletButtonProxy::getProperties() const {
|
||||||
|
|
||||||
void TabletButtonProxy::editProperties(QVariantMap properties) {
|
void TabletButtonProxy::editProperties(QVariantMap properties) {
|
||||||
std::lock_guard<std::mutex> guard(_mutex);
|
std::lock_guard<std::mutex> guard(_mutex);
|
||||||
|
|
||||||
QVariantMap::const_iterator iter = properties.constBegin();
|
QVariantMap::const_iterator iter = properties.constBegin();
|
||||||
while (iter != properties.constEnd()) {
|
while (iter != properties.constEnd()) {
|
||||||
_properties[iter.key()] = iter.value();
|
_properties[iter.key()] = iter.value();
|
||||||
|
@ -459,6 +625,10 @@ void TabletButtonProxy::editProperties(QVariantMap properties) {
|
||||||
}
|
}
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_toolbarButtonProxy) {
|
||||||
|
QMetaObject::invokeMethod(_toolbarButtonProxy, "editProperties", Qt::AutoConnection, Q_ARG(QVariantMap, properties));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "TabletScriptingInterface.moc"
|
#include "TabletScriptingInterface.moc"
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
class TabletProxy;
|
class TabletProxy;
|
||||||
class TabletButtonProxy;
|
class TabletButtonProxy;
|
||||||
|
class QmlWindowClass;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @namespace Tablet
|
* @namespace Tablet
|
||||||
|
@ -35,6 +36,9 @@ class TabletScriptingInterface : public QObject, public Dependency {
|
||||||
public:
|
public:
|
||||||
TabletScriptingInterface();
|
TabletScriptingInterface();
|
||||||
|
|
||||||
|
void setToolbarScriptingInterface(QObject* toolbarScriptingInterface) { _toolbarScriptingInterface = toolbarScriptingInterface; }
|
||||||
|
QObject* getSystemToolbarProxy();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Creates or retruns a new TabletProxy and returns it.
|
* Creates or retruns a new TabletProxy and returns it.
|
||||||
* @function Tablet.getTablet
|
* @function Tablet.getTablet
|
||||||
|
@ -43,6 +47,8 @@ public:
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE QObject* getTablet(const QString& tabletId);
|
Q_INVOKABLE QObject* getTablet(const QString& tabletId);
|
||||||
|
|
||||||
|
void setToolbarMode(bool toolbarMode);
|
||||||
|
|
||||||
void setQmlTabletRoot(QString tabletId, QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface);
|
void setQmlTabletRoot(QString tabletId, QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface);
|
||||||
|
|
||||||
void processEvent(const QKeyEvent* event);
|
void processEvent(const QKeyEvent* event);
|
||||||
|
@ -58,15 +64,20 @@ private:
|
||||||
protected:
|
protected:
|
||||||
std::mutex _mutex;
|
std::mutex _mutex;
|
||||||
std::map<QString, QSharedPointer<TabletProxy>> _tabletProxies;
|
std::map<QString, QSharedPointer<TabletProxy>> _tabletProxies;
|
||||||
|
QObject* _toolbarScriptingInterface { nullptr };
|
||||||
|
bool _toolbarMode { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @class TabletProxy
|
* @class TabletProxy
|
||||||
* @property name {string} READ_ONLY: name of this tablet
|
* @property name {string} READ_ONLY: name of this tablet
|
||||||
|
* @property toolbarMode {bool} - used to transition this tablet into and out of toolbar mode.
|
||||||
|
* When tablet is in toolbar mode, all its buttons will appear in a floating toolbar.
|
||||||
*/
|
*/
|
||||||
class TabletProxy : public QObject {
|
class TabletProxy : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QString name READ getName)
|
Q_PROPERTY(QString name READ getName)
|
||||||
|
Q_PROPERTY(bool toolbarMode READ getToolbarMode WRITE setToolbarMode)
|
||||||
public:
|
public:
|
||||||
TabletProxy(QString name);
|
TabletProxy(QString name);
|
||||||
|
|
||||||
|
@ -74,6 +85,11 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void gotoMenuScreen(const QString& submenu = "");
|
Q_INVOKABLE void gotoMenuScreen(const QString& submenu = "");
|
||||||
|
|
||||||
|
QString getName() const { return _name; }
|
||||||
|
|
||||||
|
bool getToolbarMode() const { return _toolbarMode; }
|
||||||
|
void setToolbarMode(bool toolbarMode);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* transition to the home screen
|
* transition to the home screen
|
||||||
* @function TabletProxy#gotoHomeScreen
|
* @function TabletProxy#gotoHomeScreen
|
||||||
|
@ -120,8 +136,6 @@ public:
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void updateAudioBar(const double micLevel);
|
Q_INVOKABLE void updateAudioBar(const double micLevel);
|
||||||
|
|
||||||
QString getName() const { return _name; }
|
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Used to send an event to the html/js embedded in the tablet
|
* Used to send an event to the html/js embedded in the tablet
|
||||||
* @function TabletProxy#emitScriptEvent
|
* @function TabletProxy#emitScriptEvent
|
||||||
|
@ -162,24 +176,28 @@ signals:
|
||||||
void fromQml(QVariant msg);
|
void fromQml(QVariant msg);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Signales when this tablet screen changes.
|
* Signaled when this tablet screen changes.
|
||||||
* @function TabletProxy#screenChanged
|
* @function TabletProxy#screenChanged
|
||||||
* @param type {string} - "Home", "Web", "Menu", "QML", "Closed"
|
* @param type {string} - "Home", "Web", "Menu", "QML", "Closed"
|
||||||
* @param url {string} - only valid for Web and QML.
|
* @param url {string} - only valid for Web and QML.
|
||||||
*/
|
*/
|
||||||
void screenChanged(QVariant type, QVariant url);
|
void screenChanged(QVariant type, QVariant url);
|
||||||
|
|
||||||
private slots:
|
protected slots:
|
||||||
void addButtonsToHomeScreen();
|
void addButtonsToHomeScreen();
|
||||||
void addButtonsToMenuScreen();
|
void desktopWindowClosed();
|
||||||
protected:
|
protected:
|
||||||
void removeButtonsFromHomeScreen();
|
void removeButtonsFromHomeScreen();
|
||||||
|
void addButtonsToToolbar();
|
||||||
|
void removeButtonsFromToolbar();
|
||||||
|
|
||||||
QString _name;
|
QString _name;
|
||||||
std::mutex _mutex;
|
std::mutex _mutex;
|
||||||
std::vector<QSharedPointer<TabletButtonProxy>> _tabletButtonProxies;
|
std::vector<QSharedPointer<TabletButtonProxy>> _tabletButtonProxies;
|
||||||
QQuickItem* _qmlTabletRoot { nullptr };
|
QQuickItem* _qmlTabletRoot { nullptr };
|
||||||
QObject* _qmlOffscreenSurface { nullptr };
|
QObject* _qmlOffscreenSurface { nullptr };
|
||||||
|
QmlWindowClass* _desktopWindow { nullptr };
|
||||||
|
bool _toolbarMode { false };
|
||||||
|
|
||||||
enum class State { Uninitialized, Home, Web, Menu, QML };
|
enum class State { Uninitialized, Home, Web, Menu, QML };
|
||||||
State _state { State::Uninitialized };
|
State _state { State::Uninitialized };
|
||||||
|
@ -196,6 +214,7 @@ public:
|
||||||
TabletButtonProxy(const QVariantMap& properties);
|
TabletButtonProxy(const QVariantMap& properties);
|
||||||
|
|
||||||
void setQmlButton(QQuickItem* qmlButton);
|
void setQmlButton(QQuickItem* qmlButton);
|
||||||
|
void setToolbarButtonProxy(QObject* toolbarButtonProxy);
|
||||||
|
|
||||||
QUuid getUuid() const { return _uuid; }
|
QUuid getUuid() const { return _uuid; }
|
||||||
|
|
||||||
|
@ -229,6 +248,7 @@ protected:
|
||||||
int _stableOrder;
|
int _stableOrder;
|
||||||
mutable std::mutex _mutex;
|
mutable std::mutex _mutex;
|
||||||
QQuickItem* _qmlButton { nullptr };
|
QQuickItem* _qmlButton { nullptr };
|
||||||
|
QObject* _toolbarButtonProxy { nullptr };
|
||||||
QVariantMap _properties;
|
QVariantMap _properties;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,17 @@ const QString InfoView::NAME{ "InfoView" };
|
||||||
|
|
||||||
Setting::Handle<QString> infoVersion("info-version", QString());
|
Setting::Handle<QString> infoVersion("info-version", QString());
|
||||||
|
|
||||||
InfoView::InfoView(QQuickItem* parent) : QQuickItem(parent) {
|
static bool registered{ false };
|
||||||
|
|
||||||
|
InfoView::InfoView(QQuickItem* parent) : QQuickItem(parent) {
|
||||||
|
registerType();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoView::registerType() {
|
void InfoView::registerType() {
|
||||||
|
if (!registered) {
|
||||||
qmlRegisterType<InfoView>("Hifi", 1, 0, NAME.toLocal8Bit().constData());
|
qmlRegisterType<InfoView>("Hifi", 1, 0, NAME.toLocal8Bit().constData());
|
||||||
|
registered = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString fetchVersion(const QUrl& url) {
|
QString fetchVersion(const QUrl& url) {
|
||||||
|
@ -38,11 +43,7 @@ QString fetchVersion(const QUrl& url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoView::show(const QString& path, bool firstOrChangedOnly, QString urlQuery) {
|
void InfoView::show(const QString& path, bool firstOrChangedOnly, QString urlQuery) {
|
||||||
static bool registered{ false };
|
|
||||||
if (!registered) {
|
|
||||||
registerType();
|
registerType();
|
||||||
registered = true;
|
|
||||||
}
|
|
||||||
QUrl url;
|
QUrl url;
|
||||||
if (QDir(path).isRelative()) {
|
if (QDir(path).isRelative()) {
|
||||||
url = QUrl::fromLocalFile(PathUtils::resourcesPath() + path);
|
url = QUrl::fromLocalFile(PathUtils::resourcesPath() + path);
|
||||||
|
@ -87,4 +88,3 @@ void InfoView::setUrl(const QUrl& url) {
|
||||||
emit urlChanged();
|
emit urlChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,9 @@ public:
|
||||||
QmlWindowClass();
|
QmlWindowClass();
|
||||||
~QmlWindowClass();
|
~QmlWindowClass();
|
||||||
|
|
||||||
|
virtual void initQml(QVariantMap properties);
|
||||||
|
QQuickItem* asQuickItem() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool isVisible() const;
|
bool isVisible() const;
|
||||||
void setVisible(bool visible);
|
void setVisible(bool visible);
|
||||||
|
@ -81,9 +84,6 @@ protected:
|
||||||
|
|
||||||
virtual QString qmlSource() const { return "QmlWindow.qml"; }
|
virtual QString qmlSource() const { return "QmlWindow.qml"; }
|
||||||
|
|
||||||
virtual void initQml(QVariantMap properties);
|
|
||||||
QQuickItem* asQuickItem() const;
|
|
||||||
|
|
||||||
// FIXME needs to be initialized in the ctor once we have support
|
// FIXME needs to be initialized in the ctor once we have support
|
||||||
// for tool window panes in QML
|
// for tool window panes in QML
|
||||||
bool _toolWindow { false };
|
bool _toolWindow { false };
|
||||||
|
|
|
@ -9,49 +9,30 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
var button;
|
|
||||||
var TOOLBAR_BUTTON_NAME = "MUTE";
|
|
||||||
var TABLET_BUTTON_NAME = "AUDIO";
|
var TABLET_BUTTON_NAME = "AUDIO";
|
||||||
var toolBar = null;
|
|
||||||
var tablet = null;
|
|
||||||
var isHUDUIEnabled = Settings.getValue("HUDUIEnabled");
|
|
||||||
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
|
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
|
||||||
|
|
||||||
function onMuteToggled() {
|
function onMuteToggled() {
|
||||||
if (isHUDUIEnabled) {
|
|
||||||
button.editProperties({ isActive: AudioDevice.getMuted() });
|
button.editProperties({ isActive: AudioDevice.getMuted() });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
function onClicked(){
|
function onClicked(){
|
||||||
if (isHUDUIEnabled) {
|
|
||||||
var menuItem = "Mute Microphone";
|
|
||||||
Menu.setIsOptionChecked(menuItem, !Menu.isOptionChecked(menuItem));
|
|
||||||
} else {
|
|
||||||
var entity = HMD.tabletID;
|
var entity = HMD.tabletID;
|
||||||
Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) });
|
Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) });
|
||||||
tablet.gotoMenuScreen("Audio");
|
tablet.gotoMenuScreen("Audio");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
var button = tablet.addButton({
|
||||||
button = toolBar.addButton({
|
icon: "icons/tablet-icons/mic-unmute-i.svg",
|
||||||
objectName: TOOLBAR_BUTTON_NAME,
|
activeIcon: "icons/tablet-icons/mic-mute-a.svg",
|
||||||
imageURL: Script.resolvePath("assets/images/tools/mic.svg"),
|
|
||||||
visible: true,
|
|
||||||
alpha: 0.9
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
||||||
button = tablet.addButton({
|
|
||||||
icon: "icons/tablet-icons/mic-i.svg",
|
|
||||||
text: TABLET_BUTTON_NAME,
|
text: TABLET_BUTTON_NAME,
|
||||||
sortOrder: 1
|
sortOrder: 1
|
||||||
});
|
});
|
||||||
}
|
|
||||||
onMuteToggled();
|
onMuteToggled();
|
||||||
|
|
||||||
button.clicked.connect(onClicked);
|
button.clicked.connect(onClicked);
|
||||||
|
@ -60,12 +41,7 @@ AudioDevice.muteToggled.connect(onMuteToggled);
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
button.clicked.disconnect(onClicked);
|
button.clicked.disconnect(onClicked);
|
||||||
AudioDevice.muteToggled.disconnect(onMuteToggled);
|
AudioDevice.muteToggled.disconnect(onMuteToggled);
|
||||||
if (tablet) {
|
|
||||||
tablet.removeButton(button);
|
tablet.removeButton(button);
|
||||||
}
|
|
||||||
if (toolBar) {
|
|
||||||
toolBar.removeButton(TOOLBAR_BUTTON_NAME);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}()); // END LOCAL_SCOPE
|
}()); // END LOCAL_SCOPE
|
||||||
|
|
|
@ -10,11 +10,9 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
/* global Toolbars, Script, Users, Overlays, AvatarList, Controller, Camera, getControllerWorldLocation */
|
/* global Script, Users, Overlays, AvatarList, Controller, Camera, getControllerWorldLocation */
|
||||||
|
|
||||||
|
|
||||||
(function () { // BEGIN LOCAL_SCOPE
|
(function () { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
var button;
|
var button;
|
||||||
// Used for animating and disappearing the bubble
|
// Used for animating and disappearing the bubble
|
||||||
var bubbleOverlayTimestamp;
|
var bubbleOverlayTimestamp;
|
||||||
|
@ -23,7 +21,7 @@
|
||||||
// Used for flashing the HUD button upon activation
|
// Used for flashing the HUD button upon activation
|
||||||
var bubbleButtonTimestamp;
|
var bubbleButtonTimestamp;
|
||||||
// Affects bubble height
|
// Affects bubble height
|
||||||
const BUBBLE_HEIGHT_SCALE = 0.15;
|
var BUBBLE_HEIGHT_SCALE = 0.15;
|
||||||
// The bubble model itself
|
// The bubble model itself
|
||||||
var bubbleOverlay = Overlays.addOverlay("model", {
|
var bubbleOverlay = Overlays.addOverlay("model", {
|
||||||
url: Script.resolvePath("assets/models/Bubble-v14.fbx"), // If you'd like to change the model, modify this line (and the dimensions below)
|
url: Script.resolvePath("assets/models/Bubble-v14.fbx"), // If you'd like to change the model, modify this line (and the dimensions below)
|
||||||
|
@ -39,16 +37,8 @@
|
||||||
// Is the update() function connected?
|
// Is the update() function connected?
|
||||||
var updateConnected = false;
|
var updateConnected = false;
|
||||||
|
|
||||||
const BUBBLE_VISIBLE_DURATION_MS = 3000;
|
var BUBBLE_VISIBLE_DURATION_MS = 3000;
|
||||||
const BUBBLE_RAISE_ANIMATION_DURATION_MS = 750;
|
var BUBBLE_RAISE_ANIMATION_DURATION_MS = 750;
|
||||||
const BUBBLE_HUD_ICON_FLASH_INTERVAL_MS = 500;
|
|
||||||
|
|
||||||
var ASSETS_PATH = Script.resolvePath("assets");
|
|
||||||
var TOOLS_PATH = Script.resolvePath("assets/images/tools/");
|
|
||||||
|
|
||||||
function buttonImageURL() {
|
|
||||||
return TOOLS_PATH + 'bubble.svg';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hides the bubble model overlay and resets the button flash state
|
// Hides the bubble model overlay and resets the button flash state
|
||||||
function hideOverlays() {
|
function hideOverlays() {
|
||||||
|
@ -94,7 +84,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// The bubble script's update function
|
// The bubble script's update function
|
||||||
update = function () {
|
function update() {
|
||||||
var timestamp = Date.now();
|
var timestamp = Date.now();
|
||||||
var delay = (timestamp - bubbleOverlayTimestamp);
|
var delay = (timestamp - bubbleOverlayTimestamp);
|
||||||
var overlayAlpha = 1.0 - (delay / BUBBLE_VISIBLE_DURATION_MS);
|
var overlayAlpha = 1.0 - (delay / BUBBLE_VISIBLE_DURATION_MS);
|
||||||
|
@ -146,7 +136,7 @@
|
||||||
var bubbleActive = Users.getIgnoreRadiusEnabled();
|
var bubbleActive = Users.getIgnoreRadiusEnabled();
|
||||||
writeButtonProperties(bubbleActive);
|
writeButtonProperties(bubbleActive);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// When the space bubble is toggled...
|
// When the space bubble is toggled...
|
||||||
function onBubbleToggled() {
|
function onBubbleToggled() {
|
||||||
|
@ -165,15 +155,6 @@
|
||||||
|
|
||||||
// Setup the bubble button
|
// Setup the bubble button
|
||||||
var buttonName = "BUBBLE";
|
var buttonName = "BUBBLE";
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
|
||||||
var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
|
||||||
button = toolbar.addButton({
|
|
||||||
objectName: 'bubble',
|
|
||||||
imageURL: buttonImageURL(),
|
|
||||||
visible: true,
|
|
||||||
alpha: 0.9
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
button = tablet.addButton({
|
button = tablet.addButton({
|
||||||
icon: "icons/tablet-icons/bubble-i.svg",
|
icon: "icons/tablet-icons/bubble-i.svg",
|
||||||
|
@ -181,22 +162,19 @@
|
||||||
text: buttonName,
|
text: buttonName,
|
||||||
sortOrder: 4
|
sortOrder: 4
|
||||||
});
|
});
|
||||||
}
|
|
||||||
onBubbleToggled();
|
onBubbleToggled();
|
||||||
|
|
||||||
button.clicked.connect(Users.toggleIgnoreRadius);
|
button.clicked.connect(Users.toggleIgnoreRadius);
|
||||||
Users.ignoreRadiusEnabledChanged.connect(onBubbleToggled);
|
Users.ignoreRadiusEnabledChanged.connect(onBubbleToggled);
|
||||||
Users.enteredIgnoreRadius.connect(enteredIgnoreRadius);
|
Users.enteredIgnoreRadius.connect(enteredIgnoreRadius);
|
||||||
|
|
||||||
// Cleanup the toolbar button and overlays when script is stopped
|
// Cleanup the tablet button and overlays when script is stopped
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
button.clicked.disconnect(Users.toggleIgnoreRadius);
|
button.clicked.disconnect(Users.toggleIgnoreRadius);
|
||||||
if (tablet) {
|
if (tablet) {
|
||||||
tablet.removeButton(button);
|
tablet.removeButton(button);
|
||||||
}
|
}
|
||||||
if (toolbar) {
|
|
||||||
toolbar.removeButton('bubble');
|
|
||||||
}
|
|
||||||
Users.ignoreRadiusEnabledChanged.disconnect(onBubbleToggled);
|
Users.ignoreRadiusEnabledChanged.disconnect(onBubbleToggled);
|
||||||
Users.enteredIgnoreRadius.disconnect(enteredIgnoreRadius);
|
Users.enteredIgnoreRadius.disconnect(enteredIgnoreRadius);
|
||||||
Overlays.deleteOverlay(bubbleOverlay);
|
Overlays.deleteOverlay(bubbleOverlay);
|
||||||
|
|
|
@ -480,6 +480,10 @@ var LASER_SEARCH_COLOR_XYZW = {x: 10 / 255, y: 10 / 255, z: 255 / 255, w: LASER_
|
||||||
var LASER_TRIGGER_COLOR_XYZW = {x: 250 / 255, y: 10 / 255, z: 10 / 255, w: LASER_ALPHA};
|
var LASER_TRIGGER_COLOR_XYZW = {x: 250 / 255, y: 10 / 255, z: 10 / 255, w: LASER_ALPHA};
|
||||||
var SYSTEM_LASER_DIRECTION = {x: 0, y: 0, z: -1};
|
var SYSTEM_LASER_DIRECTION = {x: 0, y: 0, z: -1};
|
||||||
var systemLaserOn = false;
|
var systemLaserOn = false;
|
||||||
|
|
||||||
|
var HIFI_POINTER_DISABLE_MESSAGE_CHANNEL = "Hifi-Pointer-Disable";
|
||||||
|
var isPointerEnabled = true;
|
||||||
|
|
||||||
function clearSystemLaser() {
|
function clearSystemLaser() {
|
||||||
if (!systemLaserOn) {
|
if (!systemLaserOn) {
|
||||||
return;
|
return;
|
||||||
|
@ -542,9 +546,8 @@ function update() {
|
||||||
return off();
|
return off();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If there's a HUD element at the (newly moved) reticle, just make it visible and bail.
|
// If there's a HUD element at the (newly moved) reticle, just make it visible and bail.
|
||||||
if (isPointingAtOverlay(hudPoint2d)) {
|
if (isPointingAtOverlay(hudPoint2d) && isPointerEnabled) {
|
||||||
if (HMD.active) {
|
if (HMD.active) {
|
||||||
Reticle.depth = hudReticleDistance();
|
Reticle.depth = hudReticleDistance();
|
||||||
|
|
||||||
|
@ -579,9 +582,25 @@ function checkSettings() {
|
||||||
}
|
}
|
||||||
checkSettings();
|
checkSettings();
|
||||||
|
|
||||||
|
// Enable/disable pointer.
|
||||||
|
function handleMessages(channel, message, sender) {
|
||||||
|
if (sender === MyAvatar.sessionUUID && channel === HIFI_POINTER_DISABLE_MESSAGE_CHANNEL) {
|
||||||
|
var data = JSON.parse(message);
|
||||||
|
if (data.pointerEnabled !== undefined) {
|
||||||
|
print("pointerEnabled: " + data.pointerEnabled);
|
||||||
|
isPointerEnabled = data.pointerEnabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages.subscribe(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL);
|
||||||
|
Messages.messageReceived.connect(handleMessages);
|
||||||
|
|
||||||
var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL);
|
var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL);
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
|
Messages.unsubscribe(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL);
|
||||||
|
Messages.messageReceived.disconnect(handleMessages);
|
||||||
Script.clearInterval(settingsChecker);
|
Script.clearInterval(settingsChecker);
|
||||||
Script.update.disconnect(update);
|
Script.update.disconnect(update);
|
||||||
OffscreenFlags.navigationFocusDisabled = false;
|
OffscreenFlags.navigationFocusDisabled = false;
|
||||||
|
|
|
@ -25,6 +25,11 @@ var OVERLAY_RAMP_RATE = 8.0;
|
||||||
|
|
||||||
var animStateHandlerID;
|
var animStateHandlerID;
|
||||||
|
|
||||||
|
var isPointingIndex = false;
|
||||||
|
var HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index";
|
||||||
|
|
||||||
|
var indexfingerJointNames = ["LeftHandIndex1", "LeftHandIndex2", "LeftHandIndex3", "RightHandIndex1", "RightHandIndex2", "RightHandIndex3"];
|
||||||
|
|
||||||
function clamp(val, min, max) {
|
function clamp(val, min, max) {
|
||||||
return Math.min(Math.max(val, min), max);
|
return Math.min(Math.max(val, min), max);
|
||||||
}
|
}
|
||||||
|
@ -43,6 +48,8 @@ function init() {
|
||||||
animStateHandler,
|
animStateHandler,
|
||||||
["leftHandOverlayAlpha", "rightHandOverlayAlpha", "leftHandGraspAlpha", "rightHandGraspAlpha"]
|
["leftHandOverlayAlpha", "rightHandOverlayAlpha", "leftHandGraspAlpha", "rightHandGraspAlpha"]
|
||||||
);
|
);
|
||||||
|
Messages.subscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL);
|
||||||
|
Messages.messageReceived.connect(handleMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
function animStateHandler(props) {
|
function animStateHandler(props) {
|
||||||
|
@ -76,11 +83,37 @@ function update(dt) {
|
||||||
} else {
|
} else {
|
||||||
rightHandOverlayAlpha = clamp(rightHandOverlayAlpha - OVERLAY_RAMP_RATE * dt, 0, 1);
|
rightHandOverlayAlpha = clamp(rightHandOverlayAlpha - OVERLAY_RAMP_RATE * dt, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Point index finger.
|
||||||
|
if (isPointingIndex) {
|
||||||
|
var zeroRotation = { x: 0, y: 0, z: 0, w: 1 };
|
||||||
|
for (var i = 0; i < indexfingerJointNames.length; i++) {
|
||||||
|
MyAvatar.setJointRotation(indexfingerJointNames[i], zeroRotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMessages(channel, message, sender) {
|
||||||
|
if (sender === MyAvatar.sessionUUID && channel === HIFI_POINT_INDEX_MESSAGE_CHANNEL) {
|
||||||
|
var data = JSON.parse(message);
|
||||||
|
if (data.pointIndex !== undefined) {
|
||||||
|
print("pointIndex: " + data.pointIndex);
|
||||||
|
isPointingIndex = data.pointIndex;
|
||||||
|
|
||||||
|
if (!isPointingIndex) {
|
||||||
|
for (var i = 0; i < indexfingerJointNames.length; i++) {
|
||||||
|
MyAvatar.clearJointData(indexfingerJointNames[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function shutdown() {
|
function shutdown() {
|
||||||
Script.update.disconnect(update);
|
Script.update.disconnect(update);
|
||||||
MyAvatar.removeAnimationStateHandler(animStateHandlerID);
|
MyAvatar.removeAnimationStateHandler(animStateHandlerID);
|
||||||
|
Messages.unsubscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL);
|
||||||
|
Messages.messageReceived.disconnect(handleMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.scriptEnding.connect(shutdown);
|
Script.scriptEnding.connect(shutdown);
|
||||||
|
|
433
scripts/system/fingerPaint.js
Normal file
433
scripts/system/fingerPaint.js
Normal file
|
@ -0,0 +1,433 @@
|
||||||
|
//
|
||||||
|
// fingerPaint.js
|
||||||
|
//
|
||||||
|
// Created by David Rowe on 15 Feb 2017
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var tablet,
|
||||||
|
button,
|
||||||
|
BUTTON_NAME = "PAINT",
|
||||||
|
isFingerPainting = false,
|
||||||
|
leftHand = null,
|
||||||
|
rightHand = null,
|
||||||
|
leftBrush = null,
|
||||||
|
rightBrush = null,
|
||||||
|
CONTROLLER_MAPPING_NAME = "com.highfidelity.fingerPaint",
|
||||||
|
isTabletDisplayed = false,
|
||||||
|
HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index",
|
||||||
|
HIFI_GRAB_DISABLE_MESSAGE_CHANNEL = "Hifi-Grab-Disable",
|
||||||
|
HIFI_POINTER_DISABLE_MESSAGE_CHANNEL = "Hifi-Pointer-Disable";
|
||||||
|
|
||||||
|
function paintBrush(name) {
|
||||||
|
// Paints in 3D.
|
||||||
|
var brushName = name,
|
||||||
|
STROKE_COLOR = { red: 250, green: 0, blue: 0 },
|
||||||
|
ERASE_SEARCH_RADIUS = 0.1, // m
|
||||||
|
isDrawingLine = false,
|
||||||
|
entityID,
|
||||||
|
basePosition,
|
||||||
|
strokePoints,
|
||||||
|
strokeNormals,
|
||||||
|
strokeWidths,
|
||||||
|
timeOfLastPoint,
|
||||||
|
MIN_STROKE_LENGTH = 0.005, // m
|
||||||
|
MIN_STROKE_INTERVAL = 66, // ms
|
||||||
|
MAX_POINTS_PER_LINE = 70; // Hard-coded limit in PolyLineEntityItem.h.
|
||||||
|
|
||||||
|
function strokeNormal() {
|
||||||
|
return Vec3.multiplyQbyV(Camera.getOrientation(), Vec3.UNIT_NEG_Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startLine(position, width) {
|
||||||
|
// Start drawing a polyline.
|
||||||
|
|
||||||
|
if (isDrawingLine) {
|
||||||
|
print("ERROR: startLine() called when already drawing line");
|
||||||
|
// Nevertheless, continue on and start a new line.
|
||||||
|
}
|
||||||
|
|
||||||
|
basePosition = position;
|
||||||
|
|
||||||
|
strokePoints = [Vec3.ZERO];
|
||||||
|
strokeNormals = [strokeNormal()];
|
||||||
|
strokeWidths = [width];
|
||||||
|
timeOfLastPoint = Date.now();
|
||||||
|
|
||||||
|
entityID = Entities.addEntity({
|
||||||
|
type: "PolyLine",
|
||||||
|
name: "fingerPainting",
|
||||||
|
color: STROKE_COLOR,
|
||||||
|
position: position,
|
||||||
|
linePoints: strokePoints,
|
||||||
|
normals: strokeNormals,
|
||||||
|
strokeWidths: strokeWidths,
|
||||||
|
dimensions: { x: 10, y: 10, z: 10 }
|
||||||
|
});
|
||||||
|
|
||||||
|
isDrawingLine = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLine(position, width) {
|
||||||
|
// Add a stroke to the polyline if stroke is a sufficient length.
|
||||||
|
var localPosition,
|
||||||
|
distanceToPrevious,
|
||||||
|
MAX_DISTANCE_TO_PREVIOUS = 1.0;
|
||||||
|
|
||||||
|
if (!isDrawingLine) {
|
||||||
|
print("ERROR: drawLine() called when not drawing line");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
localPosition = Vec3.subtract(position, basePosition);
|
||||||
|
distanceToPrevious = Vec3.distance(localPosition, strokePoints[strokePoints.length - 1]);
|
||||||
|
|
||||||
|
if (distanceToPrevious > MAX_DISTANCE_TO_PREVIOUS) {
|
||||||
|
// Ignore occasional spurious finger tip positions.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceToPrevious >= MIN_STROKE_LENGTH
|
||||||
|
&& (Date.now() - timeOfLastPoint) >= MIN_STROKE_INTERVAL
|
||||||
|
&& strokePoints.length < MAX_POINTS_PER_LINE) {
|
||||||
|
strokePoints.push(localPosition);
|
||||||
|
strokeNormals.push(strokeNormal());
|
||||||
|
strokeWidths.push(width);
|
||||||
|
timeOfLastPoint = Date.now();
|
||||||
|
|
||||||
|
Entities.editEntity(entityID, {
|
||||||
|
linePoints: strokePoints,
|
||||||
|
normals: strokeNormals,
|
||||||
|
strokeWidths: strokeWidths
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishLine(position, width) {
|
||||||
|
// Finish drawing polyline; delete if it has only 1 point.
|
||||||
|
|
||||||
|
if (!isDrawingLine) {
|
||||||
|
print("ERROR: finishLine() called when not drawing line");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strokePoints.length === 1) {
|
||||||
|
// Delete "empty" line.
|
||||||
|
Entities.deleteEntity(entityID);
|
||||||
|
}
|
||||||
|
|
||||||
|
isDrawingLine = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelLine() {
|
||||||
|
// Cancel any line being drawn.
|
||||||
|
if (isDrawingLine) {
|
||||||
|
Entities.deleteEntity(entityID);
|
||||||
|
isDrawingLine = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function eraseClosestLine(position) {
|
||||||
|
// Erase closest line that is within search radius of finger tip.
|
||||||
|
var entities,
|
||||||
|
entitiesLength,
|
||||||
|
properties,
|
||||||
|
i,
|
||||||
|
pointsLength,
|
||||||
|
j,
|
||||||
|
distance,
|
||||||
|
found = false,
|
||||||
|
foundID,
|
||||||
|
foundDistance = ERASE_SEARCH_RADIUS;
|
||||||
|
|
||||||
|
// Find entities with bounding box within search radius.
|
||||||
|
entities = Entities.findEntities(position, ERASE_SEARCH_RADIUS);
|
||||||
|
|
||||||
|
// Fine polyline entity with closest point within search radius.
|
||||||
|
for (i = 0, entitiesLength = entities.length; i < entitiesLength; i += 1) {
|
||||||
|
properties = Entities.getEntityProperties(entities[i], ["type", "position", "linePoints"]);
|
||||||
|
if (properties.type === "PolyLine") {
|
||||||
|
basePosition = properties.position;
|
||||||
|
for (j = 0, pointsLength = properties.linePoints.length; j < pointsLength; j += 1) {
|
||||||
|
distance = Vec3.distance(position, Vec3.sum(basePosition, properties.linePoints[j]));
|
||||||
|
if (distance <= foundDistance) {
|
||||||
|
found = true;
|
||||||
|
foundID = entities[i];
|
||||||
|
foundDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete found entity.
|
||||||
|
if (found) {
|
||||||
|
Entities.deleteEntity(foundID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tearDown() {
|
||||||
|
cancelLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
startLine: startLine,
|
||||||
|
drawLine: drawLine,
|
||||||
|
finishLine: finishLine,
|
||||||
|
cancelLine: cancelLine,
|
||||||
|
eraseClosestLine: eraseClosestLine,
|
||||||
|
tearDown: tearDown
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function handController(name) {
|
||||||
|
// Translates controller data into application events.
|
||||||
|
var handName = name,
|
||||||
|
|
||||||
|
triggerPressedCallback,
|
||||||
|
triggerPressingCallback,
|
||||||
|
triggerReleasedCallback,
|
||||||
|
gripPressedCallback,
|
||||||
|
|
||||||
|
rawTriggerValue = 0.0,
|
||||||
|
triggerValue = 0.0,
|
||||||
|
isTriggerPressed = false,
|
||||||
|
TRIGGER_SMOOTH_RATIO = 0.1,
|
||||||
|
TRIGGER_OFF = 0.05,
|
||||||
|
TRIGGER_ON = 0.1,
|
||||||
|
TRIGGER_START_WIDTH_RAMP = 0.15,
|
||||||
|
TRIGGER_FINISH_WIDTH_RAMP = 1.0,
|
||||||
|
TRIGGER_RAMP_WIDTH = TRIGGER_FINISH_WIDTH_RAMP - TRIGGER_START_WIDTH_RAMP,
|
||||||
|
MIN_LINE_WIDTH = 0.005,
|
||||||
|
MAX_LINE_WIDTH = 0.03,
|
||||||
|
RAMP_LINE_WIDTH = MAX_LINE_WIDTH - MIN_LINE_WIDTH,
|
||||||
|
|
||||||
|
rawGripValue = 0.0,
|
||||||
|
gripValue = 0.0,
|
||||||
|
isGripPressed = false,
|
||||||
|
GRIP_SMOOTH_RATIO = 0.1,
|
||||||
|
GRIP_OFF = 0.05,
|
||||||
|
GRIP_ON = 0.1;
|
||||||
|
|
||||||
|
function onTriggerPress(value) {
|
||||||
|
// Controller values are only updated when they change so store latest for use in update.
|
||||||
|
rawTriggerValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTriggerPress(value) {
|
||||||
|
var wasTriggerPressed,
|
||||||
|
fingerTipPosition,
|
||||||
|
lineWidth;
|
||||||
|
|
||||||
|
triggerValue = triggerValue * TRIGGER_SMOOTH_RATIO + rawTriggerValue * (1.0 - TRIGGER_SMOOTH_RATIO);
|
||||||
|
|
||||||
|
wasTriggerPressed = isTriggerPressed;
|
||||||
|
if (isTriggerPressed) {
|
||||||
|
isTriggerPressed = triggerValue > TRIGGER_OFF;
|
||||||
|
} else {
|
||||||
|
isTriggerPressed = triggerValue > TRIGGER_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wasTriggerPressed || isTriggerPressed) {
|
||||||
|
fingerTipPosition = MyAvatar.getJointPosition(handName === "left" ? "LeftHandIndex4" : "RightHandIndex4");
|
||||||
|
if (triggerValue < TRIGGER_START_WIDTH_RAMP) {
|
||||||
|
lineWidth = MIN_LINE_WIDTH;
|
||||||
|
} else {
|
||||||
|
lineWidth = MIN_LINE_WIDTH
|
||||||
|
+ (triggerValue - TRIGGER_START_WIDTH_RAMP) / TRIGGER_RAMP_WIDTH * RAMP_LINE_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wasTriggerPressed && isTriggerPressed) {
|
||||||
|
triggerPressedCallback(fingerTipPosition, lineWidth);
|
||||||
|
} else if (wasTriggerPressed && isTriggerPressed) {
|
||||||
|
triggerPressingCallback(fingerTipPosition, lineWidth);
|
||||||
|
} else {
|
||||||
|
triggerReleasedCallback(fingerTipPosition, lineWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onGripPress(value) {
|
||||||
|
// Controller values are only updated when they change so store latest for use in update.
|
||||||
|
rawGripValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateGripPress() {
|
||||||
|
var fingerTipPosition;
|
||||||
|
|
||||||
|
gripValue = gripValue * GRIP_SMOOTH_RATIO + rawGripValue * (1.0 - GRIP_SMOOTH_RATIO);
|
||||||
|
|
||||||
|
if (isGripPressed) {
|
||||||
|
isGripPressed = gripValue > GRIP_OFF;
|
||||||
|
} else {
|
||||||
|
isGripPressed = gripValue > GRIP_ON;
|
||||||
|
if (isGripPressed) {
|
||||||
|
fingerTipPosition = MyAvatar.getJointPosition(handName === "left" ? "LeftHandIndex4" : "RightHandIndex4");
|
||||||
|
gripPressedCallback(fingerTipPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUpdate() {
|
||||||
|
updateTriggerPress();
|
||||||
|
updateGripPress();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUp(onTriggerPressed, onTriggerPressing, onTriggerReleased, onGripPressed) {
|
||||||
|
triggerPressedCallback = onTriggerPressed;
|
||||||
|
triggerPressingCallback = onTriggerPressing;
|
||||||
|
triggerReleasedCallback = onTriggerReleased;
|
||||||
|
gripPressedCallback = onGripPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tearDown() {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
onTriggerPress: onTriggerPress,
|
||||||
|
onGripPress: onGripPress,
|
||||||
|
onUpdate: onUpdate,
|
||||||
|
setUp: setUp,
|
||||||
|
tearDown: tearDown
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHandFunctions() {
|
||||||
|
// Update other scripts' hand functions.
|
||||||
|
var enabled = !isFingerPainting || isTabletDisplayed;
|
||||||
|
|
||||||
|
Messages.sendMessage(HIFI_GRAB_DISABLE_MESSAGE_CHANNEL, JSON.stringify({
|
||||||
|
holdEnabled: enabled,
|
||||||
|
nearGrabEnabled: enabled,
|
||||||
|
farGrabEnabled: enabled
|
||||||
|
}), true);
|
||||||
|
Messages.sendMessage(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL, JSON.stringify({
|
||||||
|
pointerEnabled: enabled
|
||||||
|
}), true);
|
||||||
|
Messages.sendMessage(HIFI_POINT_INDEX_MESSAGE_CHANNEL, JSON.stringify({
|
||||||
|
pointIndex: !enabled
|
||||||
|
}), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableProcessing() {
|
||||||
|
// Connect controller API to handController objects.
|
||||||
|
leftHand = handController("left");
|
||||||
|
rightHand = handController("right");
|
||||||
|
var controllerMapping = Controller.newMapping(CONTROLLER_MAPPING_NAME);
|
||||||
|
controllerMapping.from(Controller.Standard.LT).to(leftHand.onTriggerPress);
|
||||||
|
controllerMapping.from(Controller.Standard.LeftGrip).to(leftHand.onGripPress);
|
||||||
|
controllerMapping.from(Controller.Standard.RT).to(rightHand.onTriggerPress);
|
||||||
|
controllerMapping.from(Controller.Standard.RightGrip).to(rightHand.onGripPress);
|
||||||
|
Controller.enableMapping(CONTROLLER_MAPPING_NAME);
|
||||||
|
|
||||||
|
// Connect handController outputs to paintBrush objects.
|
||||||
|
leftBrush = paintBrush("left");
|
||||||
|
leftHand.setUp(leftBrush.startLine, leftBrush.drawLine, leftBrush.finishLine, leftBrush.eraseClosestLine);
|
||||||
|
rightBrush = paintBrush("right");
|
||||||
|
rightHand.setUp(rightBrush.startLine, rightBrush.drawLine, rightBrush.finishLine, rightBrush.eraseClosestLine);
|
||||||
|
|
||||||
|
// Messages channels for enabling/disabling other scripts' functions.
|
||||||
|
Messages.subscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL);
|
||||||
|
Messages.subscribe(HIFI_GRAB_DISABLE_MESSAGE_CHANNEL);
|
||||||
|
Messages.subscribe(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL);
|
||||||
|
|
||||||
|
// Update hand controls.
|
||||||
|
Script.update.connect(leftHand.onUpdate);
|
||||||
|
Script.update.connect(rightHand.onUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableProcessing() {
|
||||||
|
Script.update.disconnect(leftHand.onUpdate);
|
||||||
|
Script.update.disconnect(rightHand.onUpdate);
|
||||||
|
|
||||||
|
Controller.disableMapping(CONTROLLER_MAPPING_NAME);
|
||||||
|
|
||||||
|
leftBrush.tearDown();
|
||||||
|
leftBrush = null;
|
||||||
|
leftHand.tearDown();
|
||||||
|
leftHand = null;
|
||||||
|
|
||||||
|
rightBrush.tearDown();
|
||||||
|
rightBrush = null;
|
||||||
|
rightHand.tearDown();
|
||||||
|
rightHand = null;
|
||||||
|
|
||||||
|
Messages.unsubscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL);
|
||||||
|
Messages.unsubscribe(HIFI_GRAB_DISABLE_MESSAGE_CHANNEL);
|
||||||
|
Messages.unsubscribe(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onButtonClicked() {
|
||||||
|
var wasFingerPainting = isFingerPainting;
|
||||||
|
|
||||||
|
isFingerPainting = !isFingerPainting;
|
||||||
|
button.editProperties({ isActive: isFingerPainting });
|
||||||
|
|
||||||
|
print("Finger painting: " + isFingerPainting ? "on" : "off");
|
||||||
|
|
||||||
|
if (wasFingerPainting) {
|
||||||
|
leftBrush.cancelLine();
|
||||||
|
rightBrush.cancelLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFingerPainting) {
|
||||||
|
enableProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHandFunctions();
|
||||||
|
|
||||||
|
if (!isFingerPainting) {
|
||||||
|
disableProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTabletScreenChanged(type, url) {
|
||||||
|
var TABLET_SCREEN_CLOSED = "Closed";
|
||||||
|
|
||||||
|
isTabletDisplayed = type !== TABLET_SCREEN_CLOSED;
|
||||||
|
updateHandFunctions();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
if (!tablet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tablet button.
|
||||||
|
button = tablet.addButton({
|
||||||
|
icon: "icons/tablet-icons/finger-paint-i.svg",
|
||||||
|
activeIcon: "icons/tablet-icons/finger-paint-a.svg",
|
||||||
|
text: BUTTON_NAME,
|
||||||
|
isActive: isFingerPainting
|
||||||
|
});
|
||||||
|
button.clicked.connect(onButtonClicked);
|
||||||
|
|
||||||
|
// Track whether tablet is displayed or not.
|
||||||
|
tablet.screenChanged.connect(onTabletScreenChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tearDown() {
|
||||||
|
if (!tablet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFingerPainting) {
|
||||||
|
isFingerPainting = false;
|
||||||
|
updateHandFunctions();
|
||||||
|
disableProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
tablet.screenChanged.disconnect(onTabletScreenChanged);
|
||||||
|
|
||||||
|
button.clicked.disconnect(onButtonClicked);
|
||||||
|
tablet.removeButton(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
setUp();
|
||||||
|
Script.scriptEnding.connect(tearDown);
|
||||||
|
}());
|
|
@ -10,48 +10,21 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
/* globals Tablet, Toolbars, Script, HMD, Controller, Menu */
|
/* globals Tablet, Script, HMD, Controller, Menu */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
var button;
|
|
||||||
var buttonName = "HELP";
|
var buttonName = "HELP";
|
||||||
var toolBar = null;
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
var tablet = null;
|
var button = tablet.addButton({
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
|
||||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
|
||||||
button = toolBar.addButton({
|
|
||||||
objectName: buttonName,
|
|
||||||
imageURL: Script.resolvePath("assets/images/tools/help.svg"),
|
|
||||||
visible: true,
|
|
||||||
alpha: 0.9
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
||||||
button = tablet.addButton({
|
|
||||||
icon: "icons/tablet-icons/help-i.svg",
|
icon: "icons/tablet-icons/help-i.svg",
|
||||||
activeIcon: "icons/tablet-icons/help-a.svg",
|
activeIcon: "icons/tablet-icons/help-a.svg",
|
||||||
text: buttonName,
|
text: buttonName,
|
||||||
sortOrder: 6
|
sortOrder: 6
|
||||||
});
|
});
|
||||||
}
|
|
||||||
var enabled = false;
|
var enabled = false;
|
||||||
function onClicked() {
|
function onClicked() {
|
||||||
// Similar logic to Application::showHelp()
|
|
||||||
var defaultTab = "kbm";
|
|
||||||
var handControllerName = "vive";
|
|
||||||
if (HMD.active) {
|
|
||||||
if ("Vive" in Controller.Hardware) {
|
|
||||||
defaultTab = "handControllers";
|
|
||||||
handControllerName = "vive";
|
|
||||||
} else if ("OculusTouch" in Controller.Hardware) {
|
|
||||||
defaultTab = "handControllers";
|
|
||||||
handControllerName = "oculus";
|
|
||||||
}
|
|
||||||
} else if ("SDL2" in Controller.Hardware) {
|
|
||||||
defaultTab = "gamepad";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
Menu.closeInfoView('InfoView_html/help.html');
|
Menu.closeInfoView('InfoView_html/help.html');
|
||||||
enabled = !enabled;
|
enabled = !enabled;
|
||||||
|
@ -80,9 +53,6 @@
|
||||||
if (tablet) {
|
if (tablet) {
|
||||||
tablet.removeButton(button);
|
tablet.removeButton(button);
|
||||||
}
|
}
|
||||||
if (toolBar) {
|
|
||||||
toolBar.removeButton(buttonName);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}()); // END LOCAL_SCOPE
|
}()); // END LOCAL_SCOPE
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
/*globals HMD, Toolbars, Script, Menu, Tablet, Camera */
|
/* globals HMD, Script, Menu, Tablet, Camera */
|
||||||
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
|
@ -37,20 +38,13 @@ function updateControllerDisplay() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var button;
|
var button;
|
||||||
var toolBar = null;
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
var tablet = null;
|
|
||||||
|
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
|
||||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
|
||||||
} else {
|
|
||||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Independent and Entity mode make people sick. Third Person and Mirror have traps that we need to work through.
|
// Independent and Entity mode make people sick. Third Person and Mirror have traps that we need to work through.
|
||||||
// Disable them in hmd.
|
// Disable them in hmd.
|
||||||
var desktopOnlyViews = ['Mirror', 'Independent Mode', 'Entity Mode'];
|
var desktopOnlyViews = ['Mirror', 'Independent Mode', 'Entity Mode'];
|
||||||
|
|
||||||
function onHmdChanged(isHmd) {
|
function onHmdChanged(isHmd) {
|
||||||
//TODO change button icon when the hmd changes
|
|
||||||
if (isHmd) {
|
if (isHmd) {
|
||||||
button.editProperties({
|
button.editProperties({
|
||||||
icon: "icons/tablet-icons/switch-desk-i.svg",
|
icon: "icons/tablet-icons/switch-desk-i.svg",
|
||||||
|
@ -67,25 +61,18 @@ function onHmdChanged(isHmd) {
|
||||||
});
|
});
|
||||||
updateControllerDisplay();
|
updateControllerDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onClicked() {
|
function onClicked() {
|
||||||
var isDesktop = Menu.isOptionChecked(desktopMenuItemName);
|
var isDesktop = Menu.isOptionChecked(desktopMenuItemName);
|
||||||
Menu.setIsOptionChecked(isDesktop ? headset : desktopMenuItemName, true);
|
Menu.setIsOptionChecked(isDesktop ? headset : desktopMenuItemName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headset) {
|
if (headset) {
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
|
||||||
button = toolBar.addButton({
|
|
||||||
objectName: "hmdToggle",
|
|
||||||
imageURL: Script.resolvePath("assets/images/tools/switch.svg"),
|
|
||||||
visible: true,
|
|
||||||
alpha: 0.9
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
button = tablet.addButton({
|
button = tablet.addButton({
|
||||||
icon: HMD.active ? "icons/tablet-icons/switch-desk-i.svg" : "icons/tablet-icons/switch-vr-i.svg",
|
icon: HMD.active ? "icons/tablet-icons/switch-desk-i.svg" : "icons/tablet-icons/switch-vr-i.svg",
|
||||||
text: HMD.active ? "DESKTOP" : "VR",
|
text: HMD.active ? "DESKTOP" : "VR",
|
||||||
sortOrder: 2
|
sortOrder: 2
|
||||||
});
|
});
|
||||||
}
|
|
||||||
onHmdChanged(HMD.active);
|
onHmdChanged(HMD.active);
|
||||||
|
|
||||||
button.clicked.connect(onClicked);
|
button.clicked.connect(onClicked);
|
||||||
|
@ -97,9 +84,6 @@ if (headset) {
|
||||||
if (tablet) {
|
if (tablet) {
|
||||||
tablet.removeButton(button);
|
tablet.removeButton(button);
|
||||||
}
|
}
|
||||||
if (toolBar) {
|
|
||||||
toolBar.removeButton("hmdToggle");
|
|
||||||
}
|
|
||||||
HMD.displayModeChanged.disconnect(onHmdChanged);
|
HMD.displayModeChanged.disconnect(onHmdChanged);
|
||||||
Camera.modeUpdated.disconnect(updateControllerDisplay);
|
Camera.modeUpdated.disconnect(updateControllerDisplay);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
/* global Tablet, Script, HMD, Toolbars, UserActivityLogger, Entities */
|
/* global Tablet, Script, HMD, UserActivityLogger, Entities */
|
||||||
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
@ -33,8 +33,6 @@ var QUERY_CAN_WRITE_ASSETS = "QUERY_CAN_WRITE_ASSETS";
|
||||||
var CAN_WRITE_ASSETS = "CAN_WRITE_ASSETS";
|
var CAN_WRITE_ASSETS = "CAN_WRITE_ASSETS";
|
||||||
var WARN_USER_NO_PERMISSIONS = "WARN_USER_NO_PERMISSIONS";
|
var WARN_USER_NO_PERMISSIONS = "WARN_USER_NO_PERMISSIONS";
|
||||||
|
|
||||||
var marketplaceWindow = null;
|
|
||||||
|
|
||||||
var CLARA_DOWNLOAD_TITLE = "Preparing Download";
|
var CLARA_DOWNLOAD_TITLE = "Preparing Download";
|
||||||
var messageBox = null;
|
var messageBox = null;
|
||||||
var isDownloadBeingCancelled = false;
|
var isDownloadBeingCancelled = false;
|
||||||
|
@ -57,11 +55,11 @@ Window.messageBoxClosed.connect(onMessageBoxClosed);
|
||||||
function showMarketplace() {
|
function showMarketplace() {
|
||||||
UserActivityLogger.openedMarketplace();
|
UserActivityLogger.openedMarketplace();
|
||||||
|
|
||||||
if (tablet) {
|
|
||||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||||
tablet.webEventReceived.connect(function (message) {
|
tablet.webEventReceived.connect(function (message) {
|
||||||
|
|
||||||
if (message === GOTO_DIRECTORY) {
|
if (message === GOTO_DIRECTORY) {
|
||||||
tablet.gotoWebScreen(MARKETPLACES_URL);
|
tablet.gotoWebScreen(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message === QUERY_CAN_WRITE_ASSETS) {
|
if (message === QUERY_CAN_WRITE_ASSETS) {
|
||||||
|
@ -98,11 +96,6 @@ function showMarketplace() {
|
||||||
isDownloadBeingCancelled = false;
|
isDownloadBeingCancelled = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
marketplaceWindow.setURL(MARKETPLACE_URL_INITIAL);
|
|
||||||
marketplaceWindow.setVisible(true);
|
|
||||||
marketplaceVisible = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleMarketplace() {
|
function toggleMarketplace() {
|
||||||
|
@ -111,33 +104,12 @@ function toggleMarketplace() {
|
||||||
showMarketplace();
|
showMarketplace();
|
||||||
}
|
}
|
||||||
|
|
||||||
var tablet = null;
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
var toolBar = null;
|
var marketplaceButton = tablet.addButton({
|
||||||
var marketplaceButton = null;
|
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
|
||||||
marketplaceWindow = new OverlayWebWindow({
|
|
||||||
title: "Marketplace",
|
|
||||||
source: "about:blank",
|
|
||||||
width: 900,
|
|
||||||
height: 700,
|
|
||||||
visible: false
|
|
||||||
});
|
|
||||||
marketplaceWindow.setScriptURL(MARKETPLACES_INJECT_SCRIPT_URL);
|
|
||||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
|
||||||
var toolIconUrl = Script.resolvePath("../assets/images/tools/");
|
|
||||||
marketplaceButton = toolBar.addButton({
|
|
||||||
imageURL: toolIconUrl + "market.svg",
|
|
||||||
objectName: "marketplace",
|
|
||||||
alpha: 0.9
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
||||||
marketplaceButton = tablet.addButton({
|
|
||||||
icon: "icons/tablet-icons/market-i.svg",
|
icon: "icons/tablet-icons/market-i.svg",
|
||||||
text: "MARKET",
|
text: "MARKET",
|
||||||
sortOrder: 9
|
sortOrder: 9
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function onCanWriteAssetsChanged() {
|
function onCanWriteAssetsChanged() {
|
||||||
var message = CAN_WRITE_ASSETS + " " + Entities.canWriteAssets();
|
var message = CAN_WRITE_ASSETS + " " + Entities.canWriteAssets();
|
||||||
|
@ -152,9 +124,6 @@ marketplaceButton.clicked.connect(onClick);
|
||||||
Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged);
|
Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged);
|
||||||
|
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
if (toolBar) {
|
|
||||||
toolBar.removeButton("marketplace");
|
|
||||||
}
|
|
||||||
if (tablet) {
|
if (tablet) {
|
||||||
tablet.removeButton(marketplaceButton);
|
tablet.removeButton(marketplaceButton);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
/* jslint vars: true, plusplus: true, forin: true*/
|
/* jslint vars: true, plusplus: true, forin: true*/
|
||||||
/*globals Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, OverlayWindow, Toolbars, Vec3, Quat, Controller, print, getControllerWorldLocation */
|
/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */
|
||||||
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
//
|
//
|
||||||
// pal.js
|
// pal.js
|
||||||
//
|
//
|
||||||
|
@ -15,19 +16,22 @@
|
||||||
|
|
||||||
// hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed
|
// hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed
|
||||||
// something, will revisit as this is sorta horrible.
|
// something, will revisit as this is sorta horrible.
|
||||||
const UNSELECTED_TEXTURES = {"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png"),
|
var UNSELECTED_TEXTURES = {
|
||||||
|
"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png"),
|
||||||
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png")
|
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png")
|
||||||
};
|
};
|
||||||
const SELECTED_TEXTURES = { "idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-selected.png"),
|
var SELECTED_TEXTURES = {
|
||||||
|
"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-selected.png"),
|
||||||
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-selected.png")
|
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-selected.png")
|
||||||
};
|
};
|
||||||
const HOVER_TEXTURES = { "idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-hover.png"),
|
var HOVER_TEXTURES = {
|
||||||
|
"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-hover.png"),
|
||||||
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-hover.png")
|
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-hover.png")
|
||||||
};
|
};
|
||||||
|
|
||||||
const UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6};
|
var UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6};
|
||||||
const SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29};
|
var SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29};
|
||||||
const HOVER_COLOR = {red: 0xD0, green: 0xD0, blue: 0xD0}; // almost white for now
|
var HOVER_COLOR = {red: 0xD0, green: 0xD0, blue: 0xD0}; // almost white for now
|
||||||
|
|
||||||
var conserveResources = true;
|
var conserveResources = true;
|
||||||
|
|
||||||
|
@ -94,12 +98,12 @@ ExtendedOverlay.prototype.hover = function (hovering) {
|
||||||
}
|
}
|
||||||
if (hovering) {
|
if (hovering) {
|
||||||
// un-hover the last hovering overlay
|
// un-hover the last hovering overlay
|
||||||
if (lastHoveringId && lastHoveringId != this.key) {
|
if (lastHoveringId && lastHoveringId !== this.key) {
|
||||||
ExtendedOverlay.get(lastHoveringId).hover(false);
|
ExtendedOverlay.get(lastHoveringId).hover(false);
|
||||||
}
|
}
|
||||||
lastHoveringId = this.key;
|
lastHoveringId = this.key;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
ExtendedOverlay.prototype.select = function (selected) {
|
ExtendedOverlay.prototype.select = function (selected) {
|
||||||
if (this.selected === selected) {
|
if (this.selected === selected) {
|
||||||
return;
|
return;
|
||||||
|
@ -193,17 +197,8 @@ HighlightedEntity.updateOverlays = function updateHighlightedEntities() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
|
||||||
// The qml window and communications.
|
|
||||||
//
|
|
||||||
var pal = new OverlayWindow({
|
|
||||||
title: 'People Action List',
|
|
||||||
source: 'hifi/Pal.qml',
|
|
||||||
width: 580,
|
|
||||||
height: 640,
|
|
||||||
visible: false
|
|
||||||
});
|
|
||||||
function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
|
function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
|
||||||
|
var data;
|
||||||
switch (message.method) {
|
switch (message.method) {
|
||||||
case 'selected':
|
case 'selected':
|
||||||
selectedIds = message.params;
|
selectedIds = message.params;
|
||||||
|
@ -250,7 +245,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'displayNameUpdate':
|
case 'displayNameUpdate':
|
||||||
if (MyAvatar.displayName != message.params) {
|
if (MyAvatar.displayName !== message.params) {
|
||||||
MyAvatar.displayName = message.params;
|
MyAvatar.displayName = message.params;
|
||||||
UserActivityLogger.palAction("display_name_change", "");
|
UserActivityLogger.palAction("display_name_change", "");
|
||||||
}
|
}
|
||||||
|
@ -261,12 +256,8 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendToQml(message) {
|
function sendToQml(message) {
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
|
||||||
pal.sendToQml(message);
|
|
||||||
} else {
|
|
||||||
tablet.sendToQml(message);
|
tablet.sendToQml(message);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Main operations.
|
// Main operations.
|
||||||
|
@ -385,7 +376,9 @@ function removeOverlays() {
|
||||||
selectedIds = [];
|
selectedIds = [];
|
||||||
lastHoveringId = 0;
|
lastHoveringId = 0;
|
||||||
HighlightedEntity.clearOverlays();
|
HighlightedEntity.clearOverlays();
|
||||||
ExtendedOverlay.some(function (overlay) { overlay.deleteOverlay(); });
|
ExtendedOverlay.some(function (overlay) {
|
||||||
|
overlay.deleteOverlay();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -415,12 +408,13 @@ function handleMouseMove(pickRay) { // given the pickRay, just do the hover logi
|
||||||
|
|
||||||
// handy global to keep track of which hand is the mouse (if any)
|
// handy global to keep track of which hand is the mouse (if any)
|
||||||
var currentHandPressed = 0;
|
var currentHandPressed = 0;
|
||||||
const TRIGGER_CLICK_THRESHOLD = 0.85;
|
var TRIGGER_CLICK_THRESHOLD = 0.85;
|
||||||
const TRIGGER_PRESS_THRESHOLD = 0.05;
|
var TRIGGER_PRESS_THRESHOLD = 0.05;
|
||||||
|
|
||||||
function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position
|
function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position
|
||||||
|
var pickRay;
|
||||||
if (HMD.active) {
|
if (HMD.active) {
|
||||||
if (currentHandPressed != 0) {
|
if (currentHandPressed !== 0) {
|
||||||
pickRay = controllerComputePickRay(currentHandPressed);
|
pickRay = controllerComputePickRay(currentHandPressed);
|
||||||
} else {
|
} else {
|
||||||
// nothing should hover, so
|
// nothing should hover, so
|
||||||
|
@ -436,12 +430,12 @@ function handleTriggerPressed(hand, value) {
|
||||||
// The idea is if you press one trigger, it is the one
|
// The idea is if you press one trigger, it is the one
|
||||||
// we will consider the mouse. Even if the other is pressed,
|
// we will consider the mouse. Even if the other is pressed,
|
||||||
// we ignore it until this one is no longer pressed.
|
// we ignore it until this one is no longer pressed.
|
||||||
isPressed = value > TRIGGER_PRESS_THRESHOLD;
|
var isPressed = value > TRIGGER_PRESS_THRESHOLD;
|
||||||
if (currentHandPressed == 0) {
|
if (currentHandPressed === 0) {
|
||||||
currentHandPressed = isPressed ? hand : 0;
|
currentHandPressed = isPressed ? hand : 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentHandPressed == hand) {
|
if (currentHandPressed === hand) {
|
||||||
currentHandPressed = isPressed ? hand : 0;
|
currentHandPressed = isPressed ? hand : 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -470,7 +464,7 @@ function makeClickHandler(hand) {
|
||||||
function makePressHandler(hand) {
|
function makePressHandler(hand) {
|
||||||
return function (value) {
|
return function (value) {
|
||||||
handleTriggerPressed(hand, value);
|
handleTriggerPressed(hand, value);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand));
|
triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand));
|
||||||
triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand));
|
triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand));
|
||||||
|
@ -482,17 +476,14 @@ triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Cont
|
||||||
var button;
|
var button;
|
||||||
var buttonName = "PEOPLE";
|
var buttonName = "PEOPLE";
|
||||||
var tablet = null;
|
var tablet = null;
|
||||||
var toolBar = null;
|
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
function onTabletScreenChanged(type, url) {
|
||||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
if (type !== "QML" || url !== "../Pal.qml") {
|
||||||
button = toolBar.addButton({
|
off();
|
||||||
objectName: buttonName,
|
}
|
||||||
imageURL: Script.resolvePath("assets/images/tools/people.svg"),
|
}
|
||||||
visible: true,
|
|
||||||
alpha: 0.9
|
function startup() {
|
||||||
});
|
|
||||||
pal.fromQml.connect(fromQml);
|
|
||||||
} else {
|
|
||||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
button = tablet.addButton({
|
button = tablet.addButton({
|
||||||
text: buttonName,
|
text: buttonName,
|
||||||
|
@ -500,8 +491,19 @@ if (Settings.getValue("HUDUIEnabled")) {
|
||||||
sortOrder: 7
|
sortOrder: 7
|
||||||
});
|
});
|
||||||
tablet.fromQml.connect(fromQml);
|
tablet.fromQml.connect(fromQml);
|
||||||
|
button.clicked.connect(onTabletButtonClicked);
|
||||||
|
tablet.screenChanged.connect(onTabletScreenChanged);
|
||||||
|
|
||||||
|
Users.usernameFromIDReply.connect(usernameFromIDReply);
|
||||||
|
Window.domainChanged.connect(clearLocalQMLDataAndClosePAL);
|
||||||
|
Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL);
|
||||||
|
Messages.subscribe(CHANNEL);
|
||||||
|
Messages.messageReceived.connect(receiveMessage);
|
||||||
|
Users.avatarDisconnected.connect(avatarDisconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startup();
|
||||||
|
|
||||||
var isWired = false;
|
var isWired = false;
|
||||||
var audioTimer;
|
var audioTimer;
|
||||||
var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too)
|
var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too)
|
||||||
|
@ -513,30 +515,16 @@ function off() {
|
||||||
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
||||||
isWired = false;
|
isWired = false;
|
||||||
}
|
}
|
||||||
if (audioTimer) { Script.clearInterval(audioTimer); }
|
if (audioTimer) {
|
||||||
|
Script.clearInterval(audioTimer);
|
||||||
|
}
|
||||||
triggerMapping.disable(); // It's ok if we disable twice.
|
triggerMapping.disable(); // It's ok if we disable twice.
|
||||||
triggerPressMapping.disable(); // see above
|
triggerPressMapping.disable(); // see above
|
||||||
removeOverlays();
|
removeOverlays();
|
||||||
Users.requestsDomainListData = false;
|
Users.requestsDomainListData = false;
|
||||||
}
|
}
|
||||||
function onClicked() {
|
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
function onTabletButtonClicked() {
|
||||||
if (!pal.visible) {
|
|
||||||
Users.requestsDomainListData = true;
|
|
||||||
populateUserList();
|
|
||||||
pal.raise();
|
|
||||||
isWired = true;
|
|
||||||
Script.update.connect(updateOverlays);
|
|
||||||
Controller.mousePressEvent.connect(handleMouseEvent);
|
|
||||||
Controller.mouseMoveEvent.connect(handleMouseMoveEvent);
|
|
||||||
triggerMapping.enable();
|
|
||||||
triggerPressMapping.enable();
|
|
||||||
audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS);
|
|
||||||
} else {
|
|
||||||
off();
|
|
||||||
}
|
|
||||||
pal.setVisible(!pal.visible);
|
|
||||||
} else {
|
|
||||||
tablet.loadQMLSource("../Pal.qml");
|
tablet.loadQMLSource("../Pal.qml");
|
||||||
Users.requestsDomainListData = true;
|
Users.requestsDomainListData = true;
|
||||||
populateUserList();
|
populateUserList();
|
||||||
|
@ -548,7 +536,6 @@ function onClicked() {
|
||||||
triggerPressMapping.enable();
|
triggerPressMapping.enable();
|
||||||
audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS);
|
audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Message from other scripts, such as edit.js
|
// Message from other scripts, such as edit.js
|
||||||
|
@ -562,17 +549,12 @@ function receiveMessage(channel, messageString, senderID) {
|
||||||
var message = JSON.parse(messageString);
|
var message = JSON.parse(messageString);
|
||||||
switch (message.method) {
|
switch (message.method) {
|
||||||
case 'select':
|
case 'select':
|
||||||
if (!pal.visible) {
|
|
||||||
onClicked();
|
|
||||||
}
|
|
||||||
sendToQml(message); // Accepts objects, not just strings.
|
sendToQml(message); // Accepts objects, not just strings.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print('Unrecognized PAL message', messageString);
|
print('Unrecognized PAL message', messageString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Messages.subscribe(CHANNEL);
|
|
||||||
Messages.messageReceived.connect(receiveMessage);
|
|
||||||
|
|
||||||
|
|
||||||
var AVERAGING_RATIO = 0.05;
|
var AVERAGING_RATIO = 0.05;
|
||||||
|
@ -630,57 +612,29 @@ function avatarDisconnected(nodeID) {
|
||||||
// remove from the pal list
|
// remove from the pal list
|
||||||
sendToQml({method: 'avatarDisconnected', params: [nodeID]});
|
sendToQml({method: 'avatarDisconnected', params: [nodeID]});
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// Button state.
|
|
||||||
//
|
|
||||||
function onVisibleChanged() {
|
|
||||||
button.editProperties({isActive: pal.visible});
|
|
||||||
}
|
|
||||||
button.clicked.connect(onClicked);
|
|
||||||
pal.visibleChanged.connect(onVisibleChanged);
|
|
||||||
pal.closed.connect(off);
|
|
||||||
|
|
||||||
if (!Settings.getValue("HUDUIEnabled")) {
|
|
||||||
tablet.screenChanged.connect(function (type, url) {
|
|
||||||
if (type !== "QML" || url !== "../Pal.qml") {
|
|
||||||
off();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Users.usernameFromIDReply.connect(usernameFromIDReply);
|
|
||||||
Users.avatarDisconnected.connect(avatarDisconnected);
|
|
||||||
|
|
||||||
function clearLocalQMLDataAndClosePAL() {
|
function clearLocalQMLDataAndClosePAL() {
|
||||||
sendToQml({ method: 'clearLocalQMLData' });
|
sendToQml({ method: 'clearLocalQMLData' });
|
||||||
if (pal.visible) {
|
|
||||||
onClicked(); // Close the PAL
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shutdown() {
|
||||||
|
button.clicked.disconnect(onTabletButtonClicked);
|
||||||
|
tablet.removeButton(button);
|
||||||
|
tablet.screenChanged.disconnect(onTabletScreenChanged);
|
||||||
|
|
||||||
|
Users.usernameFromIDReply.disconnect(usernameFromIDReply);
|
||||||
|
Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL);
|
||||||
|
Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL);
|
||||||
|
Messages.subscribe(CHANNEL);
|
||||||
|
Messages.messageReceived.disconnect(receiveMessage);
|
||||||
|
Users.avatarDisconnected.disconnect(avatarDisconnected);
|
||||||
|
|
||||||
|
off();
|
||||||
}
|
}
|
||||||
Window.domainChanged.connect(clearLocalQMLDataAndClosePAL);
|
|
||||||
Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Cleanup.
|
// Cleanup.
|
||||||
//
|
//
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(shutdown);
|
||||||
button.clicked.disconnect(onClicked);
|
|
||||||
if (tablet) {
|
|
||||||
tablet.removeButton(button);
|
|
||||||
}
|
|
||||||
if (toolBar) {
|
|
||||||
toolBar.removeButton(buttonName);
|
|
||||||
}
|
|
||||||
pal.visibleChanged.disconnect(onVisibleChanged);
|
|
||||||
pal.closed.disconnect(off);
|
|
||||||
Users.usernameFromIDReply.disconnect(usernameFromIDReply);
|
|
||||||
Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL);
|
|
||||||
Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL);
|
|
||||||
Messages.unsubscribe(CHANNEL);
|
|
||||||
Messages.messageReceived.disconnect(receiveMessage);
|
|
||||||
Users.avatarDisconnected.disconnect(avatarDisconnected);
|
|
||||||
off();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}()); // END LOCAL_SCOPE
|
}()); // END LOCAL_SCOPE
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
// Distributed under the Apache License, Version 2.0
|
// Distributed under the Apache License, Version 2.0
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
/* globals Tablet, Toolbars, Script, HMD, Settings, DialogsManager, Menu, Reticle, OverlayWebWindow, Desktop, Account, MyAvatar */
|
/* globals Tablet, Script, HMD, Settings, DialogsManager, Menu, Reticle, OverlayWebWindow, Desktop, Account, MyAvatar */
|
||||||
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
|
@ -17,29 +18,15 @@ var resetOverlays;
|
||||||
var reticleVisible;
|
var reticleVisible;
|
||||||
var clearOverlayWhenMoving;
|
var clearOverlayWhenMoving;
|
||||||
|
|
||||||
var button;
|
|
||||||
var buttonName = "SNAP";
|
var buttonName = "SNAP";
|
||||||
var tablet = null;
|
|
||||||
var toolBar = null;
|
|
||||||
|
|
||||||
var buttonConnected = false;
|
var buttonConnected = false;
|
||||||
|
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
var button = tablet.addButton({
|
||||||
button = toolBar.addButton({
|
|
||||||
objectName: buttonName,
|
|
||||||
imageURL: Script.resolvePath("assets/images/tools/snap.svg"),
|
|
||||||
visible: true,
|
|
||||||
alpha: 0.9,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
||||||
button = tablet.addButton({
|
|
||||||
icon: "icons/tablet-icons/snap-i.svg",
|
icon: "icons/tablet-icons/snap-i.svg",
|
||||||
text: buttonName,
|
text: buttonName,
|
||||||
sortOrder: 5
|
sortOrder: 5
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function shouldOpenFeedAfterShare() {
|
function shouldOpenFeedAfterShare() {
|
||||||
var persisted = Settings.getValue('openFeedAfterShare', true); // might answer true, false, "true", or "false"
|
var persisted = Settings.getValue('openFeedAfterShare', true); // might answer true, false, "true", or "false"
|
||||||
|
@ -159,7 +146,7 @@ function isDomainOpen(id) {
|
||||||
var url = location.metaverseServerUrl + "/api/v1/user_stories?" + options.join('&');
|
var url = location.metaverseServerUrl + "/api/v1/user_stories?" + options.join('&');
|
||||||
request.open("GET", url, false);
|
request.open("GET", url, false);
|
||||||
request.send();
|
request.send();
|
||||||
if (request.status != 200) {
|
if (request.status !== 200) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var response = JSON.parse(request.response); // Not parsed for us.
|
var response = JSON.parse(request.response); // Not parsed for us.
|
||||||
|
@ -229,9 +216,6 @@ Script.scriptEnding.connect(function () {
|
||||||
if (tablet) {
|
if (tablet) {
|
||||||
tablet.removeButton(button);
|
tablet.removeButton(button);
|
||||||
}
|
}
|
||||||
if (toolBar) {
|
|
||||||
toolBar.removeButton(buttonName);
|
|
||||||
}
|
|
||||||
Window.snapshotShared.disconnect(snapshotShared);
|
Window.snapshotShared.disconnect(snapshotShared);
|
||||||
Window.processingGif.disconnect(processingGif);
|
Window.processingGif.disconnect(processingGif);
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,53 +13,26 @@
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
var gotoQmlSource = "TabletAddressDialog.qml";
|
var gotoQmlSource = "TabletAddressDialog.qml";
|
||||||
var button;
|
|
||||||
var buttonName = "GOTO";
|
var buttonName = "GOTO";
|
||||||
var toolBar = null;
|
|
||||||
var tablet = null;
|
|
||||||
function onAddressBarShown(visible) {
|
|
||||||
if (toolBar) {
|
|
||||||
button.editProperties({isActive: visible});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onClicked(){
|
function onClicked(){
|
||||||
if (toolBar) {
|
|
||||||
DialogsManager.toggleAddressBar();
|
|
||||||
} else {
|
|
||||||
tablet.loadQMLSource(gotoQmlSource);
|
tablet.loadQMLSource(gotoQmlSource);
|
||||||
}
|
}
|
||||||
}
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
if (Settings.getValue("HUDUIEnabled")) {
|
var button = tablet.addButton({
|
||||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
|
||||||
button = toolBar.addButton({
|
|
||||||
objectName: buttonName,
|
|
||||||
imageURL: Script.resolvePath("assets/images/tools/directory.svg"),
|
|
||||||
visible: true,
|
|
||||||
alpha: 0.9
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
|
||||||
button = tablet.addButton({
|
|
||||||
icon: "icons/tablet-icons/goto-i.svg",
|
icon: "icons/tablet-icons/goto-i.svg",
|
||||||
activeIcon: "icons/tablet-icons/goto-a.svg",
|
activeIcon: "icons/tablet-icons/goto-a.svg",
|
||||||
text: buttonName,
|
text: buttonName,
|
||||||
sortOrder: 8
|
sortOrder: 8
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
button.clicked.connect(onClicked);
|
button.clicked.connect(onClicked);
|
||||||
DialogsManager.addressBarShown.connect(onAddressBarShown);
|
|
||||||
|
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
button.clicked.disconnect(onClicked);
|
button.clicked.disconnect(onClicked);
|
||||||
if (tablet) {
|
if (tablet) {
|
||||||
tablet.removeButton(button);
|
tablet.removeButton(button);
|
||||||
}
|
}
|
||||||
if (toolBar) {
|
|
||||||
toolBar.removeButton(buttonName);
|
|
||||||
}
|
|
||||||
DialogsManager.addressBarShown.disconnect(onAddressBarShown);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}()); // END LOCAL_SCOPE
|
}()); // END LOCAL_SCOPE
|
||||||
|
|
|
@ -52,6 +52,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateShowTablet() {
|
function updateShowTablet() {
|
||||||
|
|
||||||
|
// close the WebTablet if it we go into toolbar mode.
|
||||||
|
var toolbarMode = Tablet.getTablet("com.highfidelity.interface.tablet.system").toolbarMode;
|
||||||
|
if (tabletShown && toolbarMode) {
|
||||||
|
hideTabletUI();
|
||||||
|
HMD.closeTablet();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (tabletShown) {
|
if (tabletShown) {
|
||||||
var MUTE_MICROPHONE_MENU_ITEM = "Mute Microphone";
|
var MUTE_MICROPHONE_MENU_ITEM = "Mute Microphone";
|
||||||
var currentMicEnabled = !Menu.isOptionChecked(MUTE_MICROPHONE_MENU_ITEM);
|
var currentMicEnabled = !Menu.isOptionChecked(MUTE_MICROPHONE_MENU_ITEM);
|
||||||
|
@ -67,7 +76,7 @@
|
||||||
// other reason, close the tablet.
|
// other reason, close the tablet.
|
||||||
hideTabletUI();
|
hideTabletUI();
|
||||||
HMD.closeTablet();
|
HMD.closeTablet();
|
||||||
} else if (HMD.showTablet && !tabletShown) {
|
} else if (HMD.showTablet && !tabletShown && !toolbarMode) {
|
||||||
UserActivityLogger.openedTablet();
|
UserActivityLogger.openedTablet();
|
||||||
showTabletUI();
|
showTabletUI();
|
||||||
} else if (!HMD.showTablet && tabletShown) {
|
} else if (!HMD.showTablet && tabletShown) {
|
||||||
|
|
Loading…
Reference in a new issue