Merge branch 'blue' of https://github.com/samcake/hifi into purple

This commit is contained in:
sam 2017-02-01 22:01:39 -08:00
commit 387621e586
12 changed files with 358 additions and 71 deletions

View file

@ -908,31 +908,11 @@ function validateInputs() {
}
_.each(tables, function(table) {
var inputs = $(table).find('tr.' + Settings.NEW_ROW_CLASS + ':not([data-category]) input[data-changed="true"]');
var empty = false;
_.each(inputs, function(input){
var inputVal = $(input).val();
if (inputVal.length === 0) {
empty = true
markParentRowInvalid(input);
return;
}
});
if (empty) {
showErrorMessage("Error", "Empty field(s)");
inputsValid = false;
return
}
// validate keys specificially for spaces and equality to an existing key
var newKeys = $(table).find('tr.' + Settings.NEW_ROW_CLASS + ' td.key');
var keyWithSpaces = false;
var empty = false;
var duplicateKey = false;
_.each(newKeys, function(keyCell) {
@ -944,6 +924,14 @@ function validateInputs() {
return;
}
// make sure the key isn't empty
if (keyVal.length === 0) {
empty = true
markParentRowInvalid(input);
return;
}
// make sure we don't have duplicate keys in the table
var otherKeys = $(table).find('td.key').not(keyCell);
_.each(otherKeys, function(otherKeyCell) {
@ -971,6 +959,12 @@ function validateInputs() {
return
}
if (empty) {
showErrorMessage("Error", "Empty field(s)");
inputsValid = false;
return
}
if (duplicateKey) {
showErrorMessage("Error", "Two keys cannot be identical");
inputsValid = false;

View file

@ -34,6 +34,7 @@ Item {
property bool isMyCard: false
property bool selected: false
property bool isAdmin: false
property bool currentlyEditingDisplayName: false
/* User image commented out for now - will probably be re-introduced later.
Column {
@ -104,6 +105,7 @@ Item {
focus = false
myDisplayName.border.width = 0
color = hifi.colors.darkGray
currentlyEditingDisplayName = false
}
}
MouseArea {
@ -115,10 +117,12 @@ Item {
myDisplayNameText.focus ? myDisplayNameText.cursorPosition = myDisplayNameText.positionAt(mouseX, mouseY, TextInput.CursorOnCharacter) : myDisplayNameText.selectAll();
myDisplayNameText.focus = true
myDisplayNameText.color = "black"
currentlyEditingDisplayName = true
}
onDoubleClicked: {
myDisplayNameText.selectAll();
myDisplayNameText.focus = true;
currentlyEditingDisplayName = true
}
onEntered: myDisplayName.color = hifi.colors.lightGrayText
onExited: myDisplayName.color = hifi.colors.textFieldLightBackground

View file

@ -51,6 +51,7 @@ Rectangle {
// This is the container for the PAL
Rectangle {
property bool punctuationMode: false
id: palContainer
// Size
width: pal.width - 50
@ -421,6 +422,16 @@ Rectangle {
onExited: adminHelpText.color = hifi.colors.redHighlight
}
}
HifiControls.Keyboard {
id: keyboard
raised: myCard.currentlyEditingDisplayName && HMD.active
numeric: parent.punctuationMode
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
}
}
// Timer used when selecting table rows that aren't yet present in the model
// (i.e. when selecting avatars using edit.js or sphere overlays)

View file

@ -1202,8 +1202,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity,
[this](const EntityItemID& entityItemID, const PointerEvent& event) {
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
setKeyboardFocusEntity(entityItemID);
auto entity = getEntities()->getTree()->findEntityByID(entityItemID);
if (entity && entity->wantsKeyboardFocus()) {
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
setKeyboardFocusEntity(entityItemID);
}
});
connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [=](const EntityItemID& entityItemID) {
@ -4165,6 +4168,8 @@ void Application::setKeyboardFocusOverlay(unsigned int overlayID) {
auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR;
const float OVERLAY_DEPTH = 0.0105f;
setKeyboardFocusHighlight(overlay->getPosition(), overlay->getRotation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH));
} else if (_keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
}
}
}

View file

@ -651,6 +651,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data
// even when we would otherwise ignore the rest of the packet.
bool filterRejection = false;
if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) {
QByteArray simOwnerData;
@ -663,6 +664,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
if (wantTerseEditLogging() && _simulationOwner != newSimOwner) {
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << newSimOwner;
}
// This is used in the custom physics setters, below. When an entity-server filter alters
// or rejects a set of properties, it clears this. In such cases, we don't want those custom
// setters to ignore what the server says.
filterRejection = newSimOwner.getID().isNull();
if (weOwnSimulation) {
if (newSimOwner.getID().isNull() && !_simulationOwner.pendingRelease(lastEditedFromBufferAdjusted)) {
// entity-server is trying to clear our ownership (probably at our own request)
@ -715,55 +720,45 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// Note: duplicate packets are expected and not wrong. They may be sent for any number of
// reasons and the contract is that the client handles them in an idempotent manner.
auto lastEdited = lastEditedFromBufferAdjusted;
auto customUpdatePositionFromNetwork = [this, lastEdited, overwriteLocalData, weOwnSimulation](glm::vec3 value){
bool simulationChanged = lastEdited > _lastUpdatedPositionTimestamp;
bool valueChanged = value != _lastUpdatedPositionValue;
bool shouldUpdate = overwriteLocalData && !weOwnSimulation && simulationChanged && valueChanged;
if (shouldUpdate) {
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) {
bool simulationChanged = lastEdited > updatedTimestamp;
return otherOverwrites && simulationChanged && (valueChanged || filterRejection);
};
auto customUpdatePositionFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){
if (shouldUpdate(_lastUpdatedPositionTimestamp, value != _lastUpdatedPositionValue)) {
updatePositionFromNetwork(value);
_lastUpdatedPositionTimestamp = lastEdited;
_lastUpdatedPositionValue = value;
}
};
auto customUpdateRotationFromNetwork = [this, lastEdited, overwriteLocalData, weOwnSimulation](glm::quat value){
bool simulationChanged = lastEdited > _lastUpdatedRotationTimestamp;
bool valueChanged = value != _lastUpdatedRotationValue;
bool shouldUpdate = overwriteLocalData && !weOwnSimulation && simulationChanged && valueChanged;
if (shouldUpdate) {
auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value){
if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) {
updateRotationFromNetwork(value);
_lastUpdatedRotationTimestamp = lastEdited;
_lastUpdatedRotationValue = value;
}
};
auto customUpdateVelocityFromNetwork = [this, lastEdited, overwriteLocalData, weOwnSimulation](glm::vec3 value){
bool simulationChanged = lastEdited > _lastUpdatedVelocityTimestamp;
bool valueChanged = value != _lastUpdatedVelocityValue;
bool shouldUpdate = overwriteLocalData && !weOwnSimulation && simulationChanged && valueChanged;
if (shouldUpdate) {
auto customUpdateVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){
if (shouldUpdate(_lastUpdatedVelocityTimestamp, value != _lastUpdatedVelocityValue)) {
updateVelocityFromNetwork(value);
_lastUpdatedVelocityTimestamp = lastEdited;
_lastUpdatedVelocityValue = value;
}
};
auto customUpdateAngularVelocityFromNetwork = [this, lastEdited, overwriteLocalData, weOwnSimulation](glm::vec3 value){
bool simulationChanged = lastEdited > _lastUpdatedAngularVelocityTimestamp;
bool valueChanged = value != _lastUpdatedAngularVelocityValue;
bool shouldUpdate = overwriteLocalData && !weOwnSimulation && simulationChanged && valueChanged;
if (shouldUpdate) {
auto customUpdateAngularVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){
if (shouldUpdate(_lastUpdatedAngularVelocityTimestamp, value != _lastUpdatedAngularVelocityValue)) {
updateAngularVelocityFromNetwork(value);
_lastUpdatedAngularVelocityTimestamp = lastEdited;
_lastUpdatedAngularVelocityValue = value;
}
};
auto customSetAcceleration = [this, lastEdited, overwriteLocalData, weOwnSimulation](glm::vec3 value){
bool simulationChanged = lastEdited > _lastUpdatedAccelerationTimestamp;
bool valueChanged = value != _lastUpdatedAccelerationValue;
bool shouldUpdate = overwriteLocalData && !weOwnSimulation && simulationChanged && valueChanged;
if (shouldUpdate) {
auto customSetAcceleration = [this, shouldUpdate, lastEdited](glm::vec3 value){
if (shouldUpdate(_lastUpdatedAccelerationTimestamp, value != _lastUpdatedAccelerationValue)) {
setAcceleration(value);
_lastUpdatedAccelerationTimestamp = lastEdited;
_lastUpdatedAccelerationValue = value;

View file

@ -73,6 +73,9 @@ void KeyboardMouseDevice::mousePressEvent(QMouseEvent* event) {
_mousePressTime = usecTimestampNow();
_mouseMoved = false;
_mousePressPos = event->pos();
_clickDeadspotActive = true;
eraseMouseClicked();
}
@ -84,9 +87,11 @@ void KeyboardMouseDevice::mouseReleaseEvent(QMouseEvent* event) {
// input for this button we might want to add some small tolerance to this so if you do a small drag it
// still counts as a click.
static const int CLICK_TIME = USECS_PER_MSEC * 500; // 500 ms to click
if (!_mouseMoved && (usecTimestampNow() - _mousePressTime < CLICK_TIME)) {
if (_clickDeadspotActive && (usecTimestampNow() - _mousePressTime < CLICK_TIME)) {
_inputDevice->_buttonPressedMap.insert(_inputDevice->makeInput((Qt::MouseButton) event->button(), true).getChannel());
}
_clickDeadspotActive = false;
}
void KeyboardMouseDevice::eraseMouseClicked() {
@ -109,9 +114,14 @@ void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event) {
// outside of the application window, because we don't get MouseEvents when the cursor is outside
// of the application window.
_lastCursor = currentPos;
_mouseMoved = true;
eraseMouseClicked();
const int CLICK_EVENT_DEADSPOT = 6; // pixels
if (_clickDeadspotActive && (_mousePressPos - currentPos).manhattanLength() > CLICK_EVENT_DEADSPOT) {
eraseMouseClicked();
_clickDeadspotActive = false;
}
}
void KeyboardMouseDevice::wheelEvent(QWheelEvent* event) {

View file

@ -118,8 +118,10 @@ public:
protected:
QPoint _lastCursor;
QPoint _mousePressPos;
quint64 _mousePressTime;
bool _mouseMoved;
bool _clickDeadspotActive;
glm::vec2 _lastTouch;
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>() };

View file

@ -52,6 +52,7 @@ std::atomic<size_t> DECIMATED_TEXTURE_COUNT { 0 };
std::atomic<size_t> RECTIFIED_TEXTURE_COUNT { 0 };
QImage processSourceImage(const QImage& srcImage, bool cubemap) {
PROFILE_RANGE(resource_parse, "processSourceImage");
const uvec2 srcImageSize = toGlm(srcImage.size());
uvec2 targetSize = srcImageSize;
@ -72,7 +73,8 @@ QImage processSourceImage(const QImage& srcImage, bool cubemap) {
}
if (targetSize != srcImageSize) {
qDebug(modelLog) << "Resizing texture from " << srcImageSize.x << "x" << srcImageSize.y << " to " << targetSize.x << "x" << targetSize.y;
PROFILE_RANGE(resource_parse, "processSourceImage Rectify");
qDebug(modelLog) << "Resizing texture from " << srcImageSize.x << "x" << srcImageSize.y << " to " << targetSize.x << "x" << targetSize.y;
return srcImage.scaled(fromGlm(targetSize));
}
@ -109,6 +111,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
}
const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) {
PROFILE_RANGE(resource_parse, "process2DImageColor");
QImage image = processSourceImage(srcImage, false);
validAlpha = false;
alphaAsMask = true;
@ -197,10 +200,11 @@ const QImage& image, bool isLinear, bool doCompress) {
}
}
#define CPU_MIPMAPS 0
#define CPU_MIPMAPS 1
void generateMips(gpu::Texture* texture, QImage& image, gpu::Element formatMip) {
#if CPU_MIPMAPS
PROFILE_RANGE(resource_parse, "generateMips");
auto numMips = texture->evalNumMips();
for (uint16 level = 1; level < numMips; ++level) {
QSize mipSize(texture->evalMipWidth(level), texture->evalMipHeight(level));
@ -214,6 +218,7 @@ void generateMips(gpu::Texture* texture, QImage& image, gpu::Element formatMip)
void generateFaceMips(gpu::Texture* texture, QImage& image, gpu::Element formatMip, uint8 face) {
#if CPU_MIPMAPS
PROFILE_RANGE(resource_parse, "generateFaceMips");
auto numMips = texture->evalNumMips();
for (uint16 level = 1; level < numMips; ++level) {
QSize mipSize(texture->evalMipWidth(level), texture->evalMipHeight(level));
@ -226,6 +231,7 @@ void generateFaceMips(gpu::Texture* texture, QImage& image, gpu::Element formatM
}
gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips) {
PROFILE_RANGE(resource_parse, "process2DTextureColorFromImage");
bool validAlpha = false;
bool alphaAsMask = true;
QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask);
@ -304,6 +310,7 @@ gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImag
gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) {
PROFILE_RANGE(resource_parse, "createNormalTextureFromNormalImage");
QImage image = processSourceImage(srcImage, false);
if (image.format() != QImage::Format_RGB888) {
@ -338,6 +345,7 @@ double mapComponent(double sobelValue) {
}
gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) {
PROFILE_RANGE(resource_parse, "createNormalTextureFromBumpImage");
QImage image = processSourceImage(srcImage, false);
if (image.format() != QImage::Format_RGB888) {
@ -410,6 +418,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
}
gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
PROFILE_RANGE(resource_parse, "createRoughnessTextureFromImage");
QImage image = processSourceImage(srcImage, false);
if (!image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGB888) {
@ -444,6 +453,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma
}
gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& srcImage, const std::string& srcImageName) {
PROFILE_RANGE(resource_parse, "createRoughnessTextureFromGlossImage");
QImage image = processSourceImage(srcImage, false);
if (!image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGB888) {
@ -482,6 +492,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s
}
gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
PROFILE_RANGE(resource_parse, "createMetallicTextureFromImage");
QImage image = processSourceImage(srcImage, false);
if (!image.hasAlphaChannel()) {
if (image.format() != QImage::Format_RGB888) {

View file

@ -150,11 +150,11 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
if (!enableTextures) {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, nullptr);
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, nullptr);
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, nullptr);
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, nullptr);
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, nullptr);
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
return;
}

View file

@ -24,7 +24,7 @@ var DEFAULT_SCRIPTS = [
"system/goto.js",
"system/marketplaces/marketplaces.js",
"system/edit.js",
"system/users.js",
"system/tablet-users.js",
"system/selectAudioDevice.js",
"system/notifications.js",
"system/controllers/controllerDisplayManager.js",

View file

@ -13,6 +13,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Raleway:300,400,600,700"" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
body {
margin: 0;
@ -29,7 +30,7 @@
font-weight: bold;
}
.top-bar .container {
.top-bar .myContainer {
display: flex;
justify-content: space-between;
align-items: center;
@ -47,6 +48,44 @@
padding: 30px;
}
#user-info-div {
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 40px;
}
#visibility-toggle {
font-family: 'Raleway';
font-weight: bold;
font-size: 13px;
text-transform: uppercase;
vertical-align: top;
height: 28px;
min-width: 120px;
padding: 0px 18px;
margin-right: 0px;
border-radius: 5px;
border: none;
color: #121212;
background-color: #afafaf;
background: linear-gradient(#fff 20%, #afafaf 100%);
cursor: pointer;
}
#visibility-toggle:enabled:hover {
background: linear-gradient(#fff, #fff);
border: none;
}
#visibility-toggle:active {
background: linear-gradient(#afafaf, #afafaf);
}
#visibility-toggle span {
padding-left: 10px;
}
.tabs {
list-style: none;
padding: 0;
@ -99,35 +138,146 @@
cursor: pointer;
}
input[type=button].red {
color: #fff;
background-color: #94132e;
background: linear-gradient(#d42043 20%, #94132e 100%);
}
input[type=button].blue {
color: #fff;
background-color: #1080b8;
background: linear-gradient(#00b4ef 20%, #1080b8 100%);
}
input[type=button].white {
color: #121212;
background-color: #afafaf;
background: linear-gradient(#fff 20%, #afafaf 100%);
}
input[type=button].blue:hover {
input[type=button]:enabled:hover {
background: linear-gradient(#000, #000);
border: none;
}
input[type=button].red:enabled:hover {
background: linear-gradient(#d42043, #d42043);
border: none;
}
input[type=button].blue:enabled:hover {
background: linear-gradient(#00b4ef, #00b4ef);
border: none;
}
input[type=button].white:enabled:hover {
background: linear-gradient(#fff, #fff);
border: none;
}
input[type=button]:active {
background: linear-gradient(#343434, #343434);
}
input[type=button].red:active {
background: linear-gradient(#94132e, #94132e);
}
input[type=button].blue:active {
background: linear-gradient(#1080b8, #1080b8);
}
input[type=button].white:active {
background: linear-gradient(#afafaf, #afafaf);
}
input[type=button]:disabled {
color: #252525;
background: linear-gradient(#575757 20%, #252525 100%);
}
input[type=button][pressed=pressed] {
color: #00b4ef;
}
#friends-button {
margin: 0px 0px 15px 10px;
}
/*Vertically Center Modal*/
.modal {
color: black;
text-align: center;
padding: 0!important;
}
.modal:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
margin-right: -4px;
}
.modal-dialog {
display: inline-block;
text-align: left;
vertical-align: middle;
}
.dropdown-menu {
width: 280px;
}
.dropdown-menu li {
color: #333;
padding: 10px;
}
.dropdown-menu .divider {
padding: 0px;
}
.dropdown-menu li:hover {
background: #dcdcdc;
}
.dropdown-menu li h6 {
font-weight: bold;
}
.dropdown-menu li p {
font-size: 11px;
}
</style>
</head>
<body>
<div class="top-bar">
<div class="container">
<div class="myContainer">
<div>Users Online</div>
<img id="refresh-button" onclick="pollUsers()" src="https://hifi-content.s3.amazonaws.com/faye/tablet-dev/refresh-icon.svg"></img>
</div>
</div>
<div class="main">
<div id="user-info-div">
<h4></h4>
<div class="dropdown">
<button id="visibility-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Online
<span class="glyphicon glyphicon-menu-down"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="visibility-toggle">
<li class="visibility-option" data-visibility="all">
<h6>Online</h6>
<p>You will be shown online to everyone else. Anybody will be able to find you from the users online list and jump to your current location.</p>
</li>
<li role="separator" class="divider"></li>
<li class="visibility-option" data-visibility="friends">
<h6>Available to Friends Only</h6>
<p>You will be shown online only to users you have added as friends. Other users may still interact with you in the same domain, but they won't be able to find you from the users online list.</p>
</li>
<li role="separator" class="divider"></li>
<li class="visibility-option" data-visibility="none">
<h6>Appear Offline</h6>
<p>No one will be able to find you from the users online list. However, this does not prevent other users in the same domain from interacting with you. For a complete "Do not disturb" mode, you may want to go to your own private domain and set allow entering to no one.</p>
</li>
</ul>
</div>
</div>
<ul class="tabs">
<li tab-id="tab-1" class="current">Everyone (0)</li>
<li tab-id="tab-2">Friends (0)</li>
@ -140,11 +290,33 @@
<input type="button" class="blue" id="friends-button" value="Add/Remove Friends">
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">Jump to username @ Placename</h4>
</div>
<div class="modal-body">
This will teleport you to a new location and possibly another domain. Are you sure?
</div>
<div class="modal-footer">
<input type="button" data-dismiss="modal" value="Cancel">
<input type="button" data-dismiss="modal" id="jump-to-confirm-button" value="OK">
</div>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script>
var METAVERSE_API_URL = "https://metaverse.highfidelity.com/api/v1/users?status=online";
var FRIENDS_FILTER = "&filter=friends";
var myUsername = null;
var myVisibility = null;
function displayUsers(data, element) {
element.empty();
@ -155,10 +327,18 @@
$("#dev-div").append("<p>" + data.users[i].username + "is online but not in a domain</p>");
} else {
$("#dev-div").append("<li>" + data.users[i].username + " @ " + data.users[i].location.root.name + "</li>");
// Don't display yourself
if (data.users[i].username !== myUsername) {
if (data.users[i].username === myUsername) {
$("#user-info-div h4").text(data.users[i].username + " @ " + data.users[i].location.root.name);
} else {
console.log(data.users[i].username + " @ " + data.users[i].location.root.name);
element.append("<li>" + data.users[i].username + " @ " + data.users[i].location.root.name + "</li>");
// Create a list item and put user info in data-* attributes, also make it trigger the jump to confirmation modal
$("<li></li>", {
"data-toggle": "modal",
"data-target": "#myModal",
"data-username": data.users[i].username,
"data-placename": data.users[i].location.root.name,
text: data.users[i].username + " @ " + data.users[i].location.root.name
}).appendTo(element);
}
}
}
@ -201,10 +381,17 @@
// Parse the string into an object
event = JSON.parse(event);
}
if (event.type === "sendUsername") {
if (event.type === "user-info") {
myUsername = event.data.username;
$("#dev-div").append("<p>myUsername is " + myUsername + "</p>");
consoloe.log("myUsername is " + myUsername);
myVisibility = event.data.visibility;
$("#user-info-div h4").text(myUsername);
var buttonText = "Online";
if (myVisibility === "none") {
buttonText = "Appear Offline";
} else if (myVisibility === "friends") {
buttonText = "Available To Friends Only";
}
$("#visibility-toggle").html(buttonText + "<span class='glyphicon glyphicon-menu-down'></span>")
}
}
@ -222,6 +409,43 @@
$(this).addClass("current");
});
// Jump to user: Fill confirmation modal with data of the selected user
$("#myModal").on("show.bs.modal", function (event) {
// Get the element that triggered the modal
var li = $(event.relatedTarget);
// Extract info from data-* attributes
var username = li.data("username");
var placename = li.data("placename");
// Write info to the modal
var modal = $(this);
modal.find(".modal-title").text("Jump to " + username + " @ " + placename);
$("#jump-to-confirm-button").data("username", username);
})
$("#jump-to-confirm-button").click(function() {
var jumpToObject = {
"type": "jump-to",
"data": {
"username": $(this).data("username")
}
}
EventBridge.emitWebEvent(JSON.stringify(jumpToObject));
});
// Click listener for toggling who can see me
$(".visibility-option").click(function() {
myVisibility = $(this).data("visibility");
var newButtonText = $(this).find("h6").text();
$("#visibility-toggle").html(newButtonText + "<span class='glyphicon glyphicon-menu-down'></span>");
var visibilityObject = {
"type": "toggle-visibility",
"data": {
"visibility": myVisibility
}
}
EventBridge.emitWebEvent(JSON.stringify(visibilityObject));
});
// Listen for events from hifi
EventBridge.scriptEventReceived.connect(onScriptEventReceived);
@ -229,7 +453,7 @@
var eventObject = {"type": "ready"};
EventBridge.emitWebEvent(JSON.stringify(eventObject));
// Click listener mangage friends button
// Click listener for add/remove friends button
$("#friends-button").click(function() {
// Send a manage friends event to hifi
eventObject = {"type": "manage-friends"};

View file

@ -12,10 +12,26 @@
(function() { // BEGIN LOCAL_SCOPE
var USERS_URL = "https://hifi-content.s3.amazonaws.com/faye/tablet-dev/users.html";
var FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends";
var FRIENDS_WINDOW_WIDTH = 290;
var FRIENDS_WINDOW_HEIGHT = 500;
var FRIENDS_WINDOW_TITLE = "Add/Remove Friends";
// Initialise visibility based on global service
var VISIBILITY_VALUES_SET = {};
VISIBILITY_VALUES_SET["all"] = true;
VISIBILITY_VALUES_SET["friends"] = true;
VISIBILITY_VALUES_SET["none"] = true;
var myVisibility;
if (GlobalServices.findableBy in VISIBILITY_VALUES_SET) {
myVisibility = GlobalServices.findableBy;
} else {
// default to friends if it can't be determined
myVisibility = "friends";
GlobalServices.findableBy = myVisibilty;
}
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
icon: "icons/tablet-icons/people-i.svg",
@ -35,10 +51,12 @@
// send username to html
var myUsername = GlobalServices.username;
var object = {
"type": "sendUsername",
"data": {"username": myUsername}
"type": "user-info",
"data": {
"username": myUsername,
"visibility": myVisibility
}
};
print("sending username: " + myUsername);
tablet.emitScriptEvent(JSON.stringify(object));
}
if (event.type === "manage-friends") {
@ -53,6 +71,19 @@
friendsWindow.setVisible(true);
friendsWindow.raise();
}
if (event.type === "jump-to") {
if (typeof event.data.username !== undefined) {
// teleport to selected user from the online users list
location.goToUser(event.data.username);
}
}
if (event.type === "toggle-visibility") {
if (typeof event.data.visibility !== undefined) {
// update your visibility (all, friends, or none)
myVisibility = event.data.visibility;
GlobalServices.findableBy = myVisibility;
}
}
}
button.clicked.connect(onClicked);