Merge branch 'tablet-ui' into feature/can-touch-this

This commit is contained in:
Anthony J. Thibault 2017-03-10 17:05:26 -08:00
commit 07e10ae862
91 changed files with 4920 additions and 1794 deletions

View file

@ -241,6 +241,7 @@ void AudioMixer::sendStatsPacket() {
statsObject["avg_streams_per_frame"] = (float)_stats.sumStreams / (float)_numStatFrames;
statsObject["avg_listeners_per_frame"] = (float)_stats.sumListeners / (float)_numStatFrames;
statsObject["avg_listeners_(silent)_per_frame"] = (float)_stats.sumListenersSilent / (float)_numStatFrames;
statsObject["silent_packets_per_frame"] = (float)_numSilentPackets / (float)_numStatFrames;

View file

@ -106,6 +106,7 @@ void AudioMixerSlave::mix(const SharedNodePointer& node) {
sendMixPacket(node, *data, encodedBuffer);
} else {
++stats.sumListenersSilent;
sendSilentPacket(node, *data);
}
@ -221,17 +222,19 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
stats.mixTime += mixTime.count();
#endif
// use the per listener AudioLimiter to render the mixed data...
listenerData->audioLimiter.render(_mixSamples, _bufferSamples, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
// check for silent audio after the peak limiter has converted the samples
// check for silent audio before limiting
// limiting uses a dither and can only guarantee abs(sample) <= 1
bool hasAudio = false;
for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; ++i) {
if (_bufferSamples[i] != 0) {
if (_mixSamples[i] != 0.0f) {
hasAudio = true;
break;
}
}
// use the per listener AudioLimiter to render the mixed data
listenerData->audioLimiter.render(_mixSamples, _bufferSamples, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
return hasAudio;
}

View file

@ -14,6 +14,7 @@
void AudioMixerStats::reset() {
sumStreams = 0;
sumListeners = 0;
sumListenersSilent = 0;
totalMixes = 0;
hrtfRenders = 0;
hrtfSilentRenders = 0;
@ -28,6 +29,7 @@ void AudioMixerStats::reset() {
void AudioMixerStats::accumulate(const AudioMixerStats& otherStats) {
sumStreams += otherStats.sumStreams;
sumListeners += otherStats.sumListeners;
sumListenersSilent += otherStats.sumListenersSilent;
totalMixes += otherStats.totalMixes;
hrtfRenders += otherStats.hrtfRenders;
hrtfSilentRenders += otherStats.hrtfSilentRenders;

View file

@ -19,6 +19,7 @@
struct AudioMixerStats {
int sumStreams { 0 };
int sumListeners { 0 };
int sumListenersSilent { 0 };
int totalMixes { 0 };

View file

@ -21,7 +21,7 @@ macro(LINK_HIFI_LIBRARIES)
include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src")
include_directories("${CMAKE_BINARY_DIR}/libraries/${HIFI_LIBRARY}/shaders")
add_dependencies(${TARGET_NAME} ${HIFI_LIBRARY})
#add_dependencies(${TARGET_NAME} ${HIFI_LIBRARY})
# link the actual library - it is static so don't bubble it up
target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY})

View file

@ -0,0 +1,26 @@
<?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 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:18;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-width:18;stroke-linecap:round;stroke-miterlimit:10;}
.st2{fill:none;stroke:#000000;stroke-width:19;stroke-linecap:round;stroke-miterlimit:10;}
</style>
<g>
<g>
<path d="M220.3,378.4l-81.1-232c-1-2.8-3.6-4.3-6.6-4.3h-9.2c-3,0-5.6,1.5-6.6,4.3L34,378.5c-0.8,2.1-0.4,5.1,0.9,7
c1.3,1.9,3.4,3.5,5.7,3.5h15.9c3,0,5.6-2.6,6.6-5.4L90.2,305h73.7l27,78.6c1,2.8,3.6,5.4,6.6,5.4h16.2c2.3,0,4.4-1.8,5.7-3.6
C220.7,383.5,221.1,380.5,220.3,378.4z M100.3,276l25.6-73.1c0.6-1.7,1.3-3.3,1.9-5.1c0.6,1.8,1.2,3,1.7,4.5l24.9,73.7H100.3z"/>
<path d="M351.6,215.5c-9.7-11.4-24.3-17.2-43.2-17.2c-17.5,0-35.5,4.7-53.2,14.1c-3.1,1.7-4.6,5.4-3.3,8.7l5.2,13.6
c0.7,1.9,2.3,3.4,4.2,4.1c1.9,0.7,4.1,0.5,5.8-0.6c14.1-8.2,27.7-12.3,40.6-12.3c10.9,0,18.8,3.2,23.3,9.6c5.2,7.3,8,18.4,8,33
v4.6l-22.7,0.7c-25,0.6-44.7,6-58.2,16.1c-14.3,10.7-21.6,25.7-21.6,44.7c0,17.1,4.9,30.9,14.5,40.8c9.7,10,23.2,15.1,40.1,15.1
c12,0,22.8-2.7,32.2-8c5.6-3.1,11.1-7.7,16.4-13.6l1.6,13.3c0.4,3.5,3.4,6.8,6.9,6.8h10.2c3.9,0,7.6-4.4,7.6-8.3V265.9
C366,243.2,361.1,226.7,351.6,215.5z M265.1,335.2c0-11.2,3.5-19.1,10.7-24.1c8-5.6,22.1-9,42-10.1l19.1-0.9v9.6
c0,17.2-3.8,29.9-12,39.1c-8.1,9-19,13.4-33.3,13.4c-8.8,0-15.3-2.2-19.8-6.9C267.3,350.8,265.1,344.2,265.1,335.2z"/>
<path d="M451.3,439.9c-10,0-15.3-8.1-15.3-18c-0.1-22.2-0.2-298.2-0.4-320.4c-0.1-10,5.2-18.2,15.2-18.3c0.1,0,0.1,0,0.2,0
c9.9,0,15.2,8,15.3,18c0.2,22.2,0.3,298.3,0.4,320.5C466.7,431.7,461.4,439.9,451.3,439.9C451.4,439.9,451.3,439.9,451.3,439.9z"
/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,17 @@
<?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 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:18;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-width:18;stroke-linecap:round;stroke-miterlimit:10;}
.st2{fill:none;stroke:#000000;stroke-width:19;stroke-linecap:round;stroke-miterlimit:10;}
</style>
<g>
<path d="M451.6,90.8L189.4,64.9c-3.2-0.3-6.2,0.5-8.8,2.4l0.1,0L54.9,155.4l0,0c-0.5,0.3-0.5,0.7-0.9,1c-2.8,2.5-4,6.1-4,9.9v262.5
c0,6.8,4.8,12.6,11.6,13.2l262.3,25.9c0.4,0,0.8,0.1,1.2,0.1c2.7,0,5.3-0.9,7.6-2.4l0,0l125.8-88.2l0,0c0.5-0.3,0.3-0.7,0.7-1
c2.8-2.5,3.8-6.1,3.8-9.9V104.1C463,97.2,458.4,91.5,451.6,90.8z M430.1,364.7l-1.8,1.4c-0.2,0.1-0.3,0.3-0.6,0.4c0,0,0.4,0,0.4,0
L339,429.2v-230l98-69.5v222.2C436,358,435,361.1,430.1,364.7z M203.3,93l210.6,20.8l-92.4,64.7L99.6,156.6l86.7-60.8
c0.2,0,0.3,0,0.5,0c0,0,0,0,0.1,0c3.4-2.1,7.4-3.4,11.4-3.4C200,92.4,201.7,92.6,203.3,93z M313,440L76,416.7V181l237,23.3V440z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,21 @@
<?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 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:18;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-width:18;stroke-linecap:round;stroke-miterlimit:10;}
.st2{fill:none;stroke:#000000;stroke-width:19;stroke-linecap:round;stroke-miterlimit:10;}
</style>
<g>
<path d="M417.6,96.6c-90.2-90.2-236.9-90.2-327.1,0c-43.7,43.7-67.8,101.8-67.8,163.6c0,61.8,24.1,119.9,67.8,163.6
c45.1,45.1,104.3,67.6,163.6,67.6c59.2,0,118.5-22.5,163.6-67.6c43.7-43.7,67.8-101.8,67.8-163.6
C485.4,198.4,461.3,140.3,417.6,96.6z M112.7,118.8c30-30,67.2-48.4,106.1-55.3c-7.4,11.3-14,26-19.8,44
c-13.2,41.4-20.5,96.3-20.5,154.5c0,2.8,0,7,0.1,9.8c6.4,1.6,12.8,1.7,19.3,2.8c1.9,0.3,3.9,0.6,5.9,0.8c-0.1-4.4-0.1-8.8-0.1-13.3
c0-116.9,30-193.4,52.3-200c0.5-0.5,1-1,1.4-1.6c50.1,0.8,99.9,20.3,138,58.4c36.6,36.6,57.3,85,58.5,136.6
c-4.8,22.4-81.7,53.2-200.2,53.2c-115.3,0-191.3-29.1-199.6-51.4C54.9,204.9,75.6,155.9,112.7,118.8z M395.5,401.6
C356,441.1,304,460.5,252.1,460c-14.1-8.9-30.3-43.3-39.9-96.6l-25.6-1.4c3.2,19.2,7.4,38.5,12.5,54.3c5.1,16,10.9,29.4,17.3,40.1
c-38-7.2-74.3-25.5-103.7-54.9C83.2,372.1,64,334.9,57.1,294.6c11,6.9,25.2,13.2,42.3,18.7c41.4,13.2,96.3,20.5,154.5,20.5
c58.2,0,113-7.3,154.5-20.5c17.4-5.6,31.7-11.9,42.9-19C444.2,334.7,425.1,372,395.5,401.6z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,38 @@
<?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 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:18;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-width:18;stroke-linecap:round;stroke-miterlimit:10;}
.st2{fill:none;stroke:#000000;stroke-width:19;stroke-linecap:round;stroke-miterlimit:10;}
</style>
<g>
<path d="M380.7,139.8c-2.7-6.6-9.2-10.8-16.3-10.8H292v34h29.9L159,326.1V290h-36v79h1.3c0.1,2,0.5,4.1,1.3,5.9
c2.7,6.6,9.1,11.1,16.2,11.1H225v-35h-40.8L346,189.7V215h35v-62.4C382,148.5,382.4,144,380.7,139.8z"/>
<path d="M338.4,437.6c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0
C348.1,459.3,338.4,449.6,338.4,437.6z M266.9,437.6c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0
c0,12-9.7,21.7-21.7,21.7l0,0C276.6,459.3,266.9,449.6,266.9,437.6z M195.4,437.6c0-12,9.7-21.7,21.7-21.7l0,0
c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0C205.1,459.3,195.4,449.6,195.4,437.6z M123.9,437.6
c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0C133.6,459.3,123.9,449.6,123.9,437.6z"/>
<path d="M74.1,459.3c-5.7,0-11.3-2.3-15.4-6.4c-4-4-6.4-9.6-6.4-15.3c0-5.7,2.3-11.3,6.4-15.3c4-4,9.6-6.4,15.4-6.4
c5.7,0,11.3,2.3,15.3,6.4c4,4,6.4,9.6,6.4,15.3c0,5.7-2.3,11.3-6.4,15.3C85.4,457,79.8,459.3,74.1,459.3z"/>
<path d="M52.4,366.1c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0
C62.1,387.8,52.4,378,52.4,366.1z M52.4,294.6c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7
l0,0C62.1,316.3,52.4,306.5,52.4,294.6z M52.4,223.1c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0
c0,12-9.7,21.7-21.7,21.7l0,0C62.1,244.8,52.4,235,52.4,223.1z M52.4,151.5c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7
l0,0c0,12-9.7,21.7-21.7,21.7l0,0C62.1,173.2,52.4,163.5,52.4,151.5z"/>
<path d="M338.4,80c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0
C348.1,101.7,338.4,92,338.4,80z M266.9,80c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0
C276.6,101.7,266.9,92,266.9,80z M195.4,80c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0
C205.1,101.7,195.4,92,195.4,80z M123.9,80c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0
C133.6,101.7,123.9,92,123.9,80z"/>
<path d="M431.6,101.7c-5.7,0-11.3-2.3-15.3-6.4c-4-4-6.4-9.6-6.4-15.3c0-5.7,2.3-11.3,6.4-15.3c4-4,9.6-6.4,15.3-6.4
s11.3,2.3,15.3,6.4c4,4,6.4,9.6,6.4,15.3c0,5.7-2.3,11.3-6.4,15.3C442.9,99.4,437.4,101.7,431.6,101.7z"/>
<path d="M409.9,366.1c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0
C419.7,387.8,409.9,378.1,409.9,366.1z M409.9,294.6c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0
c0,12-9.7,21.7-21.7,21.7l0,0C419.7,316.3,409.9,306.5,409.9,294.6z M409.9,223.1c0-12,9.7-21.7,21.7-21.7l0,0
c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0C419.7,244.7,409.9,235,409.9,223.1z M409.9,151.5
c0-12,9.7-21.7,21.7-21.7l0,0c12,0,21.7,9.7,21.7,21.7l0,0c0,12-9.7,21.7-21.7,21.7l0,0C419.7,173.2,409.9,163.5,409.9,151.5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,34 @@
<?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 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:18;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-width:18;stroke-linecap:round;stroke-miterlimit:10;}
.st2{fill:none;stroke:#000000;stroke-width:19;stroke-linecap:round;stroke-miterlimit:10;}
</style>
<g>
<circle cx="259.2" cy="252.5" r="38.3"/>
<path d="M259.2,361.8c-60.3,0-109.3-49-109.3-109.3s49-109.3,109.3-109.3s109.3,49,109.3,109.3S319.4,361.8,259.2,361.8z
M259.2,171.8c-44.5,0-80.7,36.2-80.7,80.7s36.2,80.7,80.7,80.7s80.7-36.2,80.7-80.7S303.7,171.8,259.2,171.8z"/>
<path d="M414.1,268.5c-7.9,0-14.2-6.4-14.3-14.2c0-7.9,6.3-14.3,14.2-14.3c17.1-0.1,34.5-0.2,51.6-0.3c0,0,0.1,0,0.1,0
c7.8,0,14.2,6.3,14.3,14.2c0.1,7.9-6.3,14.3-14.2,14.4C448.8,268.3,431.4,268.4,414.1,268.5C414.2,268.5,414.1,268.5,414.1,268.5z"
/>
<path d="M105.8,268.5C105.8,268.5,105.8,268.5,105.8,268.5c-17.3-0.1-34.6-0.2-51.7-0.4c-7.9-0.1-14.2-6.5-14.1-14.4
c0.1-7.8,6.5-14.1,14.3-14.1c0.1,0,0.1,0,0.2,0c17,0.2,34.3,0.3,51.5,0.4c7.9,0,14.3,6.5,14.2,14.3
C120.1,262.2,113.7,268.5,105.8,268.5z"/>
<path d="M369.1,159.5c-3.6,0-7.3-1.4-10-4.1c-5.6-5.6-5.6-14.6-0.1-20.2c12-12.1,24.2-24.5,36.3-36.7c5.5-5.6,14.6-5.7,20.2-0.2
c5.6,5.5,5.7,14.6,0.2,20.2c-12.1,12.3-24.3,24.7-36.4,36.8C376.4,158.1,372.8,159.5,369.1,159.5z"/>
<path d="M114.4,413.7c-3.7,0-7.4-1.4-10.2-4.3c-5.5-5.6-5.4-14.7,0.2-20.2c12.2-11.9,24.5-24.1,36.7-36.1
c5.6-5.6,14.6-5.5,20.2,0.1c5.6,5.6,5.5,14.6-0.1,20.2c-12.2,12.1-24.6,24.3-36.8,36.2C121.6,412.3,118,413.7,114.4,413.7z"/>
<path d="M260.2,114.2c-7.9,0-14.2-6.4-14.3-14.2c-0.1-17-0.2-34.4-0.3-51.6c-0.1-7.9,6.3-14.3,14.2-14.4c0,0,0.1,0,0.1,0
c7.8,0,14.2,6.3,14.3,14.2c0.1,17.3,0.3,34.7,0.3,51.7C274.5,107.8,268.1,114.2,260.2,114.2C260.2,114.2,260.2,114.2,260.2,114.2z"
/>
<path d="M259.9,474.1c-0.1,0-0.1,0-0.2,0c-7.9-0.1-14.2-6.5-14.1-14.4c0.2-16.9,0.3-34.3,0.4-51.5c0-7.9,6.4-14.2,14.3-14.2
c0,0,0,0,0.1,0c7.9,0,14.3,6.5,14.2,14.3c-0.1,17.3-0.2,34.6-0.4,51.7C274,467.8,267.7,474.1,259.9,474.1z"/>
<path d="M151.2,159.3c-3.6,0-7.3-1.4-10-4.1c-12.2-12.1-24.6-24.3-36.7-36.3c-5.6-5.5-5.7-14.6-0.2-20.2c5.5-5.6,14.6-5.7,20.2-0.2
c12.2,12,24.6,24.2,36.8,36.4c5.6,5.6,5.6,14.6,0.1,20.2C158.5,157.9,154.9,159.3,151.2,159.3z"/>
<path d="M405.4,414c-3.7,0-7.4-1.4-10.2-4.3c-11.9-12.2-24-24.5-36.1-36.7c-5.6-5.6-5.5-14.6,0.1-20.2c5.6-5.6,14.6-5.5,20.2,0.1
c12.1,12.2,24.3,24.6,36.2,36.8c5.5,5.6,5.4,14.7-0.2,20.2C412.6,412.6,409,414,405.4,414z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View 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 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:18;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-width:18;stroke-linecap:round;stroke-miterlimit:10;}
.st2{fill:none;stroke:#000000;stroke-width:19;stroke-linecap:round;stroke-miterlimit:10;}
.st3{stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g>
<path d="M438,121.5c0-8-6.5-14.5-14.5-14.5h-333c-8,0-14.5,6.5-14.5,14.5v298c0,8,6.5,14.5,14.5,14.5h333c8,0,14.5-6.5,14.5-14.5
V121.5z M219.4,130H391c8.3,0,15,7.2,15,16s-6.7,16-15,16H219.4c-8.3,0-15-7.2-15-16S211.1,130,219.4,130z M171.5,128.6
c9.2,0,16.7,7.5,16.7,16.7c0,9.2-7.5,16.7-16.7,16.7c-9.2,0-16.7-7.5-16.7-16.7C154.8,136,162.3,128.6,171.5,128.6z M121,128.6
c9.2,0,16.7,7.5,16.7,16.7c0,9.2-7.5,16.7-16.7,16.7c-9.2,0-16.7-7.5-16.7-16.7C104.4,136,111.8,128.6,121,128.6z M412,405H104V186
h308V405z"/>
</g>
<g>
<path class="st3" d="M161.6,320.5h-14.3l-20.5-59.3h12.9l14.7,44.8l14.7-44.8h12.9l14.7,44.8l14.7-44.8h12.9L204,320.5h-14.3
l-14-40.6L161.6,320.5z"/>
<path class="st3" d="M299.4,296.3h-46.5c0.3,4.3,2.3,7.8,5.9,10.4c3.6,2.6,7.8,4,12.5,4c7.4,0,13.1-2.3,16.9-7l7.1,7.8
c-6.4,6.6-14.7,9.9-25,9.9c-8.3,0-15.4-2.8-21.2-8.3c-5.8-5.5-8.7-13-8.7-22.3c0-9.3,3-16.7,8.9-22.2c5.9-5.5,12.9-8.2,21-8.2
c8.1,0,14.9,2.4,20.6,7.3c5.6,4.9,8.5,11.6,8.5,20.1V296.3z M252.9,286.5h34c0-5-1.6-8.8-4.7-11.5s-7-4-11.5-4
c-4.6,0-8.7,1.4-12.3,4.2C254.7,278,252.9,281.8,252.9,286.5z"/>
<path class="st3" d="M353.6,260.3c7.9,0,14.7,2.8,20.4,8.2c5.6,5.5,8.5,12.8,8.5,22c0,9.1-2.8,16.6-8.4,22.3
c-5.6,5.7-12.1,8.6-19.6,8.6s-14.2-3.3-20.1-9.8v8.9h-12.5v-82.7h12.5v33.8C339.2,264.1,345.6,260.3,353.6,260.3z M334.1,291
c0,5.6,1.7,10.3,5.1,13.9c3.4,3.6,7.6,5.4,12.5,5.4c4.9,0,9.2-1.8,12.8-5.3c3.6-3.6,5.5-8.2,5.5-13.9c0-5.7-1.8-10.4-5.3-14.2
c-3.6-3.8-7.8-5.6-12.8-5.6c-5,0-9.2,1.9-12.6,5.6C335.8,280.6,334.1,285.3,334.1,291z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,29 @@
<?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 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path d="M331.8,283.4c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C342.1,306.6,331.8,296.2,331.8,283.4z"/>
<path d="M277.8,350.9c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C288.1,374.2,277.8,363.8,277.8,350.9z"/>
<path d="M216.3,368.8c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C226.7,392,216.3,381.6,216.3,368.8z"/>
<path d="M169.9,308.9c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C180.3,332.1,169.9,321.7,169.9,308.9z"/>
<path d="M251.2,447.4c-4.9-3.6-8.3-9.1-9.2-15.3c-0.9-6,0.6-12.3,4.2-17.2c3.6-4.9,9.1-8.3,15.2-9.1c6-0.9,12.3,0.6,17.3,4.3
c4.9,3.6,8.3,9.1,9.1,15.2c0.9,6-0.6,12.3-4.2,17.2s-9.1,8.3-15.2,9.1C262.4,452.6,256.1,451,251.2,447.4z"/>
<path d="M67.6,246.1c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C78,269.3,67.6,258.8,67.6,246.1z"/>
<path d="M178.8,199.5c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C189.1,222.7,178.8,212.2,178.8,199.5z"/>
<path d="M250.3,293.9c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C260.7,317.1,250.3,306.6,250.3,293.9z"/>
<path d="M413,242.1c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C423.5,265.3,413,255,413,242.1z"/>
<path d="M302.1,203.7c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C312.6,226.9,302.1,216.5,302.1,203.7z"/>
<path d="M132.3,113.5c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C142.8,136.6,132.3,126.2,132.3,113.5z"/>
<path d="M366.6,136.7c0-12.8,10.4-23.2,23.2-23.2l0,0c12.8,0,23.2,10.4,23.2,23.2l0,0c0,12.8-10.4,23.2-23.2,23.2l0,0
C377.1,159.9,366.6,149.5,366.6,136.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,20 @@
<?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 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path d="M494.2,117.2c-2.2-5.3-7.8-8.4-13.5-7.3l-89.9,16.4l44.9-72.6c2.8-4.6,2.3-10.5-1.2-14.5s-9.3-5.3-14.2-3l-213.1,98
c-15.3-4.9-72.2-27.3-111.4-43.2c-0.3-0.1-0.6-0.2-0.8-0.3c0,0-0.1,0-0.1,0c-0.4-0.1-0.9-0.2-1.3-0.3c-0.1,0-0.2-0.1-0.3-0.1
c-0.5-0.1-0.9-0.2-1.4-0.2c0,0,0,0-0.1,0c-0.5,0-0.9,0.1-1.4,0.1c-0.1,0-0.1,0-0.2,0c0,0-0.1,0-0.1,0c-0.5,0-0.9,0.1-1.3,0.2
c-0.1,0-0.2,0-0.3,0.1c-0.4,0.1-0.8,0.2-1.2,0.3c-0.1,0-0.1,0-0.2,0.1c-0.4,0.1-0.8,0.3-1.2,0.5c-0.1,0-0.2,0.1-0.3,0.1
c-0.8,0.4-1.6,0.9-2.3,1.5c-0.1,0.1-0.2,0.1-0.2,0.2c-0.3,0.3-0.7,0.6-1,0.9c0,0-0.1,0.1-0.1,0.1c-0.2,0.2-0.4,0.4-0.5,0.6
c-0.1,0.1-0.2,0.2-0.3,0.4c-0.1,0.1-0.1,0.2-0.2,0.3c-0.3,0.4-0.5,0.8-0.7,1.2c0,0,0,0,0,0l-27.3,52.1l-32.7,40.1
c-3.4,4.2-3.7,10.2-0.6,14.7c2.3,3.3,6.1,5.2,10,5.2c1.3,0,2.6-0.2,3.9-0.7l50.1-17l40.6-1.9l-26.7,50.3c-2.4,4.5-1.7,9.9,1.6,13.7
c0.3,0.3,25.6,29.3,51.7,57.7c15.4,16.8,28,30.1,37.6,39.6c6.6,6.5,11.6,11.2,15.6,14.4l-16,61l-45.7,18.2
c-6.3,2.5-9.3,9.6-6.8,15.8c1.9,4.8,6.5,7.7,11.3,7.7c1.5,0,3-0.3,4.5-0.9l44.5-17.7l17.2,15.4c2.3,2.1,5.2,3.1,8.1,3.1
c3.4,0,6.7-1.4,9.1-4.1c4.5-5,4-12.7-1-17.2L212.1,431l16-60.7l75.7,89.3c2.4,2.8,5.8,4.3,9.3,4.3c1.1,0,2.1-0.1,3.2-0.4l84.6-22.8
c4.8-1.3,8.4-5.4,8.9-10.4c0.6-5-2-9.8-6.4-12.1l-136.2-71.8l44.4-91.2L489.9,132C494.6,128.7,496.4,122.6,494.2,117.2z
M294.4,234.2l-122.6-55.4l41.5-20.6c0,0,0,0,0,0l180.4-82.9L294.4,234.2z M146.4,160.8l-24.8-33.2c16.7,6.6,39.3,15.5,54,21
L146.4,160.8z M87.3,166.6l-9.6-12.3l15.1-28.9l27.4,37.3l1.7,2.3L87.3,166.6z M123.2,243.6l22.8-43.3c18.3,44.8,35.2,91,47,121
C173.7,301.1,147.7,271.5,123.2,243.6z M317.4,438l-57.5-67.8l104.6,55.1L317.4,438z M223.3,336.7c-5.5-14.1-42.6-104.1-30.8-76.4
c0.6,1.4-20.5-49.2-27.9-66.3l120.9,58.9l-47.1,95L223.3,336.7z M330.5,216.7l43-62.3l70.9-16.2L330.5,216.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.9;}
.st1{fill:#FFFFFF;}
.st2{fill:#1E1E1E;}
.st3{fill:#EAEAEA;}
.st4{opacity:0.47;}
.st5{opacity:0.47;fill:#EAEAEA;}
</style>
<g>
<g class="st0">
<path class="st1" d="M50,46c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4V4c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V46z"/>
</g>
</g>
<g class="st0">
<path class="st2" d="M50,96c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4V54c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V96z"/>
</g>
<path d="M32.7,9.4c-4.3-4.3-11.2-4.3-15.5,0c-2.1,2.1-3.2,4.8-3.2,7.7c0,2.9,1.1,5.7,3.2,7.7C19.4,27,22.2,28,25,28
c2.8,0,5.6-1.1,7.7-3.2c2.1-2.1,3.2-4.8,3.2-7.7C35.9,14.2,34.8,11.4,32.7,9.4z M18.3,10.4c1.4-1.4,3.2-2.3,5-2.6
C23,8.3,22.7,9,22.4,9.9c-0.6,2-1,4.6-1,7.3c0,0.1,0,0.3,0,0.5c0.3,0.1,0.6,0.1,0.9,0.1c0.1,0,0.2,0,0.3,0c0-0.2,0-0.4,0-0.6
c0-5.5,1.4-9.2,2.5-9.5c0,0,0,0,0.1-0.1c2.4,0,4.7,1,6.5,2.8c1.7,1.7,2.7,4,2.8,6.5c-0.2,1.1-3.9,2.5-9.5,2.5
c-5.5,0-9.1-1.4-9.4-2.4C15.6,14.5,16.6,12.2,18.3,10.4z M31.7,23.8c-1.9,1.9-4.3,2.8-6.8,2.8c-0.7-0.4-1.4-2.1-1.9-4.6l-1.2-0.1
c0.2,0.9,0.4,1.8,0.6,2.6c0.2,0.8,0.5,1.4,0.8,1.9c-1.8-0.3-3.5-1.2-4.9-2.6c-1.4-1.4-2.3-3.2-2.6-5.1c0.5,0.3,1.2,0.6,2,0.9
c2,0.6,4.6,1,7.3,1s5.3-0.3,7.3-1c0.8-0.3,1.5-0.6,2-0.9C34,20.6,33.1,22.4,31.7,23.8z"/>
<g>
<path d="M11.1,37.5c0,0-0.1-0.1-0.2-0.2c-0.1-0.1-0.2-0.1-0.4-0.2c-0.2-0.1-0.3-0.1-0.5-0.2c-0.2,0-0.4-0.1-0.6-0.1
c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.2,0.3,0.2s0.3,0.1,0.5,0.2
c0.2,0.1,0.4,0.1,0.6,0.2c0.3,0.1,0.6,0.2,0.9,0.3c0.3,0.1,0.5,0.2,0.6,0.4c0.2,0.1,0.3,0.3,0.4,0.5c0.1,0.2,0.1,0.4,0.1,0.7
c0,0.3-0.1,0.6-0.2,0.9c-0.1,0.2-0.3,0.4-0.5,0.6s-0.5,0.3-0.8,0.3c-0.3,0.1-0.6,0.1-0.9,0.1c-0.5,0-1-0.1-1.4-0.2
s-0.9-0.3-1.3-0.6l0.5-1.1c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0.1,0.3,0.2,0.5,0.3s0.4,0.2,0.6,0.2c0.2,0.1,0.5,0.1,0.7,0.1
c0.7,0,1-0.2,1-0.7c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.3-0.1-0.5-0.2c-0.2-0.1-0.4-0.1-0.7-0.2
c-0.3-0.1-0.6-0.2-0.8-0.3S7.7,39,7.6,38.9c-0.2-0.1-0.3-0.3-0.3-0.5c-0.1-0.2-0.1-0.4-0.1-0.6c0-0.3,0.1-0.6,0.2-0.9
c0.1-0.3,0.3-0.5,0.5-0.6s0.5-0.3,0.7-0.4c0.3-0.1,0.6-0.1,0.9-0.1c0.5,0,0.9,0.1,1.2,0.2c0.4,0.1,0.7,0.3,1,0.5L11.1,37.5z"/>
<path d="M13.1,42.2v-6.4h2.7c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5c0.2,0.2,0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
c0,0.3,0,0.5-0.1,0.8c-0.1,0.3-0.2,0.5-0.4,0.7c-0.2,0.2-0.4,0.4-0.6,0.5c-0.2,0.1-0.5,0.2-0.8,0.2h-1.5v2.1H13.1z M14.3,39h1.4
c0.2,0,0.4-0.1,0.6-0.3c0.2-0.2,0.2-0.4,0.2-0.8c0-0.2,0-0.3-0.1-0.4c0-0.1-0.1-0.2-0.2-0.3C16.2,37.1,16.1,37,16,37
c-0.1,0-0.2-0.1-0.3-0.1h-1.4V39z"/>
<path d="M24.3,35.8v6.4H23v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6H23v-2.6H24.3z"/>
<path d="M30.3,41.1v1.1h-4.4v-6.4h4.4v1.1h-3.1v1.5h2.7v1h-2.7v1.7H30.3z"/>
<path d="M31.5,42.2v-6.4h2.8c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5c0.2,0.2,0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
c0,0.4-0.1,0.8-0.3,1.1c-0.2,0.3-0.5,0.6-0.8,0.7l1.5,2.4h-1.4L34,40.1h-1.2v2.1H31.5z M32.7,39h1.6c0.1,0,0.2,0,0.3-0.1
c0.1-0.1,0.2-0.1,0.3-0.2c0.1-0.1,0.1-0.2,0.2-0.3s0.1-0.3,0.1-0.4c0-0.1,0-0.3-0.1-0.4s-0.1-0.2-0.2-0.3c-0.1-0.1-0.2-0.2-0.3-0.2
c-0.1-0.1-0.2-0.1-0.3-0.1h-1.5V39z"/>
<path d="M42.2,41.1v1.1h-4.4v-6.4h4.4v1.1H39v1.5h2.7v1H39v1.7H42.2z"/>
</g>
<path class="st3" d="M33.1,59.4c-4.3-4.3-11.2-4.3-15.5,0c-2.1,2.1-3.2,4.8-3.2,7.7c0,2.9,1.1,5.7,3.2,7.7c2.1,2.1,4.9,3.2,7.7,3.2
c2.8,0,5.6-1.1,7.7-3.2c2.1-2.1,3.2-4.8,3.2-7.7C36.3,64.2,35.1,61.5,33.1,59.4z M18.6,60.4c1.4-1.4,3.2-2.3,5-2.6
c-0.3,0.5-0.7,1.2-0.9,2.1c-0.6,2-1,4.6-1,7.3c0,0.1,0,0.3,0,0.5c0.3,0.1,0.6,0.1,0.9,0.1c0.1,0,0.2,0,0.3,0c0-0.2,0-0.4,0-0.6
c0-5.5,1.4-9.2,2.5-9.5c0,0,0,0,0.1-0.1c2.4,0,4.7,1,6.5,2.8c1.7,1.7,2.7,4,2.8,6.5c-0.2,1.1-3.9,2.5-9.5,2.5
c-5.5,0-9.1-1.4-9.4-2.4C15.9,64.5,16.9,62.2,18.6,60.4z M32,73.8c-1.9,1.9-4.3,2.8-6.8,2.8c-0.7-0.4-1.4-2.1-1.9-4.6l-1.2-0.1
c0.2,0.9,0.4,1.8,0.6,2.6c0.2,0.8,0.5,1.4,0.8,1.9c-1.8-0.3-3.5-1.2-4.9-2.6c-1.4-1.4-2.3-3.2-2.6-5.1c0.5,0.3,1.2,0.6,2,0.9
c2,0.6,4.6,1,7.3,1s5.3-0.3,7.3-1c0.8-0.3,1.5-0.6,2-0.9C34.3,70.7,33.4,72.4,32,73.8z"/>
<g>
<path class="st3" d="M11.5,87.5c0,0-0.1-0.1-0.2-0.2c-0.1-0.1-0.2-0.1-0.4-0.2S10.5,87,10.3,87c-0.2,0-0.4-0.1-0.6-0.1
c-0.3,0-0.6,0.1-0.8,0.2s-0.3,0.3-0.3,0.5c0,0.1,0,0.2,0.1,0.3C8.9,88,9,88.1,9.1,88.2c0.1,0.1,0.3,0.1,0.5,0.2
c0.2,0.1,0.4,0.1,0.6,0.2c0.3,0.1,0.6,0.2,0.9,0.3s0.5,0.2,0.6,0.4c0.2,0.1,0.3,0.3,0.4,0.5c0.1,0.2,0.1,0.4,0.1,0.7
c0,0.3-0.1,0.6-0.2,0.9c-0.1,0.2-0.3,0.4-0.5,0.6c-0.2,0.2-0.5,0.3-0.8,0.3c-0.3,0.1-0.6,0.1-0.9,0.1c-0.5,0-1-0.1-1.4-0.2
C8,92,7.6,91.8,7.2,91.5l0.5-1.1c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0.1,0.3,0.2,0.5,0.3s0.4,0.2,0.6,0.2c0.2,0.1,0.5,0.1,0.7,0.1
c0.7,0,1-0.2,1-0.7c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.3-0.1-0.5-0.2c-0.2-0.1-0.4-0.1-0.7-0.2
c-0.3-0.1-0.6-0.2-0.8-0.3c-0.2-0.1-0.4-0.2-0.6-0.3s-0.3-0.3-0.3-0.5c-0.1-0.2-0.1-0.4-0.1-0.6c0-0.3,0.1-0.6,0.2-0.9
c0.1-0.3,0.3-0.5,0.5-0.6s0.5-0.3,0.7-0.4s0.6-0.1,0.9-0.1c0.5,0,0.9,0.1,1.2,0.2s0.7,0.3,1,0.5L11.5,87.5z"/>
<path class="st3" d="M13.4,92.2v-6.4h2.7c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5s0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
c0,0.3,0,0.5-0.1,0.8c-0.1,0.3-0.2,0.5-0.4,0.7c-0.2,0.2-0.4,0.4-0.6,0.5c-0.2,0.1-0.5,0.2-0.8,0.2h-1.5v2.1H13.4z M14.7,89h1.4
c0.2,0,0.4-0.1,0.6-0.3c0.2-0.2,0.2-0.4,0.2-0.8c0-0.2,0-0.3-0.1-0.4c0-0.1-0.1-0.2-0.2-0.3s-0.2-0.2-0.3-0.2
c-0.1,0-0.2-0.1-0.3-0.1h-1.4V89z"/>
<path class="st3" d="M24.6,85.9v6.4h-1.2v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6h2.9v-2.6H24.6z"/>
<path class="st3" d="M30.6,91.2v1.1h-4.4v-6.4h4.4v1.1h-3.1v1.5h2.7v1h-2.7v1.7H30.6z"/>
<path class="st3" d="M31.8,92.2v-6.4h2.8c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5c0.2,0.2,0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
c0,0.4-0.1,0.8-0.3,1.1s-0.5,0.6-0.8,0.7l1.5,2.4h-1.4l-1.3-2.1h-1.2v2.1H31.8z M33.1,89h1.6c0.1,0,0.2,0,0.3-0.1
c0.1-0.1,0.2-0.1,0.3-0.2c0.1-0.1,0.1-0.2,0.2-0.3s0.1-0.3,0.1-0.4c0-0.1,0-0.3-0.1-0.4s-0.1-0.2-0.2-0.3S35,87.1,34.9,87
c-0.1-0.1-0.2-0.1-0.3-0.1h-1.5V89z"/>
<path class="st3" d="M42.5,91.2v1.1h-4.4v-6.4h4.4v1.1h-3.1v1.5H42v1h-2.7v1.7H42.5z"/>
</g>
<g class="st4">
<path class="st2" d="M50,146c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V146z"/>
</g>
<path class="st5" d="M33.1,109.4c-4.3-4.3-11.2-4.3-15.5,0c-2.1,2.1-3.2,4.8-3.2,7.7c0,2.9,1.1,5.7,3.2,7.7c2.1,2.1,4.9,3.2,7.7,3.2
c2.8,0,5.6-1.1,7.7-3.2c2.1-2.1,3.2-4.8,3.2-7.7C36.3,114.2,35.1,111.5,33.1,109.4z M18.6,110.4c1.4-1.4,3.2-2.3,5-2.6
c-0.3,0.5-0.7,1.2-0.9,2.1c-0.6,2-1,4.6-1,7.3c0,0.1,0,0.3,0,0.5c0.3,0.1,0.6,0.1,0.9,0.1c0.1,0,0.2,0,0.3,0c0-0.2,0-0.4,0-0.6
c0-5.5,1.4-9.2,2.5-9.5c0,0,0,0,0.1-0.1c2.4,0,4.7,1,6.5,2.8c1.7,1.7,2.7,4,2.8,6.5c-0.2,1.1-3.9,2.5-9.5,2.5
c-5.5,0-9.1-1.4-9.4-2.4C15.9,114.5,16.9,112.2,18.6,110.4z M32,123.8c-1.9,1.9-4.3,2.8-6.8,2.8c-0.7-0.4-1.4-2.1-1.9-4.6l-1.2-0.1
c0.2,0.9,0.4,1.8,0.6,2.6c0.2,0.8,0.5,1.4,0.8,1.9c-1.8-0.3-3.5-1.2-4.9-2.6c-1.4-1.4-2.3-3.2-2.6-5.1c0.5,0.3,1.2,0.6,2,0.9
c2,0.6,4.6,1,7.3,1s5.3-0.3,7.3-1c0.8-0.3,1.5-0.6,2-0.9C34.3,120.7,33.4,122.4,32,123.8z"/>
<g class="st4">
<path class="st3" d="M11.5,137.5c0,0-0.1-0.1-0.2-0.2c-0.1-0.1-0.2-0.1-0.4-0.2s-0.3-0.1-0.5-0.2c-0.2,0-0.4-0.1-0.6-0.1
c-0.3,0-0.6,0.1-0.8,0.2s-0.3,0.3-0.3,0.5c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.2,0.3,0.2c0.1,0.1,0.3,0.1,0.5,0.2
c0.2,0.1,0.4,0.1,0.6,0.2c0.3,0.1,0.6,0.2,0.9,0.3s0.5,0.2,0.6,0.4c0.2,0.1,0.3,0.3,0.4,0.5c0.1,0.2,0.1,0.4,0.1,0.7
c0,0.3-0.1,0.6-0.2,0.9c-0.1,0.2-0.3,0.4-0.5,0.6c-0.2,0.2-0.5,0.3-0.8,0.3c-0.3,0.1-0.6,0.1-0.9,0.1c-0.5,0-1-0.1-1.4-0.2
c-0.5-0.1-0.9-0.3-1.3-0.6l0.5-1.1c0.1,0.1,0.2,0.1,0.3,0.2c0.1,0.1,0.3,0.2,0.5,0.3s0.4,0.2,0.6,0.2c0.2,0.1,0.5,0.1,0.7,0.1
c0.7,0,1-0.2,1-0.7c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.3-0.1-0.5-0.2c-0.2-0.1-0.4-0.1-0.7-0.2
c-0.3-0.1-0.6-0.2-0.8-0.3c-0.2-0.1-0.4-0.2-0.6-0.3s-0.3-0.3-0.3-0.5c-0.1-0.2-0.1-0.4-0.1-0.6c0-0.3,0.1-0.6,0.2-0.9
c0.1-0.3,0.3-0.5,0.5-0.6s0.5-0.3,0.7-0.4s0.6-0.1,0.9-0.1c0.5,0,0.9,0.1,1.2,0.2s0.7,0.3,1,0.5L11.5,137.5z"/>
<path class="st3" d="M13.4,142.2v-6.4h2.7c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5s0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
c0,0.3,0,0.5-0.1,0.8c-0.1,0.3-0.2,0.5-0.4,0.7c-0.2,0.2-0.4,0.4-0.6,0.5c-0.2,0.1-0.5,0.2-0.8,0.2h-1.5v2.1H13.4z M14.7,139h1.4
c0.2,0,0.4-0.1,0.6-0.3c0.2-0.2,0.2-0.4,0.2-0.8c0-0.2,0-0.3-0.1-0.4c0-0.1-0.1-0.2-0.2-0.3s-0.2-0.2-0.3-0.2
c-0.1,0-0.2-0.1-0.3-0.1h-1.4V139z"/>
<path class="st3" d="M24.6,135.9v6.4h-1.2v-2.7h-2.9v2.7h-1.2v-6.4h1.2v2.6h2.9v-2.6H24.6z"/>
<path class="st3" d="M30.6,141.2v1.1h-4.4v-6.4h4.4v1.1h-3.1v1.5h2.7v1h-2.7v1.7H30.6z"/>
<path class="st3" d="M31.8,142.2v-6.4h2.8c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5c0.2,0.2,0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
c0,0.4-0.1,0.8-0.3,1.1s-0.5,0.6-0.8,0.7l1.5,2.4h-1.4l-1.3-2.1h-1.2v2.1H31.8z M33.1,139h1.6c0.1,0,0.2,0,0.3-0.1
c0.1-0.1,0.2-0.1,0.3-0.2c0.1-0.1,0.1-0.2,0.2-0.3s0.1-0.3,0.1-0.4c0-0.1,0-0.3-0.1-0.4s-0.1-0.2-0.2-0.3s-0.2-0.2-0.3-0.2
c-0.1-0.1-0.2-0.1-0.3-0.1h-1.5V139z"/>
<path class="st3" d="M42.5,141.2v1.1h-4.4v-6.4h4.4v1.1h-3.1v1.5H42v1h-2.7v1.7H42.5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.1 KiB

View file

@ -15,7 +15,7 @@ import HFWebEngineProfile 1.0
WebEngineView {
id: root
profile: desktop.browserProfile
// profile: desktop.browserProfile
Component.onCompleted: {
console.log("Connecting JS messaging to Hifi Logging")

View file

@ -14,7 +14,6 @@ import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
import "." as VrControls
FocusScope {
id: root
@ -119,14 +118,14 @@ FocusScope {
}
function showList() {
var r = 20//desktop.mapFromItem(root, 0, 0, root.width, root.height);
var y = 200;
var bottom = 0 + scrollView.height;
var r = mapFromItem(root, 0, 0, root.width, root.height);
var y = r.y + r.height;
var bottom = y + scrollView.height;
if (bottom > 720) {
y -= bottom - 720 + 8;
y -= bottom - tabletRoot.height + 8;
}
scrollView.x = 0;
scrollView.y = 0;
scrollView.x = r.x;
scrollView.y = y;
popup.visible = true;
popup.forceActiveFocus();
listView.currentIndex = root.currentIndex;
@ -141,6 +140,7 @@ FocusScope {
FocusScope {
id: popup
z: 12
parent: parent
anchors.fill: parent
visible: false

View file

@ -0,0 +1,339 @@
//
// TabletCustomQueryDialog.qml
//
// Created by Vlad Stelmahovsky on 3/27/17
// 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import "../controls-uit" as ControlsUIT
import "../styles-uit"
import "../windows"
TabletModalWindow {
id: root;
HifiConstants { id: hifi; }
y: hifi.dimensions.tabletMenuHeader
title: ""
visible: true;
property bool keyboardOverride: true
signal selected(var result);
signal canceled();
property int icon: hifi.icons.none;
property string iconText: "";
property int iconSize: 35;
onIconChanged: updateIcon();
property var textInput;
property var comboBox;
property var checkBox;
onTextInputChanged: {
if (textInput && textInput.text !== undefined) {
textField.text = textInput.text;
}
}
onComboBoxChanged: {
if (comboBox && comboBox.index !== undefined) {
comboBoxField.currentIndex = comboBox.index;
}
}
onCheckBoxChanged: {
if (checkBox && checkBox.checked !== undefined) {
checkBoxField.checked = checkBox.checked;
}
}
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
onKeyboardRaisedChanged: d.resize();
property var warning: "";
property var result;
property var implicitCheckState: null;
property int titleWidth: 0;
onTitleWidthChanged: d.resize();
MouseArea {
width: parent.width
height: parent.height
}
function updateIcon() {
if (!root) {
return;
}
iconText = hifi.glyphForIcon(root.icon);
}
function updateCheckbox() {
if (checkBox.disableForItems) {
var currentItemInDisableList = false;
for (var i in checkBox.disableForItems) {
if (comboBoxField.currentIndex === checkBox.disableForItems[i]) {
currentItemInDisableList = true;
break;
}
}
if (currentItemInDisableList) {
checkBoxField.enabled = false;
if (checkBox.checkStateOnDisable !== null && checkBox.checkStateOnDisable !== undefined) {
root.implicitCheckState = checkBoxField.checked;
checkBoxField.checked = checkBox.checkStateOnDisable;
}
root.warning = checkBox.warningOnDisable;
} else {
checkBoxField.enabled = true;
if (root.implicitCheckState !== null) {
checkBoxField.checked = root.implicitCheckState;
root.implicitCheckState = null;
}
root.warning = "";
}
}
}
TabletModalFrame {
id: modalWindowItem
width: parent.width - 12
height: 240
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
QtObject {
id: d;
readonly property int minWidth: 470
readonly property int maxWidth: 470
readonly property int minHeight: 240
readonly property int maxHeight: 720
function resize() {
var targetWidth = Math.max(titleWidth, 470);
var targetHeight = (textField.visible ? textField.controlHeight + hifi.dimensions.contentSpacing.y : 0) +
(extraInputs.visible ? extraInputs.height + hifi.dimensions.contentSpacing.y : 0) +
(buttons.height + 3 * hifi.dimensions.contentSpacing.y) +
((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + hifi.dimensions.contentSpacing.y) : 0);
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
root.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ?
d.maxHeight : targetHeight);
if (checkBoxField.visible && comboBoxField.visible) {
checkBoxField.width = extraInputs.width / 2;
comboBoxField.width = extraInputs.width / 2;
} else if (!checkBoxField.visible && comboBoxField.visible) {
comboBoxField.width = extraInputs.width;
}
}
}
// Item {
// anchors {
// // top: parent.top;
// // bottom: extraInputs.visible ? extraInputs.top : buttons.top;
// left: parent.left;
// right: parent.right;
// topMargin: 20
// }
// FIXME make a text field type that can be bound to a history for autocompletion
ControlsUIT.TextField {
id: textField;
label: root.textInput.label;
focus: root.textInput ? true : false;
visible: root.textInput ? true : false;
anchors {
top: parent.top
left: parent.left;
right: parent.right;
leftMargin: 5; rightMargin: 5;
topMargin: textField.controlHeight - textField.height + 5
}
}
ControlsUIT.Keyboard {
id: keyboard
raised: keyboardEnabled && keyboardRaised
numeric: punctuationMode
anchors {
left: parent.left
right: parent.right
leftMargin: 5; rightMargin: 5;
top: textField.bottom
topMargin: raised ? hifi.dimensions.contentSpacing.y : 0
}
}
// }
Row {
id: extraInputs;
visible: Boolean(root.checkBox || root.comboBox);
anchors {
left: parent.left;
right: parent.right;
leftMargin: 5; rightMargin: 5;
top: keyboard.bottom;
topMargin: hifi.dimensions.contentSpacing.y + 20;
}
height: comboBoxField.controlHeight;
onHeightChanged: d.resize();
onWidthChanged: d.resize();
ControlsUIT.CheckBox {
id: checkBoxField;
text: root.checkBox.label;
focus: Boolean(root.checkBox);
visible: Boolean(root.checkBox);
// anchors {
// left: parent.left;
// bottom: parent.bottom;
// leftMargin: 6; // Magic number to align with warning icon
// bottomMargin: 6;
// }
}
ControlsUIT.TabletComboBox {
id: comboBoxField;
label: root.comboBox.label;
focus: Boolean(root.comboBox);
visible: Boolean(root.comboBox);
// anchors {
// right: parent.right;
// bottom: parent.bottom;
// }
model: root.comboBox ? root.comboBox.items : [];
onAccepted: {
updateCheckbox();
focus = true;
}
}
}
Row {
id: buttons;
focus: true;
spacing: hifi.dimensions.contentSpacing.x;
layoutDirection: Qt.RightToLeft;
onHeightChanged: d.resize();
onWidthChanged: {
d.resize();
resizeWarningText();
}
anchors {
bottom: parent.bottom;
left: parent.left;
right: parent.right;
bottomMargin: hifi.dimensions.contentSpacing.y;
leftMargin: 5; rightMargin: 5;
}
function resizeWarningText() {
var rowWidth = buttons.width;
var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2;
var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x;
warningText.width = rowWidth - buttonsWidth - warningIconWidth;
}
ControlsUIT.Button {
id: cancelButton;
action: cancelAction;
}
ControlsUIT.Button {
id: acceptButton;
action: acceptAction;
}
Text {
id: warningText;
visible: Boolean(root.warning);
text: root.warning;
wrapMode: Text.WordWrap;
font.italic: true;
maximumLineCount: 2;
}
HiFiGlyphs {
id: warningIcon;
visible: Boolean(root.warning);
text: hifi.glyphs.alert;
size: hifi.dimensions.controlLineHeight;
}
}
// }//column
Action {
id: cancelAction;
text: qsTr("Cancel");
shortcut: Qt.Key_Escape;
onTriggered: {
root.result = null;
root.canceled();
root.destroy();
}
}
Action {
id: acceptAction;
text: qsTr("Add");
shortcut: Qt.Key_Return;
onTriggered: {
var result = {};
if (textInput) {
result.textInput = textField.text;
}
if (comboBox) {
result.comboBox = comboBoxField.currentIndex;
result.comboBoxText = comboBoxField.currentText;
}
if (checkBox) {
result.checkBox = checkBoxField.enabled ? checkBoxField.checked : null;
}
root.result = JSON.stringify(result);
root.selected(root.result);
root.destroy();
}
}
}
Keys.onPressed: {
if (!visible) {
return;
}
switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
cancelAction.trigger();
event.accepted = true;
break;
case Qt.Key_Return:
case Qt.Key_Enter:
acceptAction.trigger();
event.accepted = true;
break;
}
}
Component.onCompleted: {
keyboardEnabled = HMD.active;
updateIcon();
updateCheckbox();
d.resize();
textField.forceActiveFocus();
}
}

View file

@ -0,0 +1,782 @@
//
// FileDialog.qml
//
// Created by Dante Ruiz on 23 Feb 2017
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import Qt.labs.folderlistmodel 2.1
import Qt.labs.settings 1.0
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import ".."
import "../controls-uit"
import "../styles-uit"
import "../windows"
import "fileDialog"
//FIXME implement shortcuts for favorite location
TabletModalWindow {
id: root
anchors.fill: parent
width: parent.width
height: parent.height
HifiConstants { id: hifi }
Settings {
category: "FileDialog"
property alias width: root.width
property alias height: root.height
property alias x: root.x
property alias y: root.y
}
// Set from OffscreenUi::getOpenFile()
property alias caption: root.title;
// Set from OffscreenUi::getOpenFile()
property alias dir: fileTableModel.folder;
// Set from OffscreenUi::getOpenFile()
property alias filter: selectionType.filtersString;
// Set from OffscreenUi::getOpenFile()
property int options; // <-- FIXME unused
property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : ""
property int iconSize: 40
property bool selectDirectory: false;
property bool showHidden: false;
// FIXME implement
property bool multiSelect: false;
property bool saveDialog: false;
property var helper: fileDialogHelper
property alias model: fileTableView.model
property var drives: helper.drives()
property int titleWidth: 0
signal selectedFile(var file);
signal canceled();
Component.onCompleted: {
fileDialogItem.keyboardEnabled = HMD.active;
// HACK: The following lines force the model to initialize properly such that the go-up button
// works properly from the initial screen.
var initialFolder = folderListModel.folder;
fileTableModel.folder = helper.pathToUrl(drives[0]);
fileTableModel.folder = initialFolder;
iconText = root.title !== "" ? hifi.glyphs.scriptUpload : "";
// Clear selection when click on external frame.
//frameClicked.connect(function() { d.clearSelection(); });
if (selectDirectory) {
currentSelection.text = d.capitalizeDrive(helper.urlToPath(initialFolder));
d.currentSelectionIsFolder = true;
d.currentSelectionUrl = initialFolder;
}
helper.contentsChanged.connect(function() {
if (folderListModel) {
// Make folderListModel refresh.
var save = folderListModel.folder;
folderListModel.folder = "";
folderListModel.folder = save;
}
});
fileTableView.forceActiveFocus();
}
TabletModalFrame {
id: fileDialogItem
width: parent.width - 6
height: parent.height - 6
anchors {
horizontalCenter: root.horizontalCenter
verticalCenter: root.verticalCenter
}
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
MouseArea {
// Clear selection when click on internal unused area.
anchors.fill: parent
onClicked: {
d.clearSelection();
}
}
Row {
id: navControls
anchors {
top: parent.top
topMargin: (fileDialogItem.hasTitle ? (fileDialogItem.frameMarginTop + hifi.dimensions.modalDialogMargin.y) : hifi.dimension.modalDialogMargin.y)
left: parent.left
leftMargin: hifi.dimensions.contentSpacing.x
}
spacing: hifi.dimensions.contentSpacing.x
GlyphButton {
id: upButton
glyph: hifi.glyphs.levelUp
width: height
size: 30
enabled: fileTableModel.parentFolder && fileTableModel.parentFolder !== ""
onClicked: d.navigateUp();
}
GlyphButton {
id: homeButton
property var destination: helper.home();
glyph: hifi.glyphs.home
size: 28
width: height
enabled: d.homeDestination ? true : false
onClicked: d.navigateHome();
}
}
TabletComboBox {
id: pathSelector
z: 10
anchors {
top: parent.top
topMargin: (fileDialogItem.hasTitle ? (fileDialogItem.frameMarginTop + hifi.dimensions.modalDialogMargin.y) : hifi.dimension.modalDialogMargin.y)
left: navControls.right
leftMargin: hifi.dimensions.contentSpacing.x
right: parent.right
}
property var lastValidFolder: helper.urlToPath(fileTableModel.folder)
function calculatePathChoices(folder) {
var folders = folder.split("/"),
choices = [],
i, length;
if (folders[folders.length - 1] === "") {
folders.pop();
}
choices.push(folders[0]);
for (i = 1, length = folders.length; i < length; i++) {
choices.push(choices[i - 1] + "/" + folders[i]);
}
if (folders[0] === "") {
// Special handling for OSX root dir.
choices[0] = "/";
}
choices.reverse();
if (drives && drives.length > 1) {
choices.push("This PC");
}
if (choices.length > 0) {
pathSelector.model = choices;
}
}
onLastValidFolderChanged: {
var folder = d.capitalizeDrive(lastValidFolder);
calculatePathChoices(folder);
}
onCurrentTextChanged: {
var folder = currentText;
if (/^[a-zA-z]:$/.test(folder)) {
folder = "file:///" + folder + "/";
} else if (folder === "This PC") {
folder = "file:///";
} else {
folder = helper.pathToUrl(folder);
}
if (helper.urlToPath(folder).toLowerCase() !== helper.urlToPath(fileTableModel.folder).toLowerCase()) {
if (root.selectDirectory) {
currentSelection.text = currentText !== "This PC" ? currentText : "";
d.currentSelectionUrl = helper.pathToUrl(currentText);
}
fileTableModel.folder = folder;
fileTableView.forceActiveFocus();
}
}
}
QtObject {
id: d
property var currentSelectionUrl;
readonly property string currentSelectionPath: helper.urlToPath(currentSelectionUrl);
property bool currentSelectionIsFolder;
property var backStack: []
property var tableViewConnection: Connections { target: fileTableView; onCurrentRowChanged: d.update(); }
property var modelConnection: Connections { target: fileTableModel; onFolderChanged: d.update(); }
property var homeDestination: helper.home();
function capitalizeDrive(path) {
// Consistently capitalize drive letter for Windows.
if (/[a-zA-Z]:/.test(path)) {
return path.charAt(0).toUpperCase() + path.slice(1);
}
return path;
}
function update() {
var row = fileTableView.currentRow;
if (row === -1) {
if (!root.selectDirectory) {
currentSelection.text = "";
currentSelectionIsFolder = false;
}
return;
}
currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
currentSelectionIsFolder = fileTableView.model.isFolder(row);
if (root.selectDirectory || !currentSelectionIsFolder) {
currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
} else {
currentSelection.text = "";
}
}
function navigateUp() {
if (fileTableModel.parentFolder && fileTableModel.parentFolder !== "") {
fileTableModel.folder = fileTableModel.parentFolder;
return true;
}
}
function navigateHome() {
fileTableModel.folder = homeDestination;
return true;
}
function clearSelection() {
fileTableView.selection.clear();
fileTableView.currentRow = -1;
update();
}
}
FolderListModel {
id: folderListModel
nameFilters: selectionType.currentFilter
showDirsFirst: true
showDotAndDotDot: false
showFiles: !root.selectDirectory
Component.onCompleted: {
showFiles = !root.selectDirectory
}
onFolderChanged: {
fileTableModel.update(); // Update once the data from the folder change is available.
}
function getItem(index, field) {
return get(index, field);
}
}
ListModel {
// Emulates FolderListModel but contains drive data.
id: driveListModel
property int count: 1
Component.onCompleted: initialize();
function initialize() {
var drive,
i;
count = drives.length;
for (i = 0; i < count; i++) {
drive = drives[i].slice(0, -1); // Remove trailing "/".
append({
fileName: drive,
fileModified: new Date(0),
fileSize: 0,
filePath: drive + "/",
fileIsDir: true,
fileNameSort: drive.toLowerCase()
});
}
}
function getItem(index, field) {
return get(index)[field];
}
}
ListModel {
id: fileTableModel
// FolderListModel has a couple of problems:
// 1) Files and directories sort case-sensitively: https://bugreports.qt.io/browse/QTBUG-48757
// 2) Cannot browse up to the "computer" level to view Windows drives: https://bugreports.qt.io/browse/QTBUG-42901
//
// To solve these problems an intermediary ListModel is used that implements proper sorting and can be populated with
// drive information when viewing at the computer level.
property var folder
property int sortOrder: Qt.AscendingOrder
property int sortColumn: 0
property var model: folderListModel
property string parentFolder: calculateParentFolder();
readonly property string rootFolder: "file:///"
function calculateParentFolder() {
if (model === folderListModel) {
if (folderListModel.parentFolder.toString() === "" && driveListModel.count > 1) {
return rootFolder;
} else {
return folderListModel.parentFolder;
}
} else {
return "";
}
}
onFolderChanged: {
if (folder === rootFolder) {
model = driveListModel;
helper.monitorDirectory("");
update();
} else {
var needsUpdate = model === driveListModel && folder === folderListModel.folder;
model = folderListModel;
folderListModel.folder = folder;
helper.monitorDirectory(helper.urlToPath(folder));
if (needsUpdate) {
update();
}
}
}
function isFolder(row) {
if (row === -1) {
return false;
}
return get(row).fileIsDir;
}
function update() {
var dataFields = ["fileName", "fileModified", "fileSize"],
sortFields = ["fileNameSort", "fileModified", "fileSize"],
dataField = dataFields[sortColumn],
sortField = sortFields[sortColumn],
sortValue,
fileName,
fileIsDir,
comparisonFunction,
lower,
middle,
upper,
rows = 0,
i;
clear();
comparisonFunction = sortOrder === Qt.AscendingOrder
? function(a, b) { return a < b; }
: function(a, b) { return a > b; }
for (i = 0; i < model.count; i++) {
fileName = model.getItem(i, "fileName");
fileIsDir = model.getItem(i, "fileIsDir");
sortValue = model.getItem(i, dataField);
if (dataField === "fileName") {
// Directories first by prefixing a "*".
// Case-insensitive.
sortValue = (fileIsDir ? "*" : "") + sortValue.toLowerCase();
}
lower = 0;
upper = rows;
while (lower < upper) {
middle = Math.floor((lower + upper) / 2);
var lessThan;
if (comparisonFunction(sortValue, get(middle)[sortField])) {
lessThan = true;
upper = middle;
} else {
lessThan = false;
lower = middle + 1;
}
}
insert(lower, {
fileName: fileName,
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
fileSize: model.getItem(i, "fileSize"),
filePath: model.getItem(i, "filePath"),
fileIsDir: fileIsDir,
fileNameSort: (fileIsDir ? "*" : "") + fileName.toLowerCase()
});
rows++;
}
d.clearSelection();
}
}
Table {
id: fileTableView
colorScheme: hifi.colorSchemes.light
anchors {
top: navControls.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: parent.left
right: parent.right
bottom: currentSelection.top
bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height
}
headerVisible: !selectDirectory
onClicked: navigateToRow(row);
onDoubleClicked: navigateToRow(row);
focus: true
Keys.onReturnPressed: navigateToCurrentRow();
Keys.onEnterPressed: navigateToCurrentRow();
sortIndicatorColumn: 0
sortIndicatorOrder: Qt.AscendingOrder
sortIndicatorVisible: true
model: fileTableModel
function updateSort() {
model.sortOrder = sortIndicatorOrder;
model.sortColumn = sortIndicatorColumn;
model.update();
}
onSortIndicatorColumnChanged: { updateSort(); }
onSortIndicatorOrderChanged: { updateSort(); }
itemDelegate: Item {
clip: true
//FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
//FontLoader { id: firaSansRegular; source: "../../fonts/FiraSans-Regular.ttf"; }
FiraSansSemiBold {
text: getText();
elide: styleData.elideMode
anchors {
left: parent.left
leftMargin: hifi.dimensions.tablePadding
right: parent.right
rightMargin: hifi.dimensions.tablePadding
verticalCenter: parent.verticalCenter
}
size: hifi.fontSizes.tableText
color: hifi.colors.baseGrayHighlight
//font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir)
//? firaSansSemiBold.name : firaSansRegular.name
function getText() {
if (styleData.row === -1) {
return styleData.value;
}
switch (styleData.column) {
case 1: return fileTableView.model.get(styleData.row).fileIsDir ? "" : styleData.value;
case 2: return fileTableView.model.get(styleData.row).fileIsDir ? "" : formatSize(styleData.value);
default: return styleData.value;
}
}
function formatSize(size) {
var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ];
var suffixIndex = 0
while ((size / 1024.0) > 1.1) {
size /= 1024.0;
++suffixIndex;
}
size = Math.round(size*1000)/1000;
size = size.toLocaleString()
return size + " " + suffixes[suffixIndex];
}
}
}
TableViewColumn {
id: fileNameColumn
role: "fileName"
title: "Name"
width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width
movable: false
resizable: true
}
TableViewColumn {
id: fileMofifiedColumn
role: "fileModified"
title: "Date"
width: 0.3 * fileTableView.width
movable: false
resizable: true
visible: !selectDirectory
}
TableViewColumn {
role: "fileSize"
title: "Size"
width: fileTableView.width - fileNameColumn.width - fileMofifiedColumn.width
movable: false
resizable: true
visible: !selectDirectory
}
function navigateToRow(row) {
currentRow = row;
navigateToCurrentRow();
}
function navigateToCurrentRow() {
var row = fileTableView.currentRow
var isFolder = model.isFolder(row);
var file = model.get(row).filePath;
if (isFolder) {
fileTableView.model.folder = helper.pathToUrl(file);
} else {
okAction.trigger();
}
}
property string prefix: ""
function addToPrefix(event) {
if (!event.text || event.text === "") {
return false;
}
var newPrefix = prefix + event.text.toLowerCase();
var matchedIndex = -1;
for (var i = 0; i < model.count; ++i) {
var name = model.get(i).fileName.toLowerCase();
if (0 === name.indexOf(newPrefix)) {
matchedIndex = i;
break;
}
}
if (matchedIndex !== -1) {
fileTableView.selection.clear();
fileTableView.selection.select(matchedIndex);
fileTableView.currentRow = matchedIndex;
fileTableView.prefix = newPrefix;
}
prefixClearTimer.restart();
return true;
}
Timer {
id: prefixClearTimer
interval: 1000
repeat: false
running: false
onTriggered: fileTableView.prefix = "";
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Backspace:
case Qt.Key_Tab:
case Qt.Key_Backtab:
event.accepted = false;
break;
default:
if (addToPrefix(event)) {
event.accepted = true
} else {
event.accepted = false;
}
break;
}
}
}
TextField {
id: currentSelection
label: selectDirectory ? "Directory:" : "File name:"
anchors {
left: parent.left
right: selectionType.visible ? selectionType.left: parent.right
rightMargin: hifi.dimensions.contentSpacing.x
leftMargin: hifi.dimensions.contentSpacing.x
bottom: keyboard.top
bottomMargin: hifi.dimensions.contentSpacing.y
}
readOnly: !root.saveDialog
activeFocusOnTab: !readOnly
onActiveFocusChanged: if (activeFocus) { selectAll(); }
onAccepted: okAction.trigger();
}
FileTypeSelection {
id: selectionType
anchors {
top: currentSelection.top
left: buttonRow.left
right: parent.right
}
visible: !selectDirectory && filtersCount > 1
KeyNavigation.left: fileTableView
KeyNavigation.right: openButton
}
Keyboard {
id: keyboard
raised: parent.keyboardEnabled && parent.keyboardRaised
numeric: parent.punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: buttonRow.top
bottomMargin: visible ? hifi.dimensions.contentSpacing.y : 0
}
}
Row {
id: buttonRow
anchors {
right: parent.right
bottom: parent.bottom
}
spacing: hifi.dimensions.contentSpacing.y
Button {
id: openButton
color: hifi.buttons.blue
action: okAction
Keys.onReturnPressed: okAction.trigger()
KeyNavigation.up: selectionType
KeyNavigation.left: selectionType
KeyNavigation.right: cancelButton
}
Button {
id: cancelButton
action: cancelAction
KeyNavigation.up: selectionType
KeyNavigation.left: openButton
KeyNavigation.right: fileTableView.contentItem
Keys.onReturnPressed: { canceled(); root.enabled = false }
}
}
Action {
id: okAction
text: currentSelection.text ? (root.selectDirectory && fileTableView.currentRow === -1 ? "Choose" : (root.saveDialog ? "Save" : "Open")) : "Open"
enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
onTriggered: {
if (!root.selectDirectory && !d.currentSelectionIsFolder
|| root.selectDirectory && fileTableView.currentRow === -1) {
okActionTimer.start();
} else {
fileTableView.navigateToCurrentRow();
}
}
}
Timer {
id: okActionTimer
interval: 50
running: false
repeat: false
onTriggered: {
if (!root.saveDialog) {
selectedFile(d.currentSelectionUrl);
root.destroy();
return;
}
// Handle the ambiguity between different cases
// * typed name (with or without extension)
// * full path vs relative vs filename only
var selection = helper.saveHelper(currentSelection.text, root.dir, selectionType.currentFilter);
if (!selection) {
desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Warning, text: "Unable to parse selection" })
return;
}
if (helper.urlIsDir(selection)) {
root.dir = selection;
currentSelection.text = "";
return;
}
// Check if the file is a valid target
if (!helper.urlIsWritable(selection)) {
desktop.messageBox({
icon: OriginalDialogs.StandardIcon.Warning,
text: "Unable to write to location " + selection
})
return;
}
if (helper.urlExists(selection)) {
var messageBox = desktop.messageBox({
icon: OriginalDialogs.StandardIcon.Question,
buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
text: "Do you wish to overwrite " + selection + "?",
});
var result = messageBox.exec();
if (OriginalDialogs.StandardButton.Yes !== result) {
return;
}
}
console.log("Selecting " + selection)
selectedFile(selection);
root.destroy();
}
}
Action {
id: cancelAction
text: "Cancel"
onTriggered: { canceled();root.destroy(); }
}
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Backspace:
event.accepted = d.navigateUp();
break;
case Qt.Key_Home:
event.accepted = d.navigateHome();
break;
}
}
}

View file

@ -0,0 +1,249 @@
//
// MessageDialog.qml
//
// Created by Bradley Austin Davis on 15 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import "../controls-uit"
import "../styles-uit"
import "../windows"
import "messageDialog"
TabletModalWindow {
id: root
HifiConstants { id: hifi }
visible: true
signal selected(int button);
MouseArea {
id: mouse;
anchors.fill: parent
}
function click(button) {
clickedButton = button;
selected(button);
destroy();
}
function exec() {
return OffscreenUi.waitForMessageBoxResult(root);
}
property alias detailedText: detailedText.text
property alias text: mainTextContainer.text
property alias informativeText: informativeTextContainer.text
property int buttons: OriginalDialogs.StandardButton.Ok
property int icon: OriginalDialogs.StandardIcon.NoIcon
property string iconText: ""
property int iconSize: 50
onIconChanged: updateIcon();
property int defaultButton: OriginalDialogs.StandardButton.NoButton;
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
focus: defaultButton === OriginalDialogs.StandardButton.NoButton
property int titleWidth: 0
onTitleWidthChanged: d.resize();
function updateIcon() {
if (!root) {
return;
}
iconText = hifi.glyphForIcon(root.icon);
}
TabletModalFrame {
id: messageBox
clip: true
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 6
height: 300
QtObject {
id: d
readonly property int minWidth: 200
readonly property int maxWidth: 1280
readonly property int minHeight: 120
readonly property int maxHeight: 720
function resize() {
var targetWidth = Math.max(titleWidth, mainTextContainer.contentWidth)
var targetHeight = mainTextContainer.height + 3 * hifi.dimensions.contentSpacing.y
+ (informativeTextContainer.text != "" ? informativeTextContainer.contentHeight + 3 * hifi.dimensions.contentSpacing.y : 0)
+ buttons.height
+ (details.implicitHeight + hifi.dimensions.contentSpacing.y) + messageBox.frameMarginTop
messageBox.height = (targetHeight < d.minHeight) ? d.minHeight: ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)
}
}
RalewaySemiBold {
id: mainTextContainer
onTextChanged: d.resize();
wrapMode: Text.WordWrap
size: hifi.fontSizes.sectionName
color: hifi.colors.baseGrayHighlight
width: parent.width - 6
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: hifi.dimensions.contentSpacing.y + messageBox.frameMarginTop
}
maximumLineCount: 30
elide: Text.ElideLeft
lineHeight: 2
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
RalewaySemiBold {
id: informativeTextContainer
onTextChanged: d.resize();
wrapMode: Text.WordWrap
size: hifi.fontSizes.sectionName
color: hifi.colors.baseGrayHighlight
anchors {
top: mainTextContainer.bottom
left: parent.left
right: parent.right
margins: 0
topMargin: text != "" ? hifi.dimensions.contentSpacing.y : 0
}
}
Flow {
id: buttons
focus: true
spacing: hifi.dimensions.contentSpacing.x
onHeightChanged: d.resize(); onWidthChanged: d.resize();
layoutDirection: Qt.RightToLeft
anchors {
top: informativeTextContainer.text == "" ? mainTextContainer.bottom : informativeTextContainer.bottom
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: 2 * hifi.dimensions.contentSpacing.y
}
MessageDialogButton { dialog: root; text: qsTr("Close"); button: OriginalDialogs.StandardButton.Close; }
MessageDialogButton { dialog: root; text: qsTr("Abort"); button: OriginalDialogs.StandardButton.Abort; }
MessageDialogButton { dialog: root; text: qsTr("Cancel"); button: OriginalDialogs.StandardButton.Cancel; }
MessageDialogButton { dialog: root; text: qsTr("Restore Defaults"); button: OriginalDialogs.StandardButton.RestoreDefaults; }
MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; }
MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; }
MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; }
MessageDialogButton { dialog: root; text: qsTr("No"); button: OriginalDialogs.StandardButton.No; }
MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; }
MessageDialogButton { dialog: root; text: qsTr("Yes"); button: OriginalDialogs.StandardButton.Yes; }
MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; }
MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; }
MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; }
MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; }
MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; }
MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; }
MessageDialogButton { dialog: root; text: qsTr("OK"); button: OriginalDialogs.StandardButton.Ok; }
Button {
id: moreButton
text: qsTr("Show Details...")
width: 160
onClicked: { content.state = (content.state === "" ? "expanded" : "") }
visible: detailedText && detailedText.length > 0
}
MessageDialogButton { dialog: root; text: qsTr("Help"); button: OriginalDialogs.StandardButton.Help; }
}
Item {
id: details
width: parent.width
implicitHeight: detailedText.implicitHeight
height: 0
clip: true
anchors {
top: buttons.bottom
left: parent.left;
right: parent.right;
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
Flickable {
id: flickable
contentHeight: detailedText.height
anchors.fill: parent
anchors.topMargin: hifi.dimensions.contentSpacing.x
anchors.bottomMargin: hifi.dimensions.contentSpacing.y
TextEdit {
id: detailedText
size: hifi.fontSizes.menuItem
color: hifi.colors.baseGrayHighlight
width: details.width
wrapMode: Text.WordWrap
readOnly: true
selectByMouse: true
anchors.margins: 0
}
}
}
states: [
State {
name: "expanded"
PropertyChanges { target: root; anchors.fill: undefined }
PropertyChanges { target: details; height: 120 }
PropertyChanges { target: moreButton; text: qsTr("Hide Details") }
}
]
Component.onCompleted: {
updateIcon();
d.resize();
}
onStateChanged: d.resize()
}
Keys.onPressed: {
if (!visible) {
return
}
if (event.modifiers === Qt.ControlModifier)
switch (event.key) {
case Qt.Key_A:
event.accepted = true
detailedText.selectAll()
break
case Qt.Key_C:
event.accepted = true
detailedText.copy()
break
case Qt.Key_Period:
if (Qt.platform.os === "osx") {
event.accepted = true
content.reject()
}
break
} else switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
event.accepted = true
root.click(OriginalDialogs.StandardButton.Cancel)
break
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
root.click(root.defaultButton)
break
}
}
}

