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

This commit is contained in:
Sam Gateau 2018-12-13 20:40:50 -08:00
commit 30277213c6
60 changed files with 3017 additions and 1311 deletions

View file

@ -395,8 +395,14 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
}
// If Avatar A's PAL WAS open but is no longer open, AND
// Avatar A should be ignoring Avatar B...
if (PALWasOpen && !PALIsOpen && shouldIgnore) {
// Avatar A is ignoring Avatar B OR Avatar B is ignoring Avatar A...
//
// This is a bit heavy-handed still - there are cases where a kill packet
// will be sent when it doesn't need to be (but where it _should_ be OK to send).
// However, it's less heavy-handed than using `shouldIgnore`.
if (PALWasOpen && !PALIsOpen &&
(destinationNode->isIgnoringNodeWithID(avatarNode->getUUID()) ||
avatarNode->isIgnoringNodeWithID(destinationNode->getUUID()))) {
// ...send a Kill Packet to Node A, instructing Node A to kill Avatar B,
// then have Node A cleanup the killed Node B.
auto packet = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason), true);

View file

@ -0,0 +1,78 @@
{
"name": "Standard to Action (No Movement)",
"channels": [
{ "from": "Standard.LT", "to": "Actions.LeftHandClick" },
{ "from": "Standard.RT", "to": "Actions.RightHandClick" },
{ "from": "Standard.LeftHand", "to": "Actions.LeftHand" },
{ "from": "Standard.LeftHandThumb1", "to": "Actions.LeftHandThumb1"},
{ "from": "Standard.LeftHandThumb2", "to": "Actions.LeftHandThumb2"},
{ "from": "Standard.LeftHandThumb3", "to": "Actions.LeftHandThumb3"},
{ "from": "Standard.LeftHandThumb4", "to": "Actions.LeftHandThumb4"},
{ "from": "Standard.LeftHandIndex1", "to": "Actions.LeftHandIndex1"},
{ "from": "Standard.LeftHandIndex2", "to": "Actions.LeftHandIndex2"},
{ "from": "Standard.LeftHandIndex3", "to": "Actions.LeftHandIndex3"},
{ "from": "Standard.LeftHandIndex4", "to": "Actions.LeftHandIndex4"},
{ "from": "Standard.LeftHandMiddle1", "to": "Actions.LeftHandMiddle1"},
{ "from": "Standard.LeftHandMiddle2", "to": "Actions.LeftHandMiddle2"},
{ "from": "Standard.LeftHandMiddle3", "to": "Actions.LeftHandMiddle3"},
{ "from": "Standard.LeftHandMiddle4", "to": "Actions.LeftHandMiddle4"},
{ "from": "Standard.LeftHandRing1", "to": "Actions.LeftHandRing1"},
{ "from": "Standard.LeftHandRing2", "to": "Actions.LeftHandRing2"},
{ "from": "Standard.LeftHandRing3", "to": "Actions.LeftHandRing3"},
{ "from": "Standard.LeftHandRing4", "to": "Actions.LeftHandRing4"},
{ "from": "Standard.LeftHandPinky1", "to": "Actions.LeftHandPinky1"},
{ "from": "Standard.LeftHandPinky2", "to": "Actions.LeftHandPinky2"},
{ "from": "Standard.LeftHandPinky3", "to": "Actions.LeftHandPinky3"},
{ "from": "Standard.LeftHandPinky4", "to": "Actions.LeftHandPinky4"},
{ "from": "Standard.RightHand", "to": "Actions.RightHand" },
{ "from": "Standard.RightHandThumb1", "to": "Actions.RightHandThumb1"},
{ "from": "Standard.RightHandThumb2", "to": "Actions.RightHandThumb2"},
{ "from": "Standard.RightHandThumb3", "to": "Actions.RightHandThumb3"},
{ "from": "Standard.RightHandThumb4", "to": "Actions.RightHandThumb4"},
{ "from": "Standard.RightHandIndex1", "to": "Actions.RightHandIndex1"},
{ "from": "Standard.RightHandIndex2", "to": "Actions.RightHandIndex2"},
{ "from": "Standard.RightHandIndex3", "to": "Actions.RightHandIndex3"},
{ "from": "Standard.RightHandIndex4", "to": "Actions.RightHandIndex4"},
{ "from": "Standard.RightHandMiddle1", "to": "Actions.RightHandMiddle1"},
{ "from": "Standard.RightHandMiddle2", "to": "Actions.RightHandMiddle2"},
{ "from": "Standard.RightHandMiddle3", "to": "Actions.RightHandMiddle3"},
{ "from": "Standard.RightHandMiddle4", "to": "Actions.RightHandMiddle4"},
{ "from": "Standard.RightHandRing1", "to": "Actions.RightHandRing1"},
{ "from": "Standard.RightHandRing2", "to": "Actions.RightHandRing2"},
{ "from": "Standard.RightHandRing3", "to": "Actions.RightHandRing3"},
{ "from": "Standard.RightHandRing4", "to": "Actions.RightHandRing4"},
{ "from": "Standard.RightHandPinky1", "to": "Actions.RightHandPinky1"},
{ "from": "Standard.RightHandPinky2", "to": "Actions.RightHandPinky2"},
{ "from": "Standard.RightHandPinky3", "to": "Actions.RightHandPinky3"},
{ "from": "Standard.RightHandPinky4", "to": "Actions.RightHandPinky4"},
{ "from": "Standard.LeftFoot", "to": "Actions.LeftFoot" },
{ "from": "Standard.RightFoot", "to": "Actions.RightFoot" },
{ "from": "Standard.Hips", "to": "Actions.Hips" },
{ "from": "Standard.Spine2", "to": "Actions.Spine2" },
{ "from": "Standard.Head", "to": "Actions.Head" },
{ "from": "Standard.LeftArm", "to": "Actions.LeftArm" },
{ "from": "Standard.RightArm", "to": "Actions.RightArm" },
{ "from": "Standard.TrackedObject00", "to" : "Actions.TrackedObject00" },
{ "from": "Standard.TrackedObject01", "to" : "Actions.TrackedObject01" },
{ "from": "Standard.TrackedObject02", "to" : "Actions.TrackedObject02" },
{ "from": "Standard.TrackedObject03", "to" : "Actions.TrackedObject03" },
{ "from": "Standard.TrackedObject04", "to" : "Actions.TrackedObject04" },
{ "from": "Standard.TrackedObject05", "to" : "Actions.TrackedObject05" },
{ "from": "Standard.TrackedObject06", "to" : "Actions.TrackedObject06" },
{ "from": "Standard.TrackedObject07", "to" : "Actions.TrackedObject07" },
{ "from": "Standard.TrackedObject08", "to" : "Actions.TrackedObject08" },
{ "from": "Standard.TrackedObject09", "to" : "Actions.TrackedObject09" },
{ "from": "Standard.TrackedObject10", "to" : "Actions.TrackedObject10" },
{ "from": "Standard.TrackedObject11", "to" : "Actions.TrackedObject11" },
{ "from": "Standard.TrackedObject12", "to" : "Actions.TrackedObject12" },
{ "from": "Standard.TrackedObject13", "to" : "Actions.TrackedObject13" },
{ "from": "Standard.TrackedObject14", "to" : "Actions.TrackedObject14" },
{ "from": "Standard.TrackedObject15", "to" : "Actions.TrackedObject15" }
]
}

View file

@ -154,4 +154,6 @@
<glyph glyph-name="40-reload" unicode="&#70;" d="M365 261c-9 1-17-5-18-15-4-45-43-80-89-80-49 0-89 40-89 89 0 19 4 45 25 65 16 15 39 23 68 25l-15-16c-6-6-6-17 0-24 4-3 8-4 12-4 4 0 9 1 12 5l43 44c2 2 3 4 4 6 2 6 1 13-4 18l-44 44c-6 6-17 6-23 0-7-7-7-17 0-24l15-15c-38-2-69-14-91-35-23-21-36-53-36-88 0-68 55-123 123-123 64 0 116 47 122 110 1 9-5 18-15 18"/>
<glyph glyph-name="forward" unicode="&#68;" d="M330 278l-95 70c-5 4-12 5-18 2-5-3-9-9-9-16l0-150c0-7 4-13 10-16 2-1 5-2 7-2 4 0 8 2 11 5l95 79c4 4 6 9 6 14-1 5-3 10-7 14"/>
<glyph glyph-name="avatar-1" unicode="&#84;" d="M396 344l-2 2c-4 4-9 5-15 5-1 0-88-13-124-14-1 0-2 0-3 0-37 0-126 15-127 15-7 1-14-2-18-8l-2-4c-3-4-3-9-2-14 2-5 5-9 10-11 16-7 69-22 85-29 3-1 10-4 10-14 1-11-4-67-10-93-7-26-18-60-19-60-3-9 2-19 11-22l11-4c4-2 9-1 13 1 5 2 8 6 9 10l31 94 28-96c2-5 5-9 9-11 3-1 5-2 8-2 2 0 4 0 7 1l10 4c8 3 12 12 10 20 0 1-8 36-16 65-4 17-6 43-7 64-1 13-1 21-3 30 0 1 2 11 10 14 10 4 81 29 80 28 6 2 10 7 11 13 1 6-1 12-5 16z m-98 54c0-24-19-43-43-43-24 0-43 19-43 43 0 23 19 42 43 42 24 0 43-19 43-42z"/>
<glyph glyph-name="steam-square" unicode="&#57397;" d="M391 327c0 15-5 28-16 39-11 11-24 16-39 16-15 0-28-5-39-16-11-11-16-24-16-39 0-15 5-28 16-39 11-11 24-16 39-16 15 0 28 5 39 16 11 11 16 24 16 39z m-174-168c0-16-5-29-16-40-11-11-25-16-40-16-11 0-21 2-30 8-9 5-16 13-20 22 9-4 19-8 28-12 11-4 22-4 34 1 11 5 19 13 24 25 5 11 5 22 0 34-5 11-13 19-25 24l-23 9c4 1 8 2 12 2 15 0 29-6 40-17 11-11 16-24 16-40z m258 234l0-274c0-23-8-42-24-58-16-16-35-24-58-24l-274 0c-23 0-42 8-58 24-16 16-24 35-24 58l0 44 49-20c4-18 12-32 26-44 14-11 30-17 49-17 19 0 37 7 51 20 15 14 23 30 25 50l99 72c28 0 53 10 73 30 20 20 30 44 30 73 0 28-10 52-30 73-20 20-45 30-73 30-28 0-53-10-73-30-20-20-30-44-30-72l-64-92c-2 0-5 0-8 0-15 0-28-4-40-11l-84 34 0 134c0 23 8 42 24 58 16 16 35 24 58 24l274 0c23 0 42-8 58-24 16-16 24-35 24-58z m-70-66c0-19-7-36-20-49-14-14-30-20-49-20-19 0-36 6-49 20-13 13-20 30-20 49 0 19 7 35 20 48 13 14 30 21 49 21 19 0 35-7 49-20 13-14 20-30 20-49z"/>
<glyph glyph-name="oculus" unicode="&#57398;" d="M431 363c-16 13-34 22-54 26-11 3-23 4-34 5-9 0-18 0-26 0-41 0-82 0-123 0-9 0-18 0-26 0-12-1-24-2-35-5-20-4-38-13-54-26-32-26-51-65-51-106 0-41 19-80 51-106 16-13 34-22 54-27 12-2 23-3 35-4 8 0 17 0 26 0 41 0 82 0 123 0 8 0 17 0 26 0 11 0 23 2 34 4 20 5 38 14 54 27 32 26 51 65 51 106 0 41-19 80-51 106z m-60-143c-6-4-13-7-20-8-7-1-14-1-22-1-49 0-99 0-148 0-8 0-15 0-22 1-7 1-14 4-20 8-12 8-19 22-19 37 0 15 7 29 19 37 6 4 13 7 20 8 7 1 14 1 22 1 49 0 99 0 148 0 8 0 15 0 22-1 7-1 14-4 20-8 12-8 19-22 19-37 0-15-7-29-19-37z"/>
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View file

