diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index c08cb44c0c..6429d6e0c6 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -1,5 +1,6 @@ "use strict"; - +/*jslint vars:true, plusplus:true, forin:true*/ +/*global Script, Settings, Window, Controller, Overlays, SoundArray, LODManager, MyAvatar, Tablet, Camera, HMD, Menu, Quat, Vec3*/ // // notifications.js // Version 0.801 @@ -56,614 +57,614 @@ // } // } -/* global Script, Controller, Overlays, SoundArray, Quat, Vec3, MyAvatar, Menu, HMD, AudioDevice, LODManager, Settings, Camera */ -(function() { // BEGIN LOCAL_SCOPE +(function () { // BEGIN LOCAL_SCOPE -Script.include("./libraries/soundArray.js"); + Script.include("./libraries/soundArray.js"); -var width = 340.0; //width of notification overlay -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 buttonLocationX = overlayLocationX + (width - 28.0); -var locationY = 20.0; // position down from top of interface window -var topMargin = 13.0; -var leftMargin = 10.0; -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 backgroundAlpha = 0; -var fontSize = 12.0; -var PERSIST_TIME_2D = 10.0; // Time in seconds before notification fades -var PERSIST_TIME_3D = 15.0; -var persistTime = PERSIST_TIME_2D; -var frame = 0; -var ourWidth = Window.innerWidth; -var ourHeight = Window.innerHeight; -var ctrlIsPressed = false; -var ready = true; -var MENU_NAME = 'Tools > Notifications'; -var PLAY_NOTIFICATION_SOUNDS_MENU_ITEM = "Play Notification Sounds"; -var NOTIFICATION_MENU_ITEM_POST = " Notifications"; -var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds"; -var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"; -var lodTextID = false; + var width = 340.0; //width of notification overlay + 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 buttonLocationX = overlayLocationX + (width - 28.0); + var locationY = 20.0; // position down from top of interface window + var topMargin = 13.0; + var leftMargin = 10.0; + 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 backgroundAlpha = 0; + var fontSize = 12.0; + var PERSIST_TIME_2D = 10.0; // Time in seconds before notification fades + var PERSIST_TIME_3D = 15.0; + var persistTime = PERSIST_TIME_2D; + var frame = 0; + var ctrlIsPressed = false; + var ready = true; + var MENU_NAME = 'Tools > Notifications'; + var PLAY_NOTIFICATION_SOUNDS_MENU_ITEM = "Play Notification Sounds"; + var NOTIFICATION_MENU_ITEM_POST = " Notifications"; + var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds"; + var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"; + var lodTextID = false; -var NotificationType = { - UNKNOWN: 0, - SNAPSHOT: 1, - LOD_WARNING: 2, - CONNECTION_REFUSED: 3, - EDIT_ERROR: 4, - TABLET: 5, - CONNECTION: 6, - properties: [ - { text: "Snapshot" }, - { text: "Level of Detail" }, - { text: "Connection Refused" }, - { text: "Edit error" }, - { text: "Tablet" }, - { text: "Connection" } - ], - getTypeFromMenuItem: function(menuItemName) { - if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) { - return NotificationType.UNKNOWN; - } - var preMenuItemName = menuItemName.substr(0, menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length); - for (var type in this.properties) { - if (this.properties[type].text === preMenuItemName) { - return parseInt(type) + 1; + var NotificationType = { + UNKNOWN: 0, + SNAPSHOT: 1, + LOD_WARNING: 2, + CONNECTION_REFUSED: 3, + EDIT_ERROR: 4, + TABLET: 5, + CONNECTION: 6, + properties: [ + { text: "Snapshot" }, + { text: "Level of Detail" }, + { text: "Connection Refused" }, + { text: "Edit error" }, + { text: "Tablet" }, + { text: "Connection" } + ], + getTypeFromMenuItem: function (menuItemName) { + var type; + if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) { + return NotificationType.UNKNOWN; } + var preMenuItemName = menuItemName.substr(0, menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length); + for (type in this.properties) { + if (this.properties[type].text === preMenuItemName) { + return parseInt(type, 10) + 1; + } + } + return NotificationType.UNKNOWN; + }, + getMenuString: function (type) { + return this.properties[type - 1].text + NOTIFICATION_MENU_ITEM_POST; } - return NotificationType.UNKNOWN; - }, - getMenuString: function(type) { - return this.properties[type - 1].text + NOTIFICATION_MENU_ITEM_POST; - } -}; - -var randomSounds = new SoundArray({ localOnly: true }, true); -var numberOfSounds = 2; -for (var i = 1; i <= numberOfSounds; i++) { - randomSounds.addSound(Script.resolvePath("assets/sounds/notification-general"+ i + ".raw")); -} - -var notifications = []; -var buttons = []; -var times = []; -var heights = []; -var myAlpha = []; -var arrays = []; -var isOnHMD = false, - 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 = []; - -// push data from above to the 2 dimensional array -function createArrays(notice, button, createTime, height, myAlpha) { - arrays.push([notice, button, createTime, height, myAlpha]); -} - -// This handles the final dismissal of a notification after fading -function dismiss(firstNoteOut, firstButOut, firstOut) { - if (firstNoteOut == lodTextID) { - lodTextID = false; - } - - Overlays.deleteOverlay(firstNoteOut); - Overlays.deleteOverlay(firstButOut); - notifications.splice(firstOut, 1); - buttons.splice(firstOut, 1); - times.splice(firstOut, 1); - heights.splice(firstOut, 1); - myAlpha.splice(firstOut, 1); - overlay3DDetails.splice(firstOut, 1); -} - -function fadeIn(noticeIn, buttonIn) { - var q = 0, - qFade, - pauseTimer = null; - - pauseTimer = Script.setInterval(function () { - q += 1; - qFade = q / 10.0; - Overlays.editOverlay(noticeIn, { alpha: qFade }); - Overlays.editOverlay(buttonIn, { alpha: qFade }); - if (q >= 9.0) { - Script.clearInterval(pauseTimer); - } - }, 10); -} - -// this fades the notification ready for dismissal, and removes it from the arrays -function fadeOut(noticeOut, buttonOut, arraysOut) { - var r = 9.0, - rFade, - pauseTimer = null; - - pauseTimer = Script.setInterval(function () { - r -= 1; - rFade = Math.max(0.0, r / 10.0); - Overlays.editOverlay(noticeOut, { alpha: rFade }); - Overlays.editOverlay(buttonOut, { alpha: rFade }); - if (r <= 0) { - dismiss(noticeOut, buttonOut, arraysOut); - arrays.splice(arraysOut, 1); - ready = true; - Script.clearInterval(pauseTimer); - } - }, 20); -} - -function calculate3DOverlayPositions(noticeWidth, noticeHeight, y) { - // Calculates overlay positions and orientations in avatar coordinates. - var noticeY, - originOffset, - notificationOrientation, - notificationPosition, - buttonPosition; - - // Notification plane positions - 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 }; -} -// Pushes data to each array and sets up data for 2nd dimension array -// to handle auxiliary data not carried by the overlay class -// specifically notification "heights", "times" of creation, and . -function notify(notice, button, height, imageProperties, image) { - var notificationText, - noticeWidth, - noticeHeight, - positions, - last; + var randomSounds = new SoundArray({ localOnly: true }, true); + var numberOfSounds = 2; + var soundIndex; + for (soundIndex = 1; soundIndex <= numberOfSounds; soundIndex++) { + randomSounds.addSound(Script.resolvePath("assets/sounds/notification-general" + soundIndex + ".raw")); + } - if (isOnHMD) { - // Calculate 3D values from 2D overlay properties. + var notifications = []; + var buttons = []; + var times = []; + var heights = []; + var myAlpha = []; + var arrays = []; + var isOnHMD = false, + 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 = []; - noticeWidth = notice.width * NOTIFICATION_3D_SCALE + NOTIFICATION_3D_BUTTON_WIDTH; - noticeHeight = notice.height * NOTIFICATION_3D_SCALE; + // push data from above to the 2 dimensional array + function createArrays(notice, button, createTime, height, myAlpha) { + arrays.push([notice, button, createTime, height, myAlpha]); + } - notice.size = { x: noticeWidth, y: noticeHeight }; - - positions = calculate3DOverlayPositions(noticeWidth, noticeHeight, notice.y); - - notice.parentID = MyAvatar.sessionUUID; - notice.parentJointIndex = -2; - - if (!image) { - 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; - - notificationText = Overlays.addOverlay("text3d", notice); - notifications.push(notificationText); - } else { - notifications.push(Overlays.addOverlay("image3d", notice)); + // This handles the final dismissal of a notification after fading + function dismiss(firstNoteOut, firstButOut, firstOut) { + if (firstNoteOut === lodTextID) { + lodTextID = false; } - button.url = button.imageURL; - button.scale = button.width * NOTIFICATION_3D_SCALE; - button.isFacingAvatar = false; - button.parentID = MyAvatar.sessionUUID; - button.parentJointIndex = -2; + Overlays.deleteOverlay(firstNoteOut); + Overlays.deleteOverlay(firstButOut); + notifications.splice(firstOut, 1); + buttons.splice(firstOut, 1); + times.splice(firstOut, 1); + heights.splice(firstOut, 1); + myAlpha.splice(firstOut, 1); + overlay3DDetails.splice(firstOut, 1); + } - buttons.push((Overlays.addOverlay("image3d", button))); - overlay3DDetails.push({ - notificationOrientation: positions.notificationOrientation, - notificationPosition: positions.notificationPosition, - buttonPosition: positions.buttonPosition, - width: noticeWidth, - height: noticeHeight - }); + function fadeIn(noticeIn, buttonIn) { + var q = 0, + qFade, + pauseTimer = null; + pauseTimer = Script.setInterval(function () { + q += 1; + qFade = q / 10.0; + Overlays.editOverlay(noticeIn, { alpha: qFade }); + Overlays.editOverlay(buttonIn, { alpha: qFade }); + if (q >= 9.0) { + Script.clearInterval(pauseTimer); + } + }, 10); + } - var defaultEyePosition, - avatarOrientation, - notificationPosition, + // this fades the notification ready for dismissal, and removes it from the arrays + function fadeOut(noticeOut, buttonOut, arraysOut) { + var r = 9.0, + rFade, + pauseTimer = null; + + pauseTimer = Script.setInterval(function () { + r -= 1; + rFade = Math.max(0.0, r / 10.0); + Overlays.editOverlay(noticeOut, { alpha: rFade }); + Overlays.editOverlay(buttonOut, { alpha: rFade }); + if (r <= 0) { + dismiss(noticeOut, buttonOut, arraysOut); + arrays.splice(arraysOut, 1); + ready = true; + Script.clearInterval(pauseTimer); + } + }, 20); + } + + function calculate3DOverlayPositions(noticeWidth, noticeHeight, y) { + // Calculates overlay positions and orientations in avatar coordinates. + var noticeY, + originOffset, notificationOrientation, + notificationPosition, buttonPosition; - if (isOnHMD && notifications.length > 0) { - // Update 3D overlays to maintain positions relative to avatar - defaultEyePosition = MyAvatar.getDefaultEyePosition(); - avatarOrientation = MyAvatar.orientation; + // Notification plane positions + 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 }; - 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 }); - } - } + // 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); - } else { - if (!image) { - notificationText = Overlays.addOverlay("text", notice); - notifications.push((notificationText)); - } else { - notifications.push(Overlays.addOverlay("image", notice)); - } - buttons.push(Overlays.addOverlay("image", button)); + // 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 + }; } - height = height + 1.0; - heights.push(height); - times.push(new Date().getTime() / 1000); - last = notifications.length - 1; - myAlpha.push(notifications[last].alpha); - createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]); - fadeIn(notifications[last], buttons[last]); + // Pushes data to each array and sets up data for 2nd dimension array + // to handle auxiliary data not carried by the overlay class + // specifically notification "heights", "times" of creation, and . + function notify(notice, button, height, imageProperties, image) { + var notificationText, + noticeWidth, + noticeHeight, + positions, + last; - if (imageProperties && !image) { - var imageHeight = notice.width / imageProperties.aspectRatio; - notice = { - x: notice.x, - y: notice.y + height, - width: notice.width, - height: imageHeight, - subImage: { x: 0, y: 0 }, + 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 }; + + positions = calculate3DOverlayPositions(noticeWidth, noticeHeight, notice.y); + + notice.parentID = MyAvatar.sessionUUID; + notice.parentJointIndex = -2; + + if (!image) { + 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; + + notificationText = Overlays.addOverlay("text3d", notice); + notifications.push(notificationText); + } else { + notifications.push(Overlays.addOverlay("image3d", notice)); + } + + button.url = button.imageURL; + button.scale = button.width * NOTIFICATION_3D_SCALE; + button.isFacingAvatar = false; + button.parentID = MyAvatar.sessionUUID; + button.parentJointIndex = -2; + + buttons.push((Overlays.addOverlay("image3d", button))); + overlay3DDetails.push({ + notificationOrientation: positions.notificationOrientation, + notificationPosition: positions.notificationPosition, + buttonPosition: positions.buttonPosition, + width: noticeWidth, + height: noticeHeight + }); + + + var defaultEyePosition, + avatarOrientation, + notificationPosition, + notificationOrientation, + buttonPosition, + notificationIndex; + + if (isOnHMD && notifications.length > 0) { + // Update 3D overlays to maintain positions relative to avatar + defaultEyePosition = MyAvatar.getDefaultEyePosition(); + avatarOrientation = MyAvatar.orientation; + + for (notificationIndex = 0; notificationIndex < notifications.length; notificationIndex += 1) { + notificationPosition = Vec3.sum(defaultEyePosition, + Vec3.multiplyQbyV(avatarOrientation, + overlay3DDetails[notificationIndex].notificationPosition)); + notificationOrientation = Quat.multiply(avatarOrientation, + overlay3DDetails[notificationIndex].notificationOrientation); + buttonPosition = Vec3.sum(defaultEyePosition, + Vec3.multiplyQbyV(avatarOrientation, + overlay3DDetails[notificationIndex].buttonPosition)); + Overlays.editOverlay(notifications[notificationIndex], { position: notificationPosition, + rotation: notificationOrientation }); + Overlays.editOverlay(buttons[notificationIndex], { position: buttonPosition, rotation: notificationOrientation }); + } + } + + } else { + if (!image) { + notificationText = Overlays.addOverlay("text", notice); + notifications.push(notificationText); + } else { + notifications.push(Overlays.addOverlay("image", notice)); + } + buttons.push(Overlays.addOverlay("image", button)); + } + + height = height + 1.0; + heights.push(height); + times.push(new Date().getTime() / 1000); + last = notifications.length - 1; + myAlpha.push(notifications[last].alpha); + createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]); + fadeIn(notifications[last], buttons[last]); + + if (imageProperties && !image) { + var imageHeight = notice.width / imageProperties.aspectRatio; + notice = { + x: notice.x, + y: notice.y + height, + width: notice.width, + height: imageHeight, + subImage: { x: 0, y: 0 }, + color: { red: 255, green: 255, blue: 255}, + visible: true, + imageURL: imageProperties.path, + alpha: backgroundAlpha + }; + notify(notice, button, imageHeight, imageProperties, true); + } + + return notificationText; + } + + var CLOSE_NOTIFICATION_ICON = Script.resolvePath("assets/images/close-small-light.svg"); + + // This function creates and sizes the overlays + function createNotification(text, notificationType, imageProperties) { + 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: CLOSE_NOTIFICATION_ICON, color: { red: 255, green: 255, blue: 255}, visible: true, - imageURL: imageProperties.path, alpha: backgroundAlpha }; - notify(notice, button, imageHeight, imageProperties, true); + + if (Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) && + Menu.isOptionChecked(NotificationType.getMenuString(notificationType))) { + randomSounds.playRandom(); + } + + return notify(noticeProperties, buttonProperties, height, imageProperties); } - return notificationText; -} - -var CLOSE_NOTIFICATION_ICON = Script.resolvePath("assets/images/close-small-light.svg"); - -// This function creates and sizes the overlays -function createNotification(text, notificationType, imageProperties) { - 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]; + function deleteNotification(index) { + var notificationTextID = notifications[index]; + if (notificationTextID === lodTextID) { + lodTextID = false; + } + Overlays.deleteOverlay(notificationTextID); + 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); } - 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: CLOSE_NOTIFICATION_ICON, - color: { red: 255, green: 255, blue: 255}, - visible: true, - alpha: backgroundAlpha - }; - - if (Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) && - Menu.isOptionChecked(NotificationType.getMenuString(notificationType))) { - randomSounds.playRandom(); - } - - return notify(noticeProperties, buttonProperties, height, imageProperties); -} - -function deleteNotification(index) { - var notificationTextID = notifications[index]; - if (notificationTextID == lodTextID) { - lodTextID = false; - } - Overlays.deleteOverlay(notificationTextID); - 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); -} - - -// Trims extra whitespace and breaks into lines of length no more than MAX_LENGTH, breaking at spaces. Trims extra whitespace. -var MAX_LENGTH = 42; -function wordWrap(string) { - var finishedLines = [], currentLine = ''; - string.split(/\s/).forEach(function (word) { - var tail = currentLine ? ' ' + word : word; - if ((currentLine.length + tail.length) <= MAX_LENGTH) { - currentLine += tail; - } else { + // Trims extra whitespace and breaks into lines of length no more than MAX_LENGTH, breaking at spaces. Trims extra whitespace. + var MAX_LENGTH = 42; + function wordWrap(string) { + var finishedLines = [], currentLine = ''; + string.split(/\s/).forEach(function (word) { + var tail = currentLine ? ' ' + word : word; + if ((currentLine.length + tail.length) <= MAX_LENGTH) { + currentLine += tail; + } else { + finishedLines.push(currentLine); + currentLine = word; + } + }); + if (currentLine) { finishedLines.push(currentLine); - currentLine = word; } - }); - if (currentLine) { - finishedLines.push(currentLine); - } - return finishedLines.join('\n'); -} - -function update() { - var nextOverlay, - noticeOut, - buttonOut, - arraysOut, - positions, - i, - j, - k; - - if (isOnHMD !== HMD.active) { - while (arrays.length > 0) { - deleteNotification(0); - } - isOnHMD = !isOnHMD; - persistTime = isOnHMD ? PERSIST_TIME_3D : PERSIST_TIME_2D; - return; + return finishedLines.join('\n'); } - frame += 1; - if ((frame % 60.0) === 0) { // only update once a second - 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; + function update() { + var noticeOut, + buttonOut, + arraysOut, + positions, + i, + j, + k; + + if (isOnHMD !== HMD.active) { + while (arrays.length > 0) { + deleteNotification(0); } - locationY = locationY + arrays[i][3]; + isOnHMD = !isOnHMD; + persistTime = isOnHMD ? PERSIST_TIME_3D : PERSIST_TIME_2D; + return; } - } - // 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); + frame += 1; + if ((frame % 60.0) === 0) { // only update once a second + locationY = 20.0; + for (i = 0; i < arrays.length; i += 1) { //repositions overlays as others fade + 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); + } } } } -} -var STARTUP_TIMEOUT = 500, // ms - startingUp = true, - startupTimer = null; + var STARTUP_TIMEOUT = 500, // ms + startingUp = true, + startupTimer = null; -function finishStartup() { - startingUp = false; - Script.clearTimeout(startupTimer); -} + function finishStartup() { + startingUp = false; + Script.clearTimeout(startupTimer); + } -function isStartingUp() { - // Is starting up until get no checks that it is starting up for STARTUP_TIMEOUT - if (startingUp) { - if (startupTimer) { - Script.clearTimeout(startupTimer); + function isStartingUp() { + // Is starting up until get no checks that it is starting up for STARTUP_TIMEOUT + if (startingUp) { + if (startupTimer) { + Script.clearTimeout(startupTimer); + } + startupTimer = Script.setTimeout(finishStartup, STARTUP_TIMEOUT); } - startupTimer = Script.setTimeout(finishStartup, STARTUP_TIMEOUT); - } - return startingUp; -} - -function onDomainConnectionRefused(reason) { - createNotification("Connection refused: " + reason, NotificationType.CONNECTION_REFUSED); -} - -function onEditError(msg) { - createNotification(wordWrap(msg), NotificationType.EDIT_ERROR); -} - -function onNotify(msg) { - createNotification(wordWrap(msg), NotificationType.UNKNOWN); // Needs a generic notification system for user feedback, thus using this -} - -function onSnapshotTaken(pathStillSnapshot, notify) { - if (notify) { - var imageProperties = { - path: "file:///" + pathStillSnapshot, - aspectRatio: Window.innerWidth / Window.innerHeight - }; - createNotification(wordWrap("Snapshot saved to " + pathStillSnapshot), NotificationType.SNAPSHOT, imageProperties); - } -} - -function tabletNotification() { - createNotification("Tablet needs your attention", NotificationType.TABLET); -} - -function processingGif() { - createNotification("Processing GIF snapshot...", NotificationType.SNAPSHOT); -} - -function connectionAdded(connectionName) { - createNotification(connectionName, NotificationType.CONNECTION); -} - -function connectionError(error) { - createNotification(wordWrap("Error trying to make connection: " + error), NotificationType.CONNECTION); -} - -// 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 }); + return startingUp; } - for (i = 0; i < buttons.length; i += 1) { - if (clickedOverlay === buttons[i]) { - deleteNotification(i); + function onDomainConnectionRefused(reason) { + createNotification("Connection refused: " + reason, NotificationType.CONNECTION_REFUSED); + } + + function onEditError(msg) { + createNotification(wordWrap(msg), NotificationType.EDIT_ERROR); + } + + function onNotify(msg) { + createNotification(wordWrap(msg), NotificationType.UNKNOWN); // Needs a generic notification system for user feedback, thus using this + } + + function onSnapshotTaken(pathStillSnapshot, notify) { + if (notify) { + var imageProperties = { + path: "file:///" + pathStillSnapshot, + aspectRatio: Window.innerWidth / Window.innerHeight + }; + createNotification(wordWrap("Snapshot saved to " + pathStillSnapshot), NotificationType.SNAPSHOT, imageProperties); } } -} -// Control key remains active only while key is held down -function keyReleaseEvent(key) { - if (key.key === 16777249) { - ctrlIsPressed = false; + function tabletNotification() { + createNotification("Tablet needs your attention", NotificationType.TABLET); } -} -// Triggers notification on specific key driven events -function keyPressEvent(key) { - if (key.key === 16777249) { - ctrlIsPressed = true; + function processingGif() { + createNotification("Processing GIF snapshot...", NotificationType.SNAPSHOT); } -} -function setup() { - Menu.addMenu(MENU_NAME); - var checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING); - checked = checked === '' ? true : checked; - Menu.addMenuItem({ - menuName: MENU_NAME, - menuItemName: PLAY_NOTIFICATION_SOUNDS_MENU_ITEM, - isCheckable: true, - isChecked: Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING) - }); - Menu.addSeparator(MENU_NAME, "Play sounds for:"); - for (var type in NotificationType.properties) { - checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + (parseInt(type) + 1)); + function connectionAdded(connectionName) { + createNotification(connectionName, NotificationType.CONNECTION); + } + + function connectionError(error) { + createNotification(wordWrap("Error trying to make connection: " + error), NotificationType.CONNECTION); + } + + // 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) { + if (key.key === 16777249) { + ctrlIsPressed = true; + } + } + + function setup() { + var type; + Menu.addMenu(MENU_NAME); + var checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING); checked = checked === '' ? true : checked; Menu.addMenuItem({ menuName: MENU_NAME, - menuItemName: NotificationType.properties[type].text + NOTIFICATION_MENU_ITEM_POST, + menuItemName: PLAY_NOTIFICATION_SOUNDS_MENU_ITEM, isCheckable: true, - isChecked: checked + isChecked: Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING) }); + Menu.addSeparator(MENU_NAME, "Play sounds for:"); + for (type in NotificationType.properties) { + checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + (parseInt(type, 10) + 1)); + checked = checked === '' ? true : checked; + Menu.addMenuItem({ + menuName: MENU_NAME, + menuItemName: NotificationType.properties[type].text + NOTIFICATION_MENU_ITEM_POST, + isCheckable: true, + isChecked: checked + }); + } } -} -// When our script shuts down, we should clean up all of our overlays -function scriptEnding() { - for (var i = 0; i < notifications.length; i++) { - Overlays.deleteOverlay(notifications[i]); - Overlays.deleteOverlay(buttons[i]); + // When our script shuts down, we should clean up all of our overlays + function scriptEnding() { + var notificationIndex; + for (notificationIndex = 0; notificationIndex < notifications.length; notificationIndex++) { + Overlays.deleteOverlay(notifications[notificationIndex]); + Overlays.deleteOverlay(buttons[notificationIndex]); + } + Menu.removeMenu(MENU_NAME); } - Menu.removeMenu(MENU_NAME); -} -function menuItemEvent(menuItem) { - if (menuItem === PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) { - Settings.setValue(PLAY_NOTIFICATION_SOUNDS_SETTING, Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM)); - return; + function menuItemEvent(menuItem) { + if (menuItem === PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) { + Settings.setValue(PLAY_NOTIFICATION_SOUNDS_SETTING, Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM)); + return; + } + var notificationType = NotificationType.getTypeFromMenuItem(menuItem); + if (notificationType !== notificationType.UNKNOWN) { + Settings.setValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + notificationType, Menu.isOptionChecked(menuItem)); + } } - var notificationType = NotificationType.getTypeFromMenuItem(menuItem); - if (notificationType !== notificationType.UNKNOWN) { - Settings.setValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + notificationType, Menu.isOptionChecked(menuItem)); - } -} -LODManager.LODDecreased.connect(function() { - var warningText = "\n" + - "Due to the complexity of the content, the \n" + - "level of detail has been decreased. " + - "You can now see: \n" + - LODManager.getLODFeedbackText(); + LODManager.LODDecreased.connect(function () { + var warningText = "\n" + + "Due to the complexity of the content, the \n" + + "level of detail has been decreased. " + + "You can now see: \n" + + LODManager.getLODFeedbackText(); - if (lodTextID === false) { - lodTextID = createNotification(warningText, NotificationType.LOD_WARNING); - } else { - Overlays.editOverlay(lodTextID, { text: warningText }); - } -}); + if (lodTextID === false) { + lodTextID = createNotification(warningText, NotificationType.LOD_WARNING); + } else { + Overlays.editOverlay(lodTextID, { text: warningText }); + } + }); -Controller.keyPressEvent.connect(keyPressEvent); -Controller.mousePressEvent.connect(mousePressEvent); -Controller.keyReleaseEvent.connect(keyReleaseEvent); -Script.update.connect(update); -Script.scriptEnding.connect(scriptEnding); -Menu.menuItemEvent.connect(menuItemEvent); -Window.domainConnectionRefused.connect(onDomainConnectionRefused); -Window.stillSnapshotTaken.connect(onSnapshotTaken); -Window.processingGifStarted.connect(processingGif); -Window.connectionAdded.connect(connectionAdded); -Window.connectionError.connect(connectionError); -Window.announcement.connect(onNotify); -Window.notifyEditError = onEditError; -Window.notify = onNotify; -Tablet.tabletNotification.connect(tabletNotification); -setup(); + Controller.keyPressEvent.connect(keyPressEvent); + Controller.mousePressEvent.connect(mousePressEvent); + Controller.keyReleaseEvent.connect(keyReleaseEvent); + Script.update.connect(update); + Script.scriptEnding.connect(scriptEnding); + Menu.menuItemEvent.connect(menuItemEvent); + Window.domainConnectionRefused.connect(onDomainConnectionRefused); + Window.stillSnapshotTaken.connect(onSnapshotTaken); + Window.processingGifStarted.connect(processingGif); + Window.connectionAdded.connect(connectionAdded); + Window.connectionError.connect(connectionError); + Window.announcement.connect(onNotify); + Window.notifyEditError = onEditError; + Window.notify = onNotify; + Tablet.tabletNotification.connect(tabletNotification); + setup(); }()); // END LOCAL_SCOPE diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 8235b69c90..8ba19d18a8 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -1,4 +1,6 @@ "use strict"; +/*jslint vars:true, plusplus:true, forin:true*/ +/*global Window, Script, Tablet, HMD, Controller, Account, XMLHttpRequest, location, print*/ // // goto.js @@ -11,35 +13,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -(function() { // BEGIN LOCAL_SCOPE +(function () { // BEGIN LOCAL_SCOPE var gotoQmlSource = "TabletAddressDialog.qml"; var buttonName = "GOTO"; var onGotoScreen = false; var shouldActivateButton = false; - - function onClicked() { - if (onGotoScreen) { - // for toolbar-mode: go back to home screen, this will close the window. - tablet.gotoHomeScreen(); - } else { - shouldActivateButton = true; - tablet.loadQMLSource(gotoQmlSource); - onGotoScreen = true; - } - } - - function onScreenChanged(type, url) { - if (url === gotoQmlSource) { - onGotoScreen = true; - shouldActivateButton = true; - button.editProperties({isActive: shouldActivateButton}); - messagesWaiting(false); - } else { - shouldActivateButton = false; - onGotoScreen = false; - button.editProperties({isActive: shouldActivateButton}); - } - } + function ignore() { } var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var NORMAL_ICON = "icons/tablet-icons/goto-i.svg"; @@ -58,10 +37,33 @@ }); } + function onClicked() { + if (onGotoScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + shouldActivateButton = true; + tablet.loadQMLSource(gotoQmlSource); + onGotoScreen = true; + } + } + + function onScreenChanged(type, url) { + ignore(type); + if (url === gotoQmlSource) { + onGotoScreen = true; + shouldActivateButton = true; + button.editProperties({isActive: shouldActivateButton}); + messagesWaiting(false); + } else { + shouldActivateButton = false; + onGotoScreen = false; + button.editProperties({isActive: shouldActivateButton}); + } + } button.clicked.connect(onClicked); tablet.screenChanged.connect(onScreenChanged); - var METAVERSE_BASE = location.metaverseServerUrl; function request(options, callback) { // cb(error, responseOfCorrectContentType) of url. A subset of npm request. var httpRequest = new XMLHttpRequest(), key; // QT bug: apparently doesn't handle onload. Workaround using readyState. @@ -129,7 +131,7 @@ uri: url }, function (error, data) { if (error || (data.status !== 'success')) { - print("Error: unable to get", url, error || response.status); + print("Error: unable to get", url, error || data.status); return; } var didNotify = false;