View file

@ -0,0 +1,206 @@
//
// QueryDialog.qml
//
// Created by Bradley Austin Davis on 22 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import "../controls-uit"
import "../styles-uit"
import "../windows"
TabletModalWindow {
id: root
HifiConstants { id: hifi }
signal selected(var result);
signal canceled();
layer.enabled: true
property int icon: hifi.icons.none
property string iconText: ""
property int iconSize: 35
MouseArea {
width: parent.width
height: parent.height
}
property bool keyboardOverride: true
onIconChanged: updateIcon();
property var items;
property string label: ""
property var result;
property alias current: textResult.text
// For text boxes
property alias placeholderText: textResult.placeholderText
// For combo boxes
property bool editable: true;
property int titleWidth: 0
onTitleWidthChanged: d.resize();
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
onKeyboardRaisedChanged: d.resize();
function updateIcon() {
if (!root) {
return;
}
iconText = hifi.glyphForIcon(root.icon);
}
TabletModalFrame {
id: modalWindowItem
width: parent.width - 12
height: 240
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
QtObject {
id: d
readonly property int minWidth: 470
readonly property int maxWidth: 470
readonly property int minHeight: 120
readonly property int maxHeight: 720
function resize() {
var targetWidth = Math.max(titleWidth, 470)
var targetHeight = (items ? comboBox.controlHeight : textResult.controlHeight) + 5 * hifi.dimensions.contentSpacing.y + buttons.height
modalWindowItem.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
modalWindowItem.height = ((targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)) + ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + 2 * hifi.dimensions.contentSpacing.y) : 0) + modalWindowItem.frameMarginTop
}
}
Item {
anchors {
top: parent.top
bottom: keyboard.top;
left: parent.left;
right: parent.right;
margins: 0
bottomMargin: 2 * hifi.dimensions.contentSpacing.y
}
// FIXME make a text field type that can be bound to a history for autocompletion
TextField {
id: textResult
label: root.label
focus: items ? false : true
visible: items ? false : true
anchors {
left: parent.left;
right: parent.right;
bottom: parent.bottom
leftMargin: 5
}
}
TabletComboBox {
id: comboBox
label: root.label
focus: true
visible: items ? true : false
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
rightMargin: 5
}
model: items ? items : []
}
}
property alias keyboardOverride: root.keyboardOverride
property alias keyboardRaised: root.keyboardRaised
property alias punctuationMode: root.punctuationMode
Keyboard {
id: keyboard
raised: keyboardEnabled && keyboardRaised
numeric: punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: buttons.top
bottomMargin: raised ? 2 * hifi.dimensions.contentSpacing.y : 0
}
}
Flow {
id: buttons
focus: true
spacing: hifi.dimensions.contentSpacing.x
onHeightChanged: d.resize(); onWidthChanged: d.resize();
layoutDirection: Qt.RightToLeft
anchors {
bottom: parent.bottom
right: parent.right
margins: 0
bottomMargin: hifi.dimensions.contentSpacing.y
}
Button { action: cancelAction }
Button { action: acceptAction }
}
Action {
id: cancelAction
text: qsTr("Cancel")
shortcut: Qt.Key_Escape
onTriggered: {
root.canceled();
root.destroy();
}
}
Action {
id: acceptAction
text: qsTr("OK")
shortcut: Qt.Key_Return
onTriggered: {
root.result = items ? comboBox.currentText : textResult.text
root.selected(root.result);
root.destroy();
}
}
}
Keys.onPressed: {
if (!visible) {
return
}
switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
cancelAction.trigger()
event.accepted = true;
break;
case Qt.Key_Return:
case Qt.Key_Enter:
acceptAction.trigger()
event.accepted = true;
break;
}
}
Component.onCompleted: {
keyboardEnabled = HMD.active;
updateIcon();
d.resize();
textResult.forceActiveFocus();
}
}