@ -603,6 +603,14 @@
<div class="icon icon-avatar-1"></div>
<input type="text" readonly="readonly" value="avatar-1">
</li>
<li>
<div class="icon icon-steam-square"></div>
<input type="text" readonly="readonly" value="steam-square">
</li>
<li>
<div class="icon icon-oculus"></div>
<input type="text" readonly="readonly" value="oculus">
</li>
</ul>
<h2>Character mapping</h2>
<ul class="glyphs character-mapping">
@ -1194,6 +1202,14 @@
<div data-icon="T" class="icon"></div>
<input type="text" readonly="readonly" value="T">
</li>
<li>
<div data-icon="&#xe035;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe035;">
</li>
<li>
<div data-icon="&#xe036;" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;#xe036;">
</li>
</ul>
</div>
<script>(function() {

View file

@ -479,3 +479,9 @@
.icon-avatar-1:before {
content: "\54";
}
.icon-steam-square:before {
content: "\e035";
}
.icon-oculus:before {
content: "\e036";
}

View file

@ -0,0 +1,4 @@
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.4866 0C4.92045 0 0.367395 4.32104 0 9.78734L5.45262 11.9841C5.93184 11.651 6.51333 11.4545 7.14145 11.4545C7.27641 11.4545 7.4083 11.4666 7.53829 11.4841L10.1047 7.72495C10.1083 5.56672 11.861 3.81818 14.0229 3.81818C16.1872 3.81818 17.9416 5.57035 17.9416 7.73182C17.9416 9.89329 16.1872 11.6455 14.0229 11.6455C14.021 11.6455 14.0189 11.6453 14.017 11.6453L10.0936 14.2008C10.0986 14.2712 10.1043 14.3419 10.1043 14.4136C10.1043 16.048 8.77791 17.3727 7.14145 17.3727C5.69539 17.3727 4.49304 16.3376 4.2325 14.969L0.378099 13.3841C1.6334 17.7801 5.6822 21 10.4866 21C16.2931 21 21 16.2991 21 10.5C21 4.70114 16.2931 0 10.4866 0ZM7.14145 16.0364C6.96655 16.0364 6.79833 16.0081 6.64044 15.9569L6.63968 15.9589L6.59151 15.939C6.54506 15.9224 6.49975 15.9037 6.45541 15.8831L5.15462 15.3483C5.50614 16.0927 6.26253 16.6091 7.14145 16.6091C8.35546 16.6091 9.33971 15.6263 9.33971 14.4136C9.33971 13.201 8.35546 12.2182 7.14145 12.2182C6.87269 12.2182 6.61636 12.2688 6.37818 12.357L7.75448 12.9114C7.76404 12.9154 7.77359 12.9188 7.78296 12.923L7.89001 12.9662L7.88714 12.9732C8.40898 13.243 8.76625 13.7861 8.76625 14.4136C8.76625 15.3098 8.03872 16.0364 7.14145 16.0364ZM16.7946 7.73182C16.7946 6.20302 15.5537 4.96364 14.0229 4.96364C12.4922 4.96364 11.2512 6.20302 11.2512 7.73182C11.2512 9.26062 12.4922 10.5 14.0229 10.5C15.5537 10.5 16.7946 9.26062 16.7946 7.73182ZM12.0158 7.73182C12.0158 6.62474 12.9144 5.72727 14.0229 5.72727C15.1314 5.72727 16.03 6.62474 16.03 7.73182C16.03 8.8389 15.1314 9.73636 14.0229 9.73636C12.9144 9.73636 12.0158 8.8389 12.0158 7.73182Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,17 @@
<svg width="360" height="85" viewBox="0 0 360 85" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M124 30V59H117.974V46.3455H108.026V59H102V30H108.026V41.1899H117.974V30H124Z" fill="#00B4F0"/>
<path d="M135 59H129V30H135V59Z" fill="#00B4F0"/>
<path d="M151.829 34.9471C150.406 34.9471 149.211 35.0608 148.187 35.3451C147.22 35.6294 146.423 36.0843 145.797 36.7098C145.171 37.3353 144.772 38.2451 144.488 39.3255C144.203 40.4059 144.089 41.7706 144.089 43.3627V45.9216C144.089 47.6275 144.203 48.9922 144.431 50.0726C144.659 51.1529 145.057 52.0059 145.626 52.5745C146.138 53.2 146.878 53.598 147.732 53.8255C148.585 54.0529 149.667 54.1667 150.919 54.1667C151.26 54.1667 151.659 54.1667 152.057 54.1098C152.455 54.1098 152.854 54.0529 153.309 53.9961V46.3765H149.78L150.35 41.7137H159V57.749C157.919 58.1471 156.553 58.4314 154.902 58.6588C153.309 58.8863 151.602 59 149.894 59C147.732 59 145.911 58.7157 144.431 58.2039C142.894 57.6922 141.699 56.8961 140.732 55.8157C139.764 54.7353 139.081 53.4275 138.626 51.7784C138.171 50.1863 138 48.2529 138 46.0922V43.1922C138 41.202 138.228 39.4392 138.626 37.7902C139.081 36.1412 139.821 34.7765 140.846 33.6392C141.87 32.502 143.236 31.5922 144.886 30.9667C146.537 30.3412 148.642 30 151.146 30C152.512 30 153.878 30.1137 155.187 30.3412C156.496 30.5686 157.577 30.8529 158.431 31.1373L157.463 35.6863C156.724 35.4588 155.87 35.2882 154.959 35.1176C154.049 35.0039 153.024 34.9471 151.829 34.9471Z" fill="#00B4F0"/>
<path d="M187 30V59H180.959V46.3455H171.041V59H165V30H171.041V41.1899H181.016V30H187Z" fill="#00B4F0"/>
<path d="M218 30L217.366 35.0384H207.597V41.0727H216.627L215.993 46.1111H207.597V59H202V30H218Z" fill="#00B4F0"/>
<path d="M229 59H223V30H229V59Z" fill="#00B4F0"/>
<path d="M233 30H242.404C244.842 30 246.873 30.3508 248.499 30.994C250.124 31.6371 251.401 32.5726 252.388 33.6835C253.375 34.8528 254.013 36.1976 254.42 37.8347C254.826 39.4718 255 41.2258 255 43.0968V45.8448C255 47.7742 254.826 49.5282 254.42 51.1653C254.013 52.8024 253.317 54.1472 252.388 55.3165C251.401 56.4859 250.124 57.3629 248.499 58.006C246.873 58.6492 244.842 59 242.404 59H233.058V30H233ZM239.095 53.9133H241.765C242.926 53.9133 243.913 53.7964 244.842 53.504C245.712 53.2117 246.467 52.744 247.047 52.1008C247.628 51.4577 248.034 50.5806 248.325 49.5282C248.615 48.4758 248.731 47.1311 248.731 45.494V43.3306C248.731 41.6935 248.615 40.3488 248.325 39.2964C248.034 38.2439 247.628 37.3669 247.047 36.7238C246.467 36.0806 245.77 35.6129 244.842 35.379C243.971 35.1452 242.926 34.9698 241.765 34.9698H239.095V53.9133Z" fill="#00B4F0"/>
<path d="M275.945 30L275.34 34.8528H264.832V41.1673H274.735L274.184 46.0202H264.887V54.1472H276L275.395 59H259V30H275.945Z" fill="#00B4F0"/>
<path d="M286.215 30V53.9616H298L297.296 59H280V30H286.215Z" fill="#00B4F0"/>
<path d="M307 59H302V30H307V59Z" fill="#00B4F0"/>
<path d="M334 30L333.307 35.0384H325.563V59H319.437V35.0384H311L311.693 30H334Z" fill="#00B4F0"/>
<path d="M347.617 41.3071L353.633 30H360L350.537 46.3455V59H344.346V46.3455L335 30H341.776L347.617 41.3071Z" fill="#00B4F0"/>
<path d="M42.1132 85C36.4528 85 30.9057 83.856 25.7547 81.6824C20.717 79.5659 16.2453 76.4771 12.3962 72.5875C8.54717 68.6978 5.49057 64.1218 3.39623 59.0882C1.13208 53.7685 -1.07963e-07 48.22 -1.07963e-07 42.4428C-1.07963e-07 36.7227 1.13208 31.1171 3.28302 25.9118C5.37736 20.821 8.43396 16.3022 12.283 12.4125C16.1321 8.52288 20.6604 5.43405 25.6415 3.31763C30.8491 1.08681 36.3396 1.09101e-07 42 1.09101e-07C47.6604 1.09101e-07 53.2076 1.14401 58.3585 3.31763C63.3962 5.43405 67.8679 8.52288 71.717 12.4125C75.566 16.3022 78.6227 20.8782 80.717 25.9118C82.9245 31.1743 84 36.7227 84 42.4428C84 48.1628 82.8679 53.7685 80.717 58.9737C78.6227 64.0646 75.566 68.5834 71.717 72.4731C67.8679 76.3627 63.3396 79.4515 58.3585 81.568C53.3208 83.856 47.7736 85 42.1132 85ZM42.1132 4.34724C21.3396 4.34724 4.41509 21.4502 4.41509 42.4428C4.41509 63.4354 21.3396 80.5384 42.1132 80.5384C62.8868 80.5384 79.8113 63.4354 79.8113 42.4428C79.8113 21.4502 62.8868 4.34724 42.1132 4.34724Z" fill="#00B4F0"/>
<path d="M54.8 60.7368V30.5158C56.6857 29.8789 58 28.0842 58 26C58 23.3947 55.8857 21.2526 53.3143 21.2526C50.7429 21.2526 48.6286 23.3947 48.6286 26C48.6286 28.0263 49.8286 29.7053 51.6 30.4579V44.5263L32.1714 35.379V24.2632C34.0571 23.6263 35.3714 21.8316 35.3714 19.7474C35.3714 17.1421 33.2571 15 30.6857 15C28.1143 15 26 17.1421 26 19.7474C26 21.7737 27.2 23.4526 28.9714 24.2053V54.6C27.2571 55.2947 26 57.0316 26 59.0579C26 61.6632 28.1143 63.8053 30.6857 63.8053C33.2571 63.8053 35.3714 61.6632 35.3714 59.0579C35.3714 56.9737 34.0571 55.1789 32.1714 54.5421V39.2L51.6 48.3474V60.7947C49.8857 61.4895 48.6286 63.2263 48.6286 65.2526C48.6286 67.8579 50.7429 70 53.3143 70C55.8857 70 58 67.8579 58 65.2526C58 63.1105 56.6857 61.3737 54.8 60.7368Z" fill="#00B4F0"/>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -54,7 +54,7 @@ Windows.Window {
onSourceChanged: {
if (dynamicContent) {
dynamicContent.destroy();
dynamicContent = null;
dynamicContent = null;
}
QmlSurface.load(source, contentHolder, function(newObject) {
dynamicContent = newObject;
@ -117,7 +117,7 @@ Windows.Window {
console.error("presentationMode should be set.");
}
}
Component.onCompleted: {
// Fix for parent loss on OSX:
parent.heightChanged.connect(updateContentParent);
@ -215,7 +215,7 @@ Windows.Window {
nativeWindow.raise();
}
}
// Handle message traffic from our loaded QML to the script that launched us
signal sendToScript(var message);

View file

@ -3,7 +3,6 @@
//
// Created by David Rowe on 3 Jun 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
@ -11,32 +10,34 @@
import Hifi 1.0
import QtQuick 2.4
import controlsUit 1.0
import stylesUit 1.0
import "windows"
import controlsUit 1.0 as HifiControlsUit
import stylesUit 1.0 as HifiStylesUit
import "LoginDialog"
ModalWindow {
FocusScope {
id: root
HifiConstants { id: hifi }
HifiStylesUit.HifiConstants { id: hifi }
objectName: "LoginDialog"
implicitWidth: 520
implicitHeight: 320
closeButtonVisible: true
destroyOnCloseButton: true
destroyOnHidden: true
visible: true
property bool shown: true
visible: shown
anchors.fill: parent
readonly property bool isTablet: false
readonly property bool isOverlay: false
property string iconText: ""
property int iconSize: 50
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
property bool isPassword: false
property string title: ""
property string text: ""
property int titleWidth: 0
keyboardOverride: true // Disable ModalWindow's keyboard.
property alias bannerWidth: banner.width
property alias bannerHeight: banner.height
function tryDestroy() {
root.destroy()
@ -47,7 +48,39 @@ ModalWindow {
Loader {
id: bodyLoader
source: loginDialog.isSteamRunning() ? "LoginDialog/SignInBody.qml" : "LoginDialog/LinkAccountBody.qml"
}
}
Image {
z: -10
id: loginDialogBackground
source: "LoginDialog/images/background.jpg"
anchors.fill: parent
}
Rectangle {
z: -6
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.65
color: "black"
}
Item {
z: -5
id: bannerContainer
width: parent.width
height: banner.height
anchors {
top: parent.top
topMargin: 0.18 * parent.height
}
Image {
id: banner
anchors.centerIn: parent
source: "../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
@ -76,7 +109,6 @@ ModalWindow {
case Qt.Key_Escape:
case Qt.Key_Back:
event.accepted = true
destroy()
break
case Qt.Key_Enter:
@ -85,4 +117,8 @@ ModalWindow {
break
}
}
Component.onCompleted: {
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
}
}

View file

@ -12,109 +12,240 @@ import Hifi 1.0
import QtQuick 2.4
import QtQuick.Controls.Styles 1.4 as OriginalStyles
import controlsUit 1.0
import stylesUit 1.0
import controlsUit 1.0 as HifiControlsUit
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
Item {
id: completeProfileBody
clip: true
width: root.pane.width
height: root.pane.height
width: root.width
height: root.height
readonly property string termsContainerText: qsTr("By creating this user profile, you agree to High Fidelity's Terms of Service")
readonly property string fontFamily: "Raleway"
readonly property int fontSize: 15
readonly property bool fontBold: true
readonly property bool withSteam: withSteam
property string errorString: errorString
QtObject {
id: d
readonly property int minWidth: 480
readonly property int maxWidth: 1280
readonly property int minWidthButton: !root.isTablet ? 256 : 174
property int maxWidth: root.width
readonly property int minHeight: 120
readonly property int maxHeight: 720
readonly property int minHeightButton: 36
property int maxHeight: root.height
function resize() {
maxWidth = root.width;
maxHeight = root.height;
if (root.isTablet === false) {
var targetWidth = Math.max(titleWidth, Math.max(additionalTextContainer.contentWidth,
termsContainer.contentWidth))
var targetWidth = Math.max(Math.max(titleWidth, Math.max(additionalTextContainer.width,
termsContainer.width)), mainContainer.width)
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
}
var targetHeight = 5 * hifi.dimensions.contentSpacing.y + buttons.height + additionalTextContainer.height + termsContainer.height
var targetHeight = Math.max(5 * hifi.dimensions.contentSpacing.y + d.minHeightButton + additionalTextContainer.height + termsContainer.height, d.maxHeight)
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
}
}
Row {
id: buttons
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: 2 * hifi.dimensions.contentSpacing.y
}
spacing: hifi.dimensions.contentSpacing.x
Item {
id: mainContainer
width: root.width
height: root.height
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Button {
anchors.verticalCenter: parent.verticalCenter
width: 200
Item {
id: contentItem
anchors.fill: parent
text: qsTr("Create your profile")
color: hifi.buttons.blue
Item {
id: errorContainer
width: parent.width
height: loginErrorMessageTextMetrics.height
anchors {
bottom: buttons.top;
bottomMargin: hifi.dimensions.contentSpacing.y;
left: buttons.left;
}
TextMetrics {
id: loginErrorMessageTextMetrics
font: loginErrorMessage.font
text: loginErrorMessage.text
}
Text {
id: loginErrorMessage;
width: root.bannerWidth
color: "red";
font.family: completeProfileBody.fontFamily
font.pixelSize: 18
font.bold: completeProfileBody.fontBold
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: completeProfileBody.errorString
visible: true
}
Component.onCompleted: {
if (loginErrorMessageTextMetrics.width > root.bannerWidth && root.isTablet) {
loginErrorMessage.wrapMode = Text.WordWrap;
loginErrorMessage.verticalAlignment = Text.AlignLeft;
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
errorContainer.height = 3 * loginErrorMessageTextMetrics.height;
}
}
}
onClicked: loginDialog.createAccountFromStream()
Item {
id: buttons
width: root.bannerWidth
height: d.minHeightButton
anchors {
top: parent.top
topMargin: (parent.height - additionalTextContainer.height) / 2 - hifi.dimensions.contentSpacing.y
left: parent.left
leftMargin: (parent.width - root.bannerWidth) / 2
}
HifiControlsUit.Button {
id: cancelButton
anchors {
top: parent.top
left: parent.left
}
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
text: qsTr("CANCEL")
color: hifi.buttons.noneBorderlessWhite
fontFamily: completeProfileBody.fontFamily
fontSize: completeProfileBody.fontSize
fontBold: completeProfileBody.fontBold
onClicked: {
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
}
}
HifiControlsUit.Button {
id: profileButton
anchors {
top: parent.top
right: parent.right
}
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
text: qsTr("Create your profile")
color: hifi.buttons.blue
fontFamily: completeProfileBody.fontFamily
fontSize: completeProfileBody.fontSize
fontBold: completeProfileBody.fontBold
onClicked: {
loginErrorMessage.visible = false;
loginDialog.createAccountFromSteam();
}
}
}
Item {
id: additionalTextContainer
width: parent.width
height: additionalTextMetrics.height
anchors {
top: buttons.bottom
horizontalCenter: parent.horizontalCenter
topMargin: hifi.dimensions.contentSpacing.y
left: parent.left
}
TextMetrics {
id: additionalTextMetrics
font: additionalText.font
text: "Already have a High Fidelity profile? Link to an existing profile here."
}
HifiStylesUit.ShortcutText {
id: additionalText
text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
font.family: completeProfileBody.fontFamily
font.pixelSize: completeProfileBody.fontSize
font.bold: completeProfileBody.fontBold
wrapMode: Text.NoWrap
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
linkColor: hifi.colors.blueAccent
onLinkActivated: {
loginDialog.isLogIn = true;
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "", "withSteam": true, "linkSteam": true });
}
Component.onCompleted: {
if (additionalTextMetrics.width > root.bannerWidth && root.isTablet) {
additionalText.width = root.bannerWidth;
additionalText.wrapMode = Text.WordWrap;
additionalText.verticalAlignment = Text.AlignLeft;
additionalText.horizontalAlignment = Text.AlignLeft;
additionalTextContainer.height = (additionalTextMetrics.width / root.bannerWidth) * additionalTextMetrics.height;
additionalTextContainer.anchors.left = buttons.left;
} else {
additionalText.anchors.centerIn = additionalTextContainer;
}
}
}
}
Item {
id: termsContainer
width: parent.width
height: termsTextMetrics.height
anchors {
top: additionalTextContainer.bottom
horizontalCenter: parent.horizontalCenter
topMargin: 2 * hifi.dimensions.contentSpacing.y
left: parent.left
}
TextMetrics {
id: termsTextMetrics
font: termsText.font
text: completeProfileBody.termsContainerText
Component.onCompleted: {
// with the link.
termsText.text = qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
}
}
HifiStylesUit.InfoItem {
id: termsText
text: completeProfileBody.termsContainerText
font.family: completeProfileBody.fontFamily
font.pixelSize: completeProfileBody.fontSize
font.bold: completeProfileBody.fontBold
wrapMode: Text.WordWrap
color: hifi.colors.lightGray
linkColor: hifi.colors.blueAccent
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
onLinkActivated: loginDialog.openUrl(link);
Component.onCompleted: {
if (termsTextMetrics.width > root.bannerWidth && root.isTablet) {
termsText.width = root.bannerWidth;
termsText.wrapMode = Text.WordWrap;
additionalText.verticalAlignment = Text.AlignLeft;
additionalText.horizontalAlignment = Text.AlignLeft;
termsContainer.height = (termsTextMetrics.width / root.bannerWidth) * termsTextMetrics.height;
termsContainer.anchors.left = buttons.left;
} else {
termsText.anchors.centerIn = termsContainer;
}
}
}
}
}
Button {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Cancel")
onClicked: root.tryDestroy()
}
}
ShortcutText {
id: additionalTextContainer
anchors {
top: buttons.bottom
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
wrapMode: Text.WordWrap
lineHeight: 2
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
onLinkActivated: {
bodyLoader.source = "LinkAccountBody.qml"
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
InfoItem {
id: termsContainer
anchors {
top: additionalTextContainer.bottom
margins: 0
topMargin: 2 * hifi.dimensions.contentSpacing.y
horizontalCenter: parent.horizontalCenter
}
width: parent.width
text: qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
wrapMode: Text.WordWrap
color: hifi.colors.baseGrayHighlight
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
fontSizeMode: Text.HorizontalFit
horizontalAlignment: Text.AlignVCenter
onLinkActivated: loginDialog.openUrl(link)
}
Component.onCompleted: {
root.title = qsTr("Complete Your Profile")
root.iconText = "<"
d.resize();
}
Connections {
@ -122,26 +253,23 @@ Item {
onHandleCreateCompleted: {
console.log("Create Succeeded")
loginDialog.loginThroughSteam()
loginDialog.loginThroughSteam();
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": true, "linkSteam": false });
}
onHandleCreateFailed: {
console.log("Create Failed: " + error)
console.log("Create Failed: " + error);
bodyLoader.source = "UsernameCollisionBody.qml"
if (!root.isTablet) {
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
onHandleLoginCompleted: {
console.log("Login Succeeded")
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLoginFailed: {
console.log("Login Failed")
bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
}
}
Component.onCompleted: {
//but rise Tablet's one instead for Tablet interface
if (root.isTablet || root.isOverlay) {
root.keyboardEnabled = HMD.active;
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
}
d.resize();
root.text = "";
}
}

View file

@ -13,408 +13,544 @@ import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 as OriginalStyles
import controlsUit 1.0
import stylesUit 1.0
import "." as LoginDialog
import controlsUit 1.0 as HifiControlsUit
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
Item {
z: -2
id: linkAccountBody
clip: true
height: root.pane.height
width: root.pane.width
property bool failAfterSignUp: false
onWidthChanged: d.resize();
function login() {
flavorText.visible = false
mainTextContainer.visible = false
toggleLoading(true)
loginDialog.login(usernameField.text, passwordField.text)
}
height: root.height
width: root.width
property int textFieldHeight: 31
property string fontFamily: "Raleway"
property int fontSize: 15
property int textFieldFontSize: 18
property bool fontBold: true
readonly property var passwordImageRatio: 16 / 23
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
onKeyboardRaisedChanged: d.resize();
property bool withSteam: false
property bool linkSteam: linkSteam
property bool withOculus: false
property string errorString: errorString
property bool lostFocus: false
QtObject {
id: d
readonly property int minWidth: 480
readonly property int maxWidth: 1280
readonly property int minWidthButton: !root.isTablet ? 256 : 174
property int maxWidth: root.width
readonly property int minHeight: 120
readonly property int maxHeight: 720
readonly property int minHeightButton: 36
property int maxHeight: root.height
function resize() {
var targetWidth = Math.max(titleWidth, form.contentWidth);
var targetHeight = hifi.dimensions.contentSpacing.y + flavorText.height + mainTextContainer.height +
4 * hifi.dimensions.contentSpacing.y + form.height;
if (additionalInformation.visible) {
targetWidth = Math.max(targetWidth, additionalInformation.width);
targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height
}
maxWidth = root.width;
maxHeight = root.height;
var targetWidth = Math.max(titleWidth, mainContainer.width);
var targetHeight = hifi.dimensions.contentSpacing.y + mainContainer.height + 4 * hifi.dimensions.contentSpacing.y;
var newWidth = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
if(!isNaN(newWidth)) {
if (!isNaN(newWidth)) {
parent.width = root.width = newWidth;
}
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
+ (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y);
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)) + hifi.dimensions.contentSpacing.y;
}
}
function toggleLoading(isLoading) {
linkAccountSpinner.visible = isLoading
form.visible = !isLoading
if (loginDialog.isSteamRunning()) {
additionalInformation.visible = !isLoading
}
function login() {
loginDialog.login(emailField.text, passwordField.text);
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam });
}
BusyIndicator {
id: linkAccountSpinner
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
topMargin: hifi.dimensions.contentSpacing.y
function init() {
// going to/from sign in/up dialog.
loginDialog.isLogIn = true;
loginErrorMessage.text = linkAccountBody.errorString;
loginErrorMessage.visible = (linkAccountBody.errorString !== "");
loginButton.text = !linkAccountBody.linkSteam ? "Log In" : "Link Account";
loginButton.color = hifi.buttons.blue;
emailField.placeholderText = "Username or Email";
var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
emailField.text = keepMeLoggedInCheckbox.checked ? savedUsername === "Unknown user" ? "" : savedUsername : "";
if (linkAccountBody.linkSteam) {
steamInfoText.anchors.top = passwordField.bottom;
keepMeLoggedInCheckbox.anchors.top = steamInfoText.bottom;
loginButton.width = (passwordField.width - hifi.dimensions.contentSpacing.x) / 2;
loginButton.anchors.right = emailField.right;
} else {
loginButton.anchors.left = emailField.left;
}
visible: false
running: true
width: 48
height: 48
loginContainer.visible = true;
}
ShortcutText {
id: flavorText
anchors {
top: parent.top
left: parent.left
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
Item {
z: 10
id: mainContainer
width: root.width
height: root.height
onHeightChanged: d.resize(); onWidthChanged: d.resize();
LoginDialog.LoginDialogLightbox {
id: lightboxPopup;
visible: false;
anchors.fill: parent;
}
text: qsTr("Sign in to High Fidelity to make friends, get HFC, and get interesting things on the Marketplace!")
width: parent.width
wrapMode: Text.WordWrap
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
}
Item {
id: loginContainer
width: emailField.width
height: errorContainer.height + emailField.height + passwordField.height + 5.5 * hifi.dimensions.contentSpacing.y +
keepMeLoggedInCheckbox.height + loginButton.height + cantAccessTextMetrics.height + continueButton.height + steamInfoTextMetrics.height
anchors {
top: parent.top
topMargin: root.bannerHeight + 0.25 * parent.height
left: parent.left
leftMargin: (parent.width - emailField.width) / 2
}
ShortcutText {
id: mainTextContainer
anchors {
top: flavorText.bottom
left: parent.left
margins: 0
topMargin: 1.5 * hifi.dimensions.contentSpacing.y
}
visible: false
text: qsTr("Username or password incorrect.")
height: flavorText.height - 20
wrapMode: Text.WordWrap
color: hifi.colors.redAccent
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
}
Column {
id: form
width: parent.width
onHeightChanged: d.resize();
anchors {
top: mainTextContainer.bottom
topMargin: 1.5 * hifi.dimensions.contentSpacing.y
}
spacing: 2 * hifi.dimensions.contentSpacing.y
TextField {
id: usernameField
text: Settings.getValue("keepMeLoggedIn/savedUsername", "");
width: parent.width
focus: true
placeholderText: "Username or Email"
activeFocusOnPress: true
onHeightChanged: d.resize(); onWidthChanged: d.resize();
ShortcutText {
z: 10
y: usernameField.height
Item {
id: errorContainer
width: loginErrorMessageTextMetrics.width
height: loginErrorMessageTextMetrics.height
anchors {
right: usernameField.right
top: usernameField.bottom
topMargin: 4
bottom: emailField.top;
bottomMargin: hifi.dimensions.contentSpacing.y;
left: emailField.left;
}
TextMetrics {
id: loginErrorMessageTextMetrics
font: loginErrorMessage.font
text: loginErrorMessage.text
}
Text {
id: loginErrorMessage;
color: "red";
font.family: linkAccountBody.fontFamily
font.pixelSize: linkAccountBody.textFieldFontSize
font.bold: linkAccountBody.fontBold
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: ""
visible: false
}
}
HifiControlsUit.TextField {
id: emailField
width: root.bannerWidth
height: linkAccountBody.textFieldHeight
font.pixelSize: linkAccountBody.textFieldFontSize
styleRenderType: Text.QtRendering
anchors {
top: parent.top
topMargin: errorContainer.height
}
placeholderText: "Username or Email"
activeFocusOnPress: true
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Tab:
event.accepted = true;
passwordField.focus = true;
break;
case Qt.Key_Backtab:
event.accepted = true;
passwordField.focus = true;
break;
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text);
}
linkAccountBody.login();
break;
}
}
onFocusChanged: {
root.text = "";
if (focus) {
root.isPassword = false;
}
}
}
HifiControlsUit.TextField {
id: passwordField
width: root.bannerWidth
height: linkAccountBody.textFieldHeight
font.pixelSize: linkAccountBody.textFieldFontSize
styleRenderType: Text.QtRendering
placeholderText: "Password"
activeFocusOnPress: true
echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
anchors {
top: emailField.bottom
topMargin: 1.5 * hifi.dimensions.contentSpacing.y
}
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
linkColor: hifi.colors.blueAccent
onLinkActivated: loginDialog.openUrl(link)
}
onFocusChanged: {
root.text = "";
}
Component.onCompleted: {
var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
usernameField.text = savedUsername === "Unknown user" ? "" : savedUsername;
}
}
TextField {
id: passwordField
width: parent.width
placeholderText: "Password"
activeFocusOnPress: true
echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
onHeightChanged: d.resize(); onWidthChanged: d.resize();
ShortcutText {
id: forgotPasswordShortcut
y: passwordField.height
z: 10
anchors {
right: passwordField.right
top: passwordField.bottom
topMargin: 4
onFocusChanged: {
root.text = "";
root.isPassword = focus;
}
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
linkColor: hifi.colors.blueAccent
onLinkActivated: loginDialog.openUrl(link)
}
onFocusChanged: {
root.text = "";
root.isPassword = true;
}
Rectangle {
id: showPasswordHitbox
z: 10
x: passwordField.width - ((passwordField.height) * 31 / 23)
width: parent.width - (parent.width - (parent.height * 31/16))
height: parent.height
anchors {
right: parent.right
}
color: "transparent"
Image {
id: showPasswordImage
width: passwordField.height * 16 / 23
height: passwordField.height * 16 / 23
Item {
id: showPasswordContainer
z: 10
// width + image's rightMargin
width: showPasswordImage.width + 8
height: parent.height
anchors {
right: parent.right
rightMargin: 8
top: parent.top
topMargin: passwordFieldMouseArea.showPassword ? 6 : 8
bottom: parent.bottom
bottomMargin: passwordFieldMouseArea.showPassword ? 5 : 8
}
source: passwordFieldMouseArea.showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg"
MouseArea {
id: passwordFieldMouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
property bool showPassword: false
onClicked: {
showPassword = !showPassword;
Image {
id: showPasswordImage
width: passwordField.height * passwordImageRatio
height: passwordField.height * passwordImageRatio
anchors {
right: parent.right
rightMargin: 8
top: parent.top
topMargin: passwordFieldMouseArea.showPassword ? 6 : 8
bottom: parent.bottom
bottomMargin: passwordFieldMouseArea.showPassword ? 5 : 8
}
source: passwordFieldMouseArea.showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg"
MouseArea {
id: passwordFieldMouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
property bool showPassword: false
onClicked: {
showPassword = !showPassword;
}
}
}
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Tab:
case Qt.Key_Backtab:
event.accepted = true;
emailField.focus = true;
break;
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text);
}
linkAccountBody.login();
break;
}
}
}
Keys.onReturnPressed: {
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
linkAccountBody.login();
}
}
InfoItem {
id: additionalInformation
visible: loginDialog.isSteamRunning()
text: qsTr("Your steam account informations will not be exposed to other users.")
wrapMode: Text.WordWrap
color: hifi.colors.baseGrayHighlight
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
}
Row {
id: buttons
spacing: hifi.dimensions.contentSpacing.y*2
onHeightChanged: d.resize(); onWidthChanged: d.resize();
anchors.horizontalCenter: parent.horizontalCenter
CheckBox {
id: autoLogoutCheckbox
checked: Settings.getValue("keepMeLoggedIn", false)
text: "Keep me logged in"
boxSize: 20;
labelFontSize: 15
color: hifi.colors.black
HifiControlsUit.CheckBox {
id: keepMeLoggedInCheckbox
checked: Settings.getValue("keepMeLoggedIn", false);
text: qsTr("Keep Me Logged In");
boxSize: 18;
labelFontFamily: linkAccountBody.fontFamily
labelFontSize: 18;
color: hifi.colors.white;
anchors {
top: passwordField.bottom;
topMargin: hifi.dimensions.contentSpacing.y;
left: passwordField.left;
}
onCheckedChanged: {
Settings.setValue("keepMeLoggedIn", checked);
if (checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text);
} else {
Settings.setValue("keepMeLoggedIn/savedUsername", "");
}
}
Component.onDestruction: {
Settings.setValue("keepMeLoggedIn", checked);
}
HifiControlsUit.Button {
id: cancelButton
width: (passwordField.width - hifi.dimensions.contentSpacing.x) / 2;
height: d.minHeightButton
text: qsTr("Cancel")
fontFamily: linkAccountBody.fontFamily
fontSize: linkAccountBody.fontSize
fontBold: linkAccountBody.fontBold
color: hifi.buttons.noneBorderlessWhite;
visible: linkAccountBody.linkSteam
anchors {
top: keepMeLoggedInCheckbox.bottom
topMargin: hifi.dimensions.contentSpacing.y
}
onClicked: {
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "errorString": "" });
}
}
Button {
id: linkAccountButton
anchors.verticalCenter: parent.verticalCenter
width: 200
text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Log in")
color: hifi.buttons.blue
HifiControlsUit.Button {
id: loginButton
width: passwordField.width
height: d.minHeightButton
text: qsTr("Log In")
fontFamily: linkAccountBody.fontFamily
fontSize: linkAccountBody.fontSize
fontBold: linkAccountBody.fontBold
anchors {
top: keepMeLoggedInCheckbox.bottom
topMargin: hifi.dimensions.contentSpacing.y
}
onClicked: {
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
linkAccountBody.login();
linkAccountBody.login()
}
}
TextMetrics {
id: steamInfoTextMetrics
font: steamInfoText.font
text: steamInfoText.text
}
Text {
id: steamInfoText
width: root.bannerWidth
visible: linkAccountBody.linkSteam
anchors {
top: loginButton.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: emailField.left
}
font.family: linkAccountBody.fontFamily
font.pixelSize: linkAccountBody.textFieldFontSize
color: "white"
text: qsTr("Your Steam account information will not be exposed to others.");
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
Component.onCompleted: {
if (steamInfoTextMetrics.width > root.bannerWidth) {
steamInfoText.wrapMode = Text.WordWrap;
}
}
}
TextMetrics {
id: cantAccessTextMetrics
font: cantAccessText.font
text: "Can't access your account?"
}
HifiStylesUit.ShortcutText {
id: cantAccessText
z: 10
visible: !linkAccountBody.linkSteam
anchors {
top: loginButton.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: emailField.left
}
font.family: linkAccountBody.fontFamily
font.pixelSize: linkAccountBody.textFieldFontSize
font.bold: linkAccountBody.fontBold
text: "<a href='https://highfidelity.com/users/password/new'> Can't access your account?</a>"
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
linkColor: hifi.colors.blueAccent
onLinkActivated: {
Tablet.playSound(TabletEnums.ButtonClick);
loginDialog.openUrl(link);
lightboxPopup.titleText = "Can't Access Account";
lightboxPopup.bodyText = lightboxPopup.cantAccessBodyText;
lightboxPopup.button2text = "CLOSE";
lightboxPopup.button2method = function() {
lightboxPopup.visible = false;
}
lightboxPopup.visible = true;
// bodyLoader.setSource("CantAccessBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader });
}
}
HifiControlsUit.Button {
id: continueButton;
width: emailField.width;
height: d.minHeightButton
color: hifi.buttons.none;
anchors {
top: cantAccessText.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: emailField.left
}
text: qsTr("CONTINUE WITH STEAM")
fontFamily: linkAccountBody.fontFamily
fontSize: linkAccountBody.fontSize
fontBold: linkAccountBody.fontBold
buttonGlyph: hifi.glyphs.steamSquare
buttonGlyphSize: 24
buttonGlyphRightMargin: 10
onClicked: {
// if (loginDialog.isOculusStoreRunning()) {
// linkAccountBody.withOculus = true;
// loginDialog.loginThroughSteam();
// } else
if (loginDialog.isSteamRunning()) {
linkAccountBody.withSteam = true;
loginDialog.loginThroughSteam();
}
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
"withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam });
}
Component.onCompleted: {
if (linkAccountBody.linkSteam) {
continueButton.visible = false;
return;
}
// if (loginDialog.isOculusStoreRunning()) {
// continueButton.text = qsTr("CONTINUE WITH OCULUS");
// continueButton.buttonGlyph = hifi.glyphs.oculus;
// } else
if (loginDialog.isSteamRunning()) {
continueButton.text = qsTr("CONTINUE WITH STEAM");
continueButton.buttonGlyph = hifi.glyphs.steamSquare;
} else {
continueButton.visible = false;
}
}
}
}
Row {
id: leftButton
anchors.horizontalCenter: parent.horizontalCenter
spacing: hifi.dimensions.contentSpacing.y*2
onHeightChanged: d.resize(); onWidthChanged: d.resize();
RalewaySemiBold {
size: hifi.fontSizes.inputLabel
anchors.verticalCenter: parent.verticalCenter
text: qsTr("New to High Fidelity?")
Item {
id: signUpContainer
width: loginContainer.width
height: signUpTextMetrics.height
visible: !linkAccountBody.linkSteam
anchors {
left: loginContainer.left
top: loginContainer.bottom
topMargin: 0.15 * parent.height
}
TextMetrics {
id: signUpTextMetrics
font: signUpText.font
text: signUpText.text
}
Text {
id: signUpText
text: qsTr("Don't have an account?")
anchors {
left: parent.left
}
lineHeight: 1
color: "white"
font.family: linkAccountBody.fontFamily
font.pixelSize: linkAccountBody.textFieldFontSize
font.bold: linkAccountBody.fontBold
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
Button {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Sign Up")
visible: !loginDialog.isSteamRunning()
onClicked: {
bodyLoader.setSource("SignUpBody.qml")
if (!root.isTablet) {
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
HifiStylesUit.ShortcutText {
id: signUpShortcutText
z: 10
font.family: linkAccountBody.fontFamily
font.pixelSize: linkAccountBody.textFieldFontSize
font.bold: linkAccountBody.fontBold
anchors {
left: signUpText.right
leftMargin: hifi.dimensions.contentSpacing.x
}
text: "<a href='https://highfidelity.com'>Sign Up</a>"
linkColor: hifi.colors.blueAccent
onLinkActivated: {
Tablet.playSound(TabletEnums.ButtonClick);
bodyLoader.setSource("SignUpBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader,
"errorString": "", "linkSteam": linkAccountBody.linkSteam });
}
}
}
TextMetrics {
id: dismissButtonTextMetrics
font: loginErrorMessage.font
text: dismissButton.text
}
HifiControlsUit.Button {
id: dismissButton
width: dismissButtonTextMetrics.width
height: d.minHeightButton
anchors {
bottom: parent.bottom
right: parent.right
margins: 3 * hifi.dimensions.contentSpacing.y
}
color: hifi.buttons.noneBorderlessWhite
text: qsTr("No thanks, take me in-world! >")
fontCapitalization: Font.MixedCase
fontFamily: linkAccountBody.fontFamily
fontSize: linkAccountBody.fontSize
fontBold: linkAccountBody.fontBold
visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam;
onClicked: {
if (loginDialog.getLoginDialogPoppedUp()) {
console.log("[ENCOURAGELOGINDIALOG]: user dismissed login screen")
var data = {
"action": "user dismissed login screen"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
loginDialog.dismissLoginDialog();
}
root.tryDestroy();
}
}
}
Connections {
target: loginDialog
onFocusEnabled: {
if (!linkAccountBody.lostFocus) {
Qt.callLater(function() {
emailField.forceActiveFocus();
});
}
}
onFocusDisabled: {
linkAccountBody.lostFocus = !root.isTablet && !root.isOverlay;
if (linkAccountBody.lostFocus) {
Qt.callLater(function() {
emailField.focus = false;
passwordField.focus = false;
});
}
}
}
Component.onCompleted: {
root.title = qsTr("Sign Into High Fidelity")
root.iconText = "<"
//dont rise local keyboard
keyboardEnabled = !root.isTablet && HMD.active;
//but rise Tablet's one instead for Tablet interface
if (root.isTablet) {
root.keyboardEnabled = HMD.active;
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
}
root.keyboardEnabled = HMD.active;
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
root.text = "";
d.resize();
if (failAfterSignUp) {
mainTextContainer.text = "Account created successfully."
flavorText.visible = true
mainTextContainer.visible = true
}
usernameField.forceActiveFocus();
}
Connections {
target: loginDialog
onHandleLoginCompleted: {
console.log("Login Succeeded, linking steam account")
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
if (poppedUp) {
console.log("[ENCOURAGELOGINDIALOG]: logging in")
var data = {
"action": "user logged in"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
Settings.setValue("loginDialogPoppedUp", false);
}
if (loginDialog.isSteamRunning()) {
loginDialog.linkSteam()
} else {
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
onHandleLoginFailed: {
console.log("Login Failed")
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
if (poppedUp) {
console.log("[ENCOURAGELOGINDIALOG]: failed logging in")
var data = {
"action": "user failed logging in"
};
UserActivityLogger.logAction("encourageLoginDialog", data);
Settings.setValue("loginDialogPoppedUp", false);
}
flavorText.visible = true
mainTextContainer.visible = true
toggleLoading(false)
}
onHandleLinkCompleted: {
console.log("Link Succeeded")
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLinkFailed: {
console.log("Link Failed")
toggleLoading(false)
}
init();
Qt.callLater(function() {
emailField.forceActiveFocus();
});
}
Keys.onPressed: {
if (!visible) {
return
return;
}
switch (event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
linkAccountBody.login()
break
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text);
linkAccountBody.login();
break;
}
}
}

View file

@ -0,0 +1,272 @@
//
// LoggingInBody.qml
//
// Created by Wayne Chen on 10/18/18
// Copyright 2018 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 Hifi 1.0
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 as OriginalStyles
import controlsUit 1.0 as HifiControlsUit
import stylesUit 1.0 as HifiStylesUit
Item {
id: loggingInBody
clip: true
height: root.height
width: root.width
property int textFieldHeight: 31
property int loggingInGlyphRightMargin: 10
property string fontFamily: "Raleway"
property int fontSize: 15
property bool fontBold: true
property bool withSteam: withSteam
property bool withOculus: withOculus
property bool linkSteam: linkSteam
QtObject {
id: d
readonly property int minWidth: 480
readonly property int minWidthButton: !root.isTablet ? 256 : 174
property int maxWidth: root.width
readonly property int minHeight: 120
readonly property int minHeightButton: 36
property int maxHeight: root.height
function resize() {
maxWidth = root.width;
maxHeight = root.height;
var targetWidth = Math.max(titleWidth, mainContainer.width);
var targetHeight = hifi.dimensions.contentSpacing.y + mainContainer.height +
4 * hifi.dimensions.contentSpacing.y;
var newWidth = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
if (!isNaN(newWidth)) {
parent.width = root.width = newWidth;
}
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)) + hifi.dimensions.contentSpacing.y;
}
}
// timer to kill the dialog upon login success
Timer {
id: successTimer
interval: 1000;
running: false;
repeat: false;
onTriggered: {
if (loginDialog.getLoginDialogPoppedUp()) {
loginDialog.dismissLoginDialog();
}
root.tryDestroy();
}
}
function init() {
// For the process of logging in.
loggingInText.wrapMode = Text.NoWrap;
if (loggingInBody.linkSteam) {
loggingInGlyph.visible = true;
loggingInText.text = "Linking to Steam";
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
loginDialog.linkSteam();
} else if (loggingInBody.withSteam) {
loggingInGlyph.visible = true;
loggingInText.text = "Logging in to Steam";
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
} else if (loggingInBody.withOculus) {
loggingInGlyph.text = hifi.glyphs.oculus;
loggingInGlyph.visible = true;
loggingInText.text = "Logging in to Oculus";
loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2;
} else {
loggingInText.text = "Logging in";
loggingInText.anchors.centerIn = loggingInHeader;
}
loggingInSpinner.visible = true;
}
function loadingSuccess() {
loggingInSpinner.visible = false;
if (loggingInBody.linkSteam) {
loggingInText.text = "Linking to Steam";
loginDialog.linkSteam();
return;
}
if (loggingInBody.withSteam) {
// reset the flag.
loggingInGlyph.visible = false;
loggingInText.text = "You are now logged into Steam!";
loggingInText.x = 0;
loggingInText.anchors.centerIn = loggingInHeader;
loggedInGlyph.visible = true;
} else if (loggingInBody.withOculus) {
// reset the flag.
loggingInGlyph.visible = false;
loggingInText.text = "You are now logged into Oculus!";
loggingInText.x = 0;
loggingInText.anchors.centerIn = loggingInHeader;
loggedInGlyph.text = hifi.glyphs.oculus;
loggedInGlyph.visible = true;
} else {
loggingInText.text = "You are now logged in!";
}
successTimer.start();
}
Item {
id: mainContainer
anchors.fill: parent
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Item {
id: loggingInContainer
anchors.fill: parent
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Item {
id: loggingInHeader
width: parent.width
height: loggingInGlyph.height
anchors {
top: parent.top
topMargin: 0.4 * parent.height
left: parent.left
}
TextMetrics {
id: loggingInGlyphTextMetrics;
font: loggingInGlyph.font;
text: loggingInGlyph.text;
}
HifiStylesUit.HiFiGlyphs {
id: loggingInGlyph;
text: hifi.glyphs.steamSquare;
// Color
color: "white";
// Size
size: 36;
// Anchors
anchors.right: loggingInText.left;
anchors.rightMargin: loggingInBody.loggingInGlyphRightMargin
anchors.bottom: parent.bottom;
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
visible: loggingInBody.withSteam || loggingInBody.withOculus;
}
TextMetrics {
id: loggingInTextMetrics;
font: loggingInText.font;
text: loggingInText.text;
}
Text {
id: loggingInText;
width: loggingInTextMetrics.width
anchors.verticalCenter: parent.verticalCenter
color: "white";
font.family: loggingInBody.fontFamily
font.pixelSize: 24
font.bold: loggingInBody.fontBold
wrapMode: Text.NoWrap
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: "Logging in"
}
}
Item {
id: loggingInFooter
width: parent.width
height: 0.5 * parent.height
anchors {
top: loggingInHeader.bottom
topMargin: 2 * hifi.dimensions.contentSpacing.y
}
AnimatedImage {
id: loggingInSpinner
source: "images/loader-snake-256.gif"
width: 64
height: width
anchors.left: parent.left;
anchors.leftMargin: (parent.width - width) / 2;
anchors.top: parent.top
anchors.topMargin: hifi.dimensions.contentSpacing.y
}
TextMetrics {
id: loggedInGlyphTextMetrics;
font: loggedInGlyph.font;
text: loggedInGlyph.text;
}
HifiStylesUit.HiFiGlyphs {
id: loggedInGlyph;
text: hifi.glyphs.steamSquare;
// color
color: "white"
// Size
size: 78;
// Anchors
anchors.left: parent.left;
anchors.leftMargin: (parent.width - loggedInGlyph.size) / 2;
anchors.top: parent.top
anchors.topMargin: hifi.dimensions.contentSpacing.y
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
visible: false;
}
}
}
}
Component.onCompleted: {
d.resize();
loggingInBody.init();
}
Connections {
target: loginDialog
onHandleLinkCompleted: {
console.log("Link Succeeded");
loggingInBody.linkSteam = false;
loggingInBody.loadingSuccess();
}
onHandleLinkFailed: {
console.log("Link Failed: " + error);
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": true, "errorString": error });
}
onHandleLoginCompleted: {
console.log("Login Succeeded");
loggingInBody.loadingSuccess();
}
onHandleLoginFailed: {
console.log("Login Failed")
loggingInSpinner.visible = false;
var errorString = "";
if (loggingInBody.linkSteam && loggingInBody.withSteam) {
errorString = "Username or password is incorrect.";
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "linkSteam": loggingInBody.linkSteam, "errorString": errorString });
} else if (loggingInBody.withSteam) {
loggingInGlyph.visible = false;
errorString = "Your Steam authentication has failed. Please make sure you are logged into Steam and try again.";
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "errorString": errorString });
} else if (loggingInBody.withOculus) {
loggingInGlyph.visible = false;
errorString = "Your Oculus authentication has failed. Please make sure you are logged into Oculus and try again."
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString });
}
else {
errorString = "Username or password is incorrect.";
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString });
}
}
}
}

View file

@ -0,0 +1,170 @@
//
// LoginDialogLightbox.qml
// qml/LoginDialog
//
// LoginDialogLightbox
//
// Created by Wayne Chen on 2018-12-07
// Copyright 2018 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 Hifi 1.0 as Hifi
import QtQuick 2.5
import QtGraphicalEffects 1.0
import stylesUit 1.0
import controlsUit 1.0 as HifiControlsUit
import "qrc:////qml//controls" as HifiControls
// references XXX from root context
Rectangle {
property string titleText;
property string bodyImageSource;
property string bodyText;
property string button1color: hifi.buttons.noneBorderlessGray;
property string button1text;
property var button1method;
property string button2color: hifi.buttons.blue;
property string button2text;
property var button2method;
property string buttonLayout: "leftright";
readonly property string cantAccessBodyText: "Please navigate to your default browser to recover your account." +
"<br><br>If you are in a VR headset, please take it off.";
id: root;
visible: false;
anchors.fill: parent;
color: Qt.rgba(0, 0, 0, 0.5);
z: 999;
HifiConstants { id: hifi; }
onVisibleChanged: {
if (!visible) {
resetLightbox();
}
}
// This object is always used in a popup.
// This MouseArea is used to prevent a user from being
// able to click on a button/mouseArea underneath the popup.
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
hoverEnabled: true;
}
Rectangle {
anchors.centerIn: parent;
width: 376;
height: childrenRect.height + 30;
color: "white";
RalewaySemiBold {
id: titleText;
text: root.titleText;
anchors.top: parent.top;
anchors.topMargin: 30;
anchors.left: parent.left;
anchors.leftMargin: 30;
anchors.right: parent.right;
anchors.rightMargin: 30;
height: paintedHeight;
color: hifi.colors.black;
size: 24;
verticalAlignment: Text.AlignTop;
wrapMode: Text.WordWrap;
}
RalewayRegular {
id: bodyText;
text: root.bodyText;
anchors.top: root.bodyImageSource ? bodyImage.bottom : (root.titleText ? titleText.bottom : parent.top);
anchors.topMargin: root.bodyImageSource ? 20 : (root.titleText ? 20 : 30);
anchors.left: parent.left;
anchors.leftMargin: 30;
anchors.right: parent.right;
anchors.rightMargin: 30;
height: paintedHeight;
color: hifi.colors.black;
size: 20;
verticalAlignment: Text.AlignTop;
wrapMode: Text.WordWrap;
}
Item {
id: buttons;
anchors.top: bodyText.bottom;
anchors.topMargin: 30;
anchors.left: parent.left;
anchors.right: parent.right;
height: root.buttonLayout === "leftright" ? 70 : 150;
// Button 1
HifiControlsUit.Button {
id: button1;
color: root.button1color;
colorScheme: hifi.colorSchemes.light;
anchors.top: root.buttonLayout === "leftright" ? parent.top : parent.top;
anchors.left: parent.left;
anchors.leftMargin: root.buttonLayout === "leftright" ? 30 : 10;
anchors.right: root.buttonLayout === "leftright" ? undefined : parent.right;
anchors.rightMargin: root.buttonLayout === "leftright" ? undefined : 10;
width: root.buttonLayout === "leftright" ? (root.button2text ? parent.width/2 - anchors.leftMargin*2 : parent.width - anchors.leftMargin * 2) :
(undefined);
height: 40;
text: root.button1text;
onClicked: {
button1method();
}
visible: (root.button1text !== "");
}
// Button 2
HifiControlsUit.Button {
id: button2;
visible: root.button2text;
color: root.button2color;
colorScheme: hifi.colorSchemes.light;
anchors.top: root.buttonLayout === "leftright" ? parent.top : button1.bottom;
anchors.topMargin: root.buttonLayout === "leftright" ? undefined : 20;
anchors.left: root.buttonLayout === "leftright" ? undefined : parent.left;
anchors.leftMargin: root.buttonLayout === "leftright" ? undefined : 10;
anchors.right: parent.right;
anchors.rightMargin: root.buttonLayout === "leftright" ? 30 : 10;
width: root.buttonLayout === "leftright" ? parent.width/2 - anchors.rightMargin*2 : undefined;
height: 40;
text: root.button2text;
onClicked: {
button2method();
}
}
}
}
//
// FUNCTION DEFINITIONS START
//
signal sendToParent(var msg);
function resetLightbox() {
root.titleText = "";
root.bodyImageSource = "";
root.bodyText = "";
root.button1color = hifi.buttons.noneBorderlessGray;
root.button1text = "";
root.button1method = function() {};
root.button2color = hifi.buttons.blue;
root.button2text = "";
root.button2method = function() {};
root.buttonLayout = "leftright";
}
//
// FUNCTION DEFINITIONS END
//
}

View file

@ -1,128 +0,0 @@
//
// SignInBody.qml
//
// Created by Clement on 7/18/16
// 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 Hifi 1.0
import QtQuick 2.7
import QtQuick.Controls.Styles 1.4 as OriginalStyles
import controlsUit 1.0
import stylesUit 1.0
Item {
id: signInBody
clip: true
height: root.pane.height
width: root.pane.width
property bool required: false
function login() {
console.log("Trying to log in")
loginDialog.loginThroughSteam()
}
function cancel() {
root.tryDestroy()
}
QtObject {
id: d
readonly property int minWidth: 480
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 + buttons.height
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
}
}
InfoItem {
id: mainTextContainer
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
text: required ? qsTr("This domain's owner requires that you sign in:")
: qsTr("Sign in to access your user account:")
wrapMode: Text.WordWrap
color: hifi.colors.baseGrayHighlight
lineHeight: 2
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
}
Row {
id: buttons
anchors {
top: mainTextContainer.bottom
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: 2 * hifi.dimensions.contentSpacing.y
}
spacing: hifi.dimensions.contentSpacing.x
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Button {
anchors.verticalCenter: parent.verticalCenter
width: undefined // invalidate so that the image's size sets the width
height: undefined // invalidate so that the image's size sets the height
focus: true
background: Image {
id: buttonImage
source: "../../images/steam-sign-in.png"
}
onClicked: signInBody.login()
}
Button {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Cancel");
onClicked: signInBody.cancel()
}
}
Component.onCompleted: {
root.title = required ? qsTr("Sign In Required")
: qsTr("Sign In")
root.iconText = ""
d.resize();
}
Connections {
target: loginDialog
onHandleLoginCompleted: {
console.log("Login Succeeded")
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLoginFailed: {
console.log("Login Failed")
bodyLoader.source = "CompleteProfileBody.qml"
if (!root.isTablet) {
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
}
}

View file

@ -11,21 +11,24 @@
import Hifi 1.0
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 as OriginalStyles
import controlsUit 1.0
import stylesUit 1.0
import controlsUit 1.0 as HifiControlsUit
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
Item {
id: signupBody
z: -2
id: signUpBody
clip: true
height: root.pane.height
width: root.pane.width
function signup() {
mainTextContainer.visible = false
toggleLoading(true)
loginDialog.signup(emailField.text, usernameField.text, passwordField.text)
}
height: root.height
width: root.width
property int textFieldHeight: 31
property string fontFamily: "Raleway"
property int fontSize: 15
property int textFieldFontSize: 18
property bool fontBold: true
readonly property var passwordImageRatio: 16 / 23
property bool keyboardEnabled: false
property bool keyboardRaised: false
@ -33,248 +36,413 @@ Item {
onKeyboardRaisedChanged: d.resize();
property string errorString: errorString
property bool linkSteam: linkSteam
property bool lostFocus: false
QtObject {
id: d
readonly property int minWidth: 480
readonly property int maxWidth: 1280
readonly property int minWidthButton: !root.isTablet ? 256 : 174
property int maxWidth: root.width
readonly property int minHeight: 120
readonly property int maxHeight: 720
readonly property int minHeightButton: 36
property int maxHeight: root.height
function resize() {
var targetWidth = Math.max(titleWidth, form.contentWidth);
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
4 * hifi.dimensions.contentSpacing.y + form.height;
maxWidth = root.width;
maxHeight = root.height;
var targetWidth = Math.max(titleWidth, mainContainer.width);
var targetHeight = hifi.dimensions.contentSpacing.y + mainContainer.height +
4 * hifi.dimensions.contentSpacing.y;
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
+ (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : 0);
var newWidth = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
if (!isNaN(newWidth)) {
parent.width = root.width = newWidth;
}
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)) + hifi.dimensions.contentSpacing.y;
}
}
function toggleLoading(isLoading) {
linkAccountSpinner.visible = isLoading
form.visible = !isLoading
leftButton.visible = !isLoading
buttons.visible = !isLoading
function signup() {
loginDialog.signup(emailField.text, usernameField.text, passwordField.text);
}
BusyIndicator {
id: linkAccountSpinner
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
topMargin: hifi.dimensions.contentSpacing.y
}
visible: false
running: true
width: 48
height: 48
function init() {
// going to/from sign in/up dialog.
loginDialog.isLogIn = false;
emailField.placeholderText = "Email";
emailField.text = "";
emailField.anchors.top = usernameField.bottom;
emailField.anchors.topMargin = 1.5 * hifi.dimensions.contentSpacing.y;
passwordField.text = "";
usernameField.forceActiveFocus();
root.text = "";
root.isPassword = false;
loginContainer.visible = true;
}
ShortcutText {
id: mainTextContainer
anchors {
top: parent.top
left: parent.left
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
visible: false
text: qsTr("There was an unknown error while creating your account.")
wrapMode: Text.WordWrap
color: hifi.colors.redAccent
horizontalAlignment: Text.AlignLeft
}
Column {
id: form
width: parent.width
Item {
id: mainContainer
width: root.width
height: root.height
onHeightChanged: d.resize(); onWidthChanged: d.resize();
anchors {
top: mainTextContainer.bottom
topMargin: 2 * hifi.dimensions.contentSpacing.y
}
spacing: 2 * hifi.dimensions.contentSpacing.y
TextField {
id: emailField
width: parent.width
label: "Email"
activeFocusOnPress: true
onFocusChanged: {
root.text = "";
Item {
id: loginContainer
width: usernameField.width
height: parent.height
anchors {
top: parent.top
topMargin: root.bannerHeight + 0.25 * parent.height
left: parent.left
leftMargin: (parent.width - usernameField.width) / 2
}
}
visible: true
TextField {
id: usernameField
width: parent.width
label: "Username"
activeFocusOnPress: true
ShortcutText {
Item {
id: errorContainer
width: parent.width
height: loginErrorMessageTextMetrics.height
anchors {
verticalCenter: parent.textFieldLabel.verticalCenter
left: parent.textFieldLabel.right
leftMargin: 10
bottom: usernameField.top;
bottomMargin: hifi.dimensions.contentSpacing.y;
left: usernameField.left;
}
TextMetrics {
id: loginErrorMessageTextMetrics
font: loginErrorMessage.font
text: loginErrorMessage.text
}
Text {
id: loginErrorMessage;
width: root.bannerWidth
color: "red";
font.family: signUpBody.fontFamily
font.pixelSize: 18
font.bold: signUpBody.fontBold
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: ""
visible: false
}
}
text: qsTr("No spaces / special chars.")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: hifi.colors.blueAccent
HifiControlsUit.TextField {
id: usernameField
width: root.bannerWidth
height: signUpBody.textFieldHeight
placeholderText: "Username"
font.pixelSize: signUpBody.textFieldFontSize
styleRenderType: Text.QtRendering
anchors {
top: parent.top
topMargin: loginErrorMessage.height
}
Keys.onPressed: {
if (!usernameField.visible) {
return;
}
switch (event.key) {
case Qt.Key_Tab:
event.accepted = true;
if (event.modifiers === Qt.ShiftModifier) {
passwordField.focus = true;
} else {
emailField.focus = true;
}
break;
case Qt.Key_Backtab:
event.accepted = true;
passwordField.focus = true;
break;
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
}
signUpBody.signup();
break;
}
}
onFocusChanged: {
root.text = "";
}
}
}
TextField {
id: passwordField
width: parent.width
label: "Password"
echoMode: TextInput.Password
activeFocusOnPress: true
ShortcutText {
anchors {
verticalCenter: parent.textFieldLabel.verticalCenter
left: parent.textFieldLabel.right
leftMargin: 10
}
text: qsTr("At least 6 characters")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: hifi.colors.blueAccent
}
onFocusChanged: {
root.text = "";
root.isPassword = focus
}
Keys.onReturnPressed: signupBody.signup()
}
Row {
id: leftButton
anchors.horizontalCenter: parent.horizontalCenter
spacing: hifi.dimensions.contentSpacing.x
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Button {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Existing User")
onClicked: {
bodyLoader.setSource("LinkAccountBody.qml")
if (!root.isTablet) {
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
if (focus) {
root.isPassword = false;
}
}
}
}
Row {
id: buttons
anchors.horizontalCenter: parent.horizontalCenter
spacing: hifi.dimensions.contentSpacing.x
onHeightChanged: d.resize(); onWidthChanged: d.resize();
HifiControlsUit.TextField {
id: emailField
width: root.bannerWidth
height: signUpBody.textFieldHeight
anchors {
top: parent.top
}
placeholderText: "Username or Email"
font.pixelSize: signUpBody.textFieldFontSize
styleRenderType: Text.QtRendering
activeFocusOnPress: true
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Tab:
event.accepted = true;
if (event.modifiers === Qt.ShiftModifier) {
if (usernameField.visible) {
usernameField.focus = true;
break;
}
}
passwordField.focus = true;
break;
case Qt.Key_Backtab:
event.accepted = true;
usernameField.focus = true;
break;
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
}
signUpBody.signup();
break;
}
}
onFocusChanged: {
root.text = "";
if (focus) {
root.isPassword = false;
}
}
}
HifiControlsUit.TextField {
id: passwordField
width: root.bannerWidth
height: signUpBody.textFieldHeight
placeholderText: "Password (min. 6 characters)"
font.pixelSize: signUpBody.textFieldFontSize
styleRenderType: Text.QtRendering
activeFocusOnPress: true
echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
anchors {
top: emailField.bottom
topMargin: 1.5 * hifi.dimensions.contentSpacing.y
}
Button {
id: linkAccountButton
anchors.verticalCenter: parent.verticalCenter
width: 200
onFocusChanged: {
root.text = "";
root.isPassword = focus;
}
text: qsTr("Sign Up")
color: hifi.buttons.blue
Item {
id: showPasswordContainer
z: 10
// width + image's rightMargin
width: showPasswordImage.width + 8
height: parent.height
anchors {
right: parent.right
}
onClicked: signupBody.signup()
Image {
id: showPasswordImage
width: passwordField.height * passwordImageRatio
height: passwordField.height * passwordImageRatio
anchors {
right: parent.right
rightMargin: 8
top: parent.top
topMargin: passwordFieldMouseArea.showPassword ? 6 : 8
bottom: parent.bottom
bottomMargin: passwordFieldMouseArea.showPassword ? 5 : 8
}
source: passwordFieldMouseArea.showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg"
MouseArea {
id: passwordFieldMouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
property bool showPassword: false
onClicked: {
showPassword = !showPassword;
}
}
}
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Tab:
event.accepted = true;
if (event.modifiers === Qt.ShiftModifier) {
emailField.focus = true;
} else if (usernameField.visible) {
usernameField.focus = true;
} else {
emailField.focus = true;
}
break;
case Qt.Key_Backtab:
event.accepted = true;
emailField.focus = true;
break;
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
}
signUpBody.signup();
break;
}
}
}
HifiControlsUit.CheckBox {
id: keepMeLoggedInCheckbox
checked: Settings.getValue("keepMeLoggedIn", false);
text: qsTr("Keep Me Logged In");
boxSize: 18;
labelFontFamily: signUpBody.fontFamily
labelFontSize: 18;
color: hifi.colors.white;
anchors {
top: passwordField.bottom;
topMargin: hifi.dimensions.contentSpacing.y;
left: passwordField.left;
}
onCheckedChanged: {
Settings.setValue("keepMeLoggedIn", checked);
if (keepMeLoggedInCheckbox.checked) {
Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text);
} else {
Settings.setValue("keepMeLoggedIn/savedUsername", "");
}
}
}
Button {
anchors.verticalCenter: parent.verticalCenter
TextMetrics {
id: cancelButtonTextMetrics
font: loginErrorMessage.font
text: cancelButton.text
}
HifiControlsUit.Button {
id: cancelButton
width: (emailField.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
anchors {
top: keepMeLoggedInCheckbox.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: parent.left
}
color: hifi.buttons.noneBorderlessWhite
text: qsTr("CANCEL")
fontFamily: signUpBody.fontFamily
fontSize: signUpBody.fontSize
fontBold: signUpBody.fontBold
onClicked: {
bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": signUpBody.linkSteam });
}
}
HifiControlsUit.Button {
id: signUpButton
width: (emailField.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
color: hifi.buttons.blue
text: qsTr("Sign Up")
fontFamily: signUpBody.fontFamily
fontSize: signUpBody.fontSize
fontBold: signUpBody.fontBold
anchors {
top: cancelButton.top
right: passwordField.right
}
text: qsTr("Cancel")
onClicked: {
signUpBody.signup();
}
}
}
}
onClicked: root.tryDestroy()
MouseArea {
z: -2
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
if (!usernameField.focus && !emailField.focus && !passwordField.focus) {
usernameField.focus = true;
}
}
}
Component.onCompleted: {
root.title = qsTr("Create an Account")
root.iconText = "<"
//dont rise local keyboard
keyboardEnabled = !root.isTablet && HMD.active;
//but rise Tablet's one instead for Tablet interface
if (root.isTablet) {
root.keyboardEnabled = HMD.active;
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
}
root.keyboardEnabled = HMD.active;
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
root.text = "";
d.resize();
emailField.forceActiveFocus();
}
Connections {
target: loginDialog
onHandleSignupCompleted: {
console.log("Sign Up Succeeded");
// now that we have an account, login with that username and password
loginDialog.login(usernameField.text, passwordField.text)
}
onHandleSignupFailed: {
console.log("Sign Up Failed")
toggleLoading(false)
mainTextContainer.text = errorString
mainTextContainer.visible = true
d.resize();
}
onHandleLoginCompleted: {
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack": false })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
onHandleLoginFailed: {
// we failed to login, show the LoginDialog so the user will try again
bodyLoader.setSource("LinkAccountBody.qml", { "failAfterSignUp": true })
if (!root.isTablet) {
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
}
}
init();
}
Keys.onPressed: {
if (!visible) {
return
return;
}
switch (event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
signupBody.signup()
break
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
signUpBody.login();
break;
}
}
Connections {
target: loginDialog
onHandleSignupCompleted: {
console.log("Sign Up Completed");
loginDialog.login(usernameField.text, passwordField.text);
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": false, "linkSteam": false });
}
onHandleSignupFailed: {
console.log("Sign Up Failed")
if (errorString !== "") {
loginErrorMessage.visible = true;
var errorStringEdited = errorString.replace(/[\n\r]+/g, "\n");
loginErrorMessage.text = errorStringEdited;
loginErrorMessageTextMetrics.text = errorString;
if (loginErrorMessageTextMetrics.width > usernameField.width) {
loginErrorMessage.wrapMode = Text.WordWrap;
loginErrorMessage.verticalAlignment = Text.AlignLeft;
loginErrorMessage.horizontalAlignment = Text.AlignLeft;
errorContainer.height = (loginErrorMessageTextMetrics.width / usernameField.width) * loginErrorMessageTextMetrics.height;
}
errorContainer.anchors.bottom = usernameField.top;
errorContainer.anchors.bottomMargin = hifi.dimensions.contentSpacing.y;
errorContainer.anchors.left = usernameField.left;
}
}
onFocusEnabled: {
if (!signUpBody.lostFocus) {
Qt.callLater(function() {
emailField.forceActiveFocus();
});
}
}
onFocusDisabled: {
signUpBody.lostFocus = !root.isTablet && !root.isOverlay;
if (signUpBody.lostFocus) {
Qt.callLater(function() {
usernameField.focus = false;
emailField.focus = false;
passwordField.focus = false;
});
}
}
}
}

View file

@ -12,169 +12,228 @@ import Hifi 1.0
import QtQuick 2.4
import QtQuick.Controls 1.4
import controlsUit 1.0
import stylesUit 1.0
import controlsUit 1.0 as HifiControlsUit
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
Item {
id: usernameCollisionBody
clip: true
width: root.pane.width
height: root.pane.height
width: root.width
height: root.height
readonly property string fontFamily: "Raleway"
readonly property int fontSize: 15
readonly property int textFieldFontSize: 18
readonly property bool fontBold: true
function create() {
mainTextContainer.visible = false
loginDialog.createAccountFromStream(textField.text)
loginDialog.createAccountFromSteam(textField.text);
}
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
onKeyboardRaisedChanged: d.resize();
property bool lostFocus: false
QtObject {
id: d
readonly property int minWidth: 480
readonly property int maxWidth: 1280
readonly property int minWidthButton: !root.isTablet ? 256 : 174
property int maxWidth: root.width
readonly property int minHeight: 120
readonly property int maxHeight: 720
readonly property int minHeightButton: 36
property int maxHeight: root.height
function resize() {
var targetWidth = Math.max(titleWidth, mainTextContainer.contentWidth)
maxWidth = root.width;
maxHeight = root.height;
var targetWidth = Math.max(titleWidth, mainContainer.width);
var targetHeight = mainTextContainer.height +
hifi.dimensions.contentSpacing.y + textField.height +
hifi.dimensions.contentSpacing.y + buttons.height
hifi.dimensions.contentSpacing.y + buttons.height;
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
+ (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y)
parent.height = root.height = Math.max(Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight)), mainContainer.height + hifi.dimensions.contentSpacing.y);
}
}
ShortcutText {
id: mainTextContainer
anchors {
top: parent.top
left: parent.left
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
text: qsTr("Your Steam username is not available.")
wrapMode: Text.WordWrap
color: hifi.colors.redAccent
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
}
TextField {
id: textField
anchors {
top: mainTextContainer.bottom
left: parent.left
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
width: parent.width
placeholderText: "Choose your own"
}
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
Keyboard {
raised: keyboardEnabled && keyboardRaised
numeric: punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: buttons.top
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
}
}
Row {
id: buttons
anchors {
bottom: parent.bottom
right: parent.right
margins: 0
bottomMargin: hifi.dimensions.contentSpacing.y
}
spacing: hifi.dimensions.contentSpacing.x
Item {
id: mainContainer
width: root.width
height: root.height
onHeightChanged: d.resize(); onWidthChanged: d.resize();
anchors.fill: parent
Button {
anchors.verticalCenter: parent.verticalCenter
width: 200
text: qsTr("Create your profile")
color: hifi.buttons.blue
onClicked: usernameCollisionBody.create()
TextMetrics {
id: mainTextContainerTextMetrics
font: mainTextContainer.font
text: mainTextContainer.text
}
Button {
anchors.verticalCenter: parent.verticalCenter
Text {
id: mainTextContainer
anchors {
top: parent.top
left: parent.left
leftMargin: (parent.width - mainTextContainer.width) / 2
topMargin: parent.height/2 - buttons.anchors.topMargin - textField.height - mainTextContainerTextMetrics.height
}
text: qsTr("Cancel")
font.family: usernameCollisionBody.fontFamily
font.pixelSize: usernameCollisionBody.fontSize
font.bold: usernameCollisionBody.fontBold
text: qsTr("Your Steam username is not available.");
wrapMode: Text.WordWrap
color: hifi.colors.redAccent
lineHeight: 1
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
}
onClicked: root.tryDestroy()
HifiControlsUit.TextField {
id: textField
anchors {
top: mainTextContainer.bottom
left: parent.left
leftMargin: (parent.width - width) / 2
topMargin: hifi.dimensions.contentSpacing.y
}
focus: true
font.family: "Fira Sans"
font.pixelSize: usernameCollisionBody.textFieldFontSize
styleRenderType: Text.QtRendering
width: root.bannerWidth
placeholderText: "Choose your own"
onFocusChanged: {
root.text = "";
if (focus) {
root.isPassword = false;
}
}
Keys.onPressed: {
if (!visible) {
return;
}
switch (event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true;
usernameCollisionBody.create();
break;
}
}
}
Item {
id: buttons
width: root.bannerWidth
height: d.minHeightButton
anchors {
top: textField.bottom
topMargin: hifi.dimensions.contentSpacing.y
left: parent.left
leftMargin: (parent.width - root.bannerWidth) / 2
}
HifiControlsUit.Button {
id: cancelButton
anchors {
top: parent.top
left: parent.left
}
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
text: qsTr("CANCEL")
color: hifi.buttons.noneBorderlessWhite
fontFamily: usernameCollisionBody.fontFamily
fontSize: usernameCollisionBody.fontSize
fontBold: usernameCollisionBody.fontBold
onClicked: {
bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "" });
}
}
HifiControlsUit.Button {
id: profileButton
anchors {
top: parent.top
right: parent.right
}
width: (parent.width - hifi.dimensions.contentSpacing.x) / 2
height: d.minHeightButton
text: qsTr("Create your profile")
color: hifi.buttons.blue
fontFamily: usernameCollisionBody.fontFamily
fontSize: usernameCollisionBody.fontSize
fontBold: usernameCollisionBody.fontBold
onClicked: {
usernameCollisionBody.create();
}
}
}
}
Component.onCompleted: {
root.title = qsTr("Complete Your Profile")
root.iconText = "<"
//dont rise local keyboard
keyboardEnabled = !root.isTablet && HMD.active;
//but rise Tablet's one instead for Tablet interface
if (root.isTablet) {
root.keyboardEnabled = HMD.active;
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
}
root.keyboardEnabled = HMD.active;
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
root.text = "";
d.resize();
}
Connections {
target: loginDialog
onHandleCreateCompleted: {
console.log("Create Succeeded")
loginDialog.loginThroughSteam()
console.log("Create Succeeded");
loginDialog.loginThroughSteam();
bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": true, "linkSteam": false })
}
onHandleCreateFailed: {
console.log("Create Failed: " + error)
mainTextContainer.visible = true
mainTextContainer.text = "\"" + textField.text + qsTr("\" is invalid or already taken.")
mainTextContainer.text = "\"" + textField.text + qsTr("\" is invalid or already taken.");
}
onHandleLoginCompleted: {
console.log("Login Succeeded")
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
bodyLoader.item.width = root.pane.width
bodyLoader.item.height = root.pane.height
console.log("Login Succeeded");
if (loginDialog.getLoginDialogPoppedUp()) {
loginDialog.dismissLoginDialog();
}
root.tryDestroy();
}
onHandleLoginFailed: {
console.log("Login Failed")
}
}
Keys.onPressed: {
if (!visible) {
return
mainTextContainer.text = "Login Failed";
}
switch (event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
usernameCollisionBody.create()
break
onFocusEnabled: {
if (!usernameCollisionBody.lostFocus) {
Qt.callLater(function() {
textField.forceActiveFocus();
});
}
}
onFocusDisabled: {
usernameCollisionBody.lostFocus = !root.isTablet && !root.isOverlay;
if (nusernameCollisionBody.lostFocus) {
Qt.callLater(function() {
textField.focus = false;
});
}
}
}
}

View file

@ -1,90 +0,0 @@
//
// WelcomeBody.qml
//
// Created by Clement on 7/18/16
// 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 Hifi 1.0
import QtQuick 2.4
import controlsUit 1.0
import stylesUit 1.0
Item {
id: welcomeBody
clip: true
width: root.pane.width
height: root.pane.height
property bool welcomeBack: false
function setTitle() {
root.title = (welcomeBack ? qsTr("Welcome back <b>") : qsTr("Welcome <b>")) + Account.username + qsTr("</b>!")
root.iconText = ""
d.resize();
}
QtObject {
id: d
readonly property int minWidth: 480
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 + buttons.height
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
}
}
InfoItem {
id: mainTextContainer
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: hifi.dimensions.contentSpacing.y
}
text: qsTr("You are now signed into High Fidelity")
wrapMode: Text.WordWrap
color: hifi.colors.baseGrayHighlight
lineHeight: 2
lineHeightMode: Text.ProportionalHeight
horizontalAlignment: Text.AlignHCenter
}
Row {
id: buttons
anchors {
top: mainTextContainer.bottom
horizontalCenter: parent.horizontalCenter
margins: 0
topMargin: 2 * hifi.dimensions.contentSpacing.y
}
spacing: hifi.dimensions.contentSpacing.x
onHeightChanged: d.resize(); onWidthChanged: d.resize();
Button {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Close");
onClicked: root.tryDestroy()
}
}
Component.onCompleted: welcomeBody.setTitle()
Connections {
target: Account
onUsernameChanged: welcomeBody.setTitle()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -0,0 +1,154 @@
//
// LoginDialog.qml
//
// Created by Wayne Chen
// Copyright 2018 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 Hifi 1.0
import QtQuick 2.4
import controlsUit 1.0 as HifiControlsUit
import stylesUit 1.0 as HifiStylesUit
import "LoginDialog"
FocusScope {
id: root
HifiStylesUit.HifiConstants { id: hifi }
objectName: "LoginDialog"
visible: true
anchors.fill: parent
readonly property bool isTablet: false
readonly property bool isOverlay: true
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
property bool isPassword: false
property string iconText: ""
property int iconSize: 50
property string title: ""
property int titleWidth: 0
property alias text: loginKeyboard.mirroredText
property alias bannerWidth: banner.width
property alias bannerHeight: banner.height
function tryDestroy() {
root.destroy()
}
LoginDialog {
id: loginDialog
anchors.fill: parent
Loader {
id: bodyLoader
anchors.fill: parent
}
}
Image {
z: -10
id: loginDialogBackground
source: "LoginDialog/images/background.jpg"
anchors.fill: parent
}
Rectangle {
z: -6
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.65
color: "black"
}
Item {
z: -5
id: bannerContainer
width: parent.width
height: banner.height
anchors {
top: parent.top
topMargin: 0.18 * parent.height
}
Image {
id: banner
anchors.centerIn: parent
source: "../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Timer {
id: keyboardTimer
repeat: false
interval: 200
onTriggered: {
if (MenuInterface.isOptionChecked("Use 3D Keyboard")) {
KeyboardScriptingInterface.raised = true;
}
}
}
HifiControlsUit.Keyboard {
id: loginKeyboard
raised: root.keyboardEnabled && root.keyboardRaised
numeric: root.punctuationMode
password: root.isPassword
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
}
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
break
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
break
}
}
Component.onDestruction: {
loginKeyboard.raised = false;
}
Component.onCompleted: {
keyboardTimer.start();
bodyLoader.setSource("LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
}
}

View file

@ -19,10 +19,14 @@ Original.Button {
property int color: 0
property int colorScheme: hifi.colorSchemes.light
property string fontFamily: "Raleway"
property int fontSize: hifi.fontSizes.buttonLabel
property bool fontBold: true
property int radius: hifi.buttons.radius
property alias implicitTextWidth: buttonText.implicitWidth
property string buttonGlyph: "";
property int buttonGlyphSize: 34;
property int buttonGlyphRightMargin: 0;
property int fontCapitalization: Font.AllUppercase
width: hifi.dimensions.buttonWidth
@ -35,13 +39,13 @@ Original.Button {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onFocusChanged: {
if (focus) {
Tablet.playSound(TabletEnums.ButtonHover);
}
}
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
}
@ -89,14 +93,21 @@ Original.Button {
}
contentItem: Item {
id: buttonContentItem
TextMetrics {
id: buttonGlyphTextMetrics;
font: buttonGlyph.font;
text: buttonGlyph.text;
}
HiFiGlyphs {
id: buttonGlyph;
visible: control.buttonGlyph !== "";
text: control.buttonGlyph === "" ? hifi.glyphs.question : control.buttonGlyph;
// Size
size: 34;
size: control.buttonGlyphSize;
// Anchors
anchors.right: buttonText.left;
anchors.rightMargin: control.buttonGlyphRightMargin
anchors.top: parent.top;
anchors.bottom: parent.bottom;
// Style
@ -106,17 +117,32 @@ Original.Button {
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
}
RalewayBold {
TextMetrics {
id: buttonTextMetrics;
font: buttonText.font;
text: buttonText.text;
}
Text {
id: buttonText;
anchors.centerIn: parent;
width: buttonTextMetrics.width
anchors.verticalCenter: parent.verticalCenter;
font.capitalization: control.fontCapitalization
color: enabled ? hifi.buttons.textColor[control.color]
: hifi.buttons.disabledTextColor[control.colorScheme]
size: control.fontSize
font.family: control.fontFamily
font.pixelSize: control.fontSize
font.bold: control.fontBold
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: control.text
Component.onCompleted: {
if (control.buttonGlyph !== "") {
buttonText.x = buttonContentItem.width/2 - buttonTextMetrics.width/2 + (buttonGlyphTextMetrics.width + control.buttonGlyphRightMargin)/2;
} else {
buttonText.anchors.centerIn = parent;
}
}
}
}
}

View file

@ -31,6 +31,7 @@ TextField {
property bool hasClearButton: false;
property string leftPermanentGlyph: "";
property string centerPlaceholderGlyph: "";
property int styleRenderType: Text.NativeRendering
placeholderText: textField.placeholderText
@ -44,8 +45,8 @@ TextField {
// workaround for https://bugreports.qt.io/browse/QTBUG-49297
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Return:
case Qt.Key_Enter:
case Qt.Key_Return:
case Qt.Key_Enter:
event.accepted = true;
// emit accepted signal manually
@ -156,6 +157,7 @@ TextField {
selectionColor: hifi.colors.primaryHighlight
padding.left: hasRoundedBorder ? textField.height / 2 : ((isSearchField || textField.leftPermanentGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding
padding.right: (hasClearButton ? textField.height - 2 : 0) + hifi.dimensions.textPadding
renderType: textField.styleRenderType
}
HifiControls.Label {

View file

@ -11,59 +11,52 @@
import Hifi 1.0
import QtQuick 2.5
import controlsUit 1.0
import stylesUit 1.0
import "../windows"
import controlsUit 1.0 as HifiControlsUit
import stylesUit 1.0 as HifiStylesUit
import "../LoginDialog"
TabletModalWindow {
id: realRoot
FocusScope {
id: root
objectName: "LoginDialog"
visible: true
anchors.fill: parent
width: parent.width
height: parent.height
signal sendToScript(var message);
signal canceled();
property bool isHMD: false
property bool gotoPreviousApp: false;
color: hifi.colors.baseGray
title: qsTr("Sign in to High Fidelity")
property alias titleWidth: root.titleWidth
property alias punctuationMode: root.punctuationMode
//fake root for shared components expecting root here
property var root: QtObject {
id: root
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
property bool isPassword: false
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
property bool isPassword: false
property alias text: loginKeyboard.mirroredText
readonly property bool isTablet: true
readonly property bool isOverlay: false
property alias text: loginKeyboard.mirroredText
readonly property bool isTablet: true
property int titleWidth: 0
property alias bannerWidth: banner.width
property alias bannerHeight: banner.height
property string iconText: hifi.glyphs.avatar
property int iconSize: 35
property alias title: realRoot.title
property real width: realRoot.width
property real height: realRoot.height
property int titleWidth: 0
property string iconText: hifi.glyphs.avatar
property int iconSize: 35
property var pane: QtObject {
property real width: root.width
property real height: root.height
}
function tryDestroy() {
canceled()
}
property var pane: QtObject {
property real width: root.width
property real height: root.height
}
//property int colorScheme: hifi.colorSchemes.dark
function tryDestroy() {
}
MouseArea {
width: realRoot.width
height: realRoot.height
width: root.width
height: root.height
}
property bool keyboardOverride: true
@ -71,29 +64,11 @@ TabletModalWindow {
property var items;
property string label: ""
//onTitleWidthChanged: d.resize();
//onKeyboardRaisedChanged: d.resize();
signal canceled();
property alias bodyLoader: bodyLoader
property alias loginDialog: loginDialog
property alias hifi: hifi
HifiConstants { id: hifi }
onCanceled: {
if (bodyLoader.active === true) {
//bodyLoader.active = false
}
if (gotoPreviousApp) {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.returnToPreviousApp();
} else {
Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen();
}
}
HifiStylesUit.HifiConstants { id: hifi }
Timer {
id: keyboardTimer
@ -107,48 +82,50 @@ TabletModalWindow {
}
}
TabletModalFrame {
id: mfRoot
LoginDialog {
id: loginDialog
width: root.width
height: root.height + frameMarginTop + hifi.dimensions.contentMargin.x
anchors.fill: parent
Loader {
id: bodyLoader
anchors.fill: parent
}
}
Image {
z: -10
id: loginDialogBackground
source: "../LoginDialog/images/background_tablet.jpg"
anchors.fill: parent
}
Item {
z: -5
id: bannerContainer
width: parent.width
height: banner.height
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
verticalCenterOffset: -loginKeyboard.height / 2
top: parent.top
topMargin: 0.18 * parent.height
}
LoginDialog {
id: loginDialog
anchors {
fill: parent
topMargin: parent.frameMarginTop
leftMargin: hifi.dimensions.contentMargin.x
rightMargin: hifi.dimensions.contentMargin.x
horizontalCenter: parent.horizontalCenter
}
Loader {
id: bodyLoader
anchors.fill: parent
anchors.horizontalCenter: parent.horizontalCenter
source: loginDialog.isSteamRunning() ? "../LoginDialog/SignInBody.qml" : "../LoginDialog/LinkAccountBody.qml"
}
Image {
id: banner
anchors.centerIn: parent
source: "../../images/high-fidelity-banner.svg"
horizontalAlignment: Image.AlignHCenter
}
}
Component.onDestruction: {
loginKeyboard.raised = false;
KeyboardScriptingInterface.raised = false;
Rectangle {
z: -6
id: opaqueRect
height: parent.height
width: parent.width
opacity: 0.65
color: "black"
}
Component.onCompleted: {
keyboardTimer.start();
}
Keyboard {
HifiControlsUit.Keyboard {
id: loginKeyboard
raised: root.keyboardEnabled && root.keyboardRaised
numeric: root.punctuationMode
@ -182,16 +159,20 @@ TabletModalWindow {
}
break
} else switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
event.accepted = true
destroy()
break
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
break
}
}
Component.onDestruction: {
loginKeyboard.raised = false;
KeyboardScriptingInterface.raised = false;
}
Component.onCompleted: {
keyboardTimer.start();
bodyLoader.setSource("../LoginDialog/LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": false });
}
}

View file

@ -1,6 +1,6 @@
import QtQuick 2.7
import QtWebEngine 1.5;
import Qt.labs.settings 1.0
import Qt.labs.settings 1.0 as QtSettings
import QtQuick.Controls 2.3
@ -74,7 +74,7 @@ OriginalDesktop.Desktop {
shown: tablet ? tablet.toolbarMode : false;
}
Settings {
QtSettings.Settings {
id: settings;
category: "toolbar";
property bool constrainToolbarToCenterX: true;

View file

@ -61,7 +61,7 @@ Rectangle {
'username';
}
sortAscending: connectionsTable.sortIndicatorOrder === Qt.AscendingOrder;
itemsPerPage: 10;
itemsPerPage: 1000;
listView: connectionsTable;
processPage: function (data) {
return data.users.map(function (user) {

View file

@ -15,10 +15,10 @@ import Qt.labs.settings 1.0
import stylesUit 1.0
import controlsUit 1.0 as HifiControls
import "../../windows"
import "../../windows" as Windows
import "../"
ScrollingWindow {
Windows.ScrollingWindow {
id: root
objectName: "RunningScripts"
title: "Running Scripts"
@ -30,7 +30,7 @@ ScrollingWindow {
minSize: Qt.vector2d(424, 300)
HifiConstants { id: hifi }
property var scripts: ScriptDiscoveryService;
property var scriptsModel: scripts.scriptsModelFilter
property var runningScriptsModel: ListModel { }
@ -45,7 +45,7 @@ ScrollingWindow {
Component {
id: letterBoxMessage
Window {
Windows.Window {
implicitWidth: 400
implicitHeight: 300
minSize: Qt.vector2d(424, 300)
@ -63,8 +63,8 @@ ScrollingWindow {
}
}
}
Timer {
id: refreshTimer
interval: 100
@ -81,7 +81,7 @@ ScrollingWindow {
running: false
onTriggered: developerMenuEnabled = MenuInterface.isOptionChecked("Developer Menu");
}
Component {
id: listModelBuilder
ListModel { }
@ -92,7 +92,7 @@ ScrollingWindow {
onScriptCountChanged: {
runningScriptsModel = listModelBuilder.createObject(root);
refreshTimer.restart();
}
}
}
Component.onCompleted: {
@ -120,7 +120,7 @@ ScrollingWindow {
// Calling `runningScriptsModel.clear()` here instead of creating a new object
// triggers some kind of weird heap corruption deep inside Qt. So instead of
// modifying the model in place, possibly triggering behaviors in the table
// instead we create a new `ListModel`, populate it and update the
// instead we create a new `ListModel`, populate it and update the
// existing model atomically.
var newRunningScriptsModel = listModelBuilder.createObject(root);
for (var i = 0; i < runningScripts.length; ++i) {
@ -177,7 +177,7 @@ ScrollingWindow {
if ((script === "controllerScripts.js") || (script === "defaultScripts.js")) {
return developerMenuEnabled;
}
return true;
}
@ -369,7 +369,7 @@ ScrollingWindow {
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.right: parent.right
TableViewColumn {
role: "display";
}
@ -447,4 +447,3 @@ ScrollingWindow {
}
}
}

View file

@ -349,5 +349,7 @@ QtObject {
readonly property string update: "\ue032"
readonly property string uninstall: "\ue033"
readonly property string verticalEllipsis: "\ue034"
readonly property string steamSquare: "\ue035"
readonly property string oculus: "\ue036"
}
}

View file

@ -97,22 +97,22 @@ Frame {
GlyphButton {
id: closeButton
visible: window.closeButtonVisible
width: 30
y: -hifi.dimensions.modalDialogTitleHeight
anchors {
top: parent.top
right: parent.right
topMargin: 10
rightMargin: 10
}
glyph: hifi.glyphs.close
size: 23
onClicked: {
window.clickedCloseButton = true;
window.destroy();
}
}
id: closeButton
visible: window.closeButtonVisible
width: 30
y: -hifi.dimensions.modalDialogTitleHeight
anchors {
top: parent.top
right: parent.right
topMargin: 10
rightMargin: 10
}
glyph: hifi.glyphs.close
size: 23
onClicked: {
window.clickedCloseButton = true;
window.destroy();
}
}
}
}

View file

@ -13,9 +13,9 @@ import QtQuick 2.5
import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0
import "."
import "." as Windows
import stylesUit 1.0
import controlsUit 1.0 as HiFiControls
import controlsUit 1.0 as HifiControlsUit
// FIXME how do I set the initial position of a window without
// overriding places where the a individual client of the window
@ -25,7 +25,7 @@ import controlsUit 1.0 as HiFiControls
// of the desktop? How do I ensure when the desktop resizes all the windows
// are still at least partially visible?
Window {
Windows.Window {
id: window
HifiConstants { id: hifi }
children: [ swallower, frame, defocuser, pane, activator ]
@ -178,7 +178,7 @@ Window {
children: [ footer ]
}
HiFiControls.Keyboard {
HifiControlsUit.Keyboard {
id: keyboard
enabled: !keyboardOverride
raised: keyboardEnabled && keyboardRaised

View file

@ -328,7 +328,13 @@ static const float INITIAL_QUERY_RADIUS = 10.0f; // priority radius for entitie
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS);
Setting::Handle<int> maxOctreePacketsPerSecond{"maxOctreePPS", DEFAULT_MAX_OCTREE_PPS};
Setting::Handle<bool> loginDialogPoppedUp{"loginDialogPoppedUp", false};
static const QString STANDARD_TO_ACTION_MAPPING_NAME = "Standard to Action";
static const QString NO_MOVEMENT_MAPPING_NAME = "Standard to Action (No Movement)";
static const QString NO_MOVEMENT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard_nomovement.json";
static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com";
static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds
@ -971,6 +977,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
_hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT),
_desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT),
_firstRun(Settings::firstRun, true),
_desktopTabletBecomesToolbarSetting("desktopTabletBecomesToolbar", DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR),
_hmdTabletBecomesToolbarSetting("hmdTabletBecomesToolbar", DEFAULT_HMD_TABLET_BECOMES_TOOLBAR),
_preferStylusOverLaserSetting("preferStylusOverLaser", DEFAULT_PREFER_STYLUS_OVER_LASER),
@ -989,12 +996,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_lastFaceTrackerUpdate(0),
_snapshotSound(nullptr),
_sampleSound(nullptr)
{
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
setProperty(hifi::properties::CRASHED, _previousSessionCrashed);
{
const QStringList args = arguments();
@ -1268,6 +1275,27 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
setCrashAnnotation("hmd", displayPlugin->isHmd() ? "1" : "0");
});
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode);
connect(this, &Application::activeDisplayPluginChanged, this, [&](){
if (getLoginDialogPoppedUp()) {
auto dialogsManager = DependencyManager::get<DialogsManager>();
auto keyboard = DependencyManager::get<Keyboard>();
if (_firstRun.get()) {
// display mode changed. Don't allow auto-switch to work after this session.
_firstRun.set(false);
}
if (isHMDMode()) {
emit loginDialogFocusDisabled();
dialogsManager->hideLoginDialog();
createLoginDialogOverlay();
} else {
getOverlays().deleteOverlay(_loginDialogOverlayID);
_loginDialogOverlayID = OverlayID();
_loginStateManager.tearDown();
dialogsManager->showLoginDialog();
emit loginDialogFocusEnabled();
}
}
});
// Save avatar location immediately after a teleport.
connect(myAvatar.get(), &MyAvatar::positionGoneTo,
@ -1472,9 +1500,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
qDebug() << "Detected installer type:" << installerType;
qDebug() << "Detected installer campaign:" << installerCampaign;
// add firstRun flag from settings to launch event
Setting::Handle<bool> firstRun { Settings::firstRun, true };
auto& userActivityLogger = UserActivityLogger::getInstance();
if (userActivityLogger.isEnabled()) {
// sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value.
@ -1523,7 +1548,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
properties["processor_l3_cache_count"] = procInfo.numProcessorCachesL3;
}
properties["first_run"] = firstRun.get();
properties["first_run"] = _firstRun.get();
// add the user's machine ID to the launch event
QString machineFingerPrint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint());
@ -1736,27 +1761,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
userInputMapper->registerDevice(_touchscreenVirtualPadDevice->getInputDevice());
}
{
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
// this will force the model the look at the correct directory (weird order of operations issue)
scriptEngines->reloadLocalFiles();
// do this as late as possible so that all required subsystems are initialized
// If we've overridden the default scripts location, just load default scripts
// otherwise, load 'em all
// we just want to see if --scripts was set, we've already parsed it and done
// the change in PathUtils. Rather than pass that in the constructor, lets just
// look (this could be debated)
QString scriptsSwitch = QString("--").append(SCRIPTS_SWITCH);
QDir defaultScriptsLocation(getCmdOption(argc, constArgv, scriptsSwitch.toStdString().c_str()));
if (!defaultScriptsLocation.exists()) {
scriptEngines->loadDefaultScripts();
scriptEngines->defaultScriptsLocationOverridden(true);
} else {
scriptEngines->loadScripts();
}
}
QString scriptsSwitch = QString("--").append(SCRIPTS_SWITCH);
_defaultScriptsLocation = getCmdOption(argc, constArgv, scriptsSwitch.toStdString().c_str());
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
@ -1777,11 +1783,27 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
}
});
connect(offscreenUi.data(), &OffscreenUi::keyboardFocusActive, [this]() {
#if !defined(Q_OS_ANDROID) && !defined(DISABLE_QML)
// Do not show login dialog if requested not to on the command line
QString hifiNoLoginCommandLineKey = QString("--").append(HIFI_NO_LOGIN_COMMAND_LINE_KEY);
int index = arguments().indexOf(hifiNoLoginCommandLineKey);
if (index != -1) {
resumeAfterLoginDialogActionTaken();
return;
}
showLoginScreen();
#else
resumeAfterLoginDialogActionTaken();
#endif
});
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
QTimer* settingsTimer = new QTimer();
moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{
// This needs to run on the settings thread, so we need to pass the `settingsTimer` as the
// This needs to run on the settings thread, so we need to pass the `settingsTimer` as the
// receiver object, otherwise it will run on the application thread and trigger a warning
// about trying to kill the timer on the main thread.
connect(qApp, &Application::beforeAboutToQuit, settingsTimer, [this, settingsTimer]{
@ -2234,29 +2256,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_snapshotSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/snapshot/snap.wav"));
QVariant testProperty = property(hifi::properties::TEST);
qDebug() << testProperty;
if (testProperty.isValid()) {
const auto testScript = property(hifi::properties::TEST).toUrl();
// Set last parameter to exit interface when the test script finishes, if so requested
DependencyManager::get<ScriptEngines>()->loadScript(testScript, false, false, false, false, quitWhenFinished);
// This is done so we don't get a "connection time-out" message when we haven't passed in a URL.
if (arguments().contains("--url")) {
auto reply = SandboxUtils::getStatus();
connect(reply, &QNetworkReply::finished, this, [this, reply] {
handleSandboxStatus(reply);
});
}
} else {
PROFILE_RANGE(render, "GetSandboxStatus");
auto reply = SandboxUtils::getStatus();
connect(reply, &QNetworkReply::finished, this, [this, reply] {
handleSandboxStatus(reply);
});
}
// Monitor model assets (e.g., from Clara.io) added to the world that may need resizing.
static const int ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS = 1000;
_addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable
@ -2330,33 +2329,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&AndroidHelper::instance(), &AndroidHelper::enterBackground, this, &Application::enterBackground);
connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground);
AndroidHelper::instance().notifyLoadComplete();
#else
#if !defined(DISABLE_QML)
// Do not show login dialog if requested not to on the command line
const QString HIFI_NO_LOGIN_COMMAND_LINE_KEY = "--no-login-suggestion";
int index = arguments().indexOf(HIFI_NO_LOGIN_COMMAND_LINE_KEY);
if (index == -1) {
// request not found
static int CHECK_LOGIN_TIMER = 3000;
QTimer* checkLoginTimer = new QTimer(this);
checkLoginTimer->setInterval(CHECK_LOGIN_TIMER);
checkLoginTimer->setSingleShot(true);
connect(checkLoginTimer, &QTimer::timeout, this, []() {
auto accountManager = DependencyManager::get<AccountManager>();
auto dialogsManager = DependencyManager::get<DialogsManager>();
if (!accountManager->isLoggedIn()) {
Setting::Handle<bool>{ "loginDialogPoppedUp", false }.set(true);
dialogsManager->showLoginDialog();
QJsonObject loginData = {};
loginData["action"] = "login dialog shown";
UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData);
}
});
Setting::Handle<bool>{ "loginDialogPoppedUp", false }.set(false);
checkLoginTimer->start();
}
#endif
#endif
pauseUntilLoginDetermined();
}
void Application::updateVerboseLogging() {
@ -2496,7 +2470,7 @@ void Application::onAboutToQuit() {
// so its persisted explicitly here
Setting::Handle<QString>{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME }.set(getActiveDisplayPlugin()->getName());
Setting::Handle<bool>{"loginDialogPoppedUp", false}.set(false);
loginDialogPoppedUp.set(false);
getActiveDisplayPlugin()->deactivate();
if (_autoSwitchDisplayModeSupportedHMDPlugin
@ -2664,7 +2638,7 @@ Application::~Application() {
// shutdown graphics engine
_graphicsEngine.shutdown();
_gameWorkload.shutdown();
DependencyManager::destroy<Preferences>();
@ -2871,6 +2845,32 @@ extern void setupPreferences();
static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, int index, bool active = false);
#endif
void Application::showLoginScreen() {
#if !defined(DISABLE_QML)
auto accountManager = DependencyManager::get<AccountManager>();
auto dialogsManager = DependencyManager::get<DialogsManager>();
if (!accountManager->isLoggedIn()) {
if (!isHMDMode()) {
auto toolbar = DependencyManager::get<ToolbarScriptingInterface>()->getToolbar("com.highfidelity.interface.toolbar.system");
toolbar->writeProperty("visible", false);
}
_loginDialogPoppedUp = true;
dialogsManager->showLoginDialog();
emit loginDialogFocusEnabled();
QJsonObject loginData = {};
loginData["action"] = "login dialog shown";
UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData);
_window->setWindowTitle("High Fidelity Interface");
} else {
resumeAfterLoginDialogActionTaken();
}
_loginDialogPoppedUp = !accountManager->isLoggedIn();
loginDialogPoppedUp.set(_loginDialogPoppedUp);
#else
resumeAfterLoginDialogActionTaken();
#endif
}
void Application::initializeUi() {
AddressBarDialog::registerType();
ErrorDialog::registerType();
@ -3017,8 +3017,7 @@ void Application::initializeUi() {
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
// first sort the plugins into groupings: standard, advanced, developer
std::stable_sort(displayPlugins.begin(), displayPlugins.end(),
[](const DisplayPluginPointer& a, const DisplayPluginPointer& b)->bool { return a->getGrouping() < b->getGrouping(); });
[](const DisplayPluginPointer& a, const DisplayPluginPointer& b) -> bool { return a->getGrouping() < b->getGrouping(); });
int dpIndex = 1;
// concatenate the groupings into a single list in the order: standard, advanced, developer
for(const auto& displayPlugin : displayPlugins) {
@ -3032,6 +3031,7 @@ void Application::initializeUi() {
}
#endif
// The display plugins are created before the menu now, so we need to do this here to hide the menu bar
// now that it exists
if (_window && _window->isFullScreen()) {
@ -3458,8 +3458,6 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
bool isUsingHMD = _displayPlugin->isHmd();
bool isUsingHMDAndHandControllers = hasHMD && hasHandControllers && isUsingHMD;
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers;
// when --url in command line, teleport to location
@ -3481,12 +3479,12 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
QString sentTo;
// If this is a first run we short-circuit the address passed in
if (firstRun.get()) {
if (_firstRun.get()) {
#if !defined(Q_OS_ANDROID)
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
#endif
firstRun.set(false);
_firstRun.set(false);
} else {
#if !defined(Q_OS_ANDROID)
@ -3572,16 +3570,7 @@ void Application::setIsServerlessMode(bool serverlessDomain) {
}
}
void Application::loadServerlessDomain(QUrl domainURL, bool errorDomain) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_ARG(QUrl, domainURL), Q_ARG(bool, errorDomain));
return;
}
if (domainURL.isEmpty()) {
return;
}
std::map<QString, QString> Application::prepareServerlessDomainContents(QUrl domainURL) {
QUuid serverlessSessionID = QUuid::createUuid();
getMyAvatar()->setSessionUUID(serverlessSessionID);
auto nodeList = DependencyManager::get<NodeList>();
@ -3605,13 +3594,43 @@ void Application::loadServerlessDomain(QUrl domainURL, bool errorDomain) {
tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), 0, 0, 0);
}
std::map<QString, QString> namedPaths = tmpTree->getNamedPaths();
if (errorDomain) {
nodeList->getDomainHandler().loadedErrorDomain(namedPaths);
} else {
nodeList->getDomainHandler().connectedToServerless(namedPaths);
return tmpTree->getNamedPaths();
}
void Application::loadServerlessDomain(QUrl domainURL) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_ARG(QUrl, domainURL));
return;
}
if (domainURL.isEmpty()) {
return;
}
auto namedPaths = prepareServerlessDomainContents(domainURL);
auto nodeList = DependencyManager::get<NodeList>();
nodeList->getDomainHandler().connectedToServerless(namedPaths);
_fullSceneReceivedCounter++;
}
void Application::loadErrorDomain(QUrl domainURL) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "loadErrorDomain", Q_ARG(QUrl, domainURL));
return;
}
if (domainURL.isEmpty()) {
return;
}
auto namedPaths = prepareServerlessDomainContents(domainURL);
auto nodeList = DependencyManager::get<NodeList>();
nodeList->getDomainHandler().loadedErrorDomain(namedPaths);
_fullSceneReceivedCounter++;
}
@ -3851,7 +3870,34 @@ void Application::keyPressEvent(QKeyEvent* event) {
return;
}
if (hasFocus()) {
if (hasFocus() && getLoginDialogPoppedUp()) {
if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->keyReleaseEvent(event);
}
bool isMeta = event->modifiers().testFlag(Qt::ControlModifier);
bool isOption = event->modifiers().testFlag(Qt::AltModifier);
switch (event->key()) {
case Qt::Key_4:
case Qt::Key_5:
case Qt::Key_6:
case Qt::Key_7:
if (isMeta || isOption) {
unsigned int index = static_cast<unsigned int>(event->key() - Qt::Key_1);
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
if (index < displayPlugins.size()) {
auto targetPlugin = displayPlugins.at(index);
QString targetName = targetPlugin->getName();
auto menu = Menu::getInstance();
QAction* action = menu->getActionForOption(targetName);
if (action && !action->isChecked()) {
action->trigger();
}
}
}
break;
}
} else if (hasFocus()) {
if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->keyPressEvent(event);
}
@ -4378,7 +4424,7 @@ void Application::wheelEvent(QWheelEvent* event) const {
_controllerScriptingInterface->emitWheelEvent(event); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface->isWheelCaptured()) {
if (_controllerScriptingInterface->isWheelCaptured() || getLoginDialogPoppedUp()) {
return;
}
@ -4973,9 +5019,8 @@ void Application::loadSettings() {
}
}
Setting::Handle<bool> firstRun { Settings::firstRun, true };
bool isFirstPerson = false;
if (firstRun.get()) {
if (_firstRun.get()) {
// If this is our first run, and no preferred devices were set, default to
// an HMD device if available.
auto displayPlugins = pluginManager->getDisplayPlugins();
@ -5125,6 +5170,124 @@ void Application::init() {
_entitySimulation->setWorkloadSpace(getEntities()->getWorkloadSpace());
}
void Application::pauseUntilLoginDetermined() {
if (QThread::currentThread() != qApp->thread()) {
QMetaObject::invokeMethod(this, "pauseUntilLoginDetermined");
return;
}
getMyAvatar()->setEnableMeshVisible(false);
_controllerScriptingInterface->disableMapping(STANDARD_TO_ACTION_MAPPING_NAME);
{
auto userInputMapper = DependencyManager::get<UserInputMapper>();
if (userInputMapper->loadMapping(NO_MOVEMENT_MAPPING_JSON)) {
_controllerScriptingInterface->enableMapping(NO_MOVEMENT_MAPPING_NAME);
}
}
const auto& nodeList = DependencyManager::get<NodeList>();
// save interstitial mode setting until resuming.
_interstitialModeEnabled = nodeList->getDomainHandler().getInterstitialModeEnabled();
nodeList->getDomainHandler().setInterstitialModeEnabled(false);
auto menu = Menu::getInstance();
menu->getMenu("Edit")->setVisible(false);
menu->getMenu("View")->setVisible(false);
menu->getMenu("Navigate")->setVisible(false);
menu->getMenu("Settings")->setVisible(false);
_developerMenuVisible = menu->getMenu("Developer")->isVisible();
menu->setIsOptionChecked(MenuOption::Stats, false);
if (_developerMenuVisible) {
menu->getMenu("Developer")->setVisible(false);
}
_previousCameraMode = _myCamera.getMode();
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
cameraModeChanged();
// disconnect domain handler.
nodeList->getDomainHandler().disconnect();
}
void Application::resumeAfterLoginDialogActionTaken() {
if (QThread::currentThread() != qApp->thread()) {
QMetaObject::invokeMethod(this, "resumeAfterLoginDialogActionTaken");
return;
}
if (!isHMDMode() && getDesktopTabletBecomesToolbarSetting()) {
auto toolbar = DependencyManager::get<ToolbarScriptingInterface>()->getToolbar("com.highfidelity.interface.toolbar.system");
toolbar->writeProperty("visible", true);
} else {
getApplicationCompositor().getReticleInterface()->setAllowMouseCapture(true);
getApplicationCompositor().getReticleInterface()->setVisible(true);
}
updateSystemTabletMode();
{
auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->unloadMapping(NO_MOVEMENT_MAPPING_JSON);
_controllerScriptingInterface->disableMapping(NO_MOVEMENT_MAPPING_NAME);
}
getMyAvatar()->setEnableMeshVisible(true);
_controllerScriptingInterface->enableMapping(STANDARD_TO_ACTION_MAPPING_NAME);
const auto& nodeList = DependencyManager::get<NodeList>();
nodeList->getDomainHandler().setInterstitialModeEnabled(_interstitialModeEnabled);
{
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
// this will force the model the look at the correct directory (weird order of operations issue)
scriptEngines->reloadLocalFiles();
if (!_defaultScriptsLocation.exists()) {
scriptEngines->loadDefaultScripts();
scriptEngines->defaultScriptsLocationOverridden(true);
} else {
scriptEngines->loadScripts();
}
}
if (_firstRun.get()) {
// not first run anymore since action was taken.
_firstRun.set(false);
}
auto accountManager = DependencyManager::get<AccountManager>();
auto addressManager = DependencyManager::get<AddressManager>();
// restart domain handler.
nodeList->getDomainHandler().resetting();
if (!accountManager->isLoggedIn()) {
addressManager->goToEntry();
} else {
QVariant testProperty = property(hifi::properties::TEST);
if (testProperty.isValid()) {
const auto testScript = property(hifi::properties::TEST).toUrl();
// Set last parameter to exit interface when the test script finishes, if so requested
DependencyManager::get<ScriptEngines>()->loadScript(testScript, false, false, false, false, quitWhenFinished);
// This is done so we don't get a "connection time-out" message when we haven't passed in a URL.
if (arguments().contains("--url")) {
auto reply = SandboxUtils::getStatus();
connect(reply, &QNetworkReply::finished, this, [this, reply] { handleSandboxStatus(reply); });
}
} else {
addressManager->loadSettings();
}
}
auto menu = Menu::getInstance();
menu->getMenu("Edit")->setVisible(true);
menu->getMenu("View")->setVisible(true);
menu->getMenu("Navigate")->setVisible(true);
menu->getMenu("Settings")->setVisible(true);
menu->getMenu("Developer")->setVisible(_developerMenuVisible);
_myCamera.setMode(_previousCameraMode);
cameraModeChanged();
}
void Application::loadAvatarScripts(const QVector<QString>& urls) {
auto scriptEngines = DependencyManager::get<ScriptEngines>();
auto runningScripts = scriptEngines->getRunningScripts();
@ -5439,6 +5602,9 @@ void Application::rotationModeChanged() const {
void Application::setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions) {
// Create focus
if (qApp->getLoginDialogPoppedUp()) {
return;
}
if (_keyboardFocusHighlightID == UNKNOWN_OVERLAY_ID || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {
_keyboardFocusHighlight = std::make_shared<Cube3DOverlay>();
_keyboardFocusHighlight->setAlpha(1.0f);
@ -5466,6 +5632,9 @@ QUuid Application::getKeyboardFocusEntity() const {
static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f;
void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) {
if (qApp->getLoginDialogPoppedUp()) {
return;
}
if (_keyboardFocusedEntity.get() != entityItemID) {
_keyboardFocusedEntity.set(entityItemID);
@ -5506,6 +5675,15 @@ OverlayID Application::getKeyboardFocusOverlay() {
void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) {
if (overlayID != _keyboardFocusedOverlay.get()) {
if (qApp->getLoginDialogPoppedUp() && !_loginDialogOverlayID.isNull()) {
if (overlayID == _loginDialogOverlayID) {
emit loginDialogFocusEnabled();
} else {
// that's the only overlay we want in focus;
return;
}
}
_keyboardFocusedOverlay.set(overlayID);
if (_keyboardFocusHighlight && _keyboardFocusedEntity.get() == UNKNOWN_ENTITY_ID) {
@ -5769,7 +5947,6 @@ void Application::update(float deltaTime) {
if (keyboardMousePlugin && keyboardMousePlugin->isActive()) {
keyboardMousePlugin->pluginUpdate(deltaTime, calibrationData);
}
// Transfer the user inputs to the driveKeys
// FIXME can we drop drive keys and just have the avatar read the action states directly?
myAvatar->clearDriveKeys();
@ -6044,6 +6221,11 @@ void Application::update(float deltaTime) {
updateLOD(deltaTime);
if (!_loginDialogOverlayID.isNull()) {
_loginStateManager.update(getMyAvatar()->getDominantHand(), _loginDialogOverlayID);
updateLoginDialogOverlayPosition();
}
// TODO: break these out into distinct perfTimers when they prove interesting
{
PROFILE_RANGE(app, "PickManager");
@ -6609,12 +6791,11 @@ void Application::goToErrorDomainURL(QUrl errorDomainURL) {
resetPhysicsReadyInformation();
setIsServerlessMode(errorDomainURL.scheme() != URL_SCHEME_HIFI);
if (isServerlessMode()) {
loadServerlessDomain(errorDomainURL, true);
loadErrorDomain(errorDomainURL);
}
updateWindowTitle();
}
void Application::resettingDomain() {
_notifiedPacketVersionMismatchThisDomain = false;
@ -7268,7 +7449,7 @@ void Application::showScriptLogs() {
}
void Application::showAssetServerWidget(QString filePath) {
if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) {
if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets() || getLoginDialogPoppedUp()) {
return;
}
static const QUrl url { "hifi/AssetServer.qml" };
@ -7904,6 +8085,9 @@ void Application::loadDomainConnectionDialog() {
}
void Application::toggleLogDialog() {
if (getLoginDialogPoppedUp()) {
return;
}
if (! _logDialog) {
_logDialog = new LogDialog(nullptr, getLogger());
}
@ -8436,6 +8620,102 @@ void Application::setShowBulletConstraintLimits(bool value) {
_physicsEngine->setShowBulletConstraintLimits(value);
}
void Application::createLoginDialogOverlay() {
const glm::vec2 LOGIN_OVERLAY_DIMENSIONS{ 0.89f, 0.5f };
const auto OVERLAY_OFFSET = glm::vec2(0.7f, -0.1f);
auto cameraPosition = _myCamera.getPosition();
auto cameraOrientation = _myCamera.getOrientation();
auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y;
auto headLookVec = (cameraOrientation * Vectors::FRONT);
// DEFAULT_DPI / tablet scale percentage
const float OVERLAY_DPI = 31.0f / (75.0f / 100.0f);
auto offset = headLookVec * OVERLAY_OFFSET.x;
auto overlayPosition = (cameraPosition + offset) + (upVec * OVERLAY_OFFSET.y);
QVariantMap overlayProperties = {
{ "name", "LoginDialogOverlay" },
{ "url", OVERLAY_LOGIN_DIALOG },
{ "position", vec3toVariant(overlayPosition) },
{ "orientation", quatToVariant(cameraOrientation) },
{ "isSolid", true },
{ "grabbable", false },
{ "ignorePickIntersection", false },
{ "alpha", 1.0 },
{ "dimensions", vec2ToVariant(LOGIN_OVERLAY_DIMENSIONS)},
{ "dpi", OVERLAY_DPI },
{ "visible", true }
};
auto& overlays = getOverlays();
_loginDialogOverlayID = overlays.addOverlay("web3d", overlayProperties);
auto loginOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays.getOverlay(_loginDialogOverlayID));
auto keyboard = DependencyManager::get<Keyboard>().data();
if (!keyboard->getAnchorID().isNull() && !_loginDialogOverlayID.isNull()) {
const auto KEYBOARD_LOCAL_ORIENTATION = glm::quat(0.0f, 0.0, 1.0f, 0.25f);
auto keyboardLocalOffset = glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
QVariantMap properties {
{ "position", vec3toVariant(loginOverlay->getWorldPosition() + keyboardLocalOffset) },
{ "orientation", quatToVariant(loginOverlay->getWorldOrientation() * KEYBOARD_LOCAL_ORIENTATION) },
};
overlays.editOverlay(keyboard->getAnchorID(), properties);
keyboard->setResetKeyboardPositionOnRaise(false);
}
setKeyboardFocusOverlay(_loginDialogOverlayID);
emit loginDialogFocusEnabled();
getApplicationCompositor().getReticleInterface()->setAllowMouseCapture(false);
getApplicationCompositor().getReticleInterface()->setVisible(false);
if (!_loginStateManager.isSetUp()) {
_loginStateManager.setUp();
}
}
void Application::updateLoginDialogOverlayPosition() {
const float LOOK_AWAY_THRESHOLD_ANGLE = 40.0f;
const auto OVERLAY_OFFSET = glm::vec2(0.7f, -0.1f);
auto& overlays = getOverlays();
auto loginOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays.getOverlay(_loginDialogOverlayID));
auto overlayPositionVec = loginOverlay->getWorldPosition();
auto cameraPositionVec = _myCamera.getPosition();
auto cameraOrientation = cancelOutRollAndPitch(_myCamera.getOrientation());
auto headLookVec = (cameraOrientation * Vectors::FRONT);
auto overlayToHeadVec = overlayPositionVec - cameraPositionVec;
auto pointAngle = (glm::acos(glm::dot(glm::normalize(overlayToHeadVec), glm::normalize(headLookVec))) * 180.0f / PI);
auto upVec = getMyAvatar()->getWorldOrientation() * Vectors::UNIT_Y;
auto offset = headLookVec * OVERLAY_OFFSET.x;
auto newOverlayPositionVec = (cameraPositionVec + offset) + (upVec * OVERLAY_OFFSET.y);
auto newOverlayOrientation = glm::inverse(glm::quat_cast(glm::lookAt(newOverlayPositionVec, cameraPositionVec, upVec))) * Quaternions::Y_180;
bool overlayOutOfBounds = glm::distance(overlayPositionVec, cameraPositionVec) > 1.0f;
if (pointAngle > LOOK_AWAY_THRESHOLD_ANGLE || overlayOutOfBounds) {
QVariantMap properties {
{"position", vec3toVariant(newOverlayPositionVec)},
{"orientation", quatToVariant(newOverlayOrientation)}
};
overlays.editOverlay(_loginDialogOverlayID, properties);
const auto KEYBOARD_LOCAL_ORIENTATION = glm::quat(0.0f, 0.0, 1.0f, 0.25f);
auto keyboardLocalOffset = glm::vec3(-0.4f * getMyAvatar()->getSensorToWorldScale(), -0.3f, 0.2f);
QVariantMap keyboardProperties {
{ "position", vec3toVariant(loginOverlay->getWorldPosition() + keyboardLocalOffset) },
{ "orientation", quatToVariant(loginOverlay->getWorldOrientation() * KEYBOARD_LOCAL_ORIENTATION) },
};
auto keyboard = DependencyManager::get<Keyboard>().data();
overlays.editOverlay(keyboard->getAnchorID(), keyboardProperties);
}
}
void Application::onDismissedLoginDialog() {
_loginDialogPoppedUp = false;
loginDialogPoppedUp.set(false);
auto keyboard = DependencyManager::get<Keyboard>().data();
keyboard->setResetKeyboardPositionOnRaise(true);
if (!_loginDialogOverlayID.isNull()) {
// deleting overlay.
getOverlays().deleteOverlay(_loginDialogOverlayID);
_loginDialogOverlayID = OverlayID();
_loginStateManager.tearDown();
}
resumeAfterLoginDialogActionTaken();
}
void Application::setShowTrackedObjects(bool value) {
_showTrackedObjects = value;
}
@ -8586,7 +8866,7 @@ void Application::updateThreadPoolCount() const {
}
void Application::updateSystemTabletMode() {
if (_settingsLoaded) {
if (_settingsLoaded && !getLoginDialogPoppedUp()) {
qApp->setProperty(hifi::properties::HMD, isHMDMode());
if (isHMDMode()) {
DependencyManager::get<TabletScriptingInterface>()->setToolbarMode(getHmdTabletBecomesToolbarSetting());
@ -8612,7 +8892,7 @@ QUuid Application::getTabletFrameID() const {
}
QVector<QUuid> Application::getTabletIDs() const {
// Most important overlays first.
// Most important overlays first.
QVector<QUuid> result;
auto HMD = DependencyManager::get<HMDScriptingInterface>();
result << HMD->getCurrentTabletScreenID();

View file

@ -56,6 +56,7 @@
#include "ConnectionMonitor.h"
#include "CursorManager.h"
#include "gpu/Context.h"
#include "LoginStateManager.h"
#include "Menu.h"
#include "octree/OctreePacketProcessor.h"
#include "render/Engine.h"
@ -97,6 +98,7 @@ static const UINT UWM_SHOW_APPLICATION =
static const QString RUNNING_MARKER_FILENAME = "Interface.running";
static const QString SCRIPTS_SWITCH = "scripts";
static const QString HIFI_NO_LOGIN_COMMAND_LINE_KEY = "no-login-suggestion";
class Application;
#if defined(qApp)
@ -232,7 +234,7 @@ public:
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
void setSettingConstrainToolbarPosition(bool setting);
Q_INVOKABLE void setMinimumGPUTextureMemStabilityCount(int stabilityCount) { _minimumGPUTextureMemSizeStabilityCount = stabilityCount; }
Q_INVOKABLE void setMinimumGPUTextureMemStabilityCount(int stabilityCount) { _minimumGPUTextureMemSizeStabilityCount = stabilityCount; }
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
@ -320,6 +322,10 @@ public:
int getOtherAvatarsReplicaCount() { return DependencyManager::get<AvatarHashMap>()->getReplicaCount(); }
void setOtherAvatarsReplicaCount(int count) { DependencyManager::get<AvatarHashMap>()->setReplicaCount(count); }
bool getLoginDialogPoppedUp() const { return _loginDialogPoppedUp; }
void createLoginDialogOverlay();
void updateLoginDialogOverlayPosition();
#if defined(Q_OS_ANDROID)
void beforeEnterBackground();
void enterBackground();
@ -338,7 +344,8 @@ signals:
void interstitialModeChanged(bool isInInterstitialMode);
void loginDialogPoppedUp();
void loginDialogFocusEnabled();
void loginDialogFocusDisabled();
void miniTabletEnabledChanged(bool enabled);
@ -362,6 +369,8 @@ public slots:
void showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const;
void showLoginScreen();
// FIXME: Move addAssetToWorld* methods to own class?
void addAssetToWorldFromURL(QString url);
void addAssetToWorldFromURLRequestFinished();
@ -440,7 +449,10 @@ public slots:
void setPreferredCursor(const QString& cursor);
void setIsServerlessMode(bool serverlessDomain);
void loadServerlessDomain(QUrl domainURL, bool errorDomain = false);
std::map<QString, QString> prepareServerlessDomainContents(QUrl domainURL);
void loadServerlessDomain(QUrl domainURL);
void loadErrorDomain(QUrl domainURL);
void setIsInterstitialMode(bool interstitialMode);
void updateVerboseLogging();
@ -505,10 +517,14 @@ private slots:
void setShowBulletConstraints(bool value);
void setShowBulletConstraintLimits(bool value);
void onDismissedLoginDialog();
void setShowTrackedObjects(bool value);
private:
void init();
void pauseUntilLoginDetermined();
void resumeAfterLoginDialogActionTaken();
bool handleKeyEventForFocusedEntityOrOverlay(QEvent* event);
bool handleFileOpenEvent(QFileOpenEvent* event);
void cleanupBeforeQuit();
@ -622,6 +638,7 @@ private:
Setting::Handle<float> _fieldOfView;
Setting::Handle<float> _hmdTabletScale;
Setting::Handle<float> _desktopTabletScale;
Setting::Handle<bool> _firstRun;
Setting::Handle<bool> _desktopTabletBecomesToolbarSetting;
Setting::Handle<bool> _hmdTabletBecomesToolbarSetting;
Setting::Handle<bool> _preferStylusOverLaserSetting;
@ -649,6 +666,7 @@ private:
ControllerScriptingInterface* _controllerScriptingInterface{ nullptr };
QPointer<LogDialog> _logDialog;
QPointer<EntityScriptServerLogDialog> _entityScriptServerLogDialog;
QDir _defaultScriptsLocation;
FileLogger* _logger;
@ -669,6 +687,13 @@ private:
glm::uvec2 _renderResolution;
int _maxOctreePPS = DEFAULT_MAX_OCTREE_PPS;
bool _interstitialModeEnabled{ false };
bool _loginDialogPoppedUp = false;
bool _developerMenuVisible{ false };
CameraMode _previousCameraMode;
OverlayID _loginDialogOverlayID;
LoginStateManager _loginStateManager;
quint64 _lastFaceTrackerUpdate;

View file

@ -0,0 +1,241 @@
//
// LoginStateManager.cpp
// interface/src
//
// Created by Wayne Chen on 11/5/18.
// Copyright 2018 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
//
#include "LoginStateManager.h"
#include <QtCore/QString>
#include <QtCore/QVariantMap>
#include <plugins/PluginUtils.h>
#include <RegisteredMetaTypes.h>
#include "controllers/StateController.h"
#include "controllers/UserInputMapper.h"
#include "raypick/PointerScriptingInterface.h"
#include "raypick/RayPickScriptingInterface.h"
#include "raypick/PickScriptingInterface.h"
#include "scripting/ControllerScriptingInterface.h"
static const float SEARCH_SPHERE_SIZE = 0.0132f;
static const QVariantMap SEARCH_SPHERE = {{"x", SEARCH_SPHERE_SIZE},
{"y", SEARCH_SPHERE_SIZE},
{"z", SEARCH_SPHERE_SIZE}};
static const int DEFAULT_SEARCH_SPHERE_DISTANCE = 1000; // how far from camera to search intersection?
static const QVariantMap COLORS_GRAB_SEARCHING_HALF_SQUEEZE = {{"red", 10},
{"green", 10},
{"blue", 255}};
static const QVariantMap COLORS_GRAB_SEARCHING_FULL_SQUEEZE = {{"red", 250},
{"green", 10},
{"blue", 10}};
static const QVariantMap COLORS_GRAB_DISTANCE_HOLD = {{"red", 238},
{"green", 75},
{"blue", 214}};
void LoginStateManager::tearDown() {
auto pointers = DependencyManager::get<PointerManager>().data();
if (pointers) {
if (_leftLoginPointerID > PointerEvent::INVALID_POINTER_ID) {
pointers->removePointer(_leftLoginPointerID);
_leftLoginPointerID = PointerEvent::INVALID_POINTER_ID;
}
if (_rightLoginPointerID > PointerEvent::INVALID_POINTER_ID) {
pointers->removePointer(_rightLoginPointerID);
_rightLoginPointerID = PointerEvent::INVALID_POINTER_ID;
}
}
}
void LoginStateManager::setUp() {
QVariantMap fullPathRenderState {
{"type", "line3d"},
{"color", COLORS_GRAB_SEARCHING_FULL_SQUEEZE},
{"visible", true},
{"alpha", 1.0f},
{"solid", true},
{"glow", 1.0f},
{"ignoreRayIntersection", true}, // always ignore this
{"drawInFront", true}, // Even when burried inside of something, show it.
{"drawHUDLayer", false}
};
QVariantMap fullEndRenderState {
{"type", "sphere"},
{"dimensions", SEARCH_SPHERE},
{"solid", true},
{"color", COLORS_GRAB_SEARCHING_FULL_SQUEEZE},
{"alpha", 0.9f},
{"ignoreRayIntersection", true},
{"drawInFront", true}, // Even when burried inside of something, show it.
{"drawHUDLayer", false},
{"visible", true}
};
QVariantMap halfPathRenderState {
{"type", "line3d"},
{"color", COLORS_GRAB_SEARCHING_HALF_SQUEEZE},
{"visible", true},
{"alpha", 1.0f},
{"solid", true},
{"glow", 1.0f},
{"ignoreRayIntersection", true}, // always ignore this
{"drawInFront", true}, // Even when burried inside of something, show it.
{"drawHUDLayer", false}
};
QVariantMap halfEndRenderState {
{"type", "sphere"},
{"dimensions", SEARCH_SPHERE},
{"solid", true},
{"color", COLORS_GRAB_SEARCHING_HALF_SQUEEZE},
{"alpha", 0.9f},
{"ignoreRayIntersection", true},
{"drawInFront", true}, // Even when burried inside of something, show it.
{"drawHUDLayer", false},
{"visible", true}
};
QVariantMap holdPathRenderState {
{"type", "line3d"},
{"color", COLORS_GRAB_DISTANCE_HOLD},
{"visible", true},
{"alpha", 1.0f},
{"solid", true},
{"glow", 1.0f},
{"ignoreRayIntersection", true}, // always ignore this
{"drawInFront", true}, // Even when burried inside of something, show it.
{"drawHUDLayer", false},
};
QVariantMap halfRenderStateIdentifier {
{"name", "half"},
{"path", halfPathRenderState},
{"end", halfEndRenderState}
};
QVariantMap fullRenderStateIdentifier {
{"name", "full"},
{"path", fullPathRenderState},
{"end", fullEndRenderState}
};
QVariantMap holdRenderStateIdentifier {
{"name", "hold"},
{"path", holdPathRenderState},
};
QVariantMap halfDefaultRenderStateIdentifier {
{"name", "half"},
{"distance", DEFAULT_SEARCH_SPHERE_DISTANCE},
{"path", halfPathRenderState}
};
QVariantMap fullDefaultRenderStateIdentifier {
{"name", "full"},
{"distance", DEFAULT_SEARCH_SPHERE_DISTANCE},
{"path", fullPathRenderState}
};
QVariantMap holdDefaultRenderStateIdentifier {
{"name", "hold"},
{"distance", DEFAULT_SEARCH_SPHERE_DISTANCE},
{"path", holdPathRenderState}
};
_renderStates = QList<QVariant>({halfRenderStateIdentifier, fullRenderStateIdentifier, holdRenderStateIdentifier});
_defaultRenderStates = QList<QVariant>({halfDefaultRenderStateIdentifier, fullDefaultRenderStateIdentifier, holdDefaultRenderStateIdentifier});
auto pointers = DependencyManager::get<PointerScriptingInterface>();
auto controller = DependencyManager::get<controller::ScriptingInterface>();
const glm::vec3 grabPointSphereOffsetLeft { -0.04f, 0.13f, 0.039f }; // x = upward, y = forward, z = lateral
const glm::vec3 grabPointSphereOffsetRight { 0.04f, 0.13f, 0.039f }; // x = upward, y = forward, z = lateral
const glm::vec3 malletOffset {glm::vec3(0.0f, 0.18f - 0.050f, 0.0f)};
QList<QVariant> leftPointerTriggerProperties;
QVariantMap ltClick1 {
{ "action", controller->getStandard()["LTClick"] },
{ "button", "Focus" }
};
QVariantMap ltClick2 {
{ "action", controller->getStandard()["LTClick"] },
{ "button", "Primary" }
};
leftPointerTriggerProperties = QList<QVariant>({ltClick1, ltClick2});
const unsigned int leftHand = 0;
QVariantMap leftPointerProperties {
{ "joint", "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND" },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "triggers", leftPointerTriggerProperties },
{ "posOffset", vec3toVariant(grabPointSphereOffsetLeft + malletOffset) },
{ "hover", true },
{ "scaleWithParent", true },
{ "distanceScaleEnd", true },
{ "hand", leftHand }
};
leftPointerProperties["renderStates"] = _renderStates;
leftPointerProperties["defaultRenderStates"] = _defaultRenderStates;
_leftLoginPointerID = pointers->createPointer(PickQuery::PickType::Ray, leftPointerProperties);
pointers->setRenderState(_leftLoginPointerID, "");
pointers->enablePointer(_leftLoginPointerID);
const unsigned int rightHand = 1;
QList<QVariant> rightPointerTriggerProperties;
QVariantMap rtClick1 {
{ "action", controller->getStandard()["RTClick"] },
{ "button", "Focus" }
};
QVariantMap rtClick2 {
{ "action", controller->getStandard()["RTClick"] },
{ "button", "Primary" }
};
rightPointerTriggerProperties = QList<QVariant>({rtClick1, rtClick2});
QVariantMap rightPointerProperties{
{ "joint", "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" },
{ "filter", PickScriptingInterface::PICK_OVERLAYS() },
{ "triggers", rightPointerTriggerProperties },
{ "posOffset", vec3toVariant(grabPointSphereOffsetRight + malletOffset) },
{ "hover", true },
{ "scaleWithParent", true },
{ "distanceScaleEnd", true },
{ "hand", rightHand }
};
rightPointerProperties["renderStates"] = _renderStates;
rightPointerProperties["defaultRenderStates"] = _defaultRenderStates;
_rightLoginPointerID = pointers->createPointer(PickQuery::PickType::Ray, rightPointerProperties);
pointers->setRenderState(_rightLoginPointerID, "");
pointers->enablePointer(_rightLoginPointerID);
}
void LoginStateManager::update(const QString dominantHand, const QUuid loginOverlayID) {
if (!isSetUp()) {
return;
}
if (_dominantHand != dominantHand) {
_dominantHand = dominantHand;
}
auto pointers = DependencyManager::get<PointerScriptingInterface>();
auto raypicks = DependencyManager::get<RayPickScriptingInterface>();
if (pointers && raypicks) {
const auto rightObjectID = raypicks->getPrevRayPickResult(_rightLoginPointerID)["objectID"].toUuid();
const auto leftObjectID = raypicks->getPrevRayPickResult(_leftLoginPointerID)["objectID"].toUuid();
const QString leftMode = (leftObjectID.isNull() || leftObjectID != loginOverlayID) ? "" : "full";
const QString rightMode = (rightObjectID.isNull() || rightObjectID != loginOverlayID) ? "" : "full";
pointers->setRenderState(_leftLoginPointerID, leftMode);
pointers->setRenderState(_rightLoginPointerID, rightMode);
if (_dominantHand == "left" && !leftObjectID.isNull()) {
// dominant is left.
pointers->setRenderState(_rightLoginPointerID, "");
pointers->setRenderState(_leftLoginPointerID, leftMode);
} else if (_dominantHand == "right" && !rightObjectID.isNull()) {
// dominant is right.
pointers->setRenderState(_leftLoginPointerID, "");
pointers->setRenderState(_rightLoginPointerID, rightMode);
}
}
}

View file

@ -0,0 +1,41 @@
//
// LoginStateManager.h
// interface/src
//
// Created by Wayne Chen on 11/5/18.
// Copyright 2018 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
//
#ifndef hifi_LoginStateManager_h
#define hifi_LoginStateManager_h
#include <QtCore/QList>
#include <QtCore/QSharedPointer>
#include <QtCore/QVariant>
#include <PointerEvent.h>
#include <shared/ReadWriteLockable.h>
class LoginStateManager : protected ReadWriteLockable {
public:
LoginStateManager() = default;
~LoginStateManager() = default;
void setUp();
void tearDown();
void update(const QString dominantHand, const QUuid loginOverlayID);
bool isSetUp() const { return (_leftLoginPointerID > PointerEvent::INVALID_POINTER_ID) && (_rightLoginPointerID > PointerEvent::INVALID_POINTER_ID); }
private:
QString _dominantHand;
QList<QVariant> _renderStates {};
QList<QVariant> _defaultRenderStates {};
unsigned int _leftLoginPointerID { PointerEvent::INVALID_POINTER_ID };
unsigned int _rightLoginPointerID { PointerEvent::INVALID_POINTER_ID };
};
#endif // hifi_LoginStateManager_h

View file

@ -123,10 +123,12 @@ Menu::Menu() {
// Edit > Running Scripts
auto action = addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J);
connect(action, &QAction::triggered, [] {
static const QUrl widgetUrl("hifi/dialogs/RunningScripts.qml");
static const QUrl tabletUrl("hifi/dialogs/TabletRunningScripts.qml");
static const QString name("RunningScripts");
qApp->showDialog(widgetUrl, tabletUrl, name);
if (!qApp->getLoginDialogPoppedUp()) {
static const QUrl widgetUrl("hifi/dialogs/RunningScripts.qml");
static const QUrl tabletUrl("hifi/dialogs/TabletRunningScripts.qml");
static const QString name("RunningScripts");
qApp->showDialog(widgetUrl, tabletUrl, name);
}
});
editMenu->addSeparator();
@ -241,8 +243,10 @@ Menu::Menu() {
// Settings > General...
action = addActionToQMenuAndActionHash(settingsMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_G, nullptr, nullptr);
connect(action, &QAction::triggered, [] {
qApp->showDialog(QString("hifi/dialogs/GeneralPreferencesDialog.qml"),
QString("hifi/tablet/TabletGeneralPreferences.qml"), "GeneralPreferencesDialog");
if (!qApp->getLoginDialogPoppedUp()) {
qApp->showDialog(QString("hifi/dialogs/GeneralPreferencesDialog.qml"),
QString("hifi/tablet/TabletGeneralPreferences.qml"), "GeneralPreferencesDialog");
}
});
// Settings > Controls...

View file

@ -413,6 +413,8 @@ public:
QVariant getPlayAreaRect();
QVector<glm::vec3> getSensorPositions();
glm::vec3 getPosition() const;
private:
bool _showTablet { false };
bool _tabletContextualMode { false };
@ -426,9 +428,6 @@ private:
int _miniTabletHand { -1 };
bool _miniTabletEnabled { true };
// Get the position of the HMD
glm::vec3 getPosition() const;
// Get the orientation of the HMD
glm::quat getOrientation() const;

View file

@ -13,6 +13,7 @@
#define hifi_KeyboardScriptingInterface_h
#include <QtCore/QObject>
#include <QtCore/QUuid>
#include "DependencyManager.h"
#include "ui/overlays/Overlay.h"

View file

@ -39,7 +39,7 @@ void DialogsManager::maybeCreateDialog(QPointer<T>& member) {
Q_CHECK_PTR(parent);
member = new T(parent);
Q_CHECK_PTR(member);
if (_hmdToolsDialog && member->windowHandle()) {
_hmdToolsDialog->watchWindow(member->windowHandle());
}
@ -117,6 +117,10 @@ void DialogsManager::showLoginDialog() {
LoginDialog::showWithSelection();
}
void DialogsManager::hideLoginDialog() {
LoginDialog::hide();
}
void DialogsManager::showUpdateDialog() {
UpdateDialog::show();
}
@ -203,4 +207,4 @@ void DialogsManager::showDomainConnectionDialog() {
_domainConnectionDialog->show();
_domainConnectionDialog->raise();
}
}

View file

@ -48,6 +48,7 @@ public slots:
void setDomainConnectionFailureVisibility(bool visible);
void toggleLoginDialog();
void showLoginDialog();
void hideLoginDialog();
void octreeStatsDetails();
void lodTools();
void hmdTools(bool showTools);

View file

@ -340,8 +340,10 @@ void Keyboard::raiseKeyboardAnchor(bool raise) const {
auto anchorOverlay = std::dynamic_pointer_cast<Cube3DOverlay>(overlays.getOverlay(anchorOverlayID));
if (anchorOverlay) {
std::pair<glm::vec3, glm::quat> keyboardLocation = calculateKeyboardPositionAndOrientation();
anchorOverlay->setWorldPosition(keyboardLocation.first);
anchorOverlay->setWorldOrientation(keyboardLocation.second);
if (_resetKeyboardPositionOnRaise) {
anchorOverlay->setWorldPosition(keyboardLocation.first);
anchorOverlay->setWorldOrientation(keyboardLocation.second);
}
anchorOverlay->setVisible(raise);
QVariantMap textDisplayProperties {
@ -442,6 +444,14 @@ void Keyboard::setPassword(bool password) {
updateTextDisplay();
}
void Keyboard::setResetKeyboardPositionOnRaise(bool reset) {
if (_resetKeyboardPositionOnRaise != reset) {
withWriteLock([&] {
_resetKeyboardPositionOnRaise = reset;
});
}
}
void Keyboard::setPreferMalletsOverLasers(bool preferMalletsOverLasers) {
_preferMalletsOverLasersSettingLock.withWriteLock([&] {
_preferMalletsOverLasers.set(preferMalletsOverLasers);
@ -911,6 +921,13 @@ void Keyboard::loadKeyboardFile(const QString& keyboardFile) {
request->send();
}
OverlayID Keyboard::getAnchorID() {
return _ignoreItemsLock.resultWithReadLock<OverlayID>([&] {
return _anchor.overlayID;
});
}
bool Keyboard::shouldProcessOverlay(const OverlayID& overlayID) const {
return (!_keyboardLayers.empty() && isLayerSwitchTimerFinished() && overlayID != _backPlate.overlayID);
}

View file

@ -95,7 +95,7 @@ public:
void registerKeyboardHighlighting();
bool isRaised() const;
void setRaised(bool raised);
void setResetKeyboardPositionOnRaise(bool reset);
bool isPassword() const;
void setPassword(bool password);
void enableRightMallet();
@ -115,6 +115,7 @@ public:
void loadKeyboardFile(const QString& keyboardFile);
QVector<OverlayID> getKeysID();
OverlayID getAnchorID();
public slots:
void handleTriggerBegin(const OverlayID& overlayID, const PointerEvent& event);
@ -160,6 +161,7 @@ private:
bool isLayerSwitchTimerFinished() const;
bool _raised { false };
bool _resetKeyboardPositionOnRaise { true };
bool _password { false };
bool _capsEnabled { false };
int _layerIndex { 0 };

View file

@ -18,6 +18,7 @@
#include <plugins/PluginManager.h>
#include <plugins/SteamClientPlugin.h>
#include <shared/GlobalAppProperties.h>
#include <ui/TabletScriptingInterface.h>
#include <UserActivityLogger.h>
@ -31,24 +32,24 @@
HIFI_QML_DEF(LoginDialog)
static const QUrl TABLET_LOGIN_DIALOG_URL("dialogs/TabletLoginDialog.qml");
const QUrl OVERLAY_LOGIN_DIALOG = PathUtils::qmlUrl("OverlayLoginDialog.qml");
LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) {
auto accountManager = DependencyManager::get<AccountManager>();
// the login hasn't been dismissed yet if the user isn't logged in and is encouraged to login.
#if !defined(Q_OS_ANDROID)
connect(accountManager.data(), &AccountManager::loginComplete,
this, &LoginDialog::handleLoginCompleted);
connect(accountManager.data(), &AccountManager::loginFailed,
this, &LoginDialog::handleLoginFailed);
connect(qApp, &Application::loginDialogFocusEnabled, this, &LoginDialog::focusEnabled);
connect(qApp, &Application::loginDialogFocusDisabled, this, &LoginDialog::focusDisabled);
connect(this, SIGNAL(dismissedLoginDialog()), qApp, SLOT(onDismissedLoginDialog()));
#endif
}
LoginDialog::~LoginDialog() {
Setting::Handle<bool> loginDialogPoppedUp{ "loginDialogPoppedUp", false };
if (loginDialogPoppedUp.get()) {
QJsonObject data;
data["action"] = "user opted out";
UserActivityLogger::getInstance().logAction("encourageLoginDialog", data);
}
loginDialogPoppedUp.set(false);
}
void LoginDialog::showWithSelection() {
@ -56,14 +57,25 @@ void LoginDialog::showWithSelection() {
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
auto hmd = DependencyManager::get<HMDScriptingInterface>();
if (tablet->getToolbarMode()) {
LoginDialog::show();
} else {
static const QUrl url("dialogs/TabletLoginDialog.qml");
tablet->initialScreen(url);
if (!hmd->getShouldShowTablet()) {
hmd->openTablet();
if (!qApp->isHMDMode()) {
if (qApp->getLoginDialogPoppedUp()) {
LoginDialog::show();
return;
} else {
if (!tablet->isPathLoaded(TABLET_LOGIN_DIALOG_URL)) {
tablet->loadQMLSource(TABLET_LOGIN_DIALOG_URL);
}
}
} else {
if (!qApp->getLoginDialogPoppedUp()) {
tablet->initialScreen(TABLET_LOGIN_DIALOG_URL);
} else {
qApp->createLoginDialogOverlay();
}
}
if (!hmd->getShouldShowTablet()) {
hmd->openTablet();
}
}
@ -82,7 +94,7 @@ void LoginDialog::toggleAction() {
connection = connect(loginAction, &QAction::triggered, accountManager.data(), &AccountManager::logout);
} else {
// change the menu item to login
loginAction->setText("Login / Sign Up");
loginAction->setText("Log In / Sign Up");
connection = connect(loginAction, &QAction::triggered, [] { LoginDialog::showWithSelection(); });
}
}
@ -92,6 +104,18 @@ bool LoginDialog::isSteamRunning() const {
return steamClient && steamClient->isRunning();
}
bool LoginDialog::isOculusStoreRunning() const {
return qApp->property(hifi::properties::OCULUS_STORE).toBool();
}
void LoginDialog::dismissLoginDialog() {
QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login);
Q_CHECK_PTR(loginAction);
loginAction->setEnabled(true);
emit dismissedLoginDialog();
}
void LoginDialog::login(const QString& username, const QString& password) const {
qDebug() << "Attempting to login " << username;
DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
@ -138,7 +162,7 @@ void LoginDialog::linkSteam() {
}
}
void LoginDialog::createAccountFromStream(QString username) {
void LoginDialog::createAccountFromSteam(QString username) {
qDebug() << "Attempting to create account from Steam info";
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
steamClient->requestTicket([this, username](Ticket ticket) {
@ -169,25 +193,7 @@ void LoginDialog::createAccountFromStream(QString username) {
}
void LoginDialog::openUrl(const QString& url) const {
auto tablet = dynamic_cast<TabletProxy*>(DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system"));
auto hmd = DependencyManager::get<HMDScriptingInterface>();
auto offscreenUi = DependencyManager::get<OffscreenUi>();
if (tablet->getToolbarMode()) {
offscreenUi->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
newObject->setProperty("url", url);
});
LoginDialog::hide();
} else {
if (!hmd->getShouldShowTablet() && !qApp->isHMDMode()) {
offscreenUi->load("Browser.qml", [=](QQmlContext* context, QObject* newObject) {
newObject->setProperty("url", url);
});
LoginDialog::hide();
} else {
tablet->gotoWebScreen(url);
}
}
QDesktopServices::openUrl(QUrl(url));
}
void LoginDialog::linkCompleted(QNetworkReply* reply) {
@ -233,6 +239,10 @@ void LoginDialog::signupCompleted(QNetworkReply* reply) {
emit handleSignupCompleted();
}
bool LoginDialog::getLoginDialogPoppedUp() const {
return qApp->getLoginDialogPoppedUp();
}
QString errorStringFromAPIObject(const QJsonValue& apiObject) {
if (apiObject.isArray()) {
return apiObject.toArray()[0].toString();

View file

@ -18,8 +18,11 @@
class QNetworkReply;
extern const QUrl OVERLAY_LOGIN_DIALOG;
class LoginDialog : public OffscreenQmlDialog {
Q_OBJECT
Q_PROPERTY(bool isLogIn READ getIsLogIn WRITE setIsLogIn)
HIFI_QML_DECL
public:
@ -40,31 +43,48 @@ signals:
void handleCreateCompleted();
void handleCreateFailed(QString error);
void handleSignupCompleted();
void handleSignupFailed(QString errorString);
// occurs upon dismissing the encouraging log in.
void dismissedLoginDialog();
void focusEnabled();
void focusDisabled();
public slots:
void linkCompleted(QNetworkReply* reply);
void linkFailed(QNetworkReply* reply);
void createCompleted(QNetworkReply* reply);
void createFailed(QNetworkReply* reply);
void signupCompleted(QNetworkReply* reply);
void signupFailed(QNetworkReply* reply);
protected slots:
Q_INVOKABLE void dismissLoginDialog();
Q_INVOKABLE bool isSteamRunning() const;
Q_INVOKABLE bool isOculusStoreRunning() const;
Q_INVOKABLE void login(const QString& username, const QString& password) const;
Q_INVOKABLE void loginThroughSteam();
Q_INVOKABLE void linkSteam();
Q_INVOKABLE void createAccountFromStream(QString username = QString());
Q_INVOKABLE void createAccountFromSteam(QString username = QString());
Q_INVOKABLE void signup(const QString& email, const QString& username, const QString& password);
Q_INVOKABLE void openUrl(const QString& url) const;
Q_INVOKABLE bool getLoginDialogPoppedUp() const;
private:
bool getIsLogIn() const { return _isLogIn; }
void setIsLogIn(const bool isLogIn) { _isLogIn = isLogIn; }
bool _isLogIn{ false };
};
#endif // hifi_LoginDialog_h

View file

@ -20,7 +20,7 @@
void StandAloneJSConsole::toggleConsole() {
QMainWindow* mainWindow = qApp->getWindow();
if (!_jsConsole) {
if (!_jsConsole && !qApp->getLoginDialogPoppedUp()) {
QDialog* dialog = new QDialog(mainWindow, Qt::WindowStaysOnTopHint);
QVBoxLayout* layout = new QVBoxLayout(dialog);
dialog->setLayout(layout);

View file

@ -49,6 +49,7 @@
#include "avatar/AvatarManager.h"
#include "AudioClient.h"
#include "LODManager.h"
#include "ui/LoginDialog.h"
#include "ui/OctreeStatsProvider.h"
#include "ui/DomainConnectionModel.h"
#include "ui/AvatarInputs.h"
@ -190,7 +191,7 @@ void Web3DOverlay::buildWebSurface() {
} else {
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), qmlSurfaceDeleter);
connect(_webSurface.data(), &hifi::qml::OffscreenSurface::rootContextCreated, [this](QQmlContext* surfaceContext) {
setupQmlSurface(_url == TabletScriptingInterface::QML);
setupQmlSurface(_url == TabletScriptingInterface::QML, _url == OVERLAY_LOGIN_DIALOG.toString());
});
_webSurface->load(_url);
_cachedWebSurface = false;
@ -221,7 +222,7 @@ bool Web3DOverlay::isWebContent() const {
return false;
}
void Web3DOverlay::setupQmlSurface(bool isTablet) {
void Web3DOverlay::setupQmlSurface(bool isTablet, bool isLoginDialog) {
_webSurface->getSurfaceContext()->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
@ -232,6 +233,12 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) {
_webSurface->getSurfaceContext()->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
if (isTablet || isLoginDialog) {
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
_webSurface->getSurfaceContext()->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("KeyboardScriptingInterface", DependencyManager::get<KeyboardScriptingInterface>().data());
}
if (isTablet) {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto flags = tabletScriptingInterface->getFlags();
@ -239,7 +246,6 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) {
_webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags);
_webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
_webSurface->getSurfaceContext()->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
_webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
_webSurface->getSurfaceContext()->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance());
@ -261,8 +267,6 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) {
_webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
_webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get<SoundCacheScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("AvatarBookmarks", DependencyManager::get<AvatarBookmarks>().data());
_webSurface->getSurfaceContext()->setContextProperty("Render", AbstractViewStateInterface::instance()->getRenderEngine()->getConfiguration().get());
_webSurface->getSurfaceContext()->setContextProperty("Workload", qApp->getGameWorkload()._engine->getConfiguration().get());
@ -274,7 +278,6 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) {
_webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance());
_webSurface->getSurfaceContext()->setContextProperty("WalletScriptingInterface", DependencyManager::get<WalletScriptingInterface>().data());
_webSurface->getSurfaceContext()->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
_webSurface->getSurfaceContext()->setContextProperty("KeyboardScriptingInterface", DependencyManager::get<KeyboardScriptingInterface>().data());
// Override min fps for tablet UI, for silky smooth scrolling
setMaxFPS(90);
@ -542,7 +545,7 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
*
* @property {string} name="" - A friendly name for the overlay.
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>.
@ -567,7 +570,7 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
* @property {string} url - The URL of the Web page to display.
* @property {string} scriptURL="" - The URL of a JavaScript file to inject into the Web page.
* @property {number} dpi=30 - The dots per inch to display the Web page at, on the overlay.
* @property {Vec2} dimensions=1,1 - The size of the overlay to display the Web page on, in meters. Synonyms:
* @property {Vec2} dimensions=1,1 - The size of the overlay to display the Web page on, in meters. Synonyms:
* <code>scale</code>, <code>size</code>.
* @property {number} maxFPS=10 - The maximum update rate for the Web overlay content, in frames/second.
* @property {boolean} showKeyboardFocusHighlight=true - If <code>true</code>, the Web overlay is highlighted when it has

View file

@ -79,7 +79,7 @@ protected:
Transform evalRenderTransform() override;
private:
void setupQmlSurface(bool isTablet);
void setupQmlSurface(bool isTablet, bool isLoginDialog);
void rebuildWebSurface();
bool isWebContent() const;

View file

@ -321,6 +321,7 @@ void ScriptEngines::loadScripts() {
// loads all saved scripts
auto runningScripts = runningScriptsHandle.get();
for (auto script : runningScripts) {
auto string = script.toString();
if (!string.isEmpty()) {

View file

@ -639,24 +639,28 @@ public:
KeyboardFocusHack() {
Q_ASSERT(_mainWindow);
QTimer::singleShot(200, [=] {
_hackWindow = new QWindow();
_hackWindow->setFlags(Qt::FramelessWindowHint);
_hackWindow->setGeometry(_mainWindow->x(), _mainWindow->y(), 10, 10);
_hackWindow->show();
_hackWindow->requestActivate();
_window = new QWindow();
_window->setFlags(Qt::FramelessWindowHint);
_window->setGeometry(_mainWindow->x(), _mainWindow->y(), 10, 10);
_window->show();
_window->requestActivate();
QTimer::singleShot(200, [=] {
_hackWindow->hide();
_hackWindow->deleteLater();
_hackWindow = nullptr;
_window->hide();
_window->deleteLater();
_window = nullptr;
_mainWindow->requestActivate();
emit keyboardFocusActive();
this->deleteLater();
});
});
}
signals:
void keyboardFocusActive();
private:
QWindow* const _mainWindow { MainWindow::findMainWindow() };
QWindow* _hackWindow { nullptr };
QWindow* _window { nullptr };
};
void OffscreenUi::createDesktop(const QUrl& url) {
@ -675,9 +679,10 @@ void OffscreenUi::createDesktop(const QUrl& url) {
menuInitializer(_vrMenu);
}
new KeyboardFocusHack();
auto keyboardFocus = new KeyboardFocusHack();
connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop()));
emit desktopReady();
connect(keyboardFocus, SIGNAL(keyboardFocusActive()), this, SIGNAL(keyboardFocusActive()));
});
}

View file

@ -244,6 +244,7 @@ signals:
// void assetDialogResponse(QString response);
// void inputDialogResponse(QVariant response);
void desktopReady();
void keyboardFocusActive();
public slots:
void removeModalDialog(QObject* modal);

View file

@ -554,6 +554,14 @@ void MenuWrapper::setEnabled(bool enabled) {
_realMenu->setEnabled(enabled);
}
bool MenuWrapper::isVisible() {
return _realMenu->menuAction()->isVisible();
}
void MenuWrapper::setVisible(bool visible) {
_realMenu->menuAction()->setVisible(visible);
}
QAction* MenuWrapper::addSeparator() {
QAction* action = _realMenu->addSeparator();
auto offscreenUi = DependencyManager::get<OffscreenUi>();

View file

@ -29,6 +29,9 @@ public:
QList<QAction*> actions();
MenuWrapper* addMenu(const QString& menuName);
void setEnabled(bool enabled = true);
bool isVisible();
void setVisible(bool visible = true);
QAction* addSeparator();
void addAction(QAction* action);

View file

@ -377,12 +377,8 @@ function deleteSendMoneyParticleEffect() {
}
function onUsernameChanged() {
if (Account.username !== Settings.getValue("keepMeLoggedIn/savedUsername")) {
Settings.setValue("keepMeLoggedIn", false);
Settings.setValue("keepMeLoggedIn/savedUsername", "");
}
}
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
var METAVERSE_SERVER_URL = Account.metaverseServerURL;
var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page.

View file

@ -1989,7 +1989,7 @@ function focusKey(value) {
if (value === 0) { // on release
cameraManager.enable();
if (selectionManager.hasSelection()) {
cameraManager.focus(selectionManager.worldPosition, selectionManager.worldDimensions,
cameraManager.focus(selectionManager.worldPosition, selectionManager.worldDimensions,
Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
}
}
@ -2239,7 +2239,7 @@ var PropertiesTool = function (opts) {
};
that.setVisible(false);
function emitScriptEvent(data) {
var dataString = JSON.stringify(data);
webView.emitScriptEvent(dataString);

View file

@ -21,7 +21,7 @@
var TEXTURE_EPSILON = 0.01;
var isVisible = false;
var VOLUME = 0.4;
var tune = SoundCache.getSound(Script.resolvePath("/~/system/assets/sounds/crystals_and_voices.mp3"));
var tune = SoundCache.getSound(Script.resourcesPath() + "sounds/crystals_and_voices.mp3");
var sample = null;
var MAX_LEFT_MARGIN = 1.9;
var INNER_CIRCLE_WIDTH = 4.7;