mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 19:59:28 +02:00
Merge pull request #4164 from ctrlaltdavid/20183
CR for 20183 Add Oculus support to notifications.js
This commit is contained in:
commit
8a32bd2eed
2 changed files with 429 additions and 254 deletions
|
@ -52,18 +52,16 @@
|
||||||
// 2. Declare a text string.
|
// 2. Declare a text string.
|
||||||
// 3. Call createNotifications(text) parsing the text.
|
// 3. Call createNotifications(text) parsing the text.
|
||||||
// example:
|
// example:
|
||||||
|
// var welcome;
|
||||||
// if (key.text == "q") { //queries number of users online
|
// if (key.text == "q") { //queries number of users online
|
||||||
// var numUsers = GlobalServices.onlineUsers.length;
|
// var welcome = "There are " + GlobalServices.onlineUsers.length + " users online now.";
|
||||||
// var welcome = "There are " + numUsers + " users online now.";
|
// createNotification(welcome);
|
||||||
// createNotification(welcome);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
var width = 340.0; //width of notification overlay
|
var width = 340.0; //width of notification overlay
|
||||||
var height = 40.0; // height of a single line notification overlay
|
|
||||||
var windowDimensions = Controller.getViewportDimensions(); // get the size of the interface window
|
var windowDimensions = Controller.getViewportDimensions(); // get the size of the interface window
|
||||||
var overlayLocationX = (windowDimensions.x - (width + 20.0));// positions window 20px from the right of the interface window
|
var overlayLocationX = (windowDimensions.x - (width + 20.0)); // positions window 20px from the right of the interface window
|
||||||
var buttonLocationX = overlayLocationX + (width - 28.0);
|
var buttonLocationX = overlayLocationX + (width - 28.0);
|
||||||
var locationY = 20.0; // position down from top of interface window
|
var locationY = 20.0; // position down from top of interface window
|
||||||
var topMargin = 13.0;
|
var topMargin = 13.0;
|
||||||
var leftMargin = 10.0;
|
var leftMargin = 10.0;
|
||||||
|
@ -71,264 +69,79 @@ var textColor = { red: 228, green: 228, blue: 228}; // text color
|
||||||
var backColor = { red: 2, green: 2, blue: 2}; // background color was 38,38,38
|
var backColor = { red: 2, green: 2, blue: 2}; // background color was 38,38,38
|
||||||
var backgroundAlpha = 0;
|
var backgroundAlpha = 0;
|
||||||
var fontSize = 12.0;
|
var fontSize = 12.0;
|
||||||
var persistTime = 10.0; // time in seconds before notification fades
|
var PERSIST_TIME_2D = 10.0; // Time in seconds before notification fades
|
||||||
|
var PERSIST_TIME_3D = 15.0;
|
||||||
|
var persistTime = PERSIST_TIME_2D;
|
||||||
var clickedText = false;
|
var clickedText = false;
|
||||||
var frame = 0;
|
var frame = 0;
|
||||||
var ourWidth = Window.innerWidth;
|
var ourWidth = Window.innerWidth;
|
||||||
var ourHeight = Window.innerHeight;
|
var ourHeight = Window.innerHeight;
|
||||||
var text = "placeholder";
|
var text = "placeholder";
|
||||||
var last_users = GlobalServices.onlineUsers;
|
var last_users = GlobalServices.onlineUsers;
|
||||||
var users = [];
|
var users = [];
|
||||||
var ctrlIsPressed = false;
|
var ctrlIsPressed = false;
|
||||||
var ready = true;
|
var ready = true;
|
||||||
|
|
||||||
// When our script shuts down, we should clean up all of our overlays
|
|
||||||
function scriptEnding() {
|
|
||||||
for (i = 0; i < notifications.length; i++) {
|
|
||||||
Overlays.deleteOverlay(notifications[i]);
|
|
||||||
Overlays.deleteOverlay(buttons[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
|
||||||
|
|
||||||
var notifications = [];
|
var notifications = [];
|
||||||
var buttons = [];
|
var buttons = [];
|
||||||
var times = [];
|
var times = [];
|
||||||
var heights = [];
|
var heights = [];
|
||||||
var myAlpha = [];
|
var myAlpha = [];
|
||||||
var arrays = [];
|
var arrays = [];
|
||||||
|
var isOnHMD = false,
|
||||||
|
ENABLE_VR_MODE = "Enable VR Mode",
|
||||||
|
NOTIFICATIONS_3D_DIRECTION = 0.0, // Degrees from avatar orientation.
|
||||||
|
NOTIFICATIONS_3D_DISTANCE = 0.6, // Horizontal distance from avatar position.
|
||||||
|
NOTIFICATIONS_3D_ELEVATION = -0.8, // Height of top middle of top notification relative to avatar eyes.
|
||||||
|
NOTIFICATIONS_3D_YAW = 0.0, // Degrees relative to notifications direction.
|
||||||
|
NOTIFICATIONS_3D_PITCH = -60.0, // Degrees from vertical.
|
||||||
|
NOTIFICATION_3D_SCALE = 0.002, // Multiplier that converts 2D overlay dimensions to 3D overlay dimensions.
|
||||||
|
NOTIFICATION_3D_BUTTON_WIDTH = 40 * NOTIFICATION_3D_SCALE, // Need a little more room for button in 3D.
|
||||||
|
overlay3DDetails = [];
|
||||||
|
|
||||||
// This function creates and sizes the overlays
|
// push data from above to the 2 dimensional array
|
||||||
function createNotification(text) {
|
function createArrays(notice, button, createTime, height, myAlpha) {
|
||||||
var count = (text.match(/\n/g) || []).length;
|
arrays.push([notice, button, createTime, height, myAlpha]);
|
||||||
var breakPoint = 43.0; // length when new line is added
|
|
||||||
var extraLine = 0;
|
|
||||||
var breaks = 0;
|
|
||||||
var height = 40.0;
|
|
||||||
var stack = 0;
|
|
||||||
if (text.length >= breakPoint) {
|
|
||||||
breaks = count;
|
|
||||||
}
|
|
||||||
var extraLine = breaks * 16.0;
|
|
||||||
for (i = 0; i < heights.length; i++) {
|
|
||||||
stack = stack + heights[i];
|
|
||||||
}
|
|
||||||
var level = (stack + 20.0);
|
|
||||||
height = height + extraLine;
|
|
||||||
var overlayProperties = {
|
|
||||||
x: overlayLocationX,
|
|
||||||
y: level,
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
color: textColor,
|
|
||||||
backgroundColor: backColor,
|
|
||||||
alpha: backgroundAlpha,
|
|
||||||
topMargin: topMargin,
|
|
||||||
leftMargin: leftMargin,
|
|
||||||
font: {size: fontSize},
|
|
||||||
text: text,
|
|
||||||
};
|
|
||||||
var bLevel = level + 12.0;
|
|
||||||
var buttonProperties = {
|
|
||||||
x: buttonLocationX,
|
|
||||||
y: bLevel,
|
|
||||||
width: 10.0,
|
|
||||||
height: 10.0,
|
|
||||||
subImage: { x: 0, y: 0, width: 10, height: 10 },
|
|
||||||
imageURL: "http://hifi-public.s3.amazonaws.com/images/close-small-light.svg",
|
|
||||||
color: { red: 255, green: 255, blue: 255},
|
|
||||||
visible: true,
|
|
||||||
alpha: backgroundAlpha,
|
|
||||||
};
|
|
||||||
|
|
||||||
Notify(overlayProperties, buttonProperties, height);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pushes data to each array and sets up data for 2nd dimension array
|
// This handles the final dismissal of a notification after fading
|
||||||
// to handle auxiliary data not carried by the overlay class
|
function dismiss(firstNoteOut, firstButOut, firstOut) {
|
||||||
// specifically notification "heights", "times" of creation, and .
|
Overlays.deleteOverlay(firstNoteOut);
|
||||||
function Notify(notice, button, height){
|
Overlays.deleteOverlay(firstButOut);
|
||||||
|
notifications.splice(firstOut, 1);
|
||||||
notifications.push((Overlays.addOverlay("text", notice)));
|
buttons.splice(firstOut, 1);
|
||||||
buttons.push((Overlays.addOverlay("image",button)));
|
times.splice(firstOut, 1);
|
||||||
times.push(new Date().getTime() / 1000);
|
heights.splice(firstOut, 1);
|
||||||
height = height + 1.0;
|
myAlpha.splice(firstOut, 1);
|
||||||
heights.push(height);
|
overlay3DDetails.splice(firstOut, 1);
|
||||||
myAlpha.push(0);
|
|
||||||
var last = notifications.length - 1;
|
|
||||||
createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]);
|
|
||||||
fadeIn(notifications[last], buttons[last])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fadeIn(noticeIn, buttonIn) {
|
function fadeIn(noticeIn, buttonIn) {
|
||||||
var myLength = arrays.length;
|
var q = 0,
|
||||||
var q = 0;
|
qFade,
|
||||||
var pauseTimer = null;
|
pauseTimer = null;
|
||||||
pauseTimer = Script.setInterval(function() {
|
|
||||||
q++;
|
pauseTimer = Script.setInterval(function () {
|
||||||
|
q += 1;
|
||||||
qFade = q / 10.0;
|
qFade = q / 10.0;
|
||||||
Overlays.editOverlay(noticeIn, {alpha: qFade});
|
Overlays.editOverlay(noticeIn, { alpha: qFade });
|
||||||
Overlays.editOverlay(buttonIn, {alpha: qFade});
|
Overlays.editOverlay(buttonIn, { alpha: qFade });
|
||||||
if (q >= 9.0) {
|
if (q >= 9.0) {
|
||||||
Script.clearInterval(pauseTimer);
|
Script.clearInterval(pauseTimer);
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// push data from above to the 2 dimensional array
|
|
||||||
function createArrays(notice, button, createTime, height, myAlpha) {
|
|
||||||
arrays.push([notice, button, createTime, height, myAlpha]);
|
|
||||||
}
|
|
||||||
// handles mouse clicks on buttons
|
|
||||||
function mousePressEvent(event) {
|
|
||||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); //identify which overlay was clicked
|
|
||||||
for (i = 0; i < buttons.length; i++) { //if user clicked a button
|
|
||||||
if(clickedOverlay == buttons[i]) {
|
|
||||||
Overlays.deleteOverlay(notifications[i]);
|
|
||||||
Overlays.deleteOverlay(buttons[i]);
|
|
||||||
notifications.splice(i, 1);
|
|
||||||
buttons.splice(i, 1);
|
|
||||||
times.splice(i, 1);
|
|
||||||
heights.splice(i, 1);
|
|
||||||
myAlpha.splice(i, 1);
|
|
||||||
arrays.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Control key remains active only while key is held down
|
|
||||||
function keyReleaseEvent(key) {
|
|
||||||
if (key.key == 16777249) {
|
|
||||||
ctrlIsPressed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triggers notification on specific key driven events
|
|
||||||
function keyPressEvent(key) {
|
|
||||||
if (key.key == 16777249) {
|
|
||||||
ctrlIsPressed = true;
|
|
||||||
}
|
|
||||||
if (key.text == "q") { //queries number of users online
|
|
||||||
var numUsers = GlobalServices.onlineUsers.length;
|
|
||||||
var welcome = "There are " + numUsers + " users online now.";
|
|
||||||
createNotification(welcome);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key.text == "s") {
|
|
||||||
if (ctrlIsPressed == true){
|
|
||||||
var noteString = "Snapshot taken.";
|
|
||||||
createNotification(noteString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// formats string to add newline every 43 chars
|
|
||||||
function wordWrap(str) {
|
|
||||||
var result = stringDivider(str, 43.0, "\n");
|
|
||||||
createNotification(result);
|
|
||||||
}
|
|
||||||
// wraps whole word to newline
|
|
||||||
function stringDivider(str, slotWidth, spaceReplacer) {
|
|
||||||
if (str.length > slotWidth) {
|
|
||||||
var p = slotWidth;
|
|
||||||
for (; p > 0 && str[p] != ' '; p--) {
|
|
||||||
}
|
|
||||||
if (p > 0) {
|
|
||||||
var left = str.substring(0, p);
|
|
||||||
var right = str.substring(p + 1);
|
|
||||||
return left + spaceReplacer + stringDivider(right, slotWidth, spaceReplacer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This fires a notification on window resize
|
|
||||||
function checkSize(){
|
|
||||||
if((Window.innerWidth != ourWidth)||(Window.innerHeight != ourHeight)) {
|
|
||||||
var windowResize = "Window has been resized";
|
|
||||||
ourWidth = Window.innerWidth;
|
|
||||||
ourHeight = Window.innerHeight;
|
|
||||||
windowDimensions = Controller.getViewportDimensions();
|
|
||||||
overlayLocationX = (windowDimensions.x - (width + 60.0));
|
|
||||||
buttonLocationX = overlayLocationX + (width - 35.0);
|
|
||||||
createNotification(windowResize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triggers notification if a user logs on or off
|
|
||||||
function onOnlineUsersChanged(users) {
|
|
||||||
if (!isStartingUp()) { // Skip user notifications at startup.
|
|
||||||
for (user in users) {
|
|
||||||
if (last_users.indexOf(users[user]) == -1.0) {
|
|
||||||
createNotification(users[user] + " has joined");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (user in last_users) {
|
|
||||||
if (users.indexOf(last_users[user]) == -1.0) {
|
|
||||||
createNotification(last_users[user] + " has left");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_users = users;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triggers notification if @MyUserName is mentioned in chat and returns the message to the notification.
|
|
||||||
function onIncomingMessage(user, message) {
|
|
||||||
var myMessage = message;
|
|
||||||
var alertMe = "@" + GlobalServices.myUsername;
|
|
||||||
var thisAlert = user + ": " + myMessage;
|
|
||||||
if (myMessage.indexOf(alertMe) > -1.0) {
|
|
||||||
wordWrap(thisAlert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Triggers mic mute notification
|
|
||||||
function onMuteStateChanged() {
|
|
||||||
var muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
|
||||||
var muteString = "Microphone is now " + muteState;
|
|
||||||
createNotification(muteString);
|
|
||||||
}
|
|
||||||
|
|
||||||
function update(){
|
|
||||||
frame++;
|
|
||||||
if ((frame % 60.0) == 0) { // only update once a second
|
|
||||||
checkSize(); // checks for size change to trigger windowResize notification
|
|
||||||
locationY = 20.0;
|
|
||||||
for (var i = 0; i < arrays.length; i++) { //repositions overlays as others fade
|
|
||||||
var nextOverlay = Overlays.getOverlayAtPoint({x: overlayLocationX, y: locationY});
|
|
||||||
Overlays.editOverlay(notifications[i], { x:overlayLocationX, y:locationY});
|
|
||||||
Overlays.editOverlay(buttons[i], { x:buttonLocationX, y:locationY + 12.0});
|
|
||||||
locationY = locationY + arrays[i][3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This checks the age of the notification and prepares to fade it after 9.0 seconds (var persistTime - 1)
|
|
||||||
for (var i = 0; i < arrays.length; i++) {
|
|
||||||
if (ready){
|
|
||||||
var j = arrays[i][2];
|
|
||||||
var k = j + persistTime;
|
|
||||||
if (k < (new Date().getTime() / 1000)) {
|
|
||||||
ready = false;
|
|
||||||
noticeOut = arrays[i][0];
|
|
||||||
buttonOut = arrays[i][1];
|
|
||||||
var arraysOut = i;
|
|
||||||
fadeOut(noticeOut, buttonOut, arraysOut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this fades the notification ready for dismissal, and removes it from the arrays
|
// this fades the notification ready for dismissal, and removes it from the arrays
|
||||||
function fadeOut(noticeOut, buttonOut, arraysOut) {
|
function fadeOut(noticeOut, buttonOut, arraysOut) {
|
||||||
var myLength = arrays.length;
|
var r = 9.0,
|
||||||
var r = 9.0;
|
rFade,
|
||||||
var pauseTimer = null;
|
pauseTimer = null;
|
||||||
pauseTimer = Script.setInterval(function() {
|
|
||||||
r--;
|
pauseTimer = Script.setInterval(function () {
|
||||||
rFade = r / 10.0;
|
r -= 1;
|
||||||
Overlays.editOverlay(noticeOut, {alpha: rFade});
|
rFade = r / 10.0;
|
||||||
Overlays.editOverlay(buttonOut, {alpha: rFade});
|
Overlays.editOverlay(noticeOut, { alpha: rFade });
|
||||||
|
Overlays.editOverlay(buttonOut, { alpha: rFade });
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
dismiss(noticeOut, buttonOut, arraysOut);
|
dismiss(noticeOut, buttonOut, arraysOut);
|
||||||
arrays.splice(arraysOut, 1);
|
arrays.splice(arraysOut, 1);
|
||||||
|
@ -338,29 +151,283 @@ function fadeOut(noticeOut, buttonOut, arraysOut) {
|
||||||
}, 20);
|
}, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This handles the final dismissal of a notification after fading
|
function calculate3DOverlayPositions(noticeWidth, noticeHeight, y) {
|
||||||
function dismiss(firstNoteOut, firstButOut, firstOut) {
|
// Calculates overlay positions and orientations in avatar coordinates.
|
||||||
var working = firstOut
|
var noticeY,
|
||||||
Overlays.deleteOverlay(firstNoteOut);
|
originOffset,
|
||||||
Overlays.deleteOverlay(firstButOut);
|
notificationOrientation,
|
||||||
notifications.splice(firstOut, 1);
|
notificationPosition,
|
||||||
buttons.splice(firstOut, 1);
|
buttonPosition;
|
||||||
times.splice(firstOut, 1);
|
|
||||||
heights.splice(firstOut, 1);
|
// Notification plane positions
|
||||||
myAlpha.splice(firstOut,1);
|
noticeY = -y * NOTIFICATION_3D_SCALE - noticeHeight / 2;
|
||||||
|
notificationPosition = { x: 0, y: noticeY, z: 0 };
|
||||||
|
buttonPosition = { x: (noticeWidth - NOTIFICATION_3D_BUTTON_WIDTH) / 2, y: noticeY, z: 0.001 };
|
||||||
|
|
||||||
|
// Rotate plane
|
||||||
|
notificationOrientation = Quat.fromPitchYawRollDegrees(NOTIFICATIONS_3D_PITCH,
|
||||||
|
NOTIFICATIONS_3D_DIRECTION + NOTIFICATIONS_3D_YAW, 0);
|
||||||
|
notificationPosition = Vec3.multiplyQbyV(notificationOrientation, notificationPosition);
|
||||||
|
buttonPosition = Vec3.multiplyQbyV(notificationOrientation, buttonPosition);
|
||||||
|
|
||||||
|
// Translate plane
|
||||||
|
originOffset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, NOTIFICATIONS_3D_DIRECTION, 0),
|
||||||
|
{ x: 0, y: 0, z: -NOTIFICATIONS_3D_DISTANCE });
|
||||||
|
originOffset.y += NOTIFICATIONS_3D_ELEVATION;
|
||||||
|
notificationPosition = Vec3.sum(originOffset, notificationPosition);
|
||||||
|
buttonPosition = Vec3.sum(originOffset, buttonPosition);
|
||||||
|
|
||||||
|
return {
|
||||||
|
notificationOrientation: notificationOrientation,
|
||||||
|
notificationPosition: notificationPosition,
|
||||||
|
buttonPosition: buttonPosition
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This reports the number of users online at startup
|
// Pushes data to each array and sets up data for 2nd dimension array
|
||||||
function reportUsers() {
|
// to handle auxiliary data not carried by the overlay class
|
||||||
var numUsers = GlobalServices.onlineUsers.length;
|
// specifically notification "heights", "times" of creation, and .
|
||||||
var welcome = "Welcome! There are " + numUsers + " users online now.";
|
function notify(notice, button, height) {
|
||||||
createNotification(welcome);
|
var noticeWidth,
|
||||||
|
noticeHeight,
|
||||||
|
positions,
|
||||||
|
last;
|
||||||
|
|
||||||
|
if (isOnHMD) {
|
||||||
|
// Calculate 3D values from 2D overlay properties.
|
||||||
|
|
||||||
|
noticeWidth = notice.width * NOTIFICATION_3D_SCALE + NOTIFICATION_3D_BUTTON_WIDTH;
|
||||||
|
noticeHeight = notice.height * NOTIFICATION_3D_SCALE;
|
||||||
|
|
||||||
|
notice.size = { x: noticeWidth, y: noticeHeight };
|
||||||
|
notice.topMargin = 0.75 * notice.topMargin * NOTIFICATION_3D_SCALE;
|
||||||
|
notice.leftMargin = 2 * notice.leftMargin * NOTIFICATION_3D_SCALE;
|
||||||
|
notice.bottomMargin = 0;
|
||||||
|
notice.rightMargin = 0;
|
||||||
|
notice.lineHeight = 10.0 * (fontSize / 12.0) * NOTIFICATION_3D_SCALE;
|
||||||
|
notice.isFacingAvatar = false;
|
||||||
|
|
||||||
|
button.url = button.imageURL;
|
||||||
|
button.scale = button.width * NOTIFICATION_3D_SCALE;
|
||||||
|
button.isFacingAvatar = false;
|
||||||
|
|
||||||
|
positions = calculate3DOverlayPositions(noticeWidth, noticeHeight, notice.y);
|
||||||
|
|
||||||
|
notifications.push((Overlays.addOverlay("text3d", notice)));
|
||||||
|
buttons.push((Overlays.addOverlay("billboard", button)));
|
||||||
|
overlay3DDetails.push({
|
||||||
|
notificationOrientation: positions.notificationOrientation,
|
||||||
|
notificationPosition: positions.notificationPosition,
|
||||||
|
buttonPosition: positions.buttonPosition,
|
||||||
|
width: noticeWidth,
|
||||||
|
height: noticeHeight
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notifications.push((Overlays.addOverlay("text", notice)));
|
||||||
|
buttons.push((Overlays.addOverlay("image", button)));
|
||||||
|
}
|
||||||
|
|
||||||
|
height = height + 1.0;
|
||||||
|
heights.push(height);
|
||||||
|
times.push(new Date().getTime() / 1000);
|
||||||
|
myAlpha.push(0);
|
||||||
|
last = notifications.length - 1;
|
||||||
|
createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]);
|
||||||
|
fadeIn(notifications[last], buttons[last]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function creates and sizes the overlays
|
||||||
|
function createNotification(text) {
|
||||||
|
var count = (text.match(/\n/g) || []).length,
|
||||||
|
breakPoint = 43.0, // length when new line is added
|
||||||
|
extraLine = 0,
|
||||||
|
breaks = 0,
|
||||||
|
height = 40.0,
|
||||||
|
stack = 0,
|
||||||
|
level,
|
||||||
|
noticeProperties,
|
||||||
|
bLevel,
|
||||||
|
buttonProperties,
|
||||||
|
i;
|
||||||
|
|
||||||
|
if (text.length >= breakPoint) {
|
||||||
|
breaks = count;
|
||||||
|
}
|
||||||
|
extraLine = breaks * 16.0;
|
||||||
|
for (i = 0; i < heights.length; i += 1) {
|
||||||
|
stack = stack + heights[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
level = (stack + 20.0);
|
||||||
|
height = height + extraLine;
|
||||||
|
noticeProperties = {
|
||||||
|
x: overlayLocationX,
|
||||||
|
y: level,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
color: textColor,
|
||||||
|
backgroundColor: backColor,
|
||||||
|
alpha: backgroundAlpha,
|
||||||
|
topMargin: topMargin,
|
||||||
|
leftMargin: leftMargin,
|
||||||
|
font: {size: fontSize},
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
|
||||||
|
bLevel = level + 12.0;
|
||||||
|
buttonProperties = {
|
||||||
|
x: buttonLocationX,
|
||||||
|
y: bLevel,
|
||||||
|
width: 10.0,
|
||||||
|
height: 10.0,
|
||||||
|
subImage: { x: 0, y: 0, width: 10, height: 10 },
|
||||||
|
imageURL: "http://hifi-public.s3.amazonaws.com/images/close-small-light.svg",
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
visible: true,
|
||||||
|
alpha: backgroundAlpha
|
||||||
|
};
|
||||||
|
|
||||||
|
notify(noticeProperties, buttonProperties, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteNotification(index) {
|
||||||
|
Overlays.deleteOverlay(notifications[index]);
|
||||||
|
Overlays.deleteOverlay(buttons[index]);
|
||||||
|
notifications.splice(index, 1);
|
||||||
|
buttons.splice(index, 1);
|
||||||
|
times.splice(index, 1);
|
||||||
|
heights.splice(index, 1);
|
||||||
|
myAlpha.splice(index, 1);
|
||||||
|
overlay3DDetails.splice(index, 1);
|
||||||
|
arrays.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wraps whole word to newline
|
||||||
|
function stringDivider(str, slotWidth, spaceReplacer) {
|
||||||
|
var p,
|
||||||
|
left,
|
||||||
|
right;
|
||||||
|
|
||||||
|
if (str.length > slotWidth) {
|
||||||
|
p = slotWidth;
|
||||||
|
while (p > 0 && str[p] !== ' ') {
|
||||||
|
p -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p > 0) {
|
||||||
|
left = str.substring(0, p);
|
||||||
|
right = str.substring(p + 1);
|
||||||
|
return left + spaceReplacer + stringDivider(right, slotWidth, spaceReplacer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// formats string to add newline every 43 chars
|
||||||
|
function wordWrap(str) {
|
||||||
|
var result = stringDivider(str, 43.0, "\n");
|
||||||
|
createNotification(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This fires a notification on window resize
|
||||||
|
function checkSize() {
|
||||||
|
if ((Window.innerWidth !== ourWidth) || (Window.innerHeight !== ourHeight)) {
|
||||||
|
var windowResize = "Window has been resized";
|
||||||
|
ourWidth = Window.innerWidth;
|
||||||
|
ourHeight = Window.innerHeight;
|
||||||
|
windowDimensions = Controller.getViewportDimensions();
|
||||||
|
overlayLocationX = (windowDimensions.x - (width + 60.0));
|
||||||
|
buttonLocationX = overlayLocationX + (width - 35.0);
|
||||||
|
createNotification(windowResize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
var nextOverlay,
|
||||||
|
noticeOut,
|
||||||
|
buttonOut,
|
||||||
|
arraysOut,
|
||||||
|
defaultEyePosition,
|
||||||
|
avatarOrientation,
|
||||||
|
notificationPosition,
|
||||||
|
notificationOrientation,
|
||||||
|
buttonPosition,
|
||||||
|
positions,
|
||||||
|
i,
|
||||||
|
j,
|
||||||
|
k;
|
||||||
|
|
||||||
|
if (isOnHMD !== Menu.isOptionChecked(ENABLE_VR_MODE)) {
|
||||||
|
while (arrays.length > 0) {
|
||||||
|
deleteNotification(0);
|
||||||
|
}
|
||||||
|
isOnHMD = !isOnHMD;
|
||||||
|
persistTime = isOnHMD ? PERSIST_TIME_3D : PERSIST_TIME_2D;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame += 1;
|
||||||
|
if ((frame % 60.0) === 0) { // only update once a second
|
||||||
|
checkSize(); // checks for size change to trigger windowResize notification
|
||||||
|
locationY = 20.0;
|
||||||
|
for (i = 0; i < arrays.length; i += 1) { //repositions overlays as others fade
|
||||||
|
nextOverlay = Overlays.getOverlayAtPoint({ x: overlayLocationX, y: locationY });
|
||||||
|
Overlays.editOverlay(notifications[i], { x: overlayLocationX, y: locationY });
|
||||||
|
Overlays.editOverlay(buttons[i], { x: buttonLocationX, y: locationY + 12.0 });
|
||||||
|
if (isOnHMD) {
|
||||||
|
positions = calculate3DOverlayPositions(overlay3DDetails[i].width, overlay3DDetails[i].height, locationY);
|
||||||
|
overlay3DDetails[i].notificationOrientation = positions.notificationOrientation;
|
||||||
|
overlay3DDetails[i].notificationPosition = positions.notificationPosition;
|
||||||
|
overlay3DDetails[i].buttonPosition = positions.buttonPosition;
|
||||||
|
}
|
||||||
|
locationY = locationY + arrays[i][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This checks the age of the notification and prepares to fade it after 9.0 seconds (var persistTime - 1)
|
||||||
|
for (i = 0; i < arrays.length; i += 1) {
|
||||||
|
if (ready) {
|
||||||
|
j = arrays[i][2];
|
||||||
|
k = j + persistTime;
|
||||||
|
if (k < (new Date().getTime() / 1000)) {
|
||||||
|
ready = false;
|
||||||
|
noticeOut = arrays[i][0];
|
||||||
|
buttonOut = arrays[i][1];
|
||||||
|
arraysOut = i;
|
||||||
|
fadeOut(noticeOut, buttonOut, arraysOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOnHMD && notifications.length > 0) {
|
||||||
|
// Update 3D overlays to maintain positions relative to avatar
|
||||||
|
defaultEyePosition = MyAvatar.getDefaultEyePosition();
|
||||||
|
avatarOrientation = MyAvatar.orientation;
|
||||||
|
|
||||||
|
for (i = 0; i < notifications.length; i += 1) {
|
||||||
|
notificationPosition = Vec3.sum(defaultEyePosition,
|
||||||
|
Vec3.multiplyQbyV(avatarOrientation, overlay3DDetails[i].notificationPosition));
|
||||||
|
notificationOrientation = Quat.multiply(avatarOrientation, overlay3DDetails[i].notificationOrientation);
|
||||||
|
buttonPosition = Vec3.sum(defaultEyePosition,
|
||||||
|
Vec3.multiplyQbyV(avatarOrientation, overlay3DDetails[i].buttonPosition));
|
||||||
|
Overlays.editOverlay(notifications[i], { position: notificationPosition, rotation: notificationOrientation });
|
||||||
|
Overlays.editOverlay(buttons[i], { position: buttonPosition, rotation: notificationOrientation });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var STARTUP_TIMEOUT = 500, // ms
|
var STARTUP_TIMEOUT = 500, // ms
|
||||||
startingUp = true,
|
startingUp = true,
|
||||||
startupTimer = null;
|
startupTimer = null;
|
||||||
|
|
||||||
|
// This reports the number of users online at startup
|
||||||
|
function reportUsers() {
|
||||||
|
var welcome;
|
||||||
|
|
||||||
|
welcome = "Welcome! There are " + GlobalServices.onlineUsers.length + " users online now.";
|
||||||
|
createNotification(welcome);
|
||||||
|
}
|
||||||
|
|
||||||
function finishStartup() {
|
function finishStartup() {
|
||||||
startingUp = false;
|
startingUp = false;
|
||||||
Script.clearTimeout(startupTimer);
|
Script.clearTimeout(startupTimer);
|
||||||
|
@ -378,6 +445,113 @@ function isStartingUp() {
|
||||||
return startingUp;
|
return startingUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Triggers notification if a user logs on or off
|
||||||
|
function onOnlineUsersChanged(users) {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
if (!isStartingUp()) { // Skip user notifications at startup.
|
||||||
|
for (i = 0; i < users.length; i += 1) {
|
||||||
|
if (last_users.indexOf(users[i]) === -1.0) {
|
||||||
|
createNotification(users[i] + " has joined");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < last_users.length; i += 1) {
|
||||||
|
if (users.indexOf(last_users[i]) === -1.0) {
|
||||||
|
createNotification(last_users[i] + " has left");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_users = users;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers notification if @MyUserName is mentioned in chat and returns the message to the notification.
|
||||||
|
function onIncomingMessage(user, message) {
|
||||||
|
var myMessage,
|
||||||
|
alertMe,
|
||||||
|
thisAlert;
|
||||||
|
|
||||||
|
myMessage = message;
|
||||||
|
alertMe = "@" + GlobalServices.myUsername;
|
||||||
|
thisAlert = user + ": " + myMessage;
|
||||||
|
|
||||||
|
if (myMessage.indexOf(alertMe) > -1.0) {
|
||||||
|
wordWrap(thisAlert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers mic mute notification
|
||||||
|
function onMuteStateChanged() {
|
||||||
|
var muteState,
|
||||||
|
muteString;
|
||||||
|
|
||||||
|
muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
||||||
|
muteString = "Microphone is now " + muteState;
|
||||||
|
createNotification(muteString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handles mouse clicks on buttons
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
var pickRay,
|
||||||
|
clickedOverlay,
|
||||||
|
i;
|
||||||
|
|
||||||
|
if (isOnHMD) {
|
||||||
|
pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
clickedOverlay = Overlays.findRayIntersection(pickRay).overlayID;
|
||||||
|
} else {
|
||||||
|
clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < buttons.length; i += 1) {
|
||||||
|
if (clickedOverlay === buttons[i]) {
|
||||||
|
deleteNotification(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control key remains active only while key is held down
|
||||||
|
function keyReleaseEvent(key) {
|
||||||
|
if (key.key === 16777249) {
|
||||||
|
ctrlIsPressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers notification on specific key driven events
|
||||||
|
function keyPressEvent(key) {
|
||||||
|
var numUsers,
|
||||||
|
welcome,
|
||||||
|
noteString;
|
||||||
|
|
||||||
|
if (key.key === 16777249) {
|
||||||
|
ctrlIsPressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.text === "q") { //queries number of users online
|
||||||
|
numUsers = GlobalServices.onlineUsers.length;
|
||||||
|
welcome = "There are " + numUsers + " users online now.";
|
||||||
|
createNotification(welcome);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.text === "s") {
|
||||||
|
if (ctrlIsPressed === true) {
|
||||||
|
noteString = "Snapshot taken.";
|
||||||
|
createNotification(noteString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When our script shuts down, we should clean up all of our overlays
|
||||||
|
function scriptEnding() {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < notifications.length; i += 1) {
|
||||||
|
Overlays.deleteOverlay(notifications[i]);
|
||||||
|
Overlays.deleteOverlay(buttons[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AudioDevice.muteToggled.connect(onMuteStateChanged);
|
AudioDevice.muteToggled.connect(onMuteStateChanged);
|
||||||
Controller.keyPressEvent.connect(keyPressEvent);
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
@ -386,3 +560,4 @@ GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
|
||||||
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
||||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
|
|
@ -51,7 +51,7 @@ public:
|
||||||
// getters
|
// getters
|
||||||
float getLeanScale() const { return _leanScale; }
|
float getLeanScale() const { return _leanScale; }
|
||||||
glm::vec3 getGravity() const { return _gravity; }
|
glm::vec3 getGravity() const { return _gravity; }
|
||||||
glm::vec3 getDefaultEyePosition() const;
|
Q_INVOKABLE glm::vec3 getDefaultEyePosition() const;
|
||||||
bool getShouldRenderLocally() const { return _shouldRender; }
|
bool getShouldRenderLocally() const { return _shouldRender; }
|
||||||
|
|
||||||
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
||||||
|
|
Loading…
Reference in a new issue