View file

@ -23,7 +23,10 @@ Preference {
Component.onCompleted: {
dataTextField.text = preference.value;
console.log("MyAvatar modelName " + MyAvatar.getFullAvatarModelName())
// FIXME: MyAvatar object isn't available in HMD mode for some reason.
if (typeof MyAvatar !== "undefined") {
console.log("MyAvatar modelName " + MyAvatar.getFullAvatarModelName())
}
console.log("Application : " + ApplicationInterface)
ApplicationInterface.fullAvatarURLChanged.connect(processNewAvatar);
}

View file

@ -1,5 +1,5 @@
//
// PreferencesDialog.qml
// GeneralPreferencesDialog.qml
//
// Created by Bradley Austin Davis on 24 Jan 2016
// Copyright 2015 High Fidelity, Inc.

View file

@ -0,0 +1,614 @@
//
// TabletAssetServer.qml
//
// Created by Vlad Stelmahovsky on 3/3/17
// 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import Qt.labs.settings 1.0
import "../../styles-uit"
import "../../controls-uit" as HifiControls
import "../../windows"
Rectangle {
id: root
objectName: "AssetServer"
property var eventBridge;
signal sendToScript(var message);
property bool isHMD: false
color: hifi.colors.baseGray
property int colorScheme: hifi.colorSchemes.dark
HifiConstants { id: hifi }
property var scripts: ScriptDiscoveryService;
property var assetProxyModel: Assets.proxyModel;
property var assetMappingsModel: Assets.mappingModel;
property var currentDirectory;
Settings {
category: "Overlay.AssetServer"
property alias directory: root.currentDirectory
}
Component.onCompleted: {
isHMD = HMD.active;
ApplicationInterface.uploadRequest.connect(uploadClicked);
assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError);
reload();
}
function doDeleteFile(path) {
console.log("Deleting " + path);
Assets.deleteMappings(path, function(err) {
if (err) {
console.log("Asset browser - error deleting path: ", path, err);
box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err);
box.selected.connect(reload);
} else {
console.log("Asset browser - finished deleting path: ", path);
reload();
}
});
}
function doRenameFile(oldPath, newPath) {
if (newPath[0] !== "/") {
newPath = "/" + newPath;
}
if (oldPath[oldPath.length - 1] === '/' && newPath[newPath.length - 1] != '/') {
// this is a folder rename but the user neglected to add a trailing slash when providing a new path
newPath = newPath + "/";
}
if (Assets.isKnownFolder(newPath)) {
box = errorMessageBox("Cannot overwrite existing directory.");
box.selected.connect(reload);
}
console.log("Asset browser - renaming " + oldPath + " to " + newPath);
Assets.renameMapping(oldPath, newPath, function(err) {
if (err) {
console.log("Asset browser - error renaming: ", oldPath, "=>", newPath, " - error ", err);
box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + err);
box.selected.connect(reload);
} else {
console.log("Asset browser - finished rename: ", oldPath, "=>", newPath);
}
reload();
});
}
function fileExists(path) {
return Assets.isKnownMapping(path);
}
function askForOverwrite(path, callback) {
var object = tabletRoot.messageBox({
icon: hifi.icons.question,
buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
defaultButton: OriginalDialogs.StandardButton.No,
title: "Overwrite File",
text: path + "\n" + "This file already exists. Do you want to overwrite it?"
});
object.selected.connect(function(button) {
if (button === OriginalDialogs.StandardButton.Yes) {
callback();
}
});
}
function canAddToWorld(path) {
var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i];
return supportedExtensions.reduce(function(total, current) {
return total | new RegExp(current).test(path);
}, false);
}
function clear() {
Assets.mappingModel.clear();
}
function reload() {
Assets.mappingModel.refresh();
treeView.selection.clear();
}
function handleGetMappingsError(errorString) {
errorMessageBox(
"There was a problem retreiving the list of assets from your Asset Server.\n"
+ errorString
);
}
function addToWorld() {
var defaultURL = assetProxyModel.data(treeView.selection.currentIndex, 0x103);
if (!defaultURL || !canAddToWorld(defaultURL)) {
return;
}
var SHAPE_TYPE_NONE = 0;
var SHAPE_TYPE_SIMPLE_HULL = 1;
var SHAPE_TYPE_SIMPLE_COMPOUND = 2;
var SHAPE_TYPE_STATIC_MESH = 3;
var SHAPE_TYPES = [];
SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision";
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model";
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes";
SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons";
var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH;
var DYNAMIC_DEFAULT = false;
var prompt = tabletRoot.customInputDialog({
textInput: {
label: "Model URL",
text: defaultURL
},
comboBox: {
label: "Automatic Collisions",
index: SHAPE_TYPE_DEFAULT,
items: SHAPE_TYPES
},
checkBox: {
label: "Dynamic",
checked: DYNAMIC_DEFAULT,
disableForItems: [
SHAPE_TYPE_STATIC_MESH
],
checkStateOnDisable: false,
warningOnDisable: "Models with automatic collisions set to 'Exact' cannot be dynamic"
}
});
prompt.selected.connect(function (jsonResult) {
if (jsonResult) {
var result = JSON.parse(jsonResult);
var url = result.textInput.trim();
var shapeType;
switch (result.comboBox) {
case SHAPE_TYPE_SIMPLE_HULL:
shapeType = "simple-hull";
break;
case SHAPE_TYPE_SIMPLE_COMPOUND:
shapeType = "simple-compound";
break;
case SHAPE_TYPE_STATIC_MESH:
shapeType = "static-mesh";
break;
default:
shapeType = "none";
}
var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT;
if (shapeType === "static-mesh" && dynamic) {
// The prompt should prevent this case
print("Error: model cannot be both static mesh and dynamic. This should never happen.");
} else if (url) {
var name = assetProxyModel.data(treeView.selection.currentIndex);
var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation)));
var gravity;
if (dynamic) {
// Create a vector <0, -10, 0>. { x: 0, y: -10, z: 0 } won't work because Qt is dumb and this is a
// different scripting engine from QTScript.
gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 10);
} else {
gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0);
}
print("Asset browser - adding asset " + url + " (" + name + ") to world.");
// Entities.addEntity doesn't work from QML, so we use this.
Entities.addModelEntity(name, url, shapeType, dynamic, addPosition, gravity);
}
}
});
}
function copyURLToClipboard(index) {
if (!index) {
index = treeView.selection.currentIndex;
}
var url = assetProxyModel.data(treeView.selection.currentIndex, 0x103);
if (!url) {
return;
}
Window.copyToClipboard(url);
}
function renameEl(index, data) {
if (!index) {
return false;
}
var path = assetProxyModel.data(index, 0x100);
if (!path) {
return false;
}
var destinationPath = path.split('/');
destinationPath[destinationPath.length - (path[path.length - 1] === '/' ? 2 : 1)] = data;
destinationPath = destinationPath.join('/').trim();
if (path === destinationPath) {
return;
}
if (!fileExists(destinationPath)) {
doRenameFile(path, destinationPath);
}
}
function renameFile(index) {
if (!index) {
index = treeView.selection.currentIndex;
}
var path = assetProxyModel.data(index, 0x100);
if (!path) {
return;
}
var object = tabletRoot.inputDialog({
label: "Enter new path:",
current: path,
placeholderText: "Enter path here"
});
object.selected.connect(function(destinationPath) {
destinationPath = destinationPath.trim();
if (path === destinationPath) {
return;
}
if (fileExists(destinationPath)) {
askForOverwrite(destinationPath, function() {
doRenameFile(path, destinationPath);
});
} else {
doRenameFile(path, destinationPath);
}
});
}
function deleteFile(index) {
if (!index) {
index = treeView.selection.currentIndex;
}
var path = assetProxyModel.data(index, 0x100);
if (!path) {
return;
}
var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101);
var typeString = isFolder ? 'folder' : 'file';
var object = tabletRoot.messageBox({
icon: hifi.icons.question,
buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No,
defaultButton: OriginalDialogs.StandardButton.Yes,
title: "Delete",
text: "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"
});
object.selected.connect(function(button) {
if (button === OriginalDialogs.StandardButton.Yes) {
doDeleteFile(path);
}
});
}
Timer {
id: doUploadTimer
property var url
property bool isConnected: false
interval: 5
repeat: false
running: false
}
property bool uploadOpen: false;
Timer {
id: timer
}
function uploadClicked(fileUrl) {
if (uploadOpen) {
return;
}
uploadOpen = true;
function doUpload(url, dropping) {
var fileUrl = fileDialogHelper.urlToPath(url);
var path = assetProxyModel.data(treeView.selection.currentIndex, 0x100);
var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/";
var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1);
Assets.uploadFile(fileUrl, directory + filename,
function() {
// Upload started
uploadSpinner.visible = true;
uploadButton.enabled = false;
uploadProgressLabel.text = "In progress...";
},
function(err, path) {
print(err, path);
if (err === "") {
uploadProgressLabel.text = "Upload Complete";
timer.interval = 1000;
timer.repeat = false;
timer.triggered.connect(function() {
uploadSpinner.visible = false;
uploadButton.enabled = true;
uploadOpen = false;
});
timer.start();
console.log("Asset Browser - finished uploading: ", fileUrl);
reload();
} else {
uploadSpinner.visible = false;
uploadButton.enabled = true;
uploadOpen = false;
if (err !== -1) {
console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err);
var box = errorMessageBox("There was an error uploading:\n" + fileUrl + "\n" + err);
box.selected.connect(reload);
}
}
}, dropping);
}
function initiateUpload(url) {
doUpload(doUploadTimer.url, false);
}
if (fileUrl) {
doUpload(fileUrl, true);
} else {
var browser = tabletRoot.fileDialog({
selectDirectory: false,
dir: currentDirectory
});
browser.canceled.connect(function() {
uploadOpen = false;
});
browser.selectedFile.connect(function(url) {
currentDirectory = browser.dir;
// Initiate upload from a timer so that file browser dialog can close beforehand.
doUploadTimer.url = url;
if (!doUploadTimer.isConnected) {
doUploadTimer.triggered.connect(function() { initiateUpload(); });
doUploadTimer.isConnected = true;
}
doUploadTimer.start();
});
}
}
function errorMessageBox(message) {
return tabletRoot.messageBox({
icon: hifi.icons.warning,
defaultButton: OriginalDialogs.StandardButton.Ok,
title: "Error",
text: message
});
}
Column {
width: parent.width
y: hifi.dimensions.tabletMenuHeader //-bgNavBar
spacing: 10
HifiControls.TabletContentSection {
id: assetDirectory
name: "Asset Directory"
isFirst: true
HifiControls.VerticalSpacer {}
Row {
id: buttonRow
width: parent.width
height: 30
spacing: hifi.dimensions.contentSpacing.x
HifiControls.GlyphButton {
glyph: hifi.glyphs.reload
color: hifi.buttons.black
colorScheme: root.colorScheme
width: hifi.dimensions.controlLineHeight
onClicked: root.reload()
}
HifiControls.Button {
text: "Add To World"
color: hifi.buttons.black
colorScheme: root.colorScheme
width: 120
enabled: canAddToWorld(assetProxyModel.data(treeView.selection.currentIndex, 0x100))
onClicked: root.addToWorld()
}
HifiControls.Button {
text: "Rename"
color: hifi.buttons.black
colorScheme: root.colorScheme
width: 80
onClicked: root.renameFile()
enabled: treeView.selection.hasSelection
}
HifiControls.Button {
id: deleteButton
text: "Delete"
color: hifi.buttons.red
colorScheme: root.colorScheme
width: 80
onClicked: root.deleteFile()
enabled: treeView.selection.hasSelection
}
}
Menu {
id: contextMenu
title: "Edit"
property var url: ""
property var currentIndex: null
MenuItem {
text: "Copy URL"
onTriggered: {
copyURLToClipboard(contextMenu.currentIndex);
}
}
MenuItem {
text: "Rename"
onTriggered: {
renameFile(contextMenu.currentIndex);
}
}
MenuItem {
text: "Delete"
onTriggered: {
deleteFile(contextMenu.currentIndex);
}
}
}
}
HifiControls.Tree {
id: treeView
height: 430
anchors.leftMargin: hifi.dimensions.contentMargin.x + 2 // Extra for border
anchors.rightMargin: hifi.dimensions.contentMargin.x + 2 // Extra for border
anchors.left: parent.left
anchors.right: parent.right
treeModel: assetProxyModel
canEdit: true
colorScheme: root.colorScheme
modifyEl: renameEl
MouseArea {
propagateComposedEvents: true
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
if (!HMD.active) { // Popup only displays properly on desktop
var index = treeView.indexAt(mouse.x, mouse.y);
treeView.selection.setCurrentIndex(index, 0x0002);
contextMenu.currentIndex = index;
contextMenu.popup();
}
}
}
}
HifiControls.TabletContentSection {
id: uploadSection
name: "Upload A File"
spacing: hifi.dimensions.contentSpacing.y
//anchors.bottom: parent.bottom
height: 65
anchors.left: parent.left
anchors.right: parent.right
Item {
height: parent.height
width: parent.width
HifiControls.Button {
id: uploadButton
anchors.right: parent.right
text: "Choose File"
color: hifi.buttons.blue
colorScheme: root.colorScheme
height: 30
width: 155
onClicked: uploadClickedTimer.running = true
// For some reason trigginer an API that enters
// an internal event loop directly from the button clicked
// trigger below causes the appliction to behave oddly.
// Most likely because the button onClicked handling is never
// completed until the function returns.
// FIXME find a better way of handling the input dialogs that
// doesn't trigger this.
Timer {
id: uploadClickedTimer
interval: 5
repeat: false
running: false
onTriggered: uploadClicked();
}
}
Item {
id: uploadSpinner
visible: false
anchors.top: parent.top
anchors.left: parent.left
width: 40
height: 32
Image {
id: image
width: 24
height: 24
source: "../../../images/Loading-Outer-Ring.png"
RotationAnimation on rotation {
loops: Animation.Infinite
from: 0
to: 360
duration: 2000
}
}
Image {
width: 24
height: 24
source: "../../../images/Loading-Inner-H.png"
}
HifiControls.Label {
id: uploadProgressLabel
anchors.left: image.right
anchors.leftMargin: 10
anchors.verticalCenter: image.verticalCenter
text: "In progress..."
colorScheme: root.colorScheme
}
}
}
}
}
}

