From a7c021e9cf410e705aac64c8ce775d3a6ab0d6a2 Mon Sep 17 00:00:00 2001 From: William Toohey Date: Tue, 29 Dec 2015 00:56:02 +1000 Subject: [PATCH] Convert UI to callbacks - reduce dependency on the Core. --- js/HuesCore.js | 123 ++++++++++++++++++++++++++++++++++++++++--------- js/HuesUI.js | 107 ++++++++++++++++++++++-------------------- 2 files changed, 157 insertions(+), 73 deletions(-) diff --git a/js/HuesCore.js b/js/HuesCore.js index 341e5ed..266c619 100644 --- a/js/HuesCore.js +++ b/js/HuesCore.js @@ -37,6 +37,60 @@ function HuesCore(defaults) { this.loopCount = 0; this.doBuildup = true; this.userInterface = null; + + this.eventListeners = { + /* callback time(hundredths) + * + * When the song time is updated - 0 for buildup, integer 10ths + * of a second otherwise + */ + time : [], + /* callback blurUpdate(xPercent, yPercent) + * + * The current blur amounts, in percent of full blur + */ + blurupdate : [], + + /* callback newsong(song) + * + * Called on song change, whether user triggered or autosong. + * Song object is passed. + */ + newsong : [], + /* callback newimage(image) + * + * Called on image change, whether user triggered or FULL AUTO mode. + * Image object is passed. + */ + newimage : [], + /* callback newimage(image) + * + * Called on colour change. + * Colour object is passed. + */ + newcolour : [], + /* callback newmode(mode) + * + * Called on mode change. + * Mode is passed as a boolean. + */ + newmode : [], + /* callback beat(beatString, beatIndex) + * + * Called on every new beat. + * beatString is a 256 char long array of current and upcoming beat chars + * beatIndex is a "safe to display" beat index. 0 during buildups, + * index % beatmap length otherwise. + */ + beat : [], + /* callback invert(isInverted) + * + * Called whenever the invert state changes. + * Invert state is passed as a boolean. + */ + invert : [] + + }; var that = this; window.onerror = function(msg, url, line, col, error) { @@ -118,6 +172,33 @@ function HuesCore(defaults) { this.animationLoop(); } +HuesCore.prototype.callEventListeners = function(ev) { + var args = Array.prototype.slice.call(arguments, 1); + this.eventListeners[ev].forEach(function(callback) { + callback.apply(null, args); + }); +} + +HuesCore.prototype.addEventListener = function(ev, callback) { + ev = ev.toLowerCase(); + if (typeof(this.eventListeners[ev]) !== "undefined") { + this.eventListeners[ev].push(callback); + } else { + throw Error("Unknown event: " + ev); + } +}; + +HuesCore.prototype.removeEventListener = function(ev, callback) { + ev = ev.toLowerCase(); + if (typeof(this.eventListeners[ev]) !== "undefined") { + this.eventListeners[ev] = this.eventListeners[ev].filter(function(a) { + return (a !== callback); + }); + } else { + throw Error("Unknown event: " + ev); + } +}; + HuesCore.prototype.resizeVisualiser = function() { this.soundManager.initVisualiser(this.visualiser.width/2); } @@ -169,9 +250,9 @@ HuesCore.prototype.animationLoop = function() { this.updateVisualiser(); var now = this.soundManager.currentTime(); if(now < 0) { - this.userInterface.updateTime(0); + this.callEventListeners("time", 0); } else { - this.userInterface.updateTime(this.soundManager.displayableTime()); + this.callEventListeners("time", this.soundManager.displayableTime()); if(this.doBuildup) { this.currentSong.buildupPlayed = true; } @@ -184,10 +265,6 @@ HuesCore.prototype.animationLoop = function() { requestAnimationFrame(function() {that.animationLoop();}); }; -HuesCore.prototype.getCurrentMode = function() { - return this.isFullAuto ? "FULL AUTO" : "NORMAL"; -}; - HuesCore.prototype.getSafeBeatIndex = function() { if(!this.soundManager.playing) { return 0; @@ -200,7 +277,7 @@ HuesCore.prototype.getSafeBeatIndex = function() { }; HuesCore.prototype.blurUpdated = function(x, y) { - this.userInterface.blurUpdated(x, y); + this.callEventListeners("blurupdate", x, y); }; HuesCore.prototype.nextSong = function() { @@ -237,7 +314,7 @@ HuesCore.prototype.setSong = function(index) { this.currentSong = {"name":"None", "title":"None", "rhythm":".", "source":null, "crc":"none", "sound":null, "enabled":true, "filename":"none"}; } console.log("Next song:", this.songIndex, this.currentSong); - this.userInterface.setSongText(); + this.callEventListeners("newsong", this.currentSong); this.loopCount = 0; if (this.currentSong.buildup) { switch (localStorage["playBuildups"]) { @@ -340,8 +417,8 @@ HuesCore.prototype.doAutoSong = function() { HuesCore.prototype.songDataUpdated = function() { if (this.currentSong) { this.beatLength = 0; - this.userInterface.setSongText(); - this.userInterface.setImageText(); + this.callEventListeners("newsong", this.currentSong); + this.callEventListeners("newimage", this.currentImage); } else { this.beatLength = -1; } @@ -385,7 +462,7 @@ HuesCore.prototype.setImage = function(index) { this.lastImageArray = []; } this.renderer.setImage(this.currentImage); - this.userInterface.setImageText(); + this.callEventListeners("newimage", this.currentImage); }; HuesCore.prototype.setImageByName = function(name) { @@ -428,8 +505,9 @@ HuesCore.prototype.randomColour = function(isFade) { HuesCore.prototype.setColour = function(index, isFade) { this.colourIndex = index; - this.renderer.setColour(this.colours[this.colourIndex].c, isFade); - this.userInterface.setColourText(); + var colour = this.colours[this.colourIndex]; + this.renderer.setColour(colour.c, isFade); + this.callEventListeners("newcolour", colour); }; HuesCore.prototype.getBeat = function(index) { @@ -441,7 +519,7 @@ HuesCore.prototype.getBeat = function(index) { }; HuesCore.prototype.beater = function(beat) { - this.userInterface.beat(); + this.callEventListeners("beat", this.getBeatString(), this.getSafeBeatIndex()); this.renderer.beat(); switch(beat) { case 'X': @@ -536,7 +614,7 @@ HuesCore.prototype.getBeatString = function(length) { HuesCore.prototype.setIsFullAuto = function(auto) { this.isFullAuto = auto; if (this.userInterface) { - this.userInterface.modeUpdated(); + this.callEventListeners("newmode", this.isFullAuto); } }; @@ -553,7 +631,7 @@ HuesCore.prototype.setInvert = function(invert) { document.documentElement.style.filter = ""; document.documentElement.style.webkitFilter = ""; } - this.userInterface.invert(invert); + this.callEventListeners("invert", invert); } HuesCore.prototype.toggleInvert = function() { @@ -567,15 +645,16 @@ HuesCore.prototype.respackLoaded = function() { HuesCore.prototype.changeUI = function(index) { if (index >= 0 && this.uiArray.length > index && this.userInterface != this.uiArray[index]) { this.hideLists(); - if(this.userInterface) + if(this.userInterface) { this.userInterface.disconnect(); + } this.userInterface = this.uiArray[index]; this.userInterface.connectCore(this); - this.userInterface.setSongText(); - this.userInterface.setImageText(); - this.userInterface.setColourText(this.colourIndex); - this.userInterface.beat(); - this.userInterface.modeUpdated(); + this.callEventListeners("newmode", this.isFullAuto); + this.callEventListeners("newsong", this.currentSong); + this.callEventListeners("newimage", this.currentImage); + this.callEventListeners("newcolour", this.colours[this.colourIndex]); + this.callEventListeners("beat", this.getBeatString(), this.getSafeBeatIndex()); } }; diff --git a/js/HuesUI.js b/js/HuesUI.js index 46f208b..12f3b48 100644 --- a/js/HuesUI.js +++ b/js/HuesUI.js @@ -55,6 +55,11 @@ function HuesUI(parent) { this.settingsToggle = null; this.hideToggle = null; + + // To deregister on UI hide we need to keep track of these + // Each callback is { name : "callbackname", func : function } + // Add using this.addCoreCallback + this.callbacks = []; // Put this near the links to song/image lists/ Bottom right alignment this.listContainer = null; @@ -66,6 +71,10 @@ function HuesUI(parent) { this.initUI(); } +HuesUI.prototype.addCoreCallback = function(name, func) { + this.callbacks.push({name : name, func : func}); +} + HuesUI.prototype.initUI = function() { var that = this; @@ -119,7 +128,7 @@ HuesUI.prototype.initUI = function() { this.timer.textContent = "T=$0x0000"; this.beatCount = document.createElement("div"); - this.beatCount.textContent = "B=$0x000"; + this.beatCount.textContent = "B=$0x0000"; this.xBlur = document.createElement("div"); this.xBlur.textContent = "X=$0x00"; @@ -143,9 +152,12 @@ HuesUI.prototype.initUI = function() { this.listContainer = document.createElement("div"); this.visualiserContainer = document.createElement("div"); - this.resizeHandler = function() { - that.resize(); - }; + this.addCoreCallback("newsong", this.newSong.bind(this)); + this.addCoreCallback("newimage", this.newImage.bind(this)); + this.addCoreCallback("newcolour", this.newColour.bind(this)); + this.addCoreCallback("blurupdate", this.blurUpdated.bind(this)); + this.addCoreCallback("time", this.updateTime.bind(this)); + this.resizeHandler = this.resize.bind(this); }; HuesUI.prototype.connectCore = function(core) { @@ -156,6 +168,9 @@ HuesUI.prototype.connectCore = function(core) { } this.visualiserContainer.appendChild(this.core.visualiser); + this.callbacks.forEach(function(callback) { + core.addEventListener(callback.name, callback.func); + }); window.addEventListener('resize', this.resizeHandler); this.resizeHandler(); }; @@ -169,7 +184,10 @@ HuesUI.prototype.disconnect = function() { while (this.visualiserContainer.firstElementChild) { this.visualiserContainer.removeChild(this.visualiserContainer.firstElementChild); } - + + this.callbacks.forEach(function(callback) { + core.removeEventListener(callback.name, callback.func); + }); window.removeEventListener('resize', this.resizeHandler); }; @@ -192,16 +210,10 @@ HuesUI.prototype.toggleHide = function() { } }; -// May do nothing, may scale elements if needed etc etc HuesUI.prototype.resize = function() {}; -HuesUI.prototype.modeUpdated = function() {}; -HuesUI.prototype.beat = function() {}; HuesUI.prototype.updateVolume = function(vol) {}; -HuesUI.prototype.invert = function(invert) {}; - -HuesUI.prototype.setSongText = function() { - var song = this.core.currentSong; +HuesUI.prototype.newSong = function(song) { if(!song) { return; } @@ -210,9 +222,7 @@ HuesUI.prototype.setSongText = function() { this.songLink.href = song.source; }; -HuesUI.prototype.setImageText = function() { - var image = this.core.currentImage; - +HuesUI.prototype.newImage = function(image) { if(!image) { return; } @@ -223,9 +233,7 @@ HuesUI.prototype.setImageText = function() { this.imageLink.href = image.source ? image.source : ""; }; -HuesUI.prototype.setColourText = function() { - var colour = this.core.colours[this.core.colourIndex]; - +HuesUI.prototype.newColour = function(colour) { this.hueName.textContent = colour.n.toUpperCase(); }; @@ -357,6 +365,9 @@ RetroUI.prototype.initUI = function() { this.visualiserContainer.className = "hues-r-visualisercontainer"; this.root.appendChild(this.visualiserContainer); + + this.addCoreCallback("beat", this.beat.bind(this)); + this.addCoreCallback("newmode", this.newMode.bind(this)); }; RetroUI.prototype.toggleHide = function(stylename) { @@ -379,16 +390,13 @@ RetroUI.prototype.connectCore = function(core) { HuesUI.prototype.connectCore.call(this, core); this.version.textContent = "V=$" + core.version; - this.modeUpdated(); }; -RetroUI.prototype.modeUpdated = function() { - this.mode.textContent = "M=" + this.core.getCurrentMode(); +RetroUI.prototype.newMode = function(isAuto) { + this.mode.textContent = "M=" + (isAuto ? "FULL AUTO" : "NORMAL"); }; -RetroUI.prototype.setImageText = function() { - var image = this.core.currentImage; - +RetroUI.prototype.newImage = function(image) { if(!image) { return; } @@ -397,19 +405,16 @@ RetroUI.prototype.setImageText = function() { this.imageLink.href = image.source; }; -RetroUI.prototype.setColourText = function(colour) { - HuesUI.prototype.setColourText.call(this, colour); +RetroUI.prototype.newColour = function(colour) { + HuesUI.prototype.newColour.call(this, colour); this.colourIndex.textContent = "C=" + this.intToHex2(this.core.colourIndex); }; -RetroUI.prototype.beat = function() { - var beats = this.core.getBeatString(); +RetroUI.prototype.beat = function(beats, index) { var rest = beats.slice(1); - this.beatBar.textContent = ">>" + rest; - - this.beatCount.textContent = "B=" + this.intToHex3(this.core.getSafeBeatIndex()); + this.beatCount.textContent = "B=" + this.intToHex3(index); }; RetroUI.prototype.resize = function() { @@ -465,14 +470,13 @@ WeedUI.prototype.toggleHide = function() { RetroUI.prototype.toggleHide.call(this, 'w'); }; -WeedUI.prototype.beat = function() { - var beats = this.core.getBeatString(); +WeedUI.prototype.beat = function(beats, index) { var rest = beats.slice(1); this.beatLeft.textContent = rest; this.beatRight.textContent = rest; - this.beatCount.textContent = "B=" + this.intToHex3(this.core.getSafeBeatIndex()); + this.beatCount.textContent = "B=" + this.intToHex3(index); if(["x", "o", "X", "O"].indexOf(beats[0]) != -1) { var beatCenter = document.createElement("div"); @@ -684,6 +688,9 @@ ModernUI.prototype.initUI = function() { this.listContainer.className = "hues-m-listcontainer"; this.root.appendChild(this.listContainer); + + this.addCoreCallback("beat", this.beat.bind(this)); + this.addCoreCallback("newmode", this.newMode.bind(this)); }; ModernUI.prototype.toggleHide = function() { @@ -713,17 +720,15 @@ ModernUI.prototype.updateVolume = function(vol) { } }; -ModernUI.prototype.modeUpdated = function() { - if(this.core.isFullAuto) { +ModernUI.prototype.newMode = function(isAuto) { + if(isAuto) { this.imageMode.innerHTML = ''; // PAUSE; } else { this.imageMode.innerHTML = "▶"; // PLAY } }; -ModernUI.prototype.beat = function() { - var beats = this.core.getBeatString(); - +ModernUI.prototype.beat = function(beats, index) { this.currentBeat = beats[0]; var rest = beats.slice(1); @@ -739,7 +744,7 @@ ModernUI.prototype.beat = function() { span.textContent = this.currentBeat; this.beatCenter.appendChild(span); } - this.beatCount.textContent = "B=" + this.intToHex4(this.core.getSafeBeatIndex()); + this.beatCount.textContent = "B=" + this.intToHex4(index); }; ModernUI.prototype.resize = function() { @@ -767,20 +772,20 @@ ModernUI.prototype.resizeImage = function() { this.resizeElement(this.imageLink, this.imageName); }; -ModernUI.prototype.setSongText = function() { - HuesUI.prototype.setSongText.call(this); +ModernUI.prototype.newSong = function(song) { + HuesUI.prototype.newSong.call(this, song); - if(!this.core.currentSong) { + if(!song) { return; } this.resizeSong(); }; -ModernUI.prototype.setImageText = function() { - HuesUI.prototype.setImageText.call(this); +ModernUI.prototype.newImage = function(image) { + HuesUI.prototype.newImage.call(this, image); - if(!this.core.currentImage) { + if(!image) { return; } @@ -913,8 +918,8 @@ XmasUI.prototype.newLight = function(l, parent) { return light; }; -XmasUI.prototype.beat = function() { - ModernUI.prototype.beat.call(this); +XmasUI.prototype.beat = function(beats, index) { + ModernUI.prototype.beat.call(this, beats, index); if(this.currentBeat != ".") { this.lights.forEach(function(light, i, a) { switch(this.currentBeat) { @@ -932,7 +937,7 @@ XmasUI.prototype.beat = function() { } }; -XmasUI.prototype.setColourText = function(colour) {}; +XmasUI.prototype.newColour = function(colour) {}; XmasUI.prototype.blurUpdated = function(x, y) {}; XmasUI.prototype.updateTime = function(time) {}; @@ -1012,8 +1017,8 @@ HalloweenUI.prototype.initUI = function() { this.root.appendChild(this.vignette); } -HalloweenUI.prototype.beat = function() { - ModernUI.prototype.beat.call(this); +HalloweenUI.prototype.beat = function(beats, index) { + ModernUI.prototype.beat.call(this, beats, index); if (this.currentBeat != ".") { var eyes = this.beatCenter.ownerDocument.createElement("div");