// HudPanel class: Creates a set of overlays of static and dynamic text entries, TextDisplay class. // Can start letter-by-letter animation for readout display effect. Script.include(["pd_utils.js"]); // Stores static or animated text overlay or image TextDisplay = function(text, offset, width, animated, color, fontSize, imageUrl) { this.text = text; this.offset = offset; // position offset from parent panel position this.animated = animated; this.panelWidth = width; this.animationFinished = false; this._letterIndex = 0; this._lineLength = 0; this._textIsPrinting = false; this._textAccumulator = ""; this._font = {}; this.blipSound = SoundCache.getSound(pd_path("sounds/textBlip1.wav")); var startText = ""; if (!this.animated) startText = this.text; var newOverlay; imageUrl = typeof imageUrl !== 'undefined' ? imageUrl : ""; if (imageUrl != "") { newOverlay = createImageOverlay(imageUrl, offset, true, 160, 128 ); } else { newOverlay = createOverlay(startText, offset, fontSize, 1.0, true ); Overlays.editOverlay(newOverlay, {color: color, backgroundAlpha: 0.0, width:width}); } this.overlay = newOverlay; this.show = function() { Overlays.editOverlay(this.overlay, {visible: true }); } this.hide = function() { Overlays.editOverlay(this.overlay, {visible: false }); } this.setPositionAsChild = function(parentPos) { var newPos = Vec3.sum(parentPos, this.offset); Overlays.editOverlay(this.overlay, {x: newPos.x, y:newPos.y }); } this.clear = function() { Overlays.editOverlay(this.overlay, {text:""}); } this.startAnimation = function() { if (!this.animated) return; this.clear(); this._letterIndex = 0; this._lineLength = 0; this._textAccumulator = ""; this.animationFinished = false; this._textIsPrinting = true; this._font = Overlays.getProperty(this.overlay, "font"); } // Call to advance a character in animated panels this.update = function() { if (!this.animated || !this._textIsPrinting) return; //printDebug("TextDisplay.update"); this.displayNextCharacter(); } // Sets and shows text all at once (no animation) this.showStaticText = function(text) { this.text = text; this.displayStoredText(); } // Display text (set previously) all at once this.displayStoredText = function() { printDebug("TextDisplay.displayStoredText: " + this.text); Overlays.editOverlay(this.overlay, {text: this.text} ); } this.displayNextCharacter = function() { var fontWidthTweak = 0.62; if (this._letterIndex >= this.text.length) { this._textIsPrinting = false; this._letterIndex = 0; this.animationFinished = true; return; } this._lineLength++; var currentLineWidth = this._lineLength * this._font.size * fontWidthTweak; var letter = this.text.charAt(this._letterIndex); if (letter == " " && currentLineWidth > this.panelWidth) { letter = "\n"; this._lineLength = 0; } this._textAccumulator += letter; this._letterIndex++; if (letter == "\n") this._lineLength = 0; Audio.playSound(this.blipSound, { position: MyAvatar.position, volume: 0.5 }); Overlays.editOverlay(this.overlay, {text: this._textAccumulator} ); } } // Collection of TextDisplays and other display objects with shared transform parent HudPanel = function(position, size, margin) { this.position = position; this.size = size; // width,height this.textDisplays = []; // Array of ALL text objects (for deletion, move, etc) this.fontSize = 15; this.charAnimInterval = 0.025; this.margin = margin; // {x,y} this.isAnimating = false; this._textDisplayDict = {}; // Lookup dictionary (by text field name) of all text objects this._animatedTextDisplays = []; // Array of all animated text objects this._totalAnimTime = 0.0; this._currentlyPlayingDisplay = -1; this.deconstruct = function() { this.deleteOverlays(); } this.show = function() { for (var displayIndex = 0; displayIndex < this.textDisplays.length; displayIndex++) this.textDisplays[displayIndex].show(); } this.hide = function() { for (var displayIndex = 0; displayIndex < this.textDisplays.length; displayIndex++) this.textDisplays[displayIndex].hide(); } this.addImageFrame = function(name, offset, width, height, imageUrl) { printDebug("Adding image frame:" + imageUrl); var newTextDisplay = new TextDisplay("", offset, false, {red:0,green:0,blue:0}, this.fontSize, false, imageUrl); Overlays.editOverlay(newTextDisplay.overlay, {width: width, height: height }); newTextDisplay.setPositionAsChild(this.position); this.textDisplays.push(newTextDisplay); } this.addRectangle = function(name, offset, width, height, color) { var newTextDisplay = new TextDisplay("", offset, false, color, this.fontSize); Overlays.editOverlay(newTextDisplay.overlay, {backgroundAlpha:0.85, width: width, height: height }); newTextDisplay.setPositionAsChild(this.position); this.textDisplays.push(newTextDisplay); } this.addStaticText = function(name, text, offset, width, color) { var animated = false; var newTextDisplay = new TextDisplay(text, offset, width, animated, color, this.fontSize); Overlays.editOverlay(newTextDisplay.overlay, {backgroundAlpha:0.0, width: width, leftMargin:this.margin.x }); newTextDisplay.setPositionAsChild(this.position); this.textDisplays.push(newTextDisplay); this._textDisplayDict[name] = newTextDisplay; } this.addDynamicText = function(name, text, offset, width, color) { var animated = true; var newTextDisplay = new TextDisplay(text, offset, width, animated, color, this.fontSize); newTextDisplay.setPositionAsChild(this.position); Overlays.editOverlay(newTextDisplay.overlay, {backgroundAlpha:0.0, width: width, leftMargin:this.margin.x }); this.textDisplays.push(newTextDisplay); this._textDisplayDict[name] = newTextDisplay; } this.setStaticText = function(name, text) { if (name in this._textDisplayDict) { // printDebug("Setting text: " + name); this._textDisplayDict[name].showStaticText(text); } } // Sets text which will animate in this.setDisplayText = function(name, text) { if (name in this._textDisplayDict) { // printDebug("Setting text: " + name); this._textDisplayDict[name].text = text; } } this.move = function(position) { this.position = position; for (var displayIndex = 0; displayIndex < this.textDisplays.length; displayIndex++) { print("Moving overlay: " + displayIndex); this.textDisplays[displayIndex].setPositionAsChild( this.position ); } } this.deleteOverlays = function() { for (var displayIndex = 0; displayIndex < this.textDisplays.length; displayIndex++) { Overlays.deleteOverlay(this.textDisplays[displayIndex].overlay); } this.textDisplays = []; } // Clears currently displayed text, if any this.clearAllDynamicText = function() { for (var i=0; i < this._animatedTextDisplays.length; i++) this._animatedTextDisplays[i].clear(); } // Clears undisplayed content this.removeAllDynamicText = function() { for (var displayIndex = 0; displayIndex < this.textDisplays.length; displayIndex++) { if (this.textDisplays[displayIndex].animated) { this.textDisplays[displayIndex].text = ""; } } } this.startAnimation_allAtOnce = function() { for (var displayIndex = 0; displayIndex < this.textDisplays.length; displayIndex++) { if (this.textDisplays[displayIndex].animated) { this.textDisplays[displayIndex].show(); this.textDisplays[displayIndex].displayStoredText(); } } } this.stopAnimation = function() { this.isAnimating = false; } this.startAnimation = function() { this.isAnimating = true; this._currentlyPlayingDisplay = 0; this._animatedTextDisplays = []; for (var displayIndex = 0; displayIndex < this.textDisplays.length; displayIndex++) { if (this.textDisplays[displayIndex].animated) { this.textDisplays[displayIndex].show(); this._animatedTextDisplays.push(this.textDisplays[displayIndex]); } } //printDebug("Num Animation layers: " + this._animatedTextDisplays.length); this.clearAllDynamicText(); if (this._animatedTextDisplays.length > 0) { this._animatedTextDisplays[this._currentlyPlayingDisplay].startAnimation(); } } // Call every frame to advance animated text displays this.scriptUpdate = function(deltaTime) { this._totalAnimTime += deltaTime; // if (this._animatedTextDisplays.length == 0) // return; // Check if running animation is done if (this.isAnimating && this._animatedTextDisplays[this._currentlyPlayingDisplay].animationFinished) { this._currentlyPlayingDisplay++; if (this._currentlyPlayingDisplay >= this._animatedTextDisplays.length) { this.isAnimating = false; return; } else { this._animatedTextDisplays[this._currentlyPlayingDisplay].startAnimation(); } } // Check if letter print timer is past interval and print a letter if (this._totalAnimTime > this.charAnimInterval) { //for (var displayIndex = 0; displayIndex < this.textDisplays.length; displayIndex++) //{ if (this.isAnimating) this._animatedTextDisplays[this._currentlyPlayingDisplay].update(); //} this._totalAnimTime = 0; } } }