View file

@ -0,0 +1,344 @@
//
// RunningScripts.qml
//
// Created by Bradley Austin Davis on 12 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import Qt.labs.settings 1.0
import "../../styles-uit"
import "../../controls-uit" as HifiControls
import "../../windows"
Rectangle {
id: root
objectName: "RunningScripts"
HifiConstants { id: hifi }
signal sendToScript(var message);
property var eventBridge;
property var scripts: ScriptDiscoveryService;
property var scriptsModel: scripts.scriptsModelFilter
property var runningScriptsModel: ListModel { }
property bool isHMD: false
color: hifi.colors.baseGray
Connections {
target: ScriptDiscoveryService
onScriptCountChanged: updateRunningScripts();
}
Component.onCompleted: {
isHMD = HMD.active;
updateRunningScripts();
}
function updateRunningScripts() {
var runningScripts = ScriptDiscoveryService.getRunning();
runningScriptsModel.clear()
for (var i = 0; i < runningScripts.length; ++i) {
runningScriptsModel.append(runningScripts[i]);
}
}
function loadScript(script) {
console.log("Load script " + script);
scripts.loadOneScript(script);
}
function reloadScript(script) {
console.log("Reload script " + script);
scripts.stopScript(script, true);
}
function stopScript(script) {
console.log("Stop script " + script);
scripts.stopScript(script);
}
function reloadAll() {
console.log("Reload all scripts");
scripts.reloadAllScripts();
}
function loadDefaults() {
console.log("Load default scripts");
scripts.loadOneScript(scripts.defaultScriptsPath + "/defaultScripts.js");
}
function stopAll() {
console.log("Stop all scripts");
scripts.stopAllScripts();
}
Column {
width: parent.width
HifiControls.TabletContentSection {
name: "Currently Running"
isFirst: true
HifiControls.VerticalSpacer {}
Row {
spacing: hifi.dimensions.contentSpacing.x
HifiControls.Button {
text: "Reload All"
color: hifi.buttons.black
onClicked: reloadAll()
}
HifiControls.Button {
text: "Remove All"
color: hifi.buttons.red
onClicked: stopAll()
}
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.Table {
model: runningScriptsModel
id: table
height: 185
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.right: parent.right
expandSelectedRow: true
itemDelegate: Item {
anchors {
left: parent ? parent.left : undefined
leftMargin: hifi.dimensions.tablePadding
right: parent ? parent.right : undefined
rightMargin: hifi.dimensions.tablePadding
}
FiraSansSemiBold {
id: textItem
text: styleData.value
size: hifi.fontSizes.tableText
color: table.colorScheme == hifi.colorSchemes.light
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
anchors {
left: parent.left
right: parent.right
top: parent.top
topMargin: 3
}
HiFiGlyphs {
id: reloadButton
text: hifi.glyphs.reloadSmall
color: reloadButtonArea.pressed ? hifi.colors.white : parent.color
anchors {
top: parent.top
right: stopButton.left
verticalCenter: parent.verticalCenter
}
MouseArea {
id: reloadButtonArea
anchors { fill: parent; margins: -2 }
onClicked: reloadScript(model.url)
}
}
HiFiGlyphs {
id: stopButton
text: hifi.glyphs.closeSmall
color: stopButtonArea.pressed ? hifi.colors.white : parent.color
anchors {
top: parent.top
right: parent.right
verticalCenter: parent.verticalCenter
}
MouseArea {
id: stopButtonArea
anchors { fill: parent; margins: -2 }
onClicked: stopScript(model.url)
}
}
}
FiraSansSemiBold {
text: runningScriptsModel.get(styleData.row) ? runningScriptsModel.get(styleData.row).url : ""
elide: Text.ElideMiddle
size: hifi.fontSizes.tableText
color: table.colorScheme == hifi.colorSchemes.light
? (styleData.selected ? hifi.colors.black : hifi.colors.lightGray)
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
anchors {
top: textItem.bottom
left: parent.left
right: parent.right
}
visible: styleData.selected
}
}
TableViewColumn {
role: "name"
}
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
}
HifiControls.TabletContentSection {
name: "Load Scripts"
HifiControls.VerticalSpacer {}
Row {
spacing: hifi.dimensions.contentSpacing.x
HifiControls.Button {
text: "from URL"
color: hifi.buttons.black
height: 26
onClicked: fromUrlTimer.running = true
// For some reason trigginer an API that enters
// an internal event loop directly from the button clicked
// trigger below causes the appliction to behave oddly.
// Most likely because the button onClicked handling is never
// completed until the function returns.
// FIXME find a better way of handling the input dialogs that
// doesn't trigger this.
Timer {
id: fromUrlTimer
interval: 5
repeat: false
running: false
onTriggered: ApplicationInterface.loadScriptURLDialog();
}
}
HifiControls.Button {
text: "from Disk"
color: hifi.buttons.black
height: 26
onClicked: fromDiskTimer.running = true
Timer {
id: fromDiskTimer
interval: 5
repeat: false
running: false
onTriggered: ApplicationInterface.loadDialog();
}
}
HifiControls.Button {
text: "Load Defaults"
color: hifi.buttons.black
height: 26
onClicked: loadDefaults()
}
}
HifiControls.VerticalSpacer {}
HifiControls.TextField {
id: filterEdit
isSearchField: true
anchors.left: parent.left
anchors.right: parent.right
colorScheme: hifi.colorSchemes.dark
placeholderText: "Filter"
onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i")
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.Tree {
id: treeView
height: 155
treeModel: scriptsModel
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.right: parent.right
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.TextField {
id: selectedScript
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: loadButton.width + hifi.dimensions.contentSpacing.x
colorScheme: hifi.colorSchemes.dark
readOnly: true
Connections {
target: treeView
onCurrentIndexChanged: {
var path = scriptsModel.data(treeView.currentIndex, 0x100)
if (path) {
selectedScript.text = path
} else {
selectedScript.text = ""
}
}
}
}
Item {
// Take the loadButton out of the column flow.
id: loadButtonContainer
anchors.top: selectedScript.top
anchors.right: parent.right
HifiControls.Button {
id: loadButton
anchors.right: parent.right
text: "Load"
color: hifi.buttons.blue
enabled: selectedScript.text != ""
onClicked: root.loadScript(selectedScript.text)
}
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight - (!isHMD ? 3 : 0)
}
HifiControls.TextAction {
id: directoryButton
icon: hifi.glyphs.script
iconSize: 24
text: "Reveal Scripts Folder"
onClicked: fileDialogHelper.openDirectory(scripts.defaultScriptsPath)
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
visible: !isHMD
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight - 3
visible: !isHMD
}
}
}
}

View file

@ -0,0 +1,354 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebEngine 1.1
import QtWebChannel 1.0
import QtQuick.Controls.Styles 1.4
import "../../controls"
import "../toolbars"
import HFWebEngineProfile 1.0
import QtGraphicalEffects 1.0
import "../../styles-uit"
StackView {
id: editRoot
objectName: "stack"
initialItem: editBasePage
property var eventBridge;
signal sendToScript(var message);
function pushSource(path) {
editRoot.push(Qt.resolvedUrl(path));
editRoot.currentItem.eventBridge = editRoot.eventBridge;
editRoot.currentItem.sendToScript.connect(editRoot.sendToScript);
}
function popSource() {
editRoot.pop();
}
Component {
id: editBasePage
TabView {
id: editTabView
// anchors.fill: parent
height: 60
Tab {
title: "CREATE"
active: true
enabled: true
property string originalUrl: ""
Rectangle {
color: "#404040"
Text {
color: "#ffffff"
text: "Choose an Entity Type to Create:"
font.pixelSize: 14
font.bold: true
anchors.top: parent.top
anchors.topMargin: 28
anchors.left: parent.left
anchors.leftMargin: 28
}
Flow {
id: createEntitiesFlow
spacing: 35
anchors.right: parent.right
anchors.rightMargin: 55
anchors.left: parent.left
anchors.leftMargin: 55
anchors.top: parent.top
anchors.topMargin: 70
NewEntityButton {
icon: "icons/create-icons/94-model-01.svg"
text: "MODEL"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newModelButton" }
});
editTabView.currentIndex = 2
}
}
NewEntityButton {
icon: "icons/create-icons/21-cube-01.svg"
text: "CUBE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newCubeButton" }
});
editTabView.currentIndex = 2
}
}
NewEntityButton {
icon: "icons/create-icons/22-sphere-01.svg"
text: "SPHERE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newSphereButton" }
});
editTabView.currentIndex = 2
}
}
NewEntityButton {
icon: "icons/create-icons/24-light-01.svg"
text: "LIGHT"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newLightButton" }
});
editTabView.currentIndex = 2
}
}
NewEntityButton {
icon: "icons/create-icons/20-text-01.svg"
text: "TEXT"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newTextButton" }
});
editTabView.currentIndex = 2
}
}
NewEntityButton {
icon: "icons/create-icons/25-web-1-01.svg"
text: "WEB"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newWebButton" }
});
editTabView.currentIndex = 2
}
}
NewEntityButton {
icon: "icons/create-icons/23-zone-01.svg"
text: "ZONE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newZoneButton" }
});
editTabView.currentIndex = 2
}
}
NewEntityButton {
icon: "icons/create-icons/90-particles-01.svg"
text: "PARTICLE"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newParticleButton" }
});
editTabView.currentIndex = 2
}
}
}
Item {
id: assetServerButton
width: 370
height: 38
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: createEntitiesFlow.bottom
anchors.topMargin: 35
Rectangle {
id: assetServerButtonBg
color: "black"
opacity: 1
radius: 6
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
}
Rectangle {
id: assetServerButtonGradient
gradient: Gradient {
GradientStop {
position: 0
color: "#383838"
}
GradientStop {
position: 1
color: "black"
}
}
opacity: 1
radius: 6
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
}
Text {
color: "#ffffff"
text: "OPEN THIS DOMAIN'S ASSET SERVER"
font.bold: true
font.pixelSize: 14
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
enabled: true
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "openAssetBrowserButton" }
});
}
onEntered: {
assetServerButton.state = "hover state";
}
onExited: {
assetServerButton.state = "base state";
}
}
states: [
State {
name: "hover state"
PropertyChanges {
target: assetServerButtonGradient
opacity: 0
}
},
State {
name: "base state"
PropertyChanges {
target: assetServerButtonGradient
opacity: 1
}
}
]
}
}
}
Tab {
title: "LIST"
active: true
enabled: true
property string originalUrl: ""
WebView {
id: entityListToolWebView
url: "../../../../../scripts/system/html/entityList.html"
eventBridge: editRoot.eventBridge
anchors.fill: parent
enabled: true
}
}
Tab {
title: "PROPERTIES"
active: true
enabled: true
property string originalUrl: ""
WebView {
id: entityPropertiesWebView
url: "../../../../../scripts/system/html/entityProperties.html"
eventBridge: editRoot.eventBridge
anchors.fill: parent
enabled: true
}
}
Tab {
title: "GRID"
active: true
enabled: true
property string originalUrl: ""
WebView {
id: gridControlsWebView
url: "../../../../../scripts/system/html/gridControls.html"
eventBridge: editRoot.eventBridge
anchors.fill: parent
enabled: true
}
}
Tab {
title: "P"
active: true
enabled: true
property string originalUrl: ""
WebView {
id: particleExplorerWebView
url: "../../../../../scripts/system/particle_explorer/particleExplorer.html"
eventBridge: editRoot.eventBridge
anchors.fill: parent
enabled: true
}
}
style: TabViewStyle {
frameOverlap: 1
tab: Rectangle {
color: styleData.selected ? "#404040" :"black"
implicitWidth: text.width + 42
implicitHeight: 40
Text {
id: text
anchors.centerIn: parent
text: styleData.title
font.pixelSize: 16
font.bold: true
color: styleData.selected ? "white" : "white"
property string glyphtext: ""
HiFiGlyphs {
anchors.centerIn: parent
size: 30
color: "#ffffff"
text: text.glyphtext
}
Component.onCompleted: if (styleData.title == "P") {
text.text = " ";
text.glyphtext = "\ue004";
}
}
}
tabBar: Rectangle {
color: "black"
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
}
}
}
}
}

View file

