mirror of
https://github.com/lubosz/overte.git
synced 2025-04-10 18:36:32 +02:00
Merge remote-tracking branch 'upstream/master' into smarter_textures
This commit is contained in:
commit
07506b0078
34 changed files with 1500 additions and 553 deletions
|
@ -40,6 +40,7 @@ module.exports = {
|
|||
"Settings": false,
|
||||
"SoundCache": false,
|
||||
"Stats": false,
|
||||
"Tablet": false,
|
||||
"TextureCache": false,
|
||||
"Toolbars": false,
|
||||
"Uuid": false,
|
||||
|
@ -61,7 +62,7 @@ module.exports = {
|
|||
"eqeqeq": ["error", "always"],
|
||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||
"keyword-spacing": ["error", { "before": true, "after": true }],
|
||||
"max-len": ["error", 128, 4],
|
||||
"max-len": ["error", 192, 4],
|
||||
"new-cap": ["error"],
|
||||
"no-floating-decimal": ["error"],
|
||||
//"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,7 +48,16 @@ OriginalDesktop.Desktop {
|
|||
// 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
|
||||
// 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 {
|
||||
id: settings;
|
||||
category: "toolbar";
|
||||
|
@ -58,8 +67,9 @@ OriginalDesktop.Desktop {
|
|||
settings.constrainToolbarToCenterX = constrain;
|
||||
}
|
||||
property var toolbars: (function (map) { // answer dictionary preloaded with sysToolbar
|
||||
return map; })({});
|
||||
|
||||
map[sysToolbar.objectName] = sysToolbar;
|
||||
return map;
|
||||
})({});
|
||||
|
||||
Component.onCompleted: {
|
||||
WebEngine.settings.javascriptCanOpenWindows = true;
|
||||
|
|
|
@ -97,10 +97,12 @@ FocusScope {
|
|||
menuPopperUpper.closeLastMenu();
|
||||
}
|
||||
|
||||
function setRootMenu(menu) {
|
||||
tabletMenu.rootMenu = menu
|
||||
function setRootMenu(rootMenu, subMenu) {
|
||||
tabletMenu.subMenu = subMenu;
|
||||
tabletMenu.rootMenu = rootMenu;
|
||||
buildMenu()
|
||||
}
|
||||
|
||||
function buildMenu() {
|
||||
// Build submenu if specified.
|
||||
if (subMenu !== "") {
|
||||
|
|
|
@ -83,7 +83,7 @@ FocusScope {
|
|||
}
|
||||
|
||||
function recalcSize() {
|
||||
if (model.count !== count || !visible) {
|
||||
if (!model || model.count !== count || !visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@ Item {
|
|||
objectName: "tabletRoot"
|
||||
property string username: "Unknown user"
|
||||
property var eventBridge;
|
||||
property string option: ""
|
||||
|
||||
property var rootMenu;
|
||||
property string subMenu: ""
|
||||
|
||||
signal showDesktop();
|
||||
|
||||
|
@ -14,7 +16,13 @@ Item {
|
|||
option = value;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -77,13 +85,15 @@ Item {
|
|||
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||
}
|
||||
if (loader.item.hasOwnProperty("subMenu")) {
|
||||
loader.item.subMenu = option;
|
||||
if (loader.item.hasOwnProperty("setRootMenu")) {
|
||||
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
||||
}
|
||||
loader.item.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
y: -parent.yOffset;
|
||||
width: parent.width
|
||||
source: "../../../icons/tablet-icons/empty-toolbar-button.svg"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Window {
|
|||
property real buttonSize: 50;
|
||||
property var buttons: []
|
||||
property var container: horizontal ? row : column
|
||||
|
||||
|
||||
Settings {
|
||||
category: "toolbar/" + window.objectName
|
||||
property alias x: window.x
|
||||
|
@ -49,6 +49,7 @@ Window {
|
|||
id: content
|
||||
implicitHeight: horizontal ? row.height : column.height
|
||||
implicitWidth: horizontal ? row.width : column.width
|
||||
property bool wasVisibleBeforeBeingPinned: false
|
||||
|
||||
Row {
|
||||
id: row
|
||||
|
@ -65,19 +66,11 @@ Window {
|
|||
Connections {
|
||||
target: desktop
|
||||
onPinnedChanged: {
|
||||
if (!window.pinned) {
|
||||
return;
|
||||
}
|
||||
var newPinned = desktop.pinned;
|
||||
for (var i in buttons) {
|
||||
var child = buttons[i];
|
||||
if (desktop.pinned) {
|
||||
if (!child.pinned) {
|
||||
child.visible = false;
|
||||
}
|
||||
} else {
|
||||
child.visible = true;
|
||||
}
|
||||
if (desktop.pinned) {
|
||||
content.wasVisibleBeforeBeingPinned = window.visible;
|
||||
window.visible = false;
|
||||
} else {
|
||||
window.visible = content.wasVisibleBeforeBeingPinned;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +99,24 @@ Window {
|
|||
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) {
|
||||
properties = properties || {}
|
||||
|
||||
|
@ -123,8 +134,12 @@ Window {
|
|||
properties.opacity = 0;
|
||||
result = toolbarButtonBuilder.createObject(container, properties);
|
||||
buttons.push(result);
|
||||
|
||||
result.opacity = 1;
|
||||
updatePinned();
|
||||
|
||||
sortButtons();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -137,6 +152,10 @@ Window {
|
|||
buttons[index].destroy();
|
||||
buttons.splice(index, 1);
|
||||
updatePinned();
|
||||
|
||||
if (buttons.length === 0) {
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
function updatePinned() {
|
||||
|
|
|
@ -11,12 +11,33 @@ StateImage {
|
|||
property int imageOnOut: 0
|
||||
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()
|
||||
|
||||
function changeProperty(key, value) {
|
||||
button[key] = value;
|
||||
}
|
||||
|
||||
function urlHelper(src) {
|
||||
if (src.match(/\bhttp/)) {
|
||||
return src;
|
||||
} else {
|
||||
return "../../../" + src;
|
||||
}
|
||||
}
|
||||
|
||||
function updateState() {
|
||||
if (!button.isEntered && !button.isActive) {
|
||||
buttonState = imageOffOut;
|
||||
|
@ -38,7 +59,7 @@ StateImage {
|
|||
running: false
|
||||
onTriggered: button.clicked();
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
hoverEnabled: true
|
||||
|
@ -53,5 +74,28 @@ StateImage {
|
|||
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 setShown(value) {
|
||||
window.shown = value;
|
||||
}
|
||||
|
||||
property var rectifier: Timer {
|
||||
property bool executing: false;
|
||||
interval: 100
|
||||
|
|
|
@ -545,6 +545,8 @@ Setting::Handle<int> sessionRunTime{ "sessionRunTime", 0 };
|
|||
|
||||
const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 100.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) :
|
||||
QApplication(argc, argv),
|
||||
|
@ -565,6 +567,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_hmdTabletScale("hmdTabletScale", DEFAULT_HMD_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),
|
||||
_scaleMirror(1.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, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount);
|
||||
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode);
|
||||
|
||||
// Save avatar location immediately after a teleport.
|
||||
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(&domainHandler, &DomainHandler::hostnameChanged, this, &Application::addAssetToWorldMessageClose);
|
||||
|
||||
updateSystemTabletMode();
|
||||
}
|
||||
|
||||
void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
|
||||
|
@ -2330,6 +2337,16 @@ void Application::setDesktopTabletScale(float 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) {
|
||||
_constrainToolbarPosition.set(setting);
|
||||
DependencyManager::get<OffscreenUi>()->setConstrainToolbarToCenterX(setting);
|
||||
|
@ -5462,6 +5479,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("Desktop", DependencyManager::get<DesktopScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
|
||||
|
||||
DependencyManager::get<TabletScriptingInterface>().data()->setToolbarScriptingInterface(DependencyManager::get<ToolbarScriptingInterface>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
||||
qScriptRegisterMetaType(scriptEngine, CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue);
|
||||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
|
@ -6679,6 +6698,12 @@ void Application::updateDisplayMode() {
|
|||
}
|
||||
|
||||
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.
|
||||
getMyAvatar()->reset(false);
|
||||
|
@ -6854,6 +6879,14 @@ void Application::updateThreadPoolCount() const {
|
|||
QThreadPool::globalInstance()->setMaxThreadCount(threadPoolSize);
|
||||
}
|
||||
|
||||
void Application::updateSystemTabletMode() {
|
||||
if (isHMDMode()) {
|
||||
DependencyManager::get<TabletScriptingInterface>()->setToolbarMode(getHmdTabletBecomesToolbarSetting());
|
||||
} else {
|
||||
DependencyManager::get<TabletScriptingInterface>()->setToolbarMode(getDesktopTabletBecomesToolbarSetting());
|
||||
}
|
||||
}
|
||||
|
||||
void Application::toggleMuteAudio() {
|
||||
auto menu = Menu::getInstance();
|
||||
menu->setIsOptionChecked(MenuOption::MuteAudio, !menu->isOptionChecked(MenuOption::MuteAudio));
|
||||
|
|
|
@ -214,6 +214,11 @@ public:
|
|||
float getDesktopTabletScale() { return _desktopTabletScale.get(); }
|
||||
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(); }
|
||||
void setSettingConstrainToolbarPosition(bool setting);
|
||||
|
||||
|
@ -310,6 +315,7 @@ public slots:
|
|||
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
|
||||
bool importEntities(const QString& url);
|
||||
void updateThreadPoolCount() const;
|
||||
void updateSystemTabletMode();
|
||||
|
||||
static void setLowVelocityFilter(bool lowVelocityFilter);
|
||||
Q_INVOKABLE void loadDialog();
|
||||
|
@ -550,6 +556,8 @@ private:
|
|||
Setting::Handle<float> _fieldOfView;
|
||||
Setting::Handle<float> _hmdTabletScale;
|
||||
Setting::Handle<float> _desktopTabletScale;
|
||||
Setting::Handle<bool> _desktopTabletBecomesToolbarSetting;
|
||||
Setting::Handle<bool> _hmdTabletBecomesToolbarSetting;
|
||||
Setting::Handle<bool> _constrainToolbarPosition;
|
||||
|
||||
float _scaleMirror;
|
||||
|
|
|
@ -92,6 +92,16 @@ void setupPreferences() {
|
|||
preference->setMax(500);
|
||||
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
|
||||
static const QString SNAPSHOTS { "Snapshots" };
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
#include <AudioInjector.h>
|
||||
|
||||
SoundEffect::~SoundEffect() {
|
||||
if (_sound) {
|
||||
_sound->deleteLater();
|
||||
}
|
||||
if (_injector) {
|
||||
// stop will cause the AudioInjector to delete itself.
|
||||
_injector->stop();
|
||||
|
|
|
@ -11,17 +11,36 @@
|
|||
#include <QtCore/QThread>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include "DependencyManager.h"
|
||||
#include <PathUtils.h>
|
||||
#include <QmlWindowClass.h>
|
||||
#include <QQmlProperty>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include "ScriptEngineLogging.h"
|
||||
#include "DependencyManager.h"
|
||||
#include "OffscreenUi.h"
|
||||
#include <OffscreenUi.h>
|
||||
#include <InfoView.h>
|
||||
#include "SoundEffect.h"
|
||||
|
||||
TabletScriptingInterface::TabletScriptingInterface() {
|
||||
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) {
|
||||
|
||||
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.
|
||||
auto tabletProxy = QSharedPointer<TabletProxy>(new TabletProxy(tabletId));
|
||||
_tabletProxies[tabletId] = tabletProxy;
|
||||
tabletProxy->setToolbarMode(_toolbarMode);
|
||||
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) {
|
||||
TabletProxy* tablet = qobject_cast<TabletProxy*>(getTablet(tabletId));
|
||||
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* VRMENU_SOURCE_URL = "TabletMenu.qml";
|
||||
|
||||
class TabletRootWindow : public QmlWindowClass {
|
||||
virtual QString qmlSource() const { return "hifi/tablet/WindowRoot.qml"; }
|
||||
};
|
||||
|
||||
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) {
|
||||
|
@ -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();
|
||||
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "setUsername", Q_ARG(const QVariant&, QVariant(getUsername())));
|
||||
|
@ -214,39 +294,61 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr
|
|||
}
|
||||
|
||||
void TabletProxy::gotoMenuScreen(const QString& submenu) {
|
||||
if (_qmlTabletRoot) {
|
||||
if (_state != State::Menu) {
|
||||
removeButtonsFromHomeScreen();
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "setOption", Q_ARG(const QVariant&, QVariant(submenu)));
|
||||
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
||||
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen()), Qt::DirectConnection);
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL)));
|
||||
_state = State::Menu;
|
||||
emit screenChanged(QVariant("Menu"), QVariant(VRMENU_SOURCE_URL));
|
||||
}
|
||||
|
||||
QObject* root = nullptr;
|
||||
if (!_toolbarMode && _qmlTabletRoot) {
|
||||
root = _qmlTabletRoot;
|
||||
} else if (_toolbarMode && _desktopWindow) {
|
||||
root = _desktopWindow->asQuickItem();
|
||||
}
|
||||
|
||||
if (root) {
|
||||
removeButtonsFromHomeScreen();
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QObject* menu = offscreenUi->getRootMenu();
|
||||
QMetaObject::invokeMethod(root, "setMenuProperties", Q_ARG(QVariant, QVariant::fromValue(menu)), Q_ARG(const QVariant&, QVariant(submenu)));
|
||||
QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL)));
|
||||
_state = State::Menu;
|
||||
emit screenChanged(QVariant("Menu"), QVariant(VRMENU_SOURCE_URL));
|
||||
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
removeButtonsFromHomeScreen();
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, path));
|
||||
QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path));
|
||||
_state = State::QML;
|
||||
emit screenChanged(QVariant("QML"), path);
|
||||
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabletProxy::gotoHomeScreen() {
|
||||
if (_qmlTabletRoot) {
|
||||
if (_state != State::Home) {
|
||||
if (_state != State::Home) {
|
||||
if (!_toolbarMode && _qmlTabletRoot) {
|
||||
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)));
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "playButtonClickSound");
|
||||
_state = State::Home;
|
||||
emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL));
|
||||
} else if (_toolbarMode && _desktopWindow) {
|
||||
// close desktop window
|
||||
if (_desktopWindow->asQuickItem()) {
|
||||
QMetaObject::invokeMethod(_desktopWindow->asQuickItem(), "setShown", Q_ARG(const QVariant&, QVariant(false)));
|
||||
}
|
||||
}
|
||||
_state = State::Home;
|
||||
emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,31 +357,52 @@ void TabletProxy::gotoWebScreen(const QString& url) {
|
|||
}
|
||||
|
||||
void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl) {
|
||||
if (_qmlTabletRoot) {
|
||||
if (_state == State::Home) {
|
||||
removeButtonsFromHomeScreen();
|
||||
}
|
||||
if (_state != State::Web) {
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL)));
|
||||
_state = State::Web;
|
||||
emit screenChanged(QVariant("Web"), QVariant(url));
|
||||
}
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)),
|
||||
Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl)));
|
||||
|
||||
QObject* root = nullptr;
|
||||
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)));
|
||||
}
|
||||
_state = State::Web;
|
||||
emit screenChanged(QVariant("Web"), QVariant(url));
|
||||
}
|
||||
|
||||
QObject* TabletProxy::addButton(const QVariant& properties) {
|
||||
auto tabletButtonProxy = QSharedPointer<TabletButtonProxy>(new TabletButtonProxy(properties.toMap()));
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
_tabletButtonProxies.push_back(tabletButtonProxy);
|
||||
if (_qmlTabletRoot) {
|
||||
if (!_toolbarMode && _qmlTabletRoot) {
|
||||
auto tablet = getQmlTablet();
|
||||
if (tablet) {
|
||||
addButtonProxyToQmlTablet(tablet, tabletButtonProxy.data());
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
|
@ -298,11 +421,18 @@ void TabletProxy::removeButton(QObject* tabletButtonProxy) {
|
|||
|
||||
auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy);
|
||||
if (iter != _tabletButtonProxies.end()) {
|
||||
if (_qmlTabletRoot) {
|
||||
if (!_toolbarMode && _qmlTabletRoot) {
|
||||
(*iter)->setQmlButton(nullptr);
|
||||
if (tablet) {
|
||||
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);
|
||||
} else {
|
||||
|
@ -329,20 +459,24 @@ void TabletProxy::updateAudioBar(const double micLevel) {
|
|||
}
|
||||
|
||||
void TabletProxy::emitScriptEvent(QVariant msg) {
|
||||
if (_qmlOffscreenSurface) {
|
||||
if (!_toolbarMode && _qmlOffscreenSurface) {
|
||||
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) {
|
||||
if (_qmlOffscreenSurface) {
|
||||
if (!_toolbarMode && _qmlOffscreenSurface) {
|
||||
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() {
|
||||
auto tablet = getQmlTablet();
|
||||
if (!tablet) {
|
||||
if (!tablet || _toolbarMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -358,30 +492,51 @@ QObject* TabletProxy::getTabletSurface() {
|
|||
return _qmlOffscreenSurface;
|
||||
}
|
||||
|
||||
void TabletProxy::addButtonsToMenuScreen() {
|
||||
if (!_qmlTabletRoot) {
|
||||
return;
|
||||
void TabletProxy::removeButtonsFromHomeScreen() {
|
||||
auto tablet = getQmlTablet();
|
||||
for (auto& buttonProxy : _tabletButtonProxies) {
|
||||
if (tablet) {
|
||||
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getProperties()));
|
||||
}
|
||||
buttonProxy->setQmlButton(nullptr);
|
||||
}
|
||||
|
||||
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::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) {
|
||||
buttonProxy->setQmlButton(nullptr);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,12 +585,14 @@ QQuickItem* TabletProxy::getQmlMenu() const {
|
|||
//
|
||||
|
||||
const QString UUID_KEY = "uuid";
|
||||
const QString OBJECT_NAME_KEY = "objectName";
|
||||
const QString STABLE_ORDER_KEY = "stableOrder";
|
||||
static int s_stableOrder = 1;
|
||||
|
||||
TabletButtonProxy::TabletButtonProxy(const QVariantMap& properties) : _uuid(QUuid::createUuid()), _stableOrder(++s_stableOrder), _properties(properties) {
|
||||
// this is used to uniquely identify this button.
|
||||
_properties[UUID_KEY] = _uuid;
|
||||
_properties[OBJECT_NAME_KEY] = _uuid.toString();
|
||||
_properties[STABLE_ORDER_KEY] = _stableOrder;
|
||||
}
|
||||
|
||||
|
@ -444,6 +601,14 @@ void TabletButtonProxy::setQmlButton(QQuickItem* 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 {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
return _properties;
|
||||
|
@ -451,6 +616,7 @@ QVariantMap TabletButtonProxy::getProperties() const {
|
|||
|
||||
void TabletButtonProxy::editProperties(QVariantMap properties) {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
|
||||
QVariantMap::const_iterator iter = properties.constBegin();
|
||||
while (iter != properties.constEnd()) {
|
||||
_properties[iter.key()] = iter.value();
|
||||
|
@ -459,6 +625,10 @@ void TabletButtonProxy::editProperties(QVariantMap properties) {
|
|||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (_toolbarButtonProxy) {
|
||||
QMetaObject::invokeMethod(_toolbarButtonProxy, "editProperties", Qt::AutoConnection, Q_ARG(QVariantMap, properties));
|
||||
}
|
||||
}
|
||||
|
||||
#include "TabletScriptingInterface.moc"
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
class TabletProxy;
|
||||
class TabletButtonProxy;
|
||||
class QmlWindowClass;
|
||||
|
||||
/**jsdoc
|
||||
* @namespace Tablet
|
||||
|
@ -35,6 +36,9 @@ class TabletScriptingInterface : public QObject, public Dependency {
|
|||
public:
|
||||
TabletScriptingInterface();
|
||||
|
||||
void setToolbarScriptingInterface(QObject* toolbarScriptingInterface) { _toolbarScriptingInterface = toolbarScriptingInterface; }
|
||||
QObject* getSystemToolbarProxy();
|
||||
|
||||
/**jsdoc
|
||||
* Creates or retruns a new TabletProxy and returns it.
|
||||
* @function Tablet.getTablet
|
||||
|
@ -43,6 +47,8 @@ public:
|
|||
*/
|
||||
Q_INVOKABLE QObject* getTablet(const QString& tabletId);
|
||||
|
||||
void setToolbarMode(bool toolbarMode);
|
||||
|
||||
void setQmlTabletRoot(QString tabletId, QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface);
|
||||
|
||||
void processEvent(const QKeyEvent* event);
|
||||
|
@ -58,15 +64,20 @@ private:
|
|||
protected:
|
||||
std::mutex _mutex;
|
||||
std::map<QString, QSharedPointer<TabletProxy>> _tabletProxies;
|
||||
QObject* _toolbarScriptingInterface { nullptr };
|
||||
bool _toolbarMode { false };
|
||||
};
|
||||
|
||||
/**jsdoc
|
||||
* @class TabletProxy
|
||||
* @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 {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ getName)
|
||||
Q_PROPERTY(bool toolbarMode READ getToolbarMode WRITE setToolbarMode)
|
||||
public:
|
||||
TabletProxy(QString name);
|
||||
|
||||
|
@ -74,6 +85,11 @@ public:
|
|||
|
||||
Q_INVOKABLE void gotoMenuScreen(const QString& submenu = "");
|
||||
|
||||
QString getName() const { return _name; }
|
||||
|
||||
bool getToolbarMode() const { return _toolbarMode; }
|
||||
void setToolbarMode(bool toolbarMode);
|
||||
|
||||
/**jsdoc
|
||||
* transition to the home screen
|
||||
* @function TabletProxy#gotoHomeScreen
|
||||
|
@ -120,8 +136,6 @@ public:
|
|||
*/
|
||||
Q_INVOKABLE void updateAudioBar(const double micLevel);
|
||||
|
||||
QString getName() const { return _name; }
|
||||
|
||||
/**jsdoc
|
||||
* Used to send an event to the html/js embedded in the tablet
|
||||
* @function TabletProxy#emitScriptEvent
|
||||
|
@ -162,24 +176,28 @@ signals:
|
|||
void fromQml(QVariant msg);
|
||||
|
||||
/**jsdoc
|
||||
* Signales when this tablet screen changes.
|
||||
* Signaled when this tablet screen changes.
|
||||
* @function TabletProxy#screenChanged
|
||||
* @param type {string} - "Home", "Web", "Menu", "QML", "Closed"
|
||||
* @param url {string} - only valid for Web and QML.
|
||||
*/
|
||||
void screenChanged(QVariant type, QVariant url);
|
||||
|
||||
private slots:
|
||||
protected slots:
|
||||
void addButtonsToHomeScreen();
|
||||
void addButtonsToMenuScreen();
|
||||
void desktopWindowClosed();
|
||||
protected:
|
||||
void removeButtonsFromHomeScreen();
|
||||
void addButtonsToToolbar();
|
||||
void removeButtonsFromToolbar();
|
||||
|
||||
QString _name;
|
||||
std::mutex _mutex;
|
||||
std::vector<QSharedPointer<TabletButtonProxy>> _tabletButtonProxies;
|
||||
QQuickItem* _qmlTabletRoot { nullptr };
|
||||
QObject* _qmlOffscreenSurface { nullptr };
|
||||
QmlWindowClass* _desktopWindow { nullptr };
|
||||
bool _toolbarMode { false };
|
||||
|
||||
enum class State { Uninitialized, Home, Web, Menu, QML };
|
||||
State _state { State::Uninitialized };
|
||||
|
@ -196,6 +214,7 @@ public:
|
|||
TabletButtonProxy(const QVariantMap& properties);
|
||||
|
||||
void setQmlButton(QQuickItem* qmlButton);
|
||||
void setToolbarButtonProxy(QObject* toolbarButtonProxy);
|
||||
|
||||
QUuid getUuid() const { return _uuid; }
|
||||
|
||||
|
@ -229,6 +248,7 @@ protected:
|
|||
int _stableOrder;
|
||||
mutable std::mutex _mutex;
|
||||
QQuickItem* _qmlButton { nullptr };
|
||||
QObject* _toolbarButtonProxy { nullptr };
|
||||
QVariantMap _properties;
|
||||
};
|
||||
|
||||
|
|
|
@ -20,17 +20,22 @@ const QString InfoView::NAME{ "InfoView" };
|
|||
|
||||
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() {
|
||||
qmlRegisterType<InfoView>("Hifi", 1, 0, NAME.toLocal8Bit().constData());
|
||||
}
|
||||
void InfoView::registerType() {
|
||||
if (!registered) {
|
||||
qmlRegisterType<InfoView>("Hifi", 1, 0, NAME.toLocal8Bit().constData());
|
||||
registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
QString fetchVersion(const QUrl& url) {
|
||||
QXmlQuery query;
|
||||
query.bindVariable("file", QVariant(url));
|
||||
query.bindVariable("file", QVariant(url));
|
||||
query.setQuery("string((doc($file)//input[@id='version'])[1]/@value)");
|
||||
QString r;
|
||||
query.evaluateTo(&r);
|
||||
|
@ -38,14 +43,10 @@ QString fetchVersion(const QUrl& url) {
|
|||
}
|
||||
|
||||
void InfoView::show(const QString& path, bool firstOrChangedOnly, QString urlQuery) {
|
||||
static bool registered{ false };
|
||||
if (!registered) {
|
||||
registerType();
|
||||
registered = true;
|
||||
}
|
||||
registerType();
|
||||
QUrl url;
|
||||
if (QDir(path).isRelative()) {
|
||||
url = QUrl::fromLocalFile(PathUtils::resourcesPath() + path);
|
||||
url = QUrl::fromLocalFile(PathUtils::resourcesPath() + path);
|
||||
} else {
|
||||
url = QUrl::fromLocalFile(path);
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ void InfoView::show(const QString& path, bool firstOrChangedOnly, QString urlQue
|
|||
const QString version = fetchVersion(url);
|
||||
// If we have version information stored
|
||||
if (lastVersion != QString::null) {
|
||||
// Check to see the document version. If it's valid and matches
|
||||
// Check to see the document version. If it's valid and matches
|
||||
// the stored version, we're done, so exit
|
||||
if (version == QString::null || version == lastVersion) {
|
||||
return;
|
||||
|
@ -87,4 +88,3 @@ void InfoView::setUrl(const QUrl& url) {
|
|||
emit urlChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,9 @@ public:
|
|||
QmlWindowClass();
|
||||
~QmlWindowClass();
|
||||
|
||||
virtual void initQml(QVariantMap properties);
|
||||
QQuickItem* asQuickItem() const;
|
||||
|
||||
public slots:
|
||||
bool isVisible() const;
|
||||
void setVisible(bool visible);
|
||||
|
@ -81,9 +84,6 @@ protected:
|
|||
|
||||
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
|
||||
// for tool window panes in QML
|
||||
bool _toolWindow { false };
|
||||
|
|
|
@ -9,49 +9,30 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// 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
|
||||
|
||||
var button;
|
||||
var TOOLBAR_BUTTON_NAME = "MUTE";
|
||||
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";
|
||||
|
||||
function onMuteToggled() {
|
||||
if (isHUDUIEnabled) {
|
||||
button.editProperties({ isActive: AudioDevice.getMuted() });
|
||||
}
|
||||
button.editProperties({ isActive: AudioDevice.getMuted() });
|
||||
}
|
||||
function onClicked(){
|
||||
if (isHUDUIEnabled) {
|
||||
var menuItem = "Mute Microphone";
|
||||
Menu.setIsOptionChecked(menuItem, !Menu.isOptionChecked(menuItem));
|
||||
} else {
|
||||
var entity = HMD.tabletID;
|
||||
Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) });
|
||||
tablet.gotoMenuScreen("Audio");
|
||||
}
|
||||
var entity = HMD.tabletID;
|
||||
Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) });
|
||||
tablet.gotoMenuScreen("Audio");
|
||||
}
|
||||
|
||||
if (Settings.getValue("HUDUIEnabled")) {
|
||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
button = toolBar.addButton({
|
||||
objectName: TOOLBAR_BUTTON_NAME,
|
||||
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,
|
||||
sortOrder: 1
|
||||
});
|
||||
}
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var button = tablet.addButton({
|
||||
icon: "icons/tablet-icons/mic-unmute-i.svg",
|
||||
activeIcon: "icons/tablet-icons/mic-mute-a.svg",
|
||||
text: TABLET_BUTTON_NAME,
|
||||
sortOrder: 1
|
||||
});
|
||||
|
||||
onMuteToggled();
|
||||
|
||||
button.clicked.connect(onClicked);
|
||||
|
@ -60,12 +41,7 @@ AudioDevice.muteToggled.connect(onMuteToggled);
|
|||
Script.scriptEnding.connect(function () {
|
||||
button.clicked.disconnect(onClicked);
|
||||
AudioDevice.muteToggled.disconnect(onMuteToggled);
|
||||
if (tablet) {
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
if (toolBar) {
|
||||
toolBar.removeButton(TOOLBAR_BUTTON_NAME);
|
||||
}
|
||||
tablet.removeButton(button);
|
||||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -10,11 +10,9 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// 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
|
||||
|
||||
var button;
|
||||
// Used for animating and disappearing the bubble
|
||||
var bubbleOverlayTimestamp;
|
||||
|
@ -23,7 +21,7 @@
|
|||
// Used for flashing the HUD button upon activation
|
||||
var bubbleButtonTimestamp;
|
||||
// Affects bubble height
|
||||
const BUBBLE_HEIGHT_SCALE = 0.15;
|
||||
var BUBBLE_HEIGHT_SCALE = 0.15;
|
||||
// The bubble model itself
|
||||
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)
|
||||
|
@ -39,16 +37,8 @@
|
|||
// Is the update() function connected?
|
||||
var updateConnected = false;
|
||||
|
||||
const BUBBLE_VISIBLE_DURATION_MS = 3000;
|
||||
const 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';
|
||||
}
|
||||
var BUBBLE_VISIBLE_DURATION_MS = 3000;
|
||||
var BUBBLE_RAISE_ANIMATION_DURATION_MS = 750;
|
||||
|
||||
// Hides the bubble model overlay and resets the button flash state
|
||||
function hideOverlays() {
|
||||
|
@ -94,7 +84,7 @@
|
|||
}
|
||||
|
||||
// The bubble script's update function
|
||||
update = function () {
|
||||
function update() {
|
||||
var timestamp = Date.now();
|
||||
var delay = (timestamp - bubbleOverlayTimestamp);
|
||||
var overlayAlpha = 1.0 - (delay / BUBBLE_VISIBLE_DURATION_MS);
|
||||
|
@ -146,7 +136,7 @@
|
|||
var bubbleActive = Users.getIgnoreRadiusEnabled();
|
||||
writeButtonProperties(bubbleActive);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// When the space bubble is toggled...
|
||||
function onBubbleToggled() {
|
||||
|
@ -165,38 +155,26 @@
|
|||
|
||||
// Setup the bubble button
|
||||
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");
|
||||
button = tablet.addButton({
|
||||
icon: "icons/tablet-icons/bubble-i.svg",
|
||||
activeIcon: "icons/tablet-icons/bubble-a.svg",
|
||||
text: buttonName,
|
||||
sortOrder: 4
|
||||
});
|
||||
}
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
button = tablet.addButton({
|
||||
icon: "icons/tablet-icons/bubble-i.svg",
|
||||
activeIcon: "icons/tablet-icons/bubble-a.svg",
|
||||
text: buttonName,
|
||||
sortOrder: 4
|
||||
});
|
||||
|
||||
onBubbleToggled();
|
||||
|
||||
button.clicked.connect(Users.toggleIgnoreRadius);
|
||||
Users.ignoreRadiusEnabledChanged.connect(onBubbleToggled);
|
||||
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 () {
|
||||
button.clicked.disconnect(Users.toggleIgnoreRadius);
|
||||
if (tablet) {
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
if (toolbar) {
|
||||
toolbar.removeButton('bubble');
|
||||
}
|
||||
Users.ignoreRadiusEnabledChanged.disconnect(onBubbleToggled);
|
||||
Users.enteredIgnoreRadius.disconnect(enteredIgnoreRadius);
|
||||
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 SYSTEM_LASER_DIRECTION = {x: 0, y: 0, z: -1};
|
||||
var systemLaserOn = false;
|
||||
|
||||
var HIFI_POINTER_DISABLE_MESSAGE_CHANNEL = "Hifi-Pointer-Disable";
|
||||
var isPointerEnabled = true;
|
||||
|
||||
function clearSystemLaser() {
|
||||
if (!systemLaserOn) {
|
||||
return;
|
||||
|
@ -542,9 +546,8 @@ function update() {
|
|||
return off();
|
||||
}
|
||||
|
||||
|
||||
// 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) {
|
||||
Reticle.depth = hudReticleDistance();
|
||||
|
||||
|
@ -579,9 +582,25 @@ function 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);
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(function () {
|
||||
Messages.unsubscribe(HIFI_POINTER_DISABLE_MESSAGE_CHANNEL);
|
||||
Messages.messageReceived.disconnect(handleMessages);
|
||||
Script.clearInterval(settingsChecker);
|
||||
Script.update.disconnect(update);
|
||||
OffscreenFlags.navigationFocusDisabled = false;
|
||||
|
|
|
@ -25,6 +25,11 @@ var OVERLAY_RAMP_RATE = 8.0;
|
|||
|
||||
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) {
|
||||
return Math.min(Math.max(val, min), max);
|
||||
}
|
||||
|
@ -43,6 +48,8 @@ function init() {
|
|||
animStateHandler,
|
||||
["leftHandOverlayAlpha", "rightHandOverlayAlpha", "leftHandGraspAlpha", "rightHandGraspAlpha"]
|
||||
);
|
||||
Messages.subscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL);
|
||||
Messages.messageReceived.connect(handleMessages);
|
||||
}
|
||||
|
||||
function animStateHandler(props) {
|
||||
|
@ -76,11 +83,37 @@ function update(dt) {
|
|||
} else {
|
||||
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() {
|
||||
Script.update.disconnect(update);
|
||||
MyAvatar.removeAnimationStateHandler(animStateHandlerID);
|
||||
Messages.unsubscribe(HIFI_POINT_INDEX_MESSAGE_CHANNEL);
|
||||
Messages.messageReceived.disconnect(handleMessages);
|
||||
}
|
||||
|
||||
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.
|
||||
// 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
|
||||
|
||||
var button;
|
||||
var buttonName = "HELP";
|
||||
var toolBar = null;
|
||||
var tablet = null;
|
||||
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",
|
||||
activeIcon: "icons/tablet-icons/help-a.svg",
|
||||
text: buttonName,
|
||||
sortOrder: 6
|
||||
});
|
||||
}
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var button = tablet.addButton({
|
||||
icon: "icons/tablet-icons/help-i.svg",
|
||||
activeIcon: "icons/tablet-icons/help-a.svg",
|
||||
text: buttonName,
|
||||
sortOrder: 6
|
||||
});
|
||||
|
||||
var enabled = false;
|
||||
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) {
|
||||
Menu.closeInfoView('InfoView_html/help.html');
|
||||
enabled = !enabled;
|
||||
|
@ -80,9 +53,6 @@
|
|||
if (tablet) {
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
if (toolBar) {
|
||||
toolBar.removeButton(buttonName);
|
||||
}
|
||||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// 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
|
||||
|
||||
|
@ -37,20 +38,13 @@ function updateControllerDisplay() {
|
|||
}
|
||||
|
||||
var button;
|
||||
var toolBar = null;
|
||||
var tablet = null;
|
||||
|
||||
if (Settings.getValue("HUDUIEnabled")) {
|
||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
} else {
|
||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
}
|
||||
var 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.
|
||||
// Disable them in hmd.
|
||||
var desktopOnlyViews = ['Mirror', 'Independent Mode', 'Entity Mode'];
|
||||
|
||||
function onHmdChanged(isHmd) {
|
||||
//TODO change button icon when the hmd changes
|
||||
if (isHmd) {
|
||||
button.editProperties({
|
||||
icon: "icons/tablet-icons/switch-desk-i.svg",
|
||||
|
@ -67,25 +61,18 @@ function onHmdChanged(isHmd) {
|
|||
});
|
||||
updateControllerDisplay();
|
||||
}
|
||||
function onClicked(){
|
||||
|
||||
function onClicked() {
|
||||
var isDesktop = Menu.isOptionChecked(desktopMenuItemName);
|
||||
Menu.setIsOptionChecked(isDesktop ? headset : desktopMenuItemName, true);
|
||||
}
|
||||
|
||||
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({
|
||||
icon: HMD.active ? "icons/tablet-icons/switch-desk-i.svg" : "icons/tablet-icons/switch-vr-i.svg",
|
||||
text: HMD.active ? "DESKTOP" : "VR",
|
||||
sortOrder: 2
|
||||
});
|
||||
}
|
||||
button = tablet.addButton({
|
||||
icon: HMD.active ? "icons/tablet-icons/switch-desk-i.svg" : "icons/tablet-icons/switch-vr-i.svg",
|
||||
text: HMD.active ? "DESKTOP" : "VR",
|
||||
sortOrder: 2
|
||||
});
|
||||
onHmdChanged(HMD.active);
|
||||
|
||||
button.clicked.connect(onClicked);
|
||||
|
@ -97,9 +84,6 @@ if (headset) {
|
|||
if (tablet) {
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
if (toolBar) {
|
||||
toolBar.removeButton("hmdToggle");
|
||||
}
|
||||
HMD.displayModeChanged.disconnect(onHmdChanged);
|
||||
Camera.modeUpdated.disconnect(updateControllerDisplay);
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// 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 }] */
|
||||
|
||||
(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 WARN_USER_NO_PERMISSIONS = "WARN_USER_NO_PERMISSIONS";
|
||||
|
||||
var marketplaceWindow = null;
|
||||
|
||||
var CLARA_DOWNLOAD_TITLE = "Preparing Download";
|
||||
var messageBox = null;
|
||||
var isDownloadBeingCancelled = false;
|
||||
|
@ -57,52 +55,47 @@ Window.messageBoxClosed.connect(onMessageBoxClosed);
|
|||
function showMarketplace() {
|
||||
UserActivityLogger.openedMarketplace();
|
||||
|
||||
if (tablet) {
|
||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
tablet.webEventReceived.connect(function (message) {
|
||||
if (message === GOTO_DIRECTORY) {
|
||||
tablet.gotoWebScreen(MARKETPLACES_URL);
|
||||
}
|
||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
tablet.webEventReceived.connect(function (message) {
|
||||
|
||||
if (message === QUERY_CAN_WRITE_ASSETS) {
|
||||
tablet.emitScriptEvent(CAN_WRITE_ASSETS + " " + Entities.canWriteAssets());
|
||||
}
|
||||
if (message === GOTO_DIRECTORY) {
|
||||
tablet.gotoWebScreen(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
}
|
||||
|
||||
if (message === WARN_USER_NO_PERMISSIONS) {
|
||||
Window.alert(NO_PERMISSIONS_ERROR_MESSAGE);
|
||||
}
|
||||
if (message === QUERY_CAN_WRITE_ASSETS) {
|
||||
tablet.emitScriptEvent(CAN_WRITE_ASSETS + " " + Entities.canWriteAssets());
|
||||
}
|
||||
|
||||
if (message.slice(0, CLARA_IO_STATUS.length) === CLARA_IO_STATUS) {
|
||||
if (isDownloadBeingCancelled) {
|
||||
return;
|
||||
}
|
||||
if (message === WARN_USER_NO_PERMISSIONS) {
|
||||
Window.alert(NO_PERMISSIONS_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
var text = message.slice(CLARA_IO_STATUS.length);
|
||||
if (messageBox === null) {
|
||||
messageBox = Window.openMessageBox(CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON);
|
||||
} else {
|
||||
Window.updateMessageBox(messageBox, CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON);
|
||||
}
|
||||
if (message.slice(0, CLARA_IO_STATUS.length) === CLARA_IO_STATUS) {
|
||||
if (isDownloadBeingCancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.slice(0, CLARA_IO_DOWNLOAD.length) === CLARA_IO_DOWNLOAD) {
|
||||
if (messageBox !== null) {
|
||||
Window.closeMessageBox(messageBox);
|
||||
messageBox = null;
|
||||
}
|
||||
return;
|
||||
var text = message.slice(CLARA_IO_STATUS.length);
|
||||
if (messageBox === null) {
|
||||
messageBox = Window.openMessageBox(CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON);
|
||||
} else {
|
||||
Window.updateMessageBox(messageBox, CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (message === CLARA_IO_CANCELLED_DOWNLOAD) {
|
||||
isDownloadBeingCancelled = false;
|
||||
if (message.slice(0, CLARA_IO_DOWNLOAD.length) === CLARA_IO_DOWNLOAD) {
|
||||
if (messageBox !== null) {
|
||||
Window.closeMessageBox(messageBox);
|
||||
messageBox = null;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
marketplaceWindow.setURL(MARKETPLACE_URL_INITIAL);
|
||||
marketplaceWindow.setVisible(true);
|
||||
marketplaceVisible = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (message === CLARA_IO_CANCELLED_DOWNLOAD) {
|
||||
isDownloadBeingCancelled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function toggleMarketplace() {
|
||||
|
@ -111,33 +104,12 @@ function toggleMarketplace() {
|
|||
showMarketplace();
|
||||
}
|
||||
|
||||
var tablet = null;
|
||||
var toolBar = null;
|
||||
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",
|
||||
text: "MARKET",
|
||||
sortOrder: 9
|
||||
});
|
||||
}
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var marketplaceButton = tablet.addButton({
|
||||
icon: "icons/tablet-icons/market-i.svg",
|
||||
text: "MARKET",
|
||||
sortOrder: 9
|
||||
});
|
||||
|
||||
function onCanWriteAssetsChanged() {
|
||||
var message = CAN_WRITE_ASSETS + " " + Entities.canWriteAssets();
|
||||
|
@ -152,9 +124,6 @@ marketplaceButton.clicked.connect(onClick);
|
|||
Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged);
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
if (toolBar) {
|
||||
toolBar.removeButton("marketplace");
|
||||
}
|
||||
if (tablet) {
|
||||
tablet.removeButton(marketplaceButton);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"use strict";
|
||||
/*jslint vars: true, plusplus: true, forin: true*/
|
||||
/*globals Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, OverlayWindow, Toolbars, Vec3, Quat, Controller, print, getControllerWorldLocation */
|
||||
/* jslint vars: true, plusplus: true, forin: true*/
|
||||
/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */
|
||||
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||
//
|
||||
// pal.js
|
||||
//
|
||||
|
@ -13,21 +14,24 @@
|
|||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
// 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.
|
||||
const 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")
|
||||
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")
|
||||
};
|
||||
const 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")
|
||||
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")
|
||||
};
|
||||
const 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")
|
||||
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")
|
||||
};
|
||||
|
||||
const UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6};
|
||||
const SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29};
|
||||
const HOVER_COLOR = {red: 0xD0, green: 0xD0, blue: 0xD0}; // almost white for now
|
||||
var UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6};
|
||||
var SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29};
|
||||
var HOVER_COLOR = {red: 0xD0, green: 0xD0, blue: 0xD0}; // almost white for now
|
||||
|
||||
var conserveResources = true;
|
||||
|
||||
|
@ -87,24 +91,24 @@ ExtendedOverlay.prototype.hover = function (hovering) {
|
|||
} else {
|
||||
lastHoveringId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.editOverlay({color: color(this.selected, hovering, this.audioLevel)});
|
||||
if (this.model) {
|
||||
this.model.editOverlay({textures: textures(this.selected, hovering)});
|
||||
}
|
||||
if (hovering) {
|
||||
// un-hover the last hovering overlay
|
||||
if (lastHoveringId && lastHoveringId != this.key) {
|
||||
if (lastHoveringId && lastHoveringId !== this.key) {
|
||||
ExtendedOverlay.get(lastHoveringId).hover(false);
|
||||
}
|
||||
lastHoveringId = this.key;
|
||||
}
|
||||
}
|
||||
};
|
||||
ExtendedOverlay.prototype.select = function (selected) {
|
||||
if (this.selected === selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
UserActivityLogger.palAction(selected ? "avatar_selected" : "avatar_deselected", this.key);
|
||||
|
||||
this.editOverlay({color: color(selected, this.hovering, this.audioLevel)});
|
||||
|
@ -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.
|
||||
var data;
|
||||
switch (message.method) {
|
||||
case 'selected':
|
||||
selectedIds = message.params;
|
||||
|
@ -250,7 +245,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
|||
}
|
||||
break;
|
||||
case 'displayNameUpdate':
|
||||
if (MyAvatar.displayName != message.params) {
|
||||
if (MyAvatar.displayName !== message.params) {
|
||||
MyAvatar.displayName = message.params;
|
||||
UserActivityLogger.palAction("display_name_change", "");
|
||||
}
|
||||
|
@ -261,11 +256,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
|||
}
|
||||
|
||||
function sendToQml(message) {
|
||||
if (Settings.getValue("HUDUIEnabled")) {
|
||||
pal.sendToQml(message);
|
||||
} else {
|
||||
tablet.sendToQml(message);
|
||||
}
|
||||
tablet.sendToQml(message);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -273,7 +264,7 @@ function sendToQml(message) {
|
|||
//
|
||||
function addAvatarNode(id) {
|
||||
var selected = ExtendedOverlay.isSelected(id);
|
||||
return new ExtendedOverlay(id, "sphere", {
|
||||
return new ExtendedOverlay(id, "sphere", {
|
||||
drawInFront: true,
|
||||
solid: true,
|
||||
alpha: 0.8,
|
||||
|
@ -341,7 +332,7 @@ function updateOverlays() {
|
|||
var target = avatar.position;
|
||||
var distance = Vec3.distance(target, eye);
|
||||
var offset = 0.2;
|
||||
|
||||
|
||||
// base offset on 1/2 distance from hips to head if we can
|
||||
var headIndex = avatar.getJointIndex("Head");
|
||||
if (headIndex > 0) {
|
||||
|
@ -350,7 +341,7 @@ function updateOverlays() {
|
|||
|
||||
// get diff between target and eye (a vector pointing to the eye from avatar position)
|
||||
var diff = Vec3.subtract(target, eye);
|
||||
|
||||
|
||||
// move a bit in front, towards the camera
|
||||
target = Vec3.subtract(target, Vec3.multiply(Vec3.normalize(diff), offset));
|
||||
|
||||
|
@ -361,12 +352,12 @@ function updateOverlays() {
|
|||
overlay.editOverlay({
|
||||
color: color(ExtendedOverlay.isSelected(id), overlay.hovering, overlay.audioLevel),
|
||||
position: target,
|
||||
dimensions: 0.032 * distance
|
||||
dimensions: 0.032 * distance
|
||||
});
|
||||
if (overlay.model) {
|
||||
overlay.model.ping = pingPong;
|
||||
overlay.model.editOverlay({
|
||||
position: target,
|
||||
position: target,
|
||||
scale: 0.2 * distance, // constant apparent size
|
||||
rotation: Camera.orientation
|
||||
});
|
||||
|
@ -385,7 +376,9 @@ function removeOverlays() {
|
|||
selectedIds = [];
|
||||
lastHoveringId = 0;
|
||||
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)
|
||||
var currentHandPressed = 0;
|
||||
const TRIGGER_CLICK_THRESHOLD = 0.85;
|
||||
const TRIGGER_PRESS_THRESHOLD = 0.05;
|
||||
var TRIGGER_CLICK_THRESHOLD = 0.85;
|
||||
var TRIGGER_PRESS_THRESHOLD = 0.05;
|
||||
|
||||
function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position
|
||||
var pickRay;
|
||||
if (HMD.active) {
|
||||
if (currentHandPressed != 0) {
|
||||
if (currentHandPressed !== 0) {
|
||||
pickRay = controllerComputePickRay(currentHandPressed);
|
||||
} else {
|
||||
// nothing should hover, so
|
||||
|
@ -433,18 +427,18 @@ function handleMouseMoveEvent(event) { // find out which overlay (if any) is ove
|
|||
handleMouseMove(pickRay);
|
||||
}
|
||||
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 ignore it until this one is no longer pressed.
|
||||
isPressed = value > TRIGGER_PRESS_THRESHOLD;
|
||||
if (currentHandPressed == 0) {
|
||||
var isPressed = value > TRIGGER_PRESS_THRESHOLD;
|
||||
if (currentHandPressed === 0) {
|
||||
currentHandPressed = isPressed ? hand : 0;
|
||||
return;
|
||||
}
|
||||
if (currentHandPressed == hand) {
|
||||
if (currentHandPressed === hand) {
|
||||
currentHandPressed = isPressed ? hand : 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// otherwise, the other hand is still triggered
|
||||
// so do nothing.
|
||||
}
|
||||
|
@ -470,7 +464,7 @@ function makeClickHandler(hand) {
|
|||
function makePressHandler(hand) {
|
||||
return function (value) {
|
||||
handleTriggerPressed(hand, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand));
|
||||
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 buttonName = "PEOPLE";
|
||||
var tablet = null;
|
||||
var toolBar = null;
|
||||
if (Settings.getValue("HUDUIEnabled")) {
|
||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
button = toolBar.addButton({
|
||||
objectName: buttonName,
|
||||
imageURL: Script.resolvePath("assets/images/tools/people.svg"),
|
||||
visible: true,
|
||||
alpha: 0.9
|
||||
});
|
||||
pal.fromQml.connect(fromQml);
|
||||
} else {
|
||||
|
||||
function onTabletScreenChanged(type, url) {
|
||||
if (type !== "QML" || url !== "../Pal.qml") {
|
||||
off();
|
||||
}
|
||||
}
|
||||
|
||||
function startup() {
|
||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
button = tablet.addButton({
|
||||
text: buttonName,
|
||||
|
@ -500,8 +491,19 @@ if (Settings.getValue("HUDUIEnabled")) {
|
|||
sortOrder: 7
|
||||
});
|
||||
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 audioTimer;
|
||||
var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too)
|
||||
|
@ -513,41 +515,26 @@ function off() {
|
|||
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
||||
isWired = false;
|
||||
}
|
||||
if (audioTimer) { Script.clearInterval(audioTimer); }
|
||||
if (audioTimer) {
|
||||
Script.clearInterval(audioTimer);
|
||||
}
|
||||
triggerMapping.disable(); // It's ok if we disable twice.
|
||||
triggerPressMapping.disable(); // see above
|
||||
removeOverlays();
|
||||
Users.requestsDomainListData = false;
|
||||
}
|
||||
function onClicked() {
|
||||
if (Settings.getValue("HUDUIEnabled")) {
|
||||
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");
|
||||
Users.requestsDomainListData = true;
|
||||
populateUserList();
|
||||
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);
|
||||
}
|
||||
|
||||
function onTabletButtonClicked() {
|
||||
tablet.loadQMLSource("../Pal.qml");
|
||||
Users.requestsDomainListData = true;
|
||||
populateUserList();
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -562,17 +549,12 @@ function receiveMessage(channel, messageString, senderID) {
|
|||
var message = JSON.parse(messageString);
|
||||
switch (message.method) {
|
||||
case 'select':
|
||||
if (!pal.visible) {
|
||||
onClicked();
|
||||
}
|
||||
sendToQml(message); // Accepts objects, not just strings.
|
||||
break;
|
||||
default:
|
||||
print('Unrecognized PAL message', messageString);
|
||||
}
|
||||
}
|
||||
Messages.subscribe(CHANNEL);
|
||||
Messages.messageReceived.connect(receiveMessage);
|
||||
|
||||
|
||||
var AVERAGING_RATIO = 0.05;
|
||||
|
@ -630,57 +612,29 @@ function avatarDisconnected(nodeID) {
|
|||
// remove from the pal list
|
||||
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() {
|
||||
sendToQml({ method: 'clearLocalQMLData' });
|
||||
if (pal.visible) {
|
||||
onClicked(); // Close the PAL
|
||||
}
|
||||
}
|
||||
Window.domainChanged.connect(clearLocalQMLDataAndClosePAL);
|
||||
Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
//
|
||||
// Cleanup.
|
||||
//
|
||||
Script.scriptEnding.connect(function () {
|
||||
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();
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(shutdown);
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
// Distributed under the Apache License, Version 2.0
|
||||
// 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
|
||||
|
||||
|
@ -17,29 +18,15 @@ var resetOverlays;
|
|||
var reticleVisible;
|
||||
var clearOverlayWhenMoving;
|
||||
|
||||
var button;
|
||||
var buttonName = "SNAP";
|
||||
var tablet = null;
|
||||
var toolBar = null;
|
||||
|
||||
var buttonConnected = false;
|
||||
|
||||
if (Settings.getValue("HUDUIEnabled")) {
|
||||
toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
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",
|
||||
text: buttonName,
|
||||
sortOrder: 5
|
||||
});
|
||||
}
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var button = tablet.addButton({
|
||||
icon: "icons/tablet-icons/snap-i.svg",
|
||||
text: buttonName,
|
||||
sortOrder: 5
|
||||
});
|
||||
|
||||
function shouldOpenFeedAfterShare() {
|
||||
var persisted = Settings.getValue('openFeedAfterShare', true); // might answer true, false, "true", or "false"
|
||||
|
@ -63,42 +50,42 @@ function confirmShare(data) {
|
|||
var isLoggedIn;
|
||||
var needsLogin = false;
|
||||
switch (message) {
|
||||
case 'ready':
|
||||
dialog.emitScriptEvent(data); // Send it.
|
||||
outstanding = 0;
|
||||
break;
|
||||
case 'openSettings':
|
||||
Desktop.show("hifi/dialogs/GeneralPreferencesDialog.qml", "GeneralPreferencesDialog");
|
||||
break;
|
||||
case 'setOpenFeedFalse':
|
||||
Settings.setValue('openFeedAfterShare', false);
|
||||
break;
|
||||
case 'setOpenFeedTrue':
|
||||
Settings.setValue('openFeedAfterShare', true);
|
||||
break;
|
||||
default:
|
||||
dialog.webEventReceived.disconnect(onMessage);
|
||||
dialog.close();
|
||||
isLoggedIn = Account.isLoggedIn();
|
||||
message.forEach(function (submessage) {
|
||||
if (submessage.share && !isLoggedIn) {
|
||||
needsLogin = true;
|
||||
submessage.share = false;
|
||||
}
|
||||
if (submessage.share) {
|
||||
print('sharing', submessage.localPath);
|
||||
outstanding++;
|
||||
Window.shareSnapshot(submessage.localPath, submessage.href);
|
||||
} else {
|
||||
print('not sharing', submessage.localPath);
|
||||
}
|
||||
});
|
||||
if (!outstanding && shouldOpenFeedAfterShare()) {
|
||||
showFeedWindow();
|
||||
case 'ready':
|
||||
dialog.emitScriptEvent(data); // Send it.
|
||||
outstanding = 0;
|
||||
break;
|
||||
case 'openSettings':
|
||||
Desktop.show("hifi/dialogs/GeneralPreferencesDialog.qml", "GeneralPreferencesDialog");
|
||||
break;
|
||||
case 'setOpenFeedFalse':
|
||||
Settings.setValue('openFeedAfterShare', false);
|
||||
break;
|
||||
case 'setOpenFeedTrue':
|
||||
Settings.setValue('openFeedAfterShare', true);
|
||||
break;
|
||||
default:
|
||||
dialog.webEventReceived.disconnect(onMessage);
|
||||
dialog.close();
|
||||
isLoggedIn = Account.isLoggedIn();
|
||||
message.forEach(function (submessage) {
|
||||
if (submessage.share && !isLoggedIn) {
|
||||
needsLogin = true;
|
||||
submessage.share = false;
|
||||
}
|
||||
if (needsLogin) { // after the possible feed, so that the login is on top
|
||||
Account.checkAndSignalForAccessToken();
|
||||
if (submessage.share) {
|
||||
print('sharing', submessage.localPath);
|
||||
outstanding++;
|
||||
Window.shareSnapshot(submessage.localPath, submessage.href);
|
||||
} else {
|
||||
print('not sharing', submessage.localPath);
|
||||
}
|
||||
});
|
||||
if (!outstanding && shouldOpenFeedAfterShare()) {
|
||||
showFeedWindow();
|
||||
}
|
||||
if (needsLogin) { // after the possible feed, so that the login is on top
|
||||
Account.checkAndSignalForAccessToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
dialog.webEventReceived.connect(onMessage);
|
||||
|
@ -159,7 +146,7 @@ function isDomainOpen(id) {
|
|||
var url = location.metaverseServerUrl + "/api/v1/user_stories?" + options.join('&');
|
||||
request.open("GET", url, false);
|
||||
request.send();
|
||||
if (request.status != 200) {
|
||||
if (request.status !== 200) {
|
||||
return false;
|
||||
}
|
||||
var response = JSON.parse(request.response); // Not parsed for us.
|
||||
|
@ -229,9 +216,6 @@ Script.scriptEnding.connect(function () {
|
|||
if (tablet) {
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
if (toolBar) {
|
||||
toolBar.removeButton(buttonName);
|
||||
}
|
||||
Window.snapshotShared.disconnect(snapshotShared);
|
||||
Window.processingGif.disconnect(processingGif);
|
||||
});
|
||||
|
|
|
@ -12,54 +12,27 @@
|
|||
//
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
var gotoQmlSource = "TabletAddressDialog.qml";
|
||||
var button;
|
||||
var gotoQmlSource = "TabletAddressDialog.qml";
|
||||
var buttonName = "GOTO";
|
||||
var toolBar = null;
|
||||
var tablet = null;
|
||||
function onAddressBarShown(visible) {
|
||||
if (toolBar) {
|
||||
button.editProperties({isActive: visible});
|
||||
}
|
||||
}
|
||||
|
||||
function onClicked(){
|
||||
if (toolBar) {
|
||||
DialogsManager.toggleAddressBar();
|
||||
} else {
|
||||
tablet.loadQMLSource(gotoQmlSource);
|
||||
}
|
||||
tablet.loadQMLSource(gotoQmlSource);
|
||||
}
|
||||
if (Settings.getValue("HUDUIEnabled")) {
|
||||
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",
|
||||
activeIcon: "icons/tablet-icons/goto-a.svg",
|
||||
text: buttonName,
|
||||
sortOrder: 8
|
||||
});
|
||||
}
|
||||
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var button = tablet.addButton({
|
||||
icon: "icons/tablet-icons/goto-i.svg",
|
||||
activeIcon: "icons/tablet-icons/goto-a.svg",
|
||||
text: buttonName,
|
||||
sortOrder: 8
|
||||
});
|
||||
|
||||
button.clicked.connect(onClicked);
|
||||
DialogsManager.addressBarShown.connect(onAddressBarShown);
|
||||
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
button.clicked.disconnect(onClicked);
|
||||
if (tablet) {
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
if (toolBar) {
|
||||
toolBar.removeButton(buttonName);
|
||||
}
|
||||
DialogsManager.addressBarShown.disconnect(onAddressBarShown);
|
||||
});
|
||||
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -52,6 +52,15 @@
|
|||
}
|
||||
|
||||
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) {
|
||||
var MUTE_MICROPHONE_MENU_ITEM = "Mute Microphone";
|
||||
var currentMicEnabled = !Menu.isOptionChecked(MUTE_MICROPHONE_MENU_ITEM);
|
||||
|
@ -67,7 +76,7 @@
|
|||
// other reason, close the tablet.
|
||||
hideTabletUI();
|
||||
HMD.closeTablet();
|
||||
} else if (HMD.showTablet && !tabletShown) {
|
||||
} else if (HMD.showTablet && !tabletShown && !toolbarMode) {
|
||||
UserActivityLogger.openedTablet();
|
||||
showTabletUI();
|
||||
} else if (!HMD.showTablet && tabletShown) {
|
||||
|
|
Loading…
Reference in a new issue