@ -0,0 +1,160 @@
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
id: newEntityButton
property var uuid;
property string text: "ENTITY"
property string icon: "icons/edit-icon.svg"
property string activeText: newEntityButton.text
property string activeIcon: newEntityButton.icon
property bool isActive: false
property bool inDebugMode: false
property bool isEntered: false
property double sortOrder: 100
property int stableOrder: 0
property var tabletRoot;
width: 100
height: 100
signal clicked()
function changeProperty(key, value) {
tabletButton[key] = value;
}
onIsActiveChanged: {
if (tabletButton.isEntered) {
tabletButton.state = (tabletButton.isActive) ? "hover active state" : "hover sate";
} else {
tabletButton.state = (tabletButton.isActive) ? "active state" : "base sate";
}
}
Rectangle {
id: buttonBg
color: "#1c1c1c"
opacity: 1
radius: 8
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
}
function urlHelper(src) {
if (src.match(/\bhttp/)) {
return src;
} else {
return "../../../" + src;
}
}
Rectangle {
id: buttonOutline
color: "#00000000"
opacity: 0
radius: 8
z: 1
border.width: 2
border.color: "#ffffff"
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
}
DropShadow {
id: glow
visible: false
anchors.fill: parent
horizontalOffset: 0
verticalOffset: 0
color: "#ffffff"
radius: 20
z: -1
samples: 41
source: buttonOutline
}
Image {
id: icon
width: 50
height: 50
visible: false
anchors.bottom: text.top
anchors.bottomMargin: 5
anchors.horizontalCenter: parent.horizontalCenter
fillMode: Image.Stretch
source: newEntityButton.urlHelper(newEntityButton.icon)
}
ColorOverlay {
id: iconColorOverlay
anchors.fill: icon
source: icon
color: "#ffffff"
}
Text {
id: text
color: "#ffffff"
text: newEntityButton.text
font.bold: true
font.pixelSize: 16
anchors.bottom: parent.bottom
anchors.bottomMargin: 12
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
enabled: true
onClicked: {
newEntityButton.clicked();
}
onEntered: {
newEntityButton.state = "hover state";
}
onExited: {
newEntityButton.state = "base state";
}
}
states: [
State {
name: "hover state"
PropertyChanges {
target: buttonOutline
opacity: 1
}
PropertyChanges {
target: glow
visible: true
}
},
State {
name: "base state"
PropertyChanges {
target: glow
visible: false
}
}
]
}

View file

@ -0,0 +1,158 @@
//
// NewModelDialog.qml
// qml/hifi
//
// Created by Seth Alves on 2017-2-10
// 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../../styles-uit"
import "../../controls-uit"
Rectangle {
id: newModelDialog
// width: parent.width
// height: parent.height
HifiConstants { id: hifi }
color: hifi.colors.baseGray;
property var eventBridge;
signal sendToScript(var message);
Column {
id: column1
anchors.rightMargin: 10
anchors.leftMargin: 10
anchors.bottomMargin: 10
anchors.topMargin: 10
anchors.fill: parent
spacing: 5
Text {
id: text1
text: qsTr("Model URL")
color: "#ffffff"
font.pixelSize: 12
}
TextInput {
id: modelURL
height: 20
text: qsTr("")
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
font.pixelSize: 12
}
Row {
id: row1
height: 400
spacing: 30
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
Column {
id: column2
width: 200
height: 400
spacing: 10
CheckBox {
id: dynamic
text: qsTr("Dynamic")
}
Row {
id: row2
width: 200
height: 400
spacing: 20
Image {
id: image1
width: 30
height: 30
source: "qrc:/qtquickplugin/images/template_image.png"
}
Text {
id: text2
width: 160
color: "#ffffff"
text: qsTr("Models with automatic collisions set to 'Exact' cannot be dynamic")
wrapMode: Text.WordWrap
font.pixelSize: 12
}
}
}
Column {
id: column3
height: 400
spacing: 10
Text {
id: text3
text: qsTr("Automatic Collisions")
color: "#ffffff"
font.pixelSize: 12
}
TabletComboBox {
id: collisionType
width: 200
z: 100
transformOrigin: Item.Center
model: ["No Collision",
"Basic - Whole model",
"Good - Sub-meshes",
"Exact - All polygons"]
}
Row {
id: row3
width: 200
height: 400
spacing: 5
anchors {
rightMargin: 15
}
Button {
id: button1
text: qsTr("Add")
z: -1
onClicked: {
newModelDialog.sendToScript({
method: "newModelDialogAdd",
params: {
textInput: modelURL.text,
checkBox: dynamic.checked,
comboBox: collisionType.currentIndex
}
});
}
}
Button {
id: button2
z: -1
text: qsTr("Cancel")
onClicked: {
newModelDialog.sendToScript({method: "newModelDialogCancel"})
}
}
}
}
}
}
}

View file

@ -0,0 +1,42 @@
//
// TabletAudioPreferences.qml
//
// Created by Davd Rowe on 7 Mar 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
//
import QtQuick 2.5
import "tabletWindows"
import "../../dialogs"
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
StackView {
id: profileRoot
initialItem: root
objectName: "stack"
property var eventBridge;
signal sendToScript(var message);
function pushSource(path) {
editRoot.push(Qt.reslovedUrl(path));
}
function popSource() {
}
TabletPreferencesDialog {
id: root
property string title: "Audio Settings"
objectName: "TabletAudioPreferences"
width: parent.width
height: parent.height
showCategories: ["Audio"]
}
}

View file

@ -0,0 +1,42 @@
//
// TabletAvatarPreferences.qml
//
// Created by Davd Rowe on 2 Mar 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
//
import QtQuick 2.5
import "tabletWindows"
import "../../dialogs"
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
StackView {
id: profileRoot
initialItem: root
objectName: "stack"
property var eventBridge;
signal sendToScript(var message);
function pushSource(path) {
editRoot.push(Qt.reslovedUrl(path));
}
function popSource() {
}
TabletPreferencesDialog {
id: root
property string title: "Avatar Preferences"
objectName: "TabletAvatarPreferences"
width: parent.width
height: parent.height
showCategories: ["Avatar Basics", "Avatar Tuning", "Avatar Camera"]
}
}

View file

@ -1,9 +1,8 @@
//
// TabletGeneralSettings.qml
// scripts/system/
// TabletGeneralPreferences.qml
//
// Created by Dante Ruiz on 9 Feb 2017
// Copyright 2016 High Fidelity, Inc.
// 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
@ -34,11 +33,10 @@ StackView {
TabletPreferencesDialog {
id: root
objectName: "GeneralPreferencesDialog"
property string title: "General Preferences"
objectName: "TabletGeneralPreferences"
width: parent.width
height: parent.height
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect"]
}
}

View file

@ -2,8 +2,14 @@ import QtQuick 2.5
import QtGraphicalEffects 1.0
import QtQuick.Controls 1.4
import QtQml 2.2
import QtWebChannel 1.0
import QtWebEngine 1.1
import HFWebEngineProfile 1.0
import "."
import "../../styles-uit"
import "../../controls"
FocusScope {
id: tabletMenu
@ -13,10 +19,11 @@ FocusScope {
height: 720
property var rootMenu: Menu { objectName:"rootMenu" }
property var point: Qt.point(50, 50)
property var point: Qt.point(50, 50);
TabletMenuStack { id: menuPopperUpper }
property string subMenu: ""
TabletMouseHandler { id: menuPopperUpper }
property var eventBridge;
signal sendToScript(var message);
Rectangle {
id: bgNavBar
@ -57,6 +64,7 @@ FocusScope {
// navigate back to root level menu
onClicked: {
buildMenu();
breadcrumbText.text = "Menu";
tabletRoot.playButtonClickSound();
}
}
@ -97,6 +105,7 @@ FocusScope {
menuPopperUpper.closeLastMenu();
}
function setRootMenu(rootMenu, subMenu) {
tabletMenu.subMenu = subMenu;
tabletMenu.rootMenu = rootMenu;
@ -116,12 +125,12 @@ FocusScope {
}
subMenu = ""; // Continue with full menu after initially displaying submenu.
if (found) {
menuPopperUpper.popup(tabletMenu, rootMenu.items[index].items);
menuPopperUpper.popup(rootMenu.items[index].items);
return;
}
}
// Otherwise build whole menu.
menuPopperUpper.popup(tabletMenu, rootMenu.items);
menuPopperUpper.popup(rootMenu.items);
}
}

View file

@ -1,7 +1,7 @@
//
// MessageDialog.qml
//
// Created by Bradley Austin Davis on 18 Jan 2016
// Created by Dante Ruiz on 13 Feb 2017
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
@ -17,19 +17,13 @@ Item {
id: root
anchors.fill: parent
objectName: "tabletMenuHandlerItem"
MouseArea {
id: menuRoot;
objectName: "tabletMenuHandlerMouseArea"
StackView {
anchors.fill: parent
enabled: d.topMenu !== null
onClicked: {
d.clearMenus();
}
}
QtObject {
id: d
objectName: "stack"
initialItem: topMenu
property var menuStack: []
property var topMenu: null;
property var modelMaker: Component { ListModel { } }
@ -53,6 +47,18 @@ Item {
}
}
function pushSource(path) {
d.push(Qt.resolvedUrl(path));
d.currentItem.eventBridge = tabletMenu.eventBridge
d.currentItem.sendToScript.connect(tabletMenu.sendToScript);
breadcrumbText.text = d.currentItem.objectName;
}
function popSource() {
console.log("trying to pop page");
d.pop();
}
function toModel(items) {
var result = modelMaker.createObject(tabletMenu);
for (var i = 0; i < items.length; ++i) {
@ -76,22 +82,18 @@ Item {
}
function popMenu() {
if (menuStack.length) {
menuStack.pop().destroy();
if (d.depth) {
d.pop();
}
if (menuStack.length) {
topMenu = menuStack[menuStack.length - 1];
if (d.depth) {
topMenu = d.currentItem;
topMenu.focus = true;
topMenu.forceActiveFocus();
// show current menu level on nav bar
if (topMenu.objectName === "") {
if (topMenu.objectName === "" || d.depth === 1) {
breadcrumbText.text = "Menu";
} else {
if (menuStack.length === 1) {
breadcrumbText.text = "Menu";
} else {
breadcrumbText.text = topMenu.objectName;
}
breadcrumbText.text = topMenu.objectName;
}
} else {
breadcrumbText.text = "Menu";
@ -100,16 +102,14 @@ Item {
}
function pushMenu(newMenu) {
menuStack.push(newMenu);
d.push({ item:newMenu, destroyOnPop: true});
topMenu = newMenu;
topMenu.focus = true;
topMenu.forceActiveFocus();
}
function clearMenus() {
while (menuStack.length) {
popMenu()
}
d.clear()
}
function clampMenuPosition(menu) {
@ -127,7 +127,7 @@ Item {
}
}
function buildMenu(items, targetPosition) {
function buildMenu(items) {
var model = toModel(items);
// Menus must be childed to desktop for Z-ordering
var newMenu = menuViewMaker.createObject(tabletMenu, { model: model, isSubMenu: topMenu !== null });
@ -158,13 +158,13 @@ Item {
}
function popup(parent, items) {
function popup(items) {
d.clearMenus();
d.buildMenu(items, point);
d.buildMenu(items);
}
function closeLastMenu() {
if (d.menuStack.length > 1) {
if (d.depth > 1) {
d.popMenu();
return true;
}

View file

@ -0,0 +1,42 @@
//
// TabletNetworkingPreferences.qml
//
// Created by Davd Rowe on 7 Mar 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
//
import QtQuick 2.5
import "tabletWindows"
import "../../dialogs"
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
StackView {
id: profileRoot
initialItem: root
objectName: "stack"
property var eventBridge;
signal sendToScript(var message);
function pushSource(path) {
editRoot.push(Qt.reslovedUrl(path));
}
function popSource() {
}
TabletPreferencesDialog {
id: root
property string title: "Networking Settings"
objectName: "NetworkingPreferences"
width: parent.width
height: parent.height
showCategories: ["Networking"]
}
}

View file

@ -1,5 +1,7 @@
import QtQuick 2.0
import Hifi 1.0
import QtQuick.Controls 1.4
import "../../dialogs"
Item {
id: tabletRoot
@ -8,19 +10,50 @@ Item {
property var eventBridge;
property var rootMenu;
property var openModal: null;
property var openMessage: null;
property string subMenu: ""
signal showDesktop();
function setOption(value) {
option = value;
}
Component { id: inputDialogBuilder; TabletQueryDialog { } }
function inputDialog(properties) {
openModal = inputDialogBuilder.createObject(tabletRoot, properties);
return openModal;
}
Component { id: messageBoxBuilder; TabletMessageBox { } }
function messageBox(properties) {
openMessage = messageBoxBuilder.createObject(tabletRoot, properties);
return openMessage;
}
Component { id: customInputDialogBuilder; TabletCustomQueryDialog { } }
function customInputDialog(properties) {
return customInputDialogBuilder.createObject(tabletRoot, properties);
}
Component { id: fileDialogBuilder; TabletFileDialog { } }
function fileDialog(properties) {
openModal = fileDialogBuilder.createObject(tabletRoot, properties);
return openModal;
}
function setMenuProperties(rootMenu, subMenu) {
tabletRoot.rootMenu = rootMenu;
tabletRoot.subMenu = subMenu;
}
function isDialogOpen() {
if (openMessage !== null || openModal !== null) {
return true;
}
return false;
}
function loadSource(url) {
loader.source = ""; // make sure we load the qml fresh each time.
loader.source = url;
@ -68,6 +101,7 @@ Item {
objectName: "loader"
asynchronous: false
width: parent.width
height: parent.height
@ -89,6 +123,12 @@ Item {
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
}
loader.item.forceActiveFocus();
if (openModal) {
openModal.canceled();
openModal.destroy();
openModal = null;
}
}
}

View file

@ -27,12 +27,22 @@ Item {
HifiConstants { id: hifi }
property var sections: []
property var showCategories: []
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
property var tablet;
function saveAll() {
dialog.forceActiveFocus(); // Accept any text box edits in progress.
for (var i = 0; i < sections.length; ++i) {
var section = sections[i];
section.saveAll();
}
closeDialog();
}
function restoreAll() {
@ -40,22 +50,59 @@ Item {
var section = sections[i];
section.restoreAll();
}
closeDialog();
}
function closeDialog() {
Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen();
}
Rectangle {
id: main
height: parent.height - 40
id: header
height: 90
anchors {
top: parent.top
bottom: footer.top
left: parent.left
right: parent.right
}
z: 100
gradient: Gradient {
GradientStop {
position: 0
color: "#2b2b2b"
}
GradientStop {
position: 1
color: "#1e1e1e"
}
}
RalewayBold {
text: title
size: 26
color: "#34a2c7"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: hifi.dimensions.contentMargin.x
}
}
Rectangle {
id: main
anchors {
top: header.bottom
bottom: footer.top
left: parent.left
right: parent.right
}
gradient: Gradient {
GradientStop {
position: 0
color: "#2b2b2b"
}
GradientStop {
@ -110,9 +157,7 @@ Item {
}
scrollView.contentHeight = scrollView.getSectionsHeight();
}
Column {
id: prefControls
@ -131,13 +176,30 @@ Item {
}
}
MouseArea {
// Defocuses the current control so that the HMD keyboard gets hidden.
// Created under the footer so that the non-button part of the footer can defocus a control.
id: mouseArea
anchors {
top: parent.top
left: parent.left
right: parent.right
bottom: keyboard.top
}
propagateComposedEvents: true
acceptedButtons: Qt.AllButtons
onPressed: {
parent.forceActiveFocus();
mouse.accepted = false;
}
}
Rectangle {
id: footer
height: 40
anchors {
top: main.bottom
bottom: parent.bottom
bottom: keyboard.top
left: parent.left
right: parent.right
}
@ -145,7 +207,6 @@ Item {
GradientStop {
position: 0
color: "#2b2b2b"
}
GradientStop {
@ -156,7 +217,7 @@ Item {
Row {
anchors {
top: parent,top
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: hifi.dimensions.contentMargin.x
}
@ -165,15 +226,39 @@ Item {
HifiControls.Button {
text: "Save changes"
color: hifi.buttons.blue
onClicked: root.saveAll()
onClicked: dialog.saveAll()
}
HifiControls.Button {
text: "Cancel"
color: hifi.buttons.white
onClicked: root.restoreAll()
onClicked: dialog.restoreAll()
}
}
}
HifiControls.Keyboard {
id: keyboard
raised: parent.keyboardEnabled && parent.keyboardRaised
numeric: parent.punctuationMode
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
}
Component.onCompleted: {
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
keyboardEnabled = HMD.active;
}
onKeyboardRaisedChanged: {
if (keyboardEnabled && keyboardRaised) {
var delta = mouseArea.mouseY - (dialog.height - footer.height - keyboard.raisedHeight -hifi.dimensions.controlLineHeight);
if (delta > 0) {
scrollView.contentY += delta;
}
}
}
}

View file

@ -14,7 +14,7 @@ import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
FontLoader { id: firaSansSemiBold; source: pathToFonts + "fonts/FiraSans-SemiBold.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter

View file

@ -14,7 +14,7 @@ import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: hiFiGlyphs; source: "../../fonts/hifi-glyphs.ttf"; }
FontLoader { id: hiFiGlyphs; source: pathToFonts + "fonts/hifi-glyphs.ttf"; }
property int size: 32
font.pixelSize: size
width: size

View file

@ -159,6 +159,7 @@ Item {
readonly property vector2d menuPadding: Qt.vector2d(14, 102)
readonly property real scrollbarBackgroundWidth: 18
readonly property real scrollbarHandleWidth: scrollbarBackgroundWidth - 2
readonly property real tabletMenuHeader: 90
}
Item {

View file

@ -14,7 +14,7 @@ import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: ralewayBold; source: "../../fonts/Raleway-Bold.ttf"; }
FontLoader { id: ralewayBold; source: pathToFonts + "fonts/Raleway-Bold.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter

View file

@ -14,7 +14,7 @@ import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: ralewayRegular; source: "../../fonts/Raleway-Regular.ttf"; }
FontLoader { id: ralewayRegular; source: pathToFonts + "fonts/Raleway-Regular.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter

View file

@ -14,7 +14,7 @@ import QtQuick.Controls.Styles 1.4
Text {
id: root
FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; }
FontLoader { id: ralewaySemiBold; source: pathToFonts + "fonts/Raleway-SemiBold.ttf"; }
property real size: 32
font.pixelSize: size
verticalAlignment: Text.AlignVCenter

View file

@ -0,0 +1,89 @@
//
// ModalFrame.qml
//
// Created by Bradley Austin Davis on 15 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import "."
import "../controls-uit"
import "../styles-uit"
Rectangle {
HifiConstants { id: hifi }
id: frameContent
readonly property bool hasTitle: root.title != ""
readonly property int frameMarginLeft: hifi.dimensions.modalDialogMargin.x
readonly property int frameMarginRight: hifi.dimensions.modalDialogMargin.x
readonly property int frameMarginTop: hifi.dimensions.modalDialogMargin.y + (frameContent.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0)
readonly property int frameMarginBottom: hifi.dimensions.modalDialogMargin.y
border {
width: hifi.dimensions.borderWidth
color: hifi.colors.lightGrayText80
}
radius: hifi.dimensions.borderRadius
color: hifi.colors.faintGray
Item {
id: frameTitle
visible: frameContent.hasTitle
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
fill: parent
topMargin: frameMarginTop
leftMargin: frameMarginLeft
rightMargin: frameMarginRight
//bottomMargin: frameMarginBottom
}
Item {
width: title.width + (icon.text !== "" ? icon.width + hifi.dimensions.contentSpacing.x : 20)
onWidthChanged: root.titleWidth = width
HiFiGlyphs {
id: icon
text: root.iconText ? root.iconText : ""
size: root.iconSize ? root.iconSize : 30
color: hifi.colors.lightGray
visible: true
anchors.verticalCenter: title.verticalCenter
anchors.leftMargin: 50
anchors.left: parent.left
}
RalewayRegular {
id: title
text: root.title
elide: Text.ElideRight
color: hifi.colors.baseGrayHighlight
size: hifi.fontSizes.overlayTitle
y: -hifi.dimensions.modalDialogTitleHeight
anchors.rightMargin: -50
anchors.right: parent.right
//anchors.horizontalCenter: parent.horizontalCenter
}
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: hifi.colors.lightGray
}
}
}

View file

@ -0,0 +1,22 @@
//
// ModalWindow.qml
//
// Created by Bradley Austin Davis on 22 Jan 2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import "."
Rectangle {
id: modalWindow
layer.enabled: true
property var title: "Modal"
width: tabletRoot.width
height: tabletRoot.height
color: "#80000000"
}

View file

@ -313,6 +313,6 @@ Fadable {
}
}
onMouseEntered: console.log("Mouse entered " + window)
onMouseExited: console.log("Mouse exited " + window)
// onMouseEntered: console.log("Mouse entered " + window)
// onMouseExited: console.log("Mouse exited " + window)
}

View file

@ -499,6 +499,7 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::set<TabletScriptingInterface>();
DependencyManager::set<ToolbarScriptingInterface>();
DependencyManager::set<UserActivityLoggerScriptingInterface>();
DependencyManager::set<AssetMappingsScriptingInterface>();
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
DependencyManager::set<SpeechRecognizer>();
@ -847,6 +848,9 @@ 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, [](){
qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode());
});
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode);
// Save avatar location immediately after a teleport.
@ -1619,17 +1623,14 @@ QString Application::getUserAgent() {
return userAgent;
}
uint64_t lastTabletUIToggle { 0 };
const uint64_t toggleTabletUILockout { 500000 };
void Application::toggleTabletUI() const {
uint64_t now = usecTimestampNow();
if (now - lastTabletUIToggle < toggleTabletUILockout) {
return;
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
bool messageOpen = tablet->isMessageDialogOpen();
if (!messageOpen) {
auto HMD = DependencyManager::get<HMDScriptingInterface>();
HMD->toggleShouldShowTablet();
}
lastTabletUIToggle = now;
auto HMD = DependencyManager::get<HMDScriptingInterface>();
HMD->toggleShouldShowTablet();
}
void Application::checkChangeCursor() {
@ -1961,12 +1962,13 @@ void Application::initializeUi() {
rootContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
rootContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface);
rootContext->setContextProperty("Rates", new RatesScriptingInterface(this));
rootContext->setContextProperty("pathToFonts", "../../");
rootContext->setContextProperty("TREE_SCALE", TREE_SCALE);
rootContext->setContextProperty("Quat", new Quat());
rootContext->setContextProperty("Vec3", new Vec3());
rootContext->setContextProperty("Uuid", new ScriptUUID());
rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface());
rootContext->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
rootContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
rootContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
@ -5790,8 +5792,23 @@ bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name)
}
void Application::toggleRunningScriptsWidget() const {
static const QUrl url("hifi/dialogs/RunningScripts.qml");
DependencyManager::get<OffscreenUi>()->show(url, "RunningScripts");
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode()) {
static const QUrl url("hifi/dialogs/RunningScripts.qml");
DependencyManager::get<OffscreenUi>()->show(url, "RunningScripts");
} else {
QQuickItem* tabletRoot = tablet->getTabletRoot();
if (!tabletRoot && !isHMDMode()) {
static const QUrl url("hifi/dialogs/RunningScripts.qml");
DependencyManager::get<OffscreenUi>()->show(url, "RunningScripts");
} else {
static const QUrl url("../../hifi/dialogs/TabletRunningScripts.qml");
tablet->pushOntoStack(url);
}
}
//DependencyManager::get<OffscreenUi>()->show(url, "RunningScripts");
//if (_runningScriptsWidget->isVisible()) {
// if (_runningScriptsWidget->hasFocus()) {
// _runningScriptsWidget->hide();
@ -5818,7 +5835,21 @@ void Application::showAssetServerWidget(QString filePath) {
emit uploadRequest(filePath);
}
};
DependencyManager::get<OffscreenUi>()->show(url, "AssetServer", startUpload);
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode()) {
DependencyManager::get<OffscreenUi>()->show(url, "AssetServer", startUpload);
} else {
QQuickItem* tabletRoot = tablet->getTabletRoot();
if (!tabletRoot && !isHMDMode()) {
DependencyManager::get<OffscreenUi>()->show(url, "AssetServer", startUpload);
} else {
static const QUrl url("../../hifi/dialogs/TabletAssetServer.qml");
tablet->pushOntoStack(url);
}
}
startUpload(nullptr, nullptr);
}
@ -5841,6 +5872,16 @@ void Application::addAssetToWorldFromURL(QString url) {
request->send();
}
void Application::showDialog(const QString& desktopURL, const QString& tabletURL, const QString& name) const {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode() || (!tablet->getTabletRoot() && !isHMDMode())) {
DependencyManager::get<OffscreenUi>()->show(desktopURL, name);
} else {
tablet->loadQMLSource(tabletURL);
}
}
void Application::addAssetToWorldFromURLRequestFinished() {
auto request = qobject_cast<ResourceRequest*>(sender());
auto url = request->getUrl().toString();
@ -6908,6 +6949,7 @@ void Application::updateThreadPoolCount() const {
}
void Application::updateSystemTabletMode() {
qApp->setProperty(hifi::properties::HMD, isHMDMode());
if (isHMDMode()) {
DependencyManager::get<TabletScriptingInterface>()->setToolbarMode(getHmdTabletBecomesToolbarSetting());
} else {

View file

@ -333,6 +333,8 @@ public slots:
void toggleRunningScriptsWidget() const;
Q_INVOKABLE void showAssetServerWidget(QString filePath = "");
void showDialog(const QString& desktopURL, const QString& tabletURL, const QString& name) const;
// FIXME: Move addAssetToWorld* methods to own class?
void addAssetToWorldFromURL(QString url);
void addAssetToWorldFromURLRequestFinished();

View file

@ -294,13 +294,15 @@ Menu::Menu() {
// Settings > General...
action = addActionToQMenuAndActionHash(settingsMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_Comma, nullptr, nullptr, QAction::PreferencesRole);
connect(action, &QAction::triggered, [] {
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/GeneralPreferencesDialog.qml"), "GeneralPreferencesDialog");
qApp->showDialog(QString("hifi/dialogs/GeneralPreferencesDialog.qml"),
QString("../../hifi/tablet/TabletGeneralPreferences.qml"), "GeneralPreferencesDialog");
});
// Settings > Avatar...
action = addActionToQMenuAndActionHash(settingsMenu, "Avatar...");
connect(action, &QAction::triggered, [] {
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/AvatarPreferencesDialog.qml"), "AvatarPreferencesDialog");
qApp->showDialog(QString("hifi/dialogs/AvatarPreferencesDialog.qml"),
QString("../../hifi/tablet/TabletAvatarPreferences.qml"), "AvatarPreferencesDialog");
});
// Settings > LOD...
@ -550,8 +552,8 @@ Menu::Menu() {
MenuWrapper* networkMenu = developerMenu->addMenu("Network");
action = addActionToQMenuAndActionHash(networkMenu, MenuOption::Networking);
connect(action, &QAction::triggered, [] {
DependencyManager::get<OffscreenUi>()->toggle(QUrl("hifi/dialogs/NetworkingPreferencesDialog.qml"),
"NetworkingPreferencesDialog");
qApp->showDialog(QString("hifi/dialogs/NetworkingPreferencesDialog.qml"),
QString("../../hifi/tablet/TabletNetworkingPreferences.qml"), "NetworkingPreferencesDialog");
});
addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()));
addCheckableActionToQMenuAndActionHash(networkMenu,
@ -612,7 +614,8 @@ Menu::Menu() {
action = addActionToQMenuAndActionHash(audioDebugMenu, "Buffers...");
connect(action, &QAction::triggered, [] {
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/AudioPreferencesDialog.qml"), "AudioPreferencesDialog");
qApp->showDialog(QString("hifi/dialogs/AudioPreferencesDialog.qml"),
QString("../../hifi/tablet/TabletAudioPreferences.qml"), "AudioPreferencesDialog");
});
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, 0, true,

View file

@ -20,6 +20,8 @@
#include <AssetClient.h>
#include <QSortFilterProxyModel>
#include "DependencyManager.h"
class AssetMappingModel : public QStandardItemModel {
Q_OBJECT
@ -39,10 +41,12 @@ private:
QHash<QString, QStandardItem*> _pathToItemMap;
};
Q_DECLARE_METATYPE(AssetMappingModel*);
Q_DECLARE_METATYPE(AssetMappingModel*)
class AssetMappingsScriptingInterface : public QObject {
class AssetMappingsScriptingInterface : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT)
Q_PROPERTY(QAbstractProxyModel* proxyModel READ getProxyModel CONSTANT)
public:

View file

@ -81,6 +81,10 @@ void HMDScriptingInterface::closeTablet() {
_showTablet = false;
}
void HMDScriptingInterface::openTablet() {
_showTablet = true;
}
QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
glm::vec3 hudIntersection;
auto instance = DependencyManager::get<HMDScriptingInterface>();
@ -131,7 +135,7 @@ glm::quat HMDScriptingInterface::getOrientation() const {
return glm::quat();
}
bool HMDScriptingInterface::isMounted() const{
bool HMDScriptingInterface::isMounted() const {
auto displayPlugin = qApp->getActiveDisplayPlugin();
return (displayPlugin->isHmd() && displayPlugin->isDisplayVisible());
}

View file

@ -76,6 +76,8 @@ public:
Q_INVOKABLE void closeTablet();
Q_INVOKABLE void openTablet();
signals:
bool shouldShowHandControllersChanged();

View file

@ -100,6 +100,9 @@ void Overlay::setProperties(const QVariantMap& properties) {
}
QVariant Overlay::getProperty(const QString& property) {
if (property == "type") {
return QVariant(getType());
}
if (property == "color") {
return xColorToVariant(_color);
}

View file

@ -711,10 +711,9 @@ PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay r
auto dimensions = thisOverlay->getSize();
glm::vec2 pos2D = projectOntoOverlayXYPlane(position, rotation, dimensions, ray, rayPickResult);
PointerEvent pointerEvent(eventType, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
PointerEvent pointerEvent(eventType, MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal,
ray.direction, toPointerButton(*event), toPointerButtons(*event), event->modifiers());
return pointerEvent;
}

View file

@ -37,8 +37,12 @@
#include <AddressManager.h>
#include "scripting/AccountScriptingInterface.h"
#include "scripting/HMDScriptingInterface.h"
#include "scripting/AssetMappingsScriptingInterface.h"
#include <Preferences.h>
#include <ScriptEngines.h>
#include "FileDialogHelper.h"
#include "avatar/AvatarManager.h"
#include "AudioClient.h"
static const float DPI = 30.47f;
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
@ -161,6 +165,10 @@ void Web3DOverlay::loadSourceURL() {
_webSurface->getRootContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
_webSurface->getRootContext()->setContextProperty("Vec3", new Vec3());
_webSurface->getRootContext()->setContextProperty("Quat", new Quat());
_webSurface->getRootContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
_webSurface->getRootContext()->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
@ -168,17 +176,30 @@ void Web3DOverlay::loadSourceURL() {
_webSurface->getRootContext()->setContextProperty("offscreenFlags", flags);
_webSurface->getRootContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
_webSurface->getRootContext()->setContextProperty("Account", AccountScriptingInterface::getInstance());
_webSurface->getRootContext()->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
_webSurface->getRootContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
_webSurface->getRootContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
_webSurface->getRootContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
_webSurface->getRootContext()->setContextProperty("pathToFonts", "../../");
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data());
// Override min fps for tablet UI, for silky smooth scrolling
_webSurface->setMaxFps(90);
setMaxFPS(90);
}
}
_webSurface->getRootContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
}
void Web3DOverlay::setMaxFPS(uint8_t maxFPS) {
_desiredMaxFPS = maxFPS;
if (_webSurface) {
_webSurface->setMaxFps(_desiredMaxFPS);
_currentMaxFPS = _desiredMaxFPS;
}
}
void Web3DOverlay::render(RenderArgs* args) {
if (!_visible || !getParentVisible()) {
return;
@ -188,9 +209,11 @@ void Web3DOverlay::render(RenderArgs* args) {
QSurface * currentSurface = currentContext->surface();
if (!_webSurface) {
_webSurface = DependencyManager::get<OffscreenQmlSurfaceCache>()->acquire(pickURL());
_webSurface->setMaxFps(10);
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
// and the current rendering load)
if (_currentMaxFPS != _desiredMaxFPS) {
setMaxFPS(_desiredMaxFPS);
}
loadSourceURL();
_webSurface->resume();
_webSurface->resize(QSize(_resolution.x, _resolution.y));
@ -240,6 +263,10 @@ void Web3DOverlay::render(RenderArgs* args) {
_emitScriptEventConnection = connect(this, &Web3DOverlay::scriptEventReceived, _webSurface.data(), &OffscreenQmlSurface::emitScriptEvent);
_webEventReceivedConnection = connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived);
} else {
if (_currentMaxFPS != _desiredMaxFPS) {
setMaxFPS(_desiredMaxFPS);
}
}
vec2 halfSize = getSize() / 2.0f;
@ -353,9 +380,8 @@ void Web3DOverlay::handlePointerEvent(const PointerEvent& event) {
QList<QTouchEvent::TouchPoint> touchPoints;
touchPoints.push_back(point);
QTouchEvent* touchEvent = new QTouchEvent(type);
QTouchEvent* touchEvent = new QTouchEvent(type, &_touchDevice, event.getKeyboardModifiers());
touchEvent->setWindow(_webSurface->getWindow());
touchEvent->setDevice(&_touchDevice);
touchEvent->setTarget(_webSurface->getRootItem());
touchEvent->setTouchPoints(touchPoints);
touchEvent->setTouchPointStates(touchPointState);
@ -396,6 +422,11 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
_dpi = dpi.toFloat();
}
auto maxFPS = properties["maxFPS"];
if (maxFPS.isValid()) {
_desiredMaxFPS = maxFPS.toInt();
}
auto showKeyboardFocusHighlight = properties["showKeyboardFocusHighlight"];
if (showKeyboardFocusHighlight.isValid()) {
_showKeyboardFocusHighlight = showKeyboardFocusHighlight.toBool();
@ -415,6 +446,9 @@ QVariant Web3DOverlay::getProperty(const QString& property) {
if (property == "dpi") {
return _dpi;
}
if (property == "maxFPS") {
return _desiredMaxFPS;
}
if (property == "showKeyboardFocusHighlight") {
return _showKeyboardFocusHighlight;
}

View file

@ -31,6 +31,7 @@ public:
QString pickURL();
void loadSourceURL();
void setMaxFPS(uint8_t maxFPS);
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
@ -75,6 +76,9 @@ private:
bool _pressed{ false };
QTouchDevice _touchDevice;
uint8_t _desiredMaxFPS { 10 };
uint8_t _currentMaxFPS { 0 };
QMetaObject::Connection _mousePressConnection;
QMetaObject::Connection _mouseReleaseConnection;
QMetaObject::Connection _mouseMoveConnection;

View file

@ -713,7 +713,8 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit mousePressOnEntity(rayPickResult.entityID, pointerEvent);
@ -753,7 +754,8 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit mouseReleaseOnEntity(rayPickResult.entityID, pointerEvent);
if (_entitiesScriptEngine) {
@ -773,7 +775,8 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit clickReleaseOnEntity(_currentClickingOnEntityID, pointerEvent);
if (_entitiesScriptEngine) {
@ -803,7 +806,8 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit mouseMoveOnEntity(rayPickResult.entityID, pointerEvent);
@ -823,7 +827,8 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
if (_entitiesScriptEngine) {
@ -864,7 +869,8 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
if (_entitiesScriptEngine) {
@ -883,7 +889,8 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event));
toPointerButton(*event), toPointerButtons(*event),
Qt::NoModifier); // TODO -- check for modifier keys?
emit holdingClickOnEntity(_currentClickingOnEntityID, pointerEvent);
if (_entitiesScriptEngine) {

View file

@ -32,6 +32,7 @@
#include <AccountManager.h>
#include <NetworkAccessManager.h>
#include <GLMHelpers.h>
#include <shared/GlobalAppProperties.h>
#include "OffscreenGLCanvas.h"
#include "GLHelpers.h"
@ -433,6 +434,7 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
auto rootContext = getRootContext();
rootContext->setContextProperty("urlHandler", new UrlHandler());
rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath()));
rootContext->setContextProperty("pathToFonts", "../../");
}
static uvec2 clampSize(const uvec2& size, uint32_t maxDimension) {
@ -911,20 +913,23 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n
return;
}
QQuickItem* item = dynamic_cast<QQuickItem*>(object);
while (item) {
// Numeric value may be set in parameter from HTML UI; for QML UI, detect numeric fields here.
numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox";
// if HMD is being worn, allow keyboard to open. allow it to close, HMD or not.
if (!raised || qApp->property(hifi::properties::HMD).toBool()) {
QQuickItem* item = dynamic_cast<QQuickItem*>(object);
while (item) {
// Numeric value may be set in parameter from HTML UI; for QML UI, detect numeric fields here.
numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox";
if (item->property("keyboardRaised").isValid()) {
// FIXME - HMD only: Possibly set value of "keyboardEnabled" per isHMDMode() for use in WebView.qml.
if (item->property("punctuationMode").isValid()) {
item->setProperty("punctuationMode", QVariant(numeric));
if (item->property("keyboardRaised").isValid()) {
// FIXME - HMD only: Possibly set value of "keyboardEnabled" per isHMDMode() for use in WebView.qml.
if (item->property("punctuationMode").isValid()) {
item->setProperty("punctuationMode", QVariant(numeric));
}
item->setProperty("keyboardRaised", QVariant(raised));
return;
}
item->setProperty("keyboardRaised", QVariant(raised));
return;
item = dynamic_cast<QQuickItem*>(item->parentItem());
}
item = dynamic_cast<QQuickItem*>(item->parentItem());
}
}

View file

@ -250,6 +250,18 @@ static QString getUsername() {
}
}
bool TabletProxy::isMessageDialogOpen() {
if (_qmlTabletRoot) {
QVariant result;
QMetaObject::invokeMethod(_qmlTabletRoot, "isDialogOpen",Qt::DirectConnection,
Q_RETURN_ARG(QVariant, result));
return result.toBool();
}
return false;
}
void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface) {
std::lock_guard<std::mutex> guard(_mutex);
_qmlOffscreenSurface = qmlOffscreenSurface;
@ -275,7 +287,8 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL)));
}
gotoHomeScreen();
// force to the tablet to go to the homescreen
loadHomeScreen(true);
QMetaObject::invokeMethod(_qmlTabletRoot, "setUsername", Q_ARG(const QVariant&, QVariant(getUsername())));
@ -293,6 +306,9 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr
}
}
void TabletProxy::gotoHomeScreen() {
loadHomeScreen(false);
}
void TabletProxy::gotoMenuScreen(const QString& submenu) {
QObject* root = nullptr;
@ -331,11 +347,53 @@ void TabletProxy::loadQMLSource(const QVariant& path) {
emit screenChanged(QVariant("QML"), path);
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
}
} else {
qCDebug(scriptengine) << "tablet cannot load QML because _qmlTabletRoot is null";
}
}
void TabletProxy::gotoHomeScreen() {
if (_state != State::Home) {
void TabletProxy::pushOntoStack(const QVariant& path) {
if (_qmlTabletRoot) {
auto stack = _qmlTabletRoot->findChild<QQuickItem*>("stack");
if (stack) {
QMetaObject::invokeMethod(stack, "pushSource", Q_ARG(const QVariant&, path));
} else {
qCDebug(scriptengine) << "tablet cannot push QML because _qmlTabletRoot doesn't have child stack";
}
} else if (_desktopWindow) {
auto stack = _desktopWindow->asQuickItem()->findChild<QQuickItem*>("stack");
if (stack) {
QMetaObject::invokeMethod(stack, "pushSource", Q_ARG(const QVariant&, path));
} else {
qCDebug(scriptengine) << "tablet cannot push QML because _desktopWindow doesn't have child stack";
}
} else {
qCDebug(scriptengine) << "tablet cannot push QML because _qmlTabletRoot or _desktopWindow is null";
}
}
void TabletProxy::popFromStack() {
if (_qmlTabletRoot) {
auto stack = _qmlTabletRoot->findChild<QQuickItem*>("stack");
if (stack) {
QMetaObject::invokeMethod(stack, "popSource");
} else {
qCDebug(scriptengine) << "tablet cannot push QML because _qmlTabletRoot doesn't have child stack";
}
} else if (_desktopWindow) {
auto stack = _desktopWindow->asQuickItem()->findChild<QQuickItem*>("stack");
if (stack) {
QMetaObject::invokeMethod(stack, "popSource");
} else {
qCDebug(scriptengine) << "tablet cannot pop QML because _desktopWindow doesn't have child stack";
}
} else {
qCDebug(scriptengine) << "tablet cannot pop QML because _qmlTabletRoot or _desktopWindow is null";
}
}
void TabletProxy::loadHomeScreen(bool forceOntoHomeScreen) {
if ((_state != State::Home && _state != State::Uninitialized) || forceOntoHomeScreen) {
if (!_toolbarMode && _qmlTabletRoot) {
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen()), Qt::DirectConnection);
@ -560,7 +618,7 @@ QQuickItem* TabletProxy::getQmlTablet() const {
}
QQuickItem* TabletProxy::getQmlMenu() const {
if (!_qmlTabletRoot) {
if (!_qmlTabletRoot) {
return nullptr;
}

View file

@ -106,6 +106,14 @@ public:
Q_INVOKABLE void gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl);
Q_INVOKABLE void loadQMLSource(const QVariant& path);
Q_INVOKABLE void pushOntoStack(const QVariant& path);
Q_INVOKABLE void popFromStack();
/** jsdoc
* Check if the tablet has a message dialog open
* @function TabletProxy#isMessageDialogOpen
*/
Q_INVOKABLE bool isMessageDialogOpen();
/**jsdoc
* Creates a new button, adds it to this and returns it.
@ -150,8 +158,14 @@ public:
*/
Q_INVOKABLE void sendToQml(QVariant msg);
/**jsdoc
* Check if the tablet is on the homescreen
* @function TabletProxy#onHomeScreen()
*/
Q_INVOKABLE bool onHomeScreen();
QQuickItem* getTabletRoot() const { return _qmlTabletRoot; }
QObject* getTabletSurface();
QQuickItem* getQmlTablet() const;
@ -188,6 +202,7 @@ protected slots:
void desktopWindowClosed();
protected:
void removeButtonsFromHomeScreen();
void loadHomeScreen(bool forceOntoHomeScreen);
void addButtonsToToolbar();
void removeButtonsFromToolbar();

View file

@ -25,9 +25,9 @@ PointerEvent::PointerEvent() {
}
PointerEvent::PointerEvent(EventType type, uint32_t id,
const glm::vec2& pos2D, const glm::vec3& pos3D,
const glm::vec3& normal, const glm::vec3& direction,
Button button, uint32_t buttons) :
const glm::vec2& pos2D, const glm::vec3& pos3D,
const glm::vec3& normal, const glm::vec3& direction,
Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers) :
_type(type),
_id(id),
_pos2D(pos2D),
@ -35,7 +35,8 @@ PointerEvent::PointerEvent(EventType type, uint32_t id,
_normal(normal),
_direction(direction),
_button(button),
_buttons(buttons)
_buttons(buttons),
_keyboardModifiers(keyboardModifiers)
{
;
}
@ -119,6 +120,8 @@ QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEve
obj.setProperty("isSecondaryHeld", areFlagsSet(event._buttons, SecondaryButton));
obj.setProperty("isTertiaryHeld", areFlagsSet(event._buttons, TertiaryButton));
obj.setProperty("keyboardModifiers", QScriptValue(event.getKeyboardModifiers()));
return obj;
}
@ -174,5 +177,7 @@ void PointerEvent::fromScriptValue(const QScriptValue& object, PointerEvent& eve
if (tertiary) {
event._buttons |= TertiaryButton;
}
event._keyboardModifiers = (Qt::KeyboardModifiers)(object.property("keyboardModifiers").toUInt32());
}
}

View file

@ -12,6 +12,8 @@
#ifndef hifi_PointerEvent_h
#define hifi_PointerEvent_h
#include <Qt>
#include <stdint.h>
#include <glm/glm.hpp>
#include <QScriptValue>
@ -35,7 +37,7 @@ public:
PointerEvent(EventType type, uint32_t id,
const glm::vec2& pos2D, const glm::vec3& pos3D,
const glm::vec3& normal, const glm::vec3& direction,
Button button, uint32_t buttons);
Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers);
static QScriptValue toScriptValue(QScriptEngine* engine, const PointerEvent& event);
static void fromScriptValue(const QScriptValue& object, PointerEvent& event);
@ -50,6 +52,7 @@ public:
const glm::vec3& getDirection() const { return _direction; }
Button getButton() const { return _button; }
uint32_t getButtons() const { return _buttons; }
Qt::KeyboardModifiers getKeyboardModifiers() const { return _keyboardModifiers; }
private:
EventType _type;
@ -61,6 +64,7 @@ private:
Button _button { NoButtons }; // button assosiated with this event, (if type is Press, this will be the button that is pressed)
uint32_t _buttons { NoButtons }; // the current state of all the buttons.
Qt::KeyboardModifiers _keyboardModifiers; // set of keys held when event was generated
};
Q_DECLARE_METATYPE(PointerEvent)

View file

@ -16,6 +16,7 @@ namespace hifi { namespace properties {
const char* OCULUS_STORE = "com.highfidelity.oculusStore";
const char* TEST = "com.highfidelity.test";
const char* TRACING = "com.highfidelity.tracing";
const char* HMD = "com.highfidelity.hmd";
namespace gl {
const char* BACKEND = "com.highfidelity.gl.backend";

View file

@ -18,6 +18,7 @@ namespace hifi { namespace properties {
extern const char* OCULUS_STORE;
extern const char* TEST;
extern const char* TRACING;
extern const char* HMD;
namespace gl {
extern const char* BACKEND;

View file

@ -1,3 +1,3 @@
set(TARGET_NAME ui)
setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebSockets XmlPatterns)
link_hifi_libraries(shared networking gl)
link_hifi_libraries(shared networking gl script-engine)

View file

@ -19,7 +19,8 @@
#include <AbstractUriHandler.h>
#include <AccountManager.h>
#include <DependencyManager.h>
#include <TabletScriptingInterface.h>
#include "FileDialogHelper.h"
#include "VrMenu.h"
@ -210,9 +211,19 @@ QQuickItem* OffscreenUi::createMessageBox(Icon icon, const QString& title, const
map.insert("buttons", buttons.operator int());
map.insert("defaultButton", defaultButton);
QVariant result;
bool invokeResult = QMetaObject::invokeMethod(_desktop, "messageBox",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
bool invokeResult;
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode()) {
invokeResult = QMetaObject::invokeMethod(_desktop, "messageBox",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
} else {
QQuickItem* tabletRoot = tablet->getTabletRoot();
invokeResult = QMetaObject::invokeMethod(tabletRoot, "messageBox",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
}
if (!invokeResult) {
qWarning() << "Failed to create message box";
@ -405,10 +416,21 @@ QQuickItem* OffscreenUi::createInputDialog(const Icon icon, const QString& title
map.insert("label", label);
map.insert("current", current);
QVariant result;
bool invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
bool invokeResult;
if (tablet->getToolbarMode()) {
invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
} else {
QQuickItem* tabletRoot = tablet->getTabletRoot();
invokeResult = QMetaObject::invokeMethod(tabletRoot, "inputDialog",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
}
if (!invokeResult) {
qWarning() << "Failed to create message box";
return nullptr;
@ -422,10 +444,21 @@ QQuickItem* OffscreenUi::createCustomInputDialog(const Icon icon, const QString&
map.insert("title", title);
map.insert("icon", icon);
QVariant result;
bool invokeResult = QMetaObject::invokeMethod(_desktop, "customInputDialog",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
bool invokeResult;
if (tablet->getToolbarMode()) {
invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
} else {
QQuickItem* tabletRoot = tablet->getTabletRoot();
invokeResult = QMetaObject::invokeMethod(tabletRoot, "inputDialog",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
}
if (!invokeResult) {
qWarning() << "Failed to create custom message box";
return nullptr;
@ -569,9 +602,19 @@ private slots:
QString OffscreenUi::fileDialog(const QVariantMap& properties) {
QVariant buildDialogResult;
bool invokeResult = QMetaObject::invokeMethod(_desktop, "fileDialog",
Q_RETURN_ARG(QVariant, buildDialogResult),
Q_ARG(QVariant, QVariant::fromValue(properties)));
bool invokeResult;
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode()) {
invokeResult = QMetaObject::invokeMethod(_desktop, "fileDialog",
Q_RETURN_ARG(QVariant, buildDialogResult),
Q_ARG(QVariant, QVariant::fromValue(properties)));
} else {
QQuickItem* tabletRoot = tablet->getTabletRoot();
invokeResult = QMetaObject::invokeMethod(tabletRoot, "fileDialog",
Q_RETURN_ARG(QVariant, buildDialogResult),
Q_ARG(QVariant, QVariant::fromValue(properties)));
}
if (!invokeResult) {
qWarning() << "Failed to create file open dialog";

View file

@ -1,5 +1,5 @@
//
// stats.qml
// Stats.qml
// scripts/developer/utilities/audio
//
// Created by Zach Pomerantz on 9/22/2016
@ -12,22 +12,21 @@ import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
import "../../../../resources/qml/controls-uit" as HifiControls
Column {
id: stats
width: parent.width
height: parent.height
property bool showGraphs: toggleGraphs.checked
RowLayout {
Item {
width: parent.width
height: 30
Button {
HifiControls.Button {
id: toggleGraphs
property bool checked: false
Layout.alignment: Qt.AlignCenter
anchors.horizontalCenter: parent.horizontalCenter
text: checked ? "Hide graphs" : "Show graphs"
onClicked: function() { checked = !checked; }
}
@ -35,11 +34,9 @@ Column {
Grid {
width: parent.width
height: parent.height - 30
Column {
width: parent.width / 2
height: parent.height
Section {
label: "Latency"
@ -76,7 +73,6 @@ Column {
Column {
width: parent.width / 2
height: parent.height
Section {
label: "Mixer (upstream)"
@ -92,4 +88,3 @@ Column {
}
}
}

View file

@ -0,0 +1,89 @@
//
// TabletStats.qml
// scripts/developer/utilities/audio
//
// Created by David Rowe on 3 Mar 2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
import "../../../../resources/qml/styles-uit"
Item {
id: dialog
width: 480
height: 720
HifiConstants { id: hifi }
Rectangle {
id: header
height: 90
anchors {
top: parent.top
left: parent.left
right: parent.right
}
z: 100
gradient: Gradient {
GradientStop {
position: 0
color: "#2b2b2b"
}
GradientStop {
position: 1
color: "#1e1e1e"
}
}
RalewayBold {
text: "Audio Interface Statistics"
size: 26
color: "#34a2c7"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: hifi.dimensions.contentMargin.x // ####### hifi is not defined
}
}
Rectangle {
id: main
anchors {
top: header.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
}
gradient: Gradient {
GradientStop {
position: 0
color: "#2b2b2b"
}
GradientStop {
position: 1
color: "#0f212e"
}
}
Flickable {
id: scrollView
width: parent.width
height: parent.height
contentWidth: parent.width
contentHeight: stats.height
Stats {
id: stats
}
}
}
}

View file

@ -9,17 +9,23 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var INITIAL_WIDTH = 400;
var INITIAL_OFFSET = 50;
if (HMD.active && !Settings.getValue("HUDUIEnabled")) {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var qml = Script.resolvePath("TabletStats.qml");
tablet.loadQMLSource(qml);
Script.stop();
// Set up the qml ui
var qml = Script.resolvePath('stats.qml');
var window = new OverlayWindow({
title: 'Audio Interface Statistics',
source: qml,
width: 500, height: 520 // stats.qml may be too large for some screens
});
window.setPosition(INITIAL_OFFSET, INITIAL_OFFSET);
} else {
var INITIAL_WIDTH = 400;
var INITIAL_OFFSET = 50;
window.closed.connect(function() { Script.stop(); });
var qml = Script.resolvePath("Stats.qml");
var window = new OverlayWindow({
title: "Audio Interface Statistics",
source: qml,
width: 500, height: 520 // stats.qml may be too large for some screens
});
window.setPosition(INITIAL_OFFSET, INITIAL_OFFSET);
window.closed.connect(function () { Script.stop(); });
}

View file

@ -72,6 +72,9 @@ tablet.screenChanged.connect(onScreenChanged);
AudioDevice.muteToggled.connect(onMuteToggled);
Script.scriptEnding.connect(function () {
if (onAudioScreen) {
tablet.gotoHomeScreen();
}
button.clicked.disconnect(onClicked);
tablet.screenChanged.disconnect(onScreenChanged);
AudioDevice.muteToggled.disconnect(onMuteToggled);

View file

@ -13,8 +13,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings,
Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset, setGrabCommunications,
Menu, HMD, isInEditMode */
Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset,
setGrabCommunications, Menu, HMD, isInEditMode */
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
(function() { // BEGIN LOCAL_SCOPE
@ -28,7 +28,7 @@ Script.include("/~/system/libraries/controllers.js");
//
var WANT_DEBUG = false;
var WANT_DEBUG_STATE = false;
var WANT_DEBUG_STATE = true;
var WANT_DEBUG_SEARCH_NAME = null;
var FORCE_IGNORE_IK = false;
@ -1027,6 +1027,7 @@ function MyController(hand) {
this.grabPointIntersectsEntity = false;
this.stylus = null;
this.homeButtonTouched = false;
this.editTriggered = false;
this.controllerJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ?
"_CONTROLLER_RIGHTHAND" :
@ -1389,7 +1390,7 @@ function MyController(hand) {
}
var searchSphereLocation = Vec3.sum(distantPickRay.origin,
Vec3.multiply(distantPickRay.direction, this.searchSphereDistance));
Vec3.multiply(distantPickRay.direction, this.searchSphereDistance));
this.searchSphereOn(searchSphereLocation, SEARCH_SPHERE_SIZE * this.searchSphereDistance,
(this.triggerSmoothedGrab() || this.secondarySqueezed()) ?
COLORS_GRAB_SEARCHING_FULL_SQUEEZE :
@ -1709,6 +1710,10 @@ function MyController(hand) {
this.checkForUnexpectedChildren();
if (this.editTriggered) {
this.editTriggered = false;
}
if (this.triggerSmoothedReleased() && this.secondaryReleased()) {
this.waitForTriggerRelease = false;
}
@ -2177,23 +2182,21 @@ function MyController(hand) {
return aDistance - bDistance;
});
entity = grabbableEntities[0];
name = entityPropertiesCache.getProps(entity).name;
this.grabbedThingID = entity;
this.grabbedIsOverlay = false;
if (this.entityWantsTrigger(entity)) {
if (this.triggerSmoothedGrab()) {
this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'");
return;
if (!isInEditMode() || entity == HMD.tabletID) { // tablet is grabbable, even when editing
name = entityPropertiesCache.getProps(entity).name;
this.grabbedThingID = entity;
this.grabbedIsOverlay = false;
if (this.entityWantsTrigger(entity)) {
if (this.triggerSmoothedGrab()) {
this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'");
return;
}
} else {
// potentialNearTriggerEntity = entity;
}
} else {
// If near something grabbable, grab it!
if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) {
this.setState(STATE_NEAR_GRABBING, "near grab entity '" + name + "'");
return;
} else {
// potentialNearGrabEntity = entity;
// If near something grabbable, grab it!
if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) {
this.setState(STATE_NEAR_GRABBING, "near grab entity '" + name + "'");
return;
}
}
}
}
@ -2208,6 +2211,21 @@ function MyController(hand) {
}
}
if (isInEditMode()) {
this.searchIndicatorOn(rayPickInfo.searchRay);
if (this.triggerSmoothedGrab()) {
if (!this.editTriggered && rayPickInfo.entityID) {
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
method: "selectEntity",
entityID: rayPickInfo.entityID
}));
}
this.editTriggered = true;
}
Reticle.setVisible(false);
return;
}
if (rayPickInfo.entityID) {
entity = rayPickInfo.entityID;
name = entityPropertiesCache.getProps(entity).name;
@ -2277,12 +2295,12 @@ function MyController(hand) {
return false;
};
this.handleLaserOnWebEntity = function(rayPickInfo) {
this.handleLaserOnWebEntity = function (rayPickInfo) {
var pointerEvent;
if (rayPickInfo.entityID && Entities.wantsHandControllerPointerEvents(rayPickInfo.entityID)) {
var entity = rayPickInfo.entityID;
var props = entityPropertiesCache.getProps(entity);
var name = props.name;
var name = entityPropertiesCache.getProps(entity).name;
if (Entities.keyboardFocusEntity != entity) {
Overlays.keyboardFocusOverlay = 0;
@ -2293,7 +2311,7 @@ function MyController(hand) {
id: this.hand + 1, // 0 is reserved for hardware mouse
pos2D: projectOntoEntityXYPlane(entity, rayPickInfo.intersection),
pos3D: rayPickInfo.intersection,
normal: rayPickInfo.normal,
normal: rayPickInfo.normal,
direction: rayPickInfo.searchRay.direction,
button: "None"
};
@ -2325,12 +2343,13 @@ function MyController(hand) {
Entities.sendHoverOverEntity(entity, pointerEvent);
}
if (this.triggerSmoothedGrab() && (!isEditing() || this.isTablet(entity))) {
if (this.triggerSmoothedGrab()) {
this.grabbedThingID = entity;
this.grabbedIsOverlay = false;
this.setState(STATE_ENTITY_LASER_TOUCHING, "begin touching entity '" + name + "'");
return true;
}
} else if (this.hoverEntity) {
pointerEvent = {
type: "Move",
@ -2343,13 +2362,13 @@ function MyController(hand) {
return false;
};
this.handleLaserOnWebOverlay = function(rayPickInfo) {
this.handleLaserOnWebOverlay = function (rayPickInfo) {
var pointerEvent;
var overlay;
if (rayPickInfo.overlayID) {
overlay = rayPickInfo.overlayID;
var overlay = rayPickInfo.overlayID;
if (Overlays.getProperty(overlay, "type") != "web3d") {
return false;
}
if (Overlays.keyboardFocusOverlay != overlay) {
Entities.keyboardFocusEntity = null;
Overlays.keyboardFocusOverlay = overlay;
@ -3366,7 +3385,7 @@ function MyController(hand) {
entityPropertiesCache.addEntity(this.grabbedThingID);
if (this.state == STATE_ENTITY_LASER_TOUCHING && !this.triggerSmoothedGrab()) {
if (this.state == STATE_ENTITY_LASER_TOUCHING && !this.triggerSmoothedGrab()) { // AJT:
this.setState(STATE_OFF, "released trigger");
return;
}
@ -3663,6 +3682,8 @@ function MyController(hand) {
this.cleanup = function() {
this.release();
this.grabPointSphereOff();
this.hideStylus();
this.overlayLineOff();
};
this.thisHandIsParent = function(props) {

View file

@ -1,7 +1,6 @@
"use strict";
// newEditEntities.js
// examples
// edit.js
//
// Created by Brad Hefta-Gaub on 10/2/14.
// Persist toolbar by HRS 6/11/15.
@ -13,6 +12,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager, Overlays, OverlayWebWindow, UserActivityLogger, Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera, progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, ParticleExplorerTool */
(function() { // BEGIN LOCAL_SCOPE
var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
@ -59,18 +60,13 @@ selectionManager.addEventListener(function () {
const KEY_P = 80; //Key code for letter p used for Parenting hotkey.
var DEGREES_TO_RADIANS = Math.PI / 180.0;
var RADIANS_TO_DEGREES = 180.0 / Math.PI;
var epsilon = 0.001;
var MIN_ANGULAR_SIZE = 2;
var MAX_ANGULAR_SIZE = 45;
var allowLargeModels = true;
var allowSmallModels = true;
var SPAWN_DISTANCE = 1;
var DEFAULT_DIMENSION = 0.20;
var DEFAULT_TEXT_DIMENSION_X = 1.0;
var DEFAULT_TEXT_DIMENSION_Y = 1.0;
var DEFAULT_TEXT_DIMENSION_Z = 0.01;
var DEFAULT_DIMENSIONS = {
x: DEFAULT_DIMENSION,
@ -85,7 +81,6 @@ var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode";
var MENU_SHOW_ZONES_IN_EDIT_MODE = "Show Zones in Edit Mode";
var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled";
var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode";
@ -157,13 +152,13 @@ function hideMarketplace() {
marketplaceWindow.setURL("about:blank");
}
function toggleMarketplace() {
if (marketplaceWindow.visible) {
hideMarketplace();
} else {
showMarketplace();
}
}
// function toggleMarketplace() {
// if (marketplaceWindow.visible) {
// hideMarketplace();
// } else {
// showMarketplace();
// }
// }
var TOOLS_PATH = Script.resolvePath("assets/images/tools/");
@ -176,8 +171,6 @@ var toolBar = (function () {
tablet = null;
function createNewEntity(properties) {
Settings.setValue(EDIT_SETTING, false);
var dimensions = properties.dimensions ? properties.dimensions : DEFAULT_DIMENSIONS;
var position = getPositionToCreateEntity();
var entityID = null;
@ -185,8 +178,12 @@ var toolBar = (function () {
position = grid.snapToSurface(grid.snapToGrid(position, false, dimensions), dimensions),
properties.position = position;
entityID = Entities.addEntity(properties);
if (properties.type == "ParticleEffect") {
selectParticleEntity(entityID);
}
} else {
Window.notifyEditError("Can't create " + properties.type + ": " + properties.type + " would be out of bounds.");
Window.notifyEditError("Can't create " + properties.type + ": " +
properties.type + " would be out of bounds.");
}
selectionManager.clearSelections();
@ -206,24 +203,63 @@ var toolBar = (function () {
}
}
var buttonHandlers = {}; // only used to tablet mode
function addButton(name, image, handler) {
var imageUrl = TOOLS_PATH + image;
var button = toolBar.addButton({
objectName: name,
imageURL: imageUrl,
imageOffOut: 1,
imageOffIn: 2,
imageOnOut: 0,
imageOnIn: 2,
alpha: 0.9,
visible: true
});
if (handler) {
button.clicked.connect(function () {
Script.setTimeout(handler, 100);
});
buttonHandlers[name] = handler;
}
var SHAPE_TYPE_NONE = 0;
var SHAPE_TYPE_SIMPLE_HULL = 1;
var SHAPE_TYPE_SIMPLE_COMPOUND = 2;
var SHAPE_TYPE_STATIC_MESH = 3;
var DYNAMIC_DEFAULT = false;
function handleNewModelDialogResult(result) {
if (result) {
var url = result.textInput;
var shapeType;
switch (result.comboBox) {
case SHAPE_TYPE_SIMPLE_HULL:
shapeType = "simple-hull";
break;
case SHAPE_TYPE_SIMPLE_COMPOUND:
shapeType = "simple-compound";
break;
case SHAPE_TYPE_STATIC_MESH:
shapeType = "static-mesh";
break;
default:
shapeType = "none";
}
var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT;
if (shapeType === "static-mesh" && dynamic) {
// The prompt should prevent this case
print("Error: model cannot be both static mesh and dynamic. This should never happen.");
} else if (url) {
createNewEntity({
type: "Model",
modelURL: url,
shapeType: shapeType,
dynamic: dynamic,
gravity: dynamic ? { x: 0, y: -10, z: 0 } : { x: 0, y: 0, z: 0 }
});
}
}
}
function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.popFromStack();
switch (message.method) {
case "newModelDialogAdd":
handleNewModelDialogResult(message.params);
break;
case "newEntityButtonClicked":
buttonHandlers[message.params.buttonName]();
break;
}
return button;
}
function initialize() {
@ -240,101 +276,40 @@ var toolBar = (function () {
}
});
if (Settings.getValue("HUDUIEnabled")) {
systemToolbar = Toolbars.getToolbar(SYSTEM_TOOLBAR);
activeButton = systemToolbar.addButton({
objectName: EDIT_TOGGLE_BUTTON,
imageURL: TOOLS_PATH + "edit.svg",
visible: true,
alpha: 0.9,
defaultState: 1
});
} else {
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
activeButton = tablet.addButton({
icon: "icons/tablet-icons/edit-i.svg",
activeIcon: "icons/tablet-icons/edit-a.svg",
text: "EDIT",
sortOrder: 10
});
}
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
activeButton = tablet.addButton({
icon: "icons/tablet-icons/edit-i.svg",
activeIcon: "icons/tablet-icons/edit-a.svg",
text: "EDIT",
sortOrder: 10
});
tablet.screenChanged.connect(function (type, url) {
if (isActive && (type !== "QML" || url !== "Edit.qml")) {
that.toggle();
}
});
tablet.fromQml.connect(fromQml);
activeButton.clicked.connect(function() {
that.toggle();
});
toolBar = Toolbars.getToolbar(EDIT_TOOLBAR);
toolBar.writeProperty("shown", false);
addButton("openAssetBrowserButton","assets-01.svg",function(){
addButton("openAssetBrowserButton", "assets-01.svg", function(){
Window.showAssetServer();
})
});
addButton("newModelButton", "model-01.svg", function () {
var SHAPE_TYPE_NONE = 0;
var SHAPE_TYPE_SIMPLE_HULL = 1;
var SHAPE_TYPE_SIMPLE_COMPOUND = 2;
var SHAPE_TYPE_STATIC_MESH = 3;
var SHAPE_TYPES = [];
SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision";
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model";
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes";
SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons";
var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH;
var DYNAMIC_DEFAULT = false;
var result = Window.customPrompt({
textInput: {
label: "Model URL"
},
comboBox: {
label: "Automatic Collisions",
index: SHAPE_TYPE_DEFAULT,
items: SHAPE_TYPES
},
checkBox: {
label: "Dynamic",
checked: DYNAMIC_DEFAULT,
disableForItems: [
SHAPE_TYPE_STATIC_MESH
],
checkStateOnDisable: false,
warningOnDisable: "Models with automatic collisions set to 'Exact' cannot be dynamic"
}
});
if (result) {
var url = result.textInput;
var shapeType;
switch (result.comboBox) {
case SHAPE_TYPE_SIMPLE_HULL:
shapeType = "simple-hull";
break;
case SHAPE_TYPE_SIMPLE_COMPOUND:
shapeType = "simple-compound";
break;
case SHAPE_TYPE_STATIC_MESH:
shapeType = "static-mesh";
break;
default:
shapeType = "none";
}
var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT;
if (shapeType === "static-mesh" && dynamic) {
// The prompt should prevent this case
print("Error: model cannot be both static mesh and dynamic. This should never happen.");
} else if (url) {
createNewEntity({
type: "Model",
modelURL: url,
shapeType: shapeType,
dynamic: dynamic,
gravity: dynamic ? { x: 0, y: -10, z: 0 } : { x: 0, y: 0, z: 0 }
});
}
}
// tablet version of new-model dialog
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.pushOntoStack("NewModelDialog.qml");
});
addButton("newCubeButton", "cube-01.svg", function () {
@ -456,10 +431,12 @@ var toolBar = (function () {
entityListTool.clearEntityList();
};
that.toggle = function () {
that.setActive(!isActive);
activeButton.editProperties({isActive: isActive});
if (!isActive) {
tablet.gotoHomeScreen();
}
};
that.setActive = function (active) {
@ -489,6 +466,8 @@ var toolBar = (function () {
cameraManager.disable();
selectionDisplay.triggerMapping.disable();
} else {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.loadQMLSource("Edit.qml");
UserActivityLogger.enabledEdit();
entityListTool.setVisible(true);
gridTool.setVisible(true);
@ -499,13 +478,6 @@ var toolBar = (function () {
// everybody else to think that Interface has lost focus overall. fogbugzid:558
// Window.setFocus();
}
// Sets visibility of tool buttons, excluding the power button
toolBar.writeProperty("shown", active);
var visible = toolBar.readProperty("visible");
if (active && !visible) {
toolBar.writeProperty("shown", false);
toolBar.writeProperty("shown", true);
}
lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
};
@ -642,7 +614,6 @@ var idleMouseTimerId = null;
var CLICK_TIME_THRESHOLD = 500 * 1000; // 500 ms
var CLICK_MOVE_DISTANCE_THRESHOLD = 20;
var IDLE_MOUSE_TIMEOUT = 200;
var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0;
var lastMouseMoveEvent = null;
@ -772,6 +743,12 @@ function mouseClickEvent(event) {
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
if (event.isShifted) {
particleExplorerTool.destroyWebView();
}
if (properties.type !== "ParticleEffect") {
particleExplorerTool.destroyWebView();
}
if (!event.isShifted) {
selectionManager.setSelections([foundEntity]);
@ -1297,11 +1274,11 @@ function getPositionToCreateEntity() {
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(direction, distance));
if (Camera.mode === "entity" || Camera.mode === "independent") {
position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.orientation), distance))
position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.orientation), distance));
}
position.y += 0.5;
if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
return null
return null;
}
return position;
}
@ -1315,11 +1292,11 @@ function getPositionToImportEntity() {
var position = Vec3.sum(MyAvatar.position, Vec3.multiply(direction, longest));
if (Camera.mode === "entity" || Camera.mode === "independent") {
position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.orientation), longest))
position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.orientation), longest));
}
if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
return null
return null;
}
return position;
@ -1527,11 +1504,11 @@ var ServerScriptStatusMonitor = function(entityID, statusCallback) {
Entities.getServerScriptStatus(entityID, onStatusReceived);
}
}, 1000);
};
}
};
self.stop = function() {
self.active = false;
}
};
Entities.getServerScriptStatus(entityID, onStatusReceived);
};
@ -1539,11 +1516,9 @@ var ServerScriptStatusMonitor = function(entityID, statusCallback) {
var PropertiesTool = function (opts) {
var that = {};
var webView = new OverlayWebWindow({
title: 'Entity Properties',
source: ENTITY_PROPERTIES_URL,
toolWindow: true
});
var webView = null;
webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
webView.setVisible = function(value) {};
var visible = false;
@ -1562,7 +1537,7 @@ var PropertiesTool = function (opts) {
function updateScriptStatus(info) {
info.type = "server_script_status";
webView.emitScriptEvent(JSON.stringify(info));
};
}
function resetScriptStatus() {
updateScriptStatus({
@ -1621,7 +1596,7 @@ var PropertiesTool = function (opts) {
data = JSON.parse(data);
}
catch(e) {
print('Edit.js received web event that was not valid json.')
print('Edit.js received web event that was not valid json.');
return;
}
var i, properties, dY, diff, newPosition;
@ -1639,15 +1614,15 @@ var PropertiesTool = function (opts) {
for (i = 0; i < selectionManager.selections.length; i++) {
Entities.editEntity(selectionManager.selections[i], properties);
}
} else {
} else if (data.properties) {
if (data.properties.dynamic === false) {
// this object is leaving dynamic, so we zero its velocities
data.properties["velocity"] = {
data.properties.velocity = {
x: 0,
y: 0,
z: 0
};
data.properties["angularVelocity"] = {
data.properties.angularVelocity = {
x: 0,
y: 0,
z: 0
@ -1960,6 +1935,21 @@ var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace");
var propertiesTool = new PropertiesTool();
var particleExplorerTool = new ParticleExplorerTool();
var selectedParticleEntity = 0;
function selectParticleEntity(entityID) {
var properties = Entities.getEntityProperties(entityID);
var particleData = {
messageType: "particle_settings",
currentProperties: properties
};
particleExplorerTool.destroyWebView();
particleExplorerTool.createWebView();
selectedParticleEntity = entityID;
particleExplorerTool.setActiveParticleEntity(entityID);
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
}
entityListTool.webView.webEventReceived.connect(function (data) {
data = JSON.parse(data);
if(data.type === 'parent') {
@ -1975,22 +1965,7 @@ entityListTool.webView.webEventReceived.connect(function (data) {
return;
}
// Destroy the old particles web view first
particleExplorerTool.destroyWebView();
particleExplorerTool.createWebView();
var properties = Entities.getEntityProperties(ids[0]);
var particleData = {
messageType: "particle_settings",
currentProperties: properties
};
selectedParticleEntity = ids[0];
particleExplorerTool.setActiveParticleEntity(ids[0]);
particleExplorerTool.webView.webEventReceived.connect(function (data) {
data = JSON.parse(data);
if (data.messageType === "page_loaded") {
particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData));
}
});
selectParticleEntity(ids[0]);
} else {
selectedParticleEntity = 0;
particleExplorerTool.destroyWebView();

View file

@ -18,7 +18,7 @@
var buttonName = "Settings";
var toolBar = null;
var tablet = null;
var settings = "TabletGeneralSettings.qml"
var settings = "TabletGeneralPreferences.qml"
function onClicked(){
if (tablet) {
tablet.loadQMLSource(settings);

View file

@ -18,13 +18,14 @@ var button;
var buttonName = "GOTO";
var toolBar = null;
var tablet = null;
var onGotoScreen = false;
function onAddressBarShown(visible) {
button.editProperties({isActive: visible});
}
function onClicked(){
DialogsManager.toggleAddressBar();
onGotoScreen = !onGotoScreen;
}
if (Settings.getValue("HUDUIEnabled")) {
@ -49,6 +50,9 @@ button.clicked.connect(onClicked);
DialogsManager.addressBarShown.connect(onAddressBarShown);
Script.scriptEnding.connect(function () {
if (onGotoScreen) {
DialogsManager.toggleAddressBar();
}
button.clicked.disconnect(onClicked);
if (tablet) {
tablet.removeButton(button);

View file

@ -48,6 +48,9 @@
}, POLL_RATE);
Script.scriptEnding.connect(function () {
if (enabled) {
Menu.closeInfoView('InfoView_html/help.html');
}
button.clicked.disconnect(onClicked);
Script.clearInterval(interval);
if (tablet) {

View file

@ -871,6 +871,7 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
float: right;
margin-right: 0;
background-color: #ff0000;
min-width: 90px;
}
#entity-list {

View file

@ -77,7 +77,7 @@
</div>
<div id="id" class="property value">
<label>ID:</label>
<span id="property-id" class="selectable"></span>
<input type="text" id="property-id" readonly>
</div>
<div class="section-header hyperlink-group hyperlink-section">
<label>Hyperlink</label><span>M</span>

View file

@ -338,10 +338,10 @@ function loaded() {
}
} else if (data.type == "update") {
var newEntities = data.entities;
if (newEntities.length == 0) {
if (newEntities && newEntities.length == 0) {
elNoEntitiesMessage.style.display = "block";
elFooter.firstChild.nodeValue = "0 entities found";
} else {
} else if (newEntities) {
elNoEntitiesMessage.style.display = "none";
for (var i = 0; i < newEntities.length; i++) {
var id = newEntities[i].id;

View file

@ -758,16 +758,16 @@ function loaded() {
}
} else if (data.type == "update") {
if (data.selections.length == 0) {
if (!data.selections || data.selections.length == 0) {
if (editor !== null && lastEntityID !== null) {
saveJSONUserData(true);
deleteJSONEditor();
}
elTypeIcon.style.display = "none";
elType.innerHTML = "<i>No selection</i>";
elID.innerHTML = "";
elID.value = "";
disableProperties();
} else if (data.selections.length > 1) {
} else if (data.selections && data.selections.length > 1) {
deleteJSONEditor();
var selections = data.selections;
@ -795,7 +795,7 @@ function loaded() {
elTypeIcon.innerHTML = ICON_FOR_TYPE[type];
elTypeIcon.style.display = "inline-block";
elID.innerHTML = ids.join("<br>");
elID.value = "";
disableProperties();
} else {
@ -808,7 +808,7 @@ function loaded() {
//the event bridge and json parsing handle our avatar id string differently.
lastEntityID = '"' + properties.id + '"';
elID.innerHTML = properties.id;
elID.value = properties.id;
elType.innerHTML = properties.type;
elTypeIcon.innerHTML = ICON_FOR_TYPE[properties.type];

View file

@ -45,6 +45,10 @@ function calcSpawnInfo(hand, height) {
var headPos = (HMD.active && Camera.mode === "first person") ? HMD.position : Camera.position;
var headRot = (HMD.active && Camera.mode === "first person") ? HMD.orientation : Camera.orientation;
if (!hand) {
hand = NO_HANDS;
}
if (HMD.active && hand !== NO_HANDS) {
var handController = getControllerWorldLocation(hand, true);
var controllerPosition = handController.position;
@ -96,7 +100,7 @@ function calcSpawnInfo(hand, height) {
* @param hand [number] -1 indicates no hand, Controller.Standard.RightHand or Controller.Standard.LeftHand
* @param clientOnly [bool] true indicates tablet model is only visible to client.
*/
WebTablet = function (url, width, dpi, hand, clientOnly) {
WebTablet = function (url, width, dpi, hand, clientOnly, location) {
var _this = this;
@ -134,6 +138,10 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
// compute position, rotation & parentJointIndex of the tablet
this.calculateTabletAttachmentProperties(hand, true, tabletProperties);
if (location) {
tabletProperties.localPosition = location.localPosition;
tabletProperties.localRotation = location.localRotation;
}
this.cleanUpOldTablets();
@ -185,10 +193,16 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var onHomeScreen = tablet.onHomeScreen();
if (onHomeScreen) {
HMD.closeTablet();
var isMessageOpen = tablet.isMessageDialogOpen();
if (isMessageOpen === false) {
HMD.closeTablet();
}
} else {
tablet.gotoHomeScreen();
_this.setHomeButtonTexture();
var isMessageOpen = tablet.isMessageDialogOpen();
if (isMessageOpen === false) {
tablet.gotoHomeScreen();
_this.setHomeButtonTexture();
}
}
}
};
@ -467,11 +481,16 @@ WebTablet.prototype.mousePressEvent = function (event) {
if (overlayPickResults.intersects && overlayPickResults.overlayID === this.homeButtonID) {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var onHomeScreen = tablet.onHomeScreen();
var isMessageOpen = tablet.isMessageDialogOpen();
if (onHomeScreen) {
HMD.closeTablet();
if (isMessageOpen === false) {
HMD.closeTablet();
}
} else {
tablet.gotoHomeScreen();
this.setHomeButtonTexture();
if (isMessageOpen === false) {
tablet.gotoHomeScreen();
this.setHomeButtonTexture();
}
}
} else if (!HMD.active && (!overlayPickResults.intersects || overlayPickResults.overlayID !== this.webOverlayID)) {
this.dragging = true;

View file

@ -1,13 +1,22 @@
var ENTITY_LIST_HTML_URL = Script.resolvePath('../html/entityList.html');
"use strict";
// entityList.js
//
// Copyright 2014 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
//
/* global EntityListTool, Tablet, selectionManager, Entities, Camera, MyAvatar, Vec3, Menu, Messages,
cameraManager, MENU_EASE_ON_FOCUS, deleteSelectedEntities, toggleSelectedEntitiesLocked, toggleSelectedEntitiesVisible */
EntityListTool = function(opts) {
var that = {};
var url = ENTITY_LIST_HTML_URL;
var webView = new OverlayWebWindow({
title: 'Entity List', source: url, toolWindow: true
});
var webView = null;
webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
webView.setVisible = function(value) {};
var filterInView = false;
var searchRadius = 100;
@ -25,7 +34,7 @@ EntityListTool = function(opts) {
that.toggleVisible = function() {
that.setVisible(!visible);
}
};
selectionManager.addEventListener(function() {
var selectedIDs = [];
@ -44,7 +53,7 @@ EntityListTool = function(opts) {
that.clearEntityList = function () {
var data = {
type: 'clearEntityList'
}
};
webView.emitScriptEvent(JSON.stringify(data));
};
@ -86,8 +95,8 @@ EntityListTool = function(opts) {
}
var selectedIDs = [];
for (var i = 0; i < selectionManager.selections.length; i++) {
selectedIDs.push(selectionManager.selections[i].id);
for (var j = 0; j < selectionManager.selections.length; j++) {
selectedIDs.push(selectionManager.selections[j].id);
}
var data = {
@ -96,7 +105,7 @@ EntityListTool = function(opts) {
selectedIDs: selectedIDs,
};
webView.emitScriptEvent(JSON.stringify(data));
}
};
webView.webEventReceived.connect(function(data) {
data = JSON.parse(data);
@ -149,11 +158,11 @@ EntityListTool = function(opts) {
}
});
webView.visibleChanged.connect(function () {
if (webView.visible) {
that.sendUpdate();
}
});
// webView.visibleChanged.connect(function () {
// if (webView.visible) {
// that.sendUpdate();
// }
// });
return that;
};

View file

@ -11,6 +11,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global HIFI_PUBLIC_BUCKET, SPACE_LOCAL, Script, SelectionManager */
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
SPACE_LOCAL = "local";
@ -28,7 +30,7 @@ SelectionManager = (function() {
var that = {};
function subscribeToUpdateMessages() {
Messages.subscribe('entityToolUpdates');
Messages.subscribe("entityToolUpdates");
Messages.messageReceived.connect(handleEntitySelectionToolUpdates);
}
@ -40,8 +42,20 @@ SelectionManager = (function() {
return;
}
if (message === 'callUpdate') {
that._update();
var messageParsed;
try {
messageParsed = JSON.parse(message);
} catch (err) {
print("error -- entitySelectionTool got malformed message: " + message);
}
// if (message === 'callUpdate') {
// that._update();
// }
if (messageParsed.method === "selectEntity") {
print("setting selection to " + messageParsed.entityID);
that.setSelections([messageParsed.entityID]);
}
}
@ -149,13 +163,14 @@ SelectionManager = (function() {
};
that._update = function(selectionUpdated) {
if (that.selections.length == 0) {
var properties = null;
if (that.selections.length === 0) {
that.localDimensions = null;
that.localPosition = null;
that.worldDimensions = null;
that.worldPosition = null;
} else if (that.selections.length == 1) {
var properties = Entities.getEntityProperties(that.selections[0]);
properties = Entities.getEntityProperties(that.selections[0]);
that.localDimensions = properties.dimensions;
that.localPosition = properties.position;
that.localRotation = properties.rotation;
@ -170,7 +185,7 @@ SelectionManager = (function() {
that.localDimensions = null;
that.localPosition = null;
var properties = Entities.getEntityProperties(that.selections[0]);
properties = Entities.getEntityProperties(that.selections[0]);
var brn = properties.boundingBox.brn;
var tfl = properties.boundingBox.tfl;
@ -203,9 +218,9 @@ SelectionManager = (function() {
SelectionDisplay.setSpaceMode(SPACE_WORLD);
}
for (var i = 0; i < listeners.length; i++) {
for (var j = 0; j < listeners.length; j++) {
try {
listeners[i](selectionUpdated === true);
listeners[j](selectionUpdated === true);
} catch (e) {
print("EntitySelectionTool got exception: " + JSON.stringify(e));
}
@ -229,8 +244,8 @@ function getRelativeCenterPosition(dimensions, registrationPoint) {
return {
x: -dimensions.x * (registrationPoint.x - 0.5),
y: -dimensions.y * (registrationPoint.y - 0.5),
z: -dimensions.z * (registrationPoint.z - 0.5),
}
z: -dimensions.z * (registrationPoint.z - 0.5)
};
}
SelectionDisplay = (function() {
@ -253,7 +268,7 @@ SelectionDisplay = (function() {
var spaceMode = SPACE_LOCAL;
var mode = "UNKNOWN";
var overlayNames = new Array();
var overlayNames = [];
var lastCameraPosition = Camera.getPosition();
var lastCameraOrientation = Camera.getOrientation();
@ -679,8 +694,7 @@ SelectionDisplay = (function() {
green: 0,
blue: 0
},
ignoreRayIntersection: true, // always ignore this
visible: false,
ignoreRayIntersection: true // always ignore this
});
var yRailOverlay = Overlays.addOverlay("line3d", {
visible: false,
@ -700,8 +714,7 @@ SelectionDisplay = (function() {
green: 255,
blue: 0
},
ignoreRayIntersection: true, // always ignore this
visible: false,
ignoreRayIntersection: true // always ignore this
});
var zRailOverlay = Overlays.addOverlay("line3d", {
visible: false,
@ -721,8 +734,7 @@ SelectionDisplay = (function() {
green: 0,
blue: 255
},
ignoreRayIntersection: true, // always ignore this
visible: false,
ignoreRayIntersection: true // always ignore this
});
var rotateZeroOverlay = Overlays.addOverlay("line3d", {
@ -1022,30 +1034,13 @@ SelectionDisplay = (function() {
that.triggered = true;
if (activeHand !== hand) {
// No switching while the other is already triggered, so no need to release.
activeHand = (activeHand === Controller.Standard.RightHand) ? Controller.Standard.LeftHand : Controller.Standard.RightHand;
activeHand = (activeHand === Controller.Standard.RightHand) ?
Controller.Standard.LeftHand : Controller.Standard.RightHand;
}
if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(Reticle.position)) {
return;
}
var eventResult = that.mousePressEvent({});
if (!eventResult || (eventResult === 'selectionBox')) {
var pickRay = controllerComputePickRay();
if (pickRay) {
var entityIntersection = Entities.findRayIntersection(pickRay, true);
var overlayIntersection = Overlays.findRayIntersection(pickRay);
if (entityIntersection.intersects &&
(!overlayIntersection.intersects || (entityIntersection.distance < overlayIntersection.distance))) {
if (HMD.tabletID === entityIntersection.entityID) {
return;
}
selectionManager.setSelections([entityIntersection.entityID]);
}
}
}
that.mousePressEvent({});
} else if (that.triggered && (value < that.TRIGGER_OFF_VALUE)) {
that.triggered = false;
that.mouseReleaseEvent({});
@ -1054,6 +1049,8 @@ SelectionDisplay = (function() {
}
that.triggerMapping.from(Controller.Standard.RT).peek().to(makeTriggerHandler(Controller.Standard.RightHand));
that.triggerMapping.from(Controller.Standard.LT).peek().to(makeTriggerHandler(Controller.Standard.LeftHand));
function controllerComputePickRay() {
var controllerPose = getControllerWorldLocation(activeHand, true);
if (controllerPose.valid && that.triggered) {
@ -1072,7 +1069,7 @@ SelectionDisplay = (function() {
onBegin: tool.onBegin,
onMove: tool.onMove,
onEnd: tool.onEnd,
}
};
}
@ -1080,8 +1077,8 @@ SelectionDisplay = (function() {
for (var i = 0; i < allOverlays.length; i++) {
Overlays.deleteOverlay(allOverlays[i]);
}
for (var i = 0; i < selectionBoxes.length; i++) {
Overlays.deleteOverlay(selectionBoxes[i]);
for (var j = 0; j < selectionBoxes.length; j++) {
Overlays.deleteOverlay(selectionBoxes[j]);
}
};
@ -1125,7 +1122,7 @@ SelectionDisplay = (function() {
});
that.updateHandles();
}
};
that.updateRotationHandles = function() {
var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1;
@ -1572,7 +1569,7 @@ SelectionDisplay = (function() {
that.unselectAll = function() {};
that.updateHandles = function() {
if (SelectionManager.selections.length == 0) {
if (SelectionManager.selections.length === 0) {
that.setOverlaysVisible(false);
return;
}
@ -1608,7 +1605,8 @@ SelectionDisplay = (function() {
var bottom = -registrationPointDimensions.y;
var top = dimensions.y - registrationPointDimensions.y;
var near = -registrationPointDimensions.z;
var front = far = dimensions.z - registrationPointDimensions.z;
var far = dimensions.z - registrationPointDimensions.z;
var front = far;
var worldTop = SelectionManager.worldDimensions.y / 2;
@ -1808,9 +1806,9 @@ SelectionDisplay = (function() {
if (selectionManager.selections.length == 1) {
var properties = Entities.getEntityProperties(selectionManager.selections[0]);
if (properties.type == "Light" && properties.isSpotlight == true) {
var stretchHandlesVisible = false;
var extendedStretchHandlesVisible = false;
if (properties.type == "Light" && properties.isSpotlight) {
stretchHandlesVisible = false;
extendedStretchHandlesVisible = false;
Overlays.editOverlay(grabberSpotLightCenter, {
position: position,
@ -1903,9 +1901,9 @@ SelectionDisplay = (function() {
Overlays.editOverlay(grabberPointLightN, {
visible: false
});
} else if (properties.type == "Light" && properties.isSpotlight == false) {
var stretchHandlesVisible = false;
var extendedStretchHandlesVisible = false;
} else if (properties.type == "Light" && !properties.isSpotlight) {
stretchHandlesVisible = false;
extendedStretchHandlesVisible = false;
Overlays.editOverlay(grabberPointLightT, {
position: TOP,
rotation: rotation,
@ -2171,23 +2169,23 @@ SelectionDisplay = (function() {
}));
}
var i = 0;
i = 0;
// Only show individual selections boxes if there is more than 1 selection
if (selectionManager.selections.length > 1) {
for (; i < selectionManager.selections.length; i++) {
var properties = Entities.getEntityProperties(selectionManager.selections[i]);
var props = Entities.getEntityProperties(selectionManager.selections[i]);
// Adjust overlay position to take registrationPoint into account
// centeredRP = registrationPoint with range [-0.5, 0.5]
var centeredRP = Vec3.subtract(properties.registrationPoint, {
var centeredRP = Vec3.subtract(props.registrationPoint, {
x: 0.5,
y: 0.5,
z: 0.5
});
var offset = vec3Mult(properties.dimensions, centeredRP);
var offset = vec3Mult(props.dimensions, centeredRP);
offset = Vec3.multiply(-1, offset);
offset = Vec3.multiplyQbyV(properties.rotation, offset);
var boxPosition = Vec3.sum(properties.position, offset);
offset = Vec3.multiplyQbyV(props.rotation, offset);
var boxPosition = Vec3.sum(props.position, offset);
var color = {red: 255, green: 128, blue: 0};
if (i >= selectionManager.selections.length - 1) color = {red: 255, green: 255, blue: 64};
@ -2195,8 +2193,8 @@ SelectionDisplay = (function() {
Overlays.editOverlay(selectionBoxes[i], {
position: boxPosition,
color: color,
rotation: properties.rotation,
dimensions: properties.dimensions,
rotation: props.rotation,
dimensions: props.dimensions,
visible: true,
});
}
@ -2588,11 +2586,11 @@ SelectionDisplay = (function() {
y: v1.y * v2.y,
z: v1.z * v2.z
};
}
// stretchMode - name of mode
// direction - direction to stretch in
// pivot - point to use as a pivot
// offset - the position of the overlay tool relative to the selections center position
};
// stretchMode - name of mode
// direction - direction to stretch in
// pivot - point to use as a pivot
// offset - the position of the overlay tool relative to the selections center position
var makeStretchTool = function(stretchMode, direction, pivot, offset, customOnMove) {
var signs = {
x: direction.x < 0 ? -1 : (direction.x > 0 ? 1 : 0),
@ -2644,7 +2642,7 @@ SelectionDisplay = (function() {
});
// Scale pivot to be in the same range as registrationPoint
var scaledPivot = Vec3.multiply(0.5, pivot)
var scaledPivot = Vec3.multiply(0.5, pivot);
deltaPivot = Vec3.subtract(centeredRP, scaledPivot);
var scaledOffset = Vec3.multiply(0.5, offset);
@ -2656,14 +2654,16 @@ SelectionDisplay = (function() {
var scaledOffsetWorld = vec3Mult(initialDimensions, offsetRP);
pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld));
var start = null;
var end = null;
if (numDimensions == 1 && mask.x) {
var start = Vec3.multiplyQbyV(rotation, {
start = Vec3.multiplyQbyV(rotation, {
x: -10000,
y: 0,
z: 0
});
start = Vec3.sum(start, properties.position);
var end = Vec3.multiplyQbyV(rotation, {
end = Vec3.multiplyQbyV(rotation, {
x: 10000,
y: 0,
z: 0
@ -2676,13 +2676,13 @@ SelectionDisplay = (function() {
});
}
if (numDimensions == 1 && mask.y) {
var start = Vec3.multiplyQbyV(rotation, {
start = Vec3.multiplyQbyV(rotation, {
x: 0,
y: -10000,
z: 0
});
start = Vec3.sum(start, properties.position);
var end = Vec3.multiplyQbyV(rotation, {
end = Vec3.multiplyQbyV(rotation, {
x: 0,
y: 10000,
z: 0
@ -2695,13 +2695,13 @@ SelectionDisplay = (function() {
});
}
if (numDimensions == 1 && mask.z) {
var start = Vec3.multiplyQbyV(rotation, {
start = Vec3.multiplyQbyV(rotation, {
x: 0,
y: 0,
z: -10000
});
start = Vec3.sum(start, properties.position);
var end = Vec3.multiplyQbyV(rotation, {
end = Vec3.multiplyQbyV(rotation, {
x: 0,
y: 0,
z: 10000
@ -2734,13 +2734,13 @@ SelectionDisplay = (function() {
};
}
} else if (numDimensions == 2) {
if (mask.x == 0) {
if (mask.x === 0) {
planeNormal = {
x: 1,
y: 0,
z: 0
};
} else if (mask.y == 0) {
} else if (mask.y === 0) {
planeNormal = {
x: 0,
y: 1,
@ -2898,7 +2898,7 @@ SelectionDisplay = (function() {
});
SelectionManager._update();
};
}
function radiusStretchFunc(vector, change) {
var props = selectionManager.savedProperties[selectionManager.selections[0]];
@ -3889,11 +3889,9 @@ SelectionDisplay = (function() {
Overlays.editOverlay(rollHandle, {
ignoreRayIntersection: true
});
var result = Overlays.findRayIntersection(pickRay);
result = Overlays.findRayIntersection(pickRay);
if (result.intersects) {
if (wantDebug) {
print("something intersects... ");
print(" result.overlayID:" + result.overlayID + "[" + overlayNames[result.overlayID] + "]");
@ -4423,7 +4421,7 @@ SelectionDisplay = (function() {
scale: handleSize / 1.25,
});
}
}
};
Script.update.connect(that.updateHandleSizes);
that.mouseReleaseEvent = function(event) {

View file

@ -228,10 +228,9 @@ GridTool = function(opts) {
var verticalGrid = opts.verticalGrid;
var listeners = [];
var url = GRID_CONTROLS_HTML_URL;
var webView = new OverlayWebWindow({
title: 'Grid', source: url, toolWindow: true
});
var webView = null;
webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
webView.setVisible = function(value) {};
horizontalGrid.addListener(function(data) {
webView.emitScriptEvent(JSON.stringify(data));

View file

@ -121,6 +121,7 @@ function onClick() {
if (onMarketplaceScreen) {
// for toolbar-mode: go back to home screen, this will close the window.
tablet.gotoHomeScreen();
onMarketplaceScreen = false;
} else {
var entity = HMD.tabletID;
Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})});
@ -140,6 +141,9 @@ tablet.screenChanged.connect(onScreenChanged);
Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged);
Script.scriptEnding.connect(function () {
if (onMarketplaceScreen) {
tablet.gotoHomeScreen();
}
tablet.removeButton(marketplaceButton);
tablet.screenChanged.disconnect(onScreenChanged);
Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged);

View file

@ -48,6 +48,9 @@ var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-
tablet.screenChanged.connect(onScreenChanged);
Script.scriptEnding.connect(function () {
if (onMenuScreen) {
tablet.gotoHomeScreen();
}
button.clicked.disconnect(onClicked);
tablet.removeButton(button);
tablet.screenChanged.disconnect(onScreenChanged);

View file

@ -696,6 +696,9 @@ function clearLocalQMLDataAndClosePAL() {
}
function shutdown() {
if (onPalScreen) {
tablet.gotoHomeScreen();
}
button.clicked.disconnect(onTabletButtonClicked);
tablet.removeButton(button);
tablet.screenChanged.disconnect(onTabletScreenChanged);

View file

@ -76,4 +76,4 @@ body{
</div>
</body>
</html>
</html>

View file

@ -32,6 +32,8 @@ var gui = null;
var settings = new Settings();
var updateInterval;
var active = false;
var currentInputField;
var storedController;
//CHANGE TO WHITELIST
@ -358,9 +360,25 @@ function listenForSettingsUpdates() {
settings[key] = value;
});
loadGUI();
}
if (gui) {
manuallyUpdateDisplay();
} else {
loadGUI();
}
if (!active) {
// gui.toggleHide();
gui.closed = false;
}
active = true;
} else if (data.messageType === "particle_close") {
// none of this seems to work.
// if (active) {
// gui.toggleHide();
// }
active = false;
gui.closed = true;
}
});
}
@ -505,4 +523,4 @@ function registerDOMElementsForListenerBlocking() {
});
});
});
}
}

View file

@ -18,26 +18,21 @@ ParticleExplorerTool = function() {
var that = {};
that.createWebView = function() {
var url = PARTICLE_EXPLORER_HTML_URL;
that.webView = new OverlayWebWindow({
title: 'Particle Explorer',
source: url,
toolWindow: true
});
that.webView.setVisible(true);
that.webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
that.webView.setVisible = function(value) {};
that.webView.webEventReceived.connect(that.webEventReceived);
}
that.destroyWebView = function() {
if (!that.webView) {
return;
}
that.webView.close();
that.webView = null;
that.activeParticleEntity = 0;
var messageData = {
messageType: "particle_close"
};
that.webView.emitScriptEvent(JSON.stringify(messageData));
}
that.webEventReceived = function(data) {
@ -51,8 +46,5 @@ ParticleExplorerTool = function() {
that.activeParticleEntity = id;
}
return that;
};
};

View file

@ -191,12 +191,12 @@ function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) {
if (clearOverlayWhenMoving) {
MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog
}
HMD.openTablet();
}
function processingGif() {
// show hud
Reticle.visible = reticleVisible;
button.clicked.disconnect(onClicked);
buttonConnected = false;
// show overlays if they were on
@ -211,8 +211,10 @@ Window.snapshotShared.connect(snapshotShared);
Window.processingGif.connect(processingGif);
Script.scriptEnding.connect(function () {
button.clicked.disconnect(onClicked);
buttonConnected = false;
if (buttonConnected) {
button.clicked.disconnect(onClicked);
buttonConnected = false;
}
if (tablet) {
tablet.removeButton(button);
}

View file

@ -12,21 +12,47 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* global Script, HMD, WebTablet, UIWebTablet, UserActivityLogger, Settings, Entities, Messages, Tablet, Overlays, MyAvatar */
/* global Script, HMD, WebTablet, UIWebTablet, UserActivityLogger, Settings, Entities, Messages, Tablet, Overlays,
MyAvatar, Menu */
(function() { // BEGIN LOCAL_SCOPE
var tabletShown = false;
var tabletLocation = null;
var tabletRezzed = false;
var activeHand = null;
var DEFAULT_WIDTH = 0.4375;
var DEFAULT_TABLET_SCALE = 100;
var preMakeTime = Date.now();
var validCheckTime = Date.now();
var debugTablet = false;
UIWebTablet = null;
Script.include("../libraries/WebTablet.js");
function showTabletUI() {
tabletShown = true;
print("show tablet-ui");
function tabletIsValid() {
if (!UIWebTablet) {
return false;
}
if (UIWebTablet.tabletIsOverlay && Overlays.getProperty(HMD.tabletID, "type") != "model") {
if (debugTablet) {
print("TABLET is invalid due to frame: " + JSON.stringify(Overlays.getProperty(HMD.tabletID, "type")));
}
return false;
}
if (Overlays.getProperty(HMD.homeButtonID, "type") != "sphere" ||
Overlays.getProperty(HMD.tabletScreenID, "type") != "web3d") {
if (debugTablet) {
print("TABLET is invalid due to other");
}
return false;
}
return true;
}
var DEFAULT_WIDTH = 0.4375;
var DEFAULT_TABLET_SCALE = 100;
function rezTablet() {
if (debugTablet) {
print("TABLET rezzing");
}
var toolbarMode = Tablet.getTablet("com.highfidelity.interface.tablet.system").toolbarMode;
var TABLET_SCALE = DEFAULT_TABLET_SCALE;
if (toolbarMode) {
@ -34,37 +60,98 @@
} else {
TABLET_SCALE = Settings.getValue("hmdTabletScale") || DEFAULT_TABLET_SCALE;
}
UIWebTablet = new WebTablet("qml/hifi/tablet/TabletRoot.qml", DEFAULT_WIDTH * (TABLET_SCALE / 100), null, activeHand, true);
UIWebTablet = new WebTablet("qml/hifi/tablet/TabletRoot.qml",
DEFAULT_WIDTH * (TABLET_SCALE / 100),
null, activeHand, true);
UIWebTablet.register();
HMD.tabletID = UIWebTablet.tabletEntityID;
HMD.homeButtonID = UIWebTablet.homeButtonID;
HMD.tabletScreenID = UIWebTablet.webOverlayID;
tabletRezzed = true;
}
function showTabletUI() {
tabletShown = true;
if (!tabletRezzed) {
rezTablet(false);
}
if (UIWebTablet && tabletRezzed) {
if (debugTablet) {
print("TABLET in showTabletUI, already rezzed");
}
var tabletProperties = {};
UIWebTablet.calculateTabletAttachmentProperties(activeHand, true, tabletProperties);
tabletProperties.visible = true;
if (UIWebTablet.tabletIsOverlay) {
Overlays.editOverlay(HMD.tabletID, tabletProperties);
}
Overlays.editOverlay(HMD.homeButtonID, { visible: true });
Overlays.editOverlay(HMD.tabletScreenID, { visible: true });
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 90 });
}
}
function hideTabletUI() {
tabletShown = false;
print("hide tablet-ui");
if (!UIWebTablet) {
return;
}
if (UIWebTablet.tabletIsOverlay) {
if (debugTablet) {
print("TABLET hide");
}
if (Settings.getValue("tabletVisibleToOthers")) {
closeTabletUI();
} else {
// Overlays.editOverlay(HMD.tabletID, { localPosition: { x: -1000, y: 0, z:0 } });
Overlays.editOverlay(HMD.tabletID, { visible: false });
Overlays.editOverlay(HMD.homeButtonID, { visible: false });
Overlays.editOverlay(HMD.tabletScreenID, { visible: false });
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 1 });
}
} else {
closeTabletUI();
}
}
function closeTabletUI() {
tabletShown = false;
if (UIWebTablet) {
if (UIWebTablet.onClose) {
UIWebTablet.onClose();
}
tabletLocation = UIWebTablet.getLocation();
if (debugTablet) {
print("TABLET close");
}
UIWebTablet.unregister();
UIWebTablet.destroy();
UIWebTablet = null;
HMD.tabletID = null;
HMD.homeButtonID = null;
HMD.tabletScreenID = null;
} else if (debugTablet) {
print("TABLET closeTabletUI, UIWebTablet is null");
}
tabletRezzed = false;
}
function updateShowTablet() {
var MSECS_PER_SEC = 1000.0;
var now = Date.now();
// close the WebTablet if it we go into toolbar mode.
var toolbarMode = Tablet.getTablet("com.highfidelity.interface.tablet.system").toolbarMode;
var visibleToOthers = Settings.getValue("tabletVisibleToOthers");
if (tabletShown && toolbarMode) {
hideTabletUI();
closeTabletUI();
HMD.closeTablet();
return;
}
@ -78,19 +165,48 @@
tablet.updateAudioBar(currentMicLevel);
}
if (tabletShown && UIWebTablet && Overlays.getOverlayType(UIWebTablet.webOverlayID) != "web3d") {
// when we switch domains, the tablet entity gets destroyed and recreated. this causes
// the overlay to be deleted, but not recreated. If the overlay is deleted for this or any
// other reason, close the tablet.
hideTabletUI();
HMD.closeTablet();
} else if (HMD.showTablet && !tabletShown && !toolbarMode) {
UserActivityLogger.openedTablet(Settings.getValue("tabletVisibleToOthers"));
if (validCheckTime - now > MSECS_PER_SEC) {
validCheckTime = now;
if (tabletRezzed && UIWebTablet && !tabletIsValid()) {
// when we switch domains, the tablet entity gets destroyed and recreated. this causes
// the overlay to be deleted, but not recreated. If the overlay is deleted for this or any
// other reason, close the tablet.
closeTabletUI();
HMD.closeTablet();
if (debugTablet) {
print("TABLET autodestroying");
}
}
}
if (HMD.showTablet && !tabletShown && !toolbarMode) {
UserActivityLogger.openedTablet(visibleToOthers);
showTabletUI();
} else if (!HMD.showTablet && tabletShown) {
UserActivityLogger.closedTablet();
hideTabletUI();
if (visibleToOthers) {
closeTabletUI();
} else {
hideTabletUI();
}
}
// if the tablet is an overlay, attempt to pre-create it and then hide it so that when it's
// summoned, it will appear quickly.
if (!toolbarMode && !visibleToOthers) {
if (now - preMakeTime > MSECS_PER_SEC) {
preMakeTime = now;
if (!tabletIsValid()) {
closeTabletUI();
rezTablet(false);
tabletShown = false;
} else if (!tabletShown) {
hideTabletUI();
}
}
}
}
function toggleHand(channel, hand, senderUUID, localOnly) {

View file

@ -67,7 +67,6 @@
}
function onWebEventReceived(event) {
print("Script received a web event, its type is " + typeof event);
if (typeof event === "string") {
event = JSON.parse(event);
}
@ -115,6 +114,9 @@
tablet.screenChanged.connect(onScreenChanged);
function cleanup() {
if (onUsersScreen) {
tablet.gotoHomeScreen();
}
button.clicked.disconnect(onClicked);
tablet.removeButton(button);
}

File diff suppressed because it is too large Load diff