audioLayer panel injection

dependencies hashes:
openFrameworks d78075f4bca6be2a2533c6e51a75cc1f18404501
ofxMsdfgen e14da13d02c4dff04fb69d7923469f606924e6c3
ofxGPUFont d482bb7cbdf6b296fa4ab5abcf73fb5ff8c8b239
ofxVariableLab 0b5f9bdebc1e5550621957e73c040c258ec6317b
ofxProfiler a868e34fa1a79189dd4fbdede2938e308535e5e8
theatre 15b2b9543be7a9ed5c8889e04df715f91d479d45
This commit is contained in:
themancalledjakob 2024-04-14 17:36:04 +02:00
parent 8353bb837c
commit 3b6a57024d
6 changed files with 281 additions and 46 deletions

View file

@ -732,3 +732,19 @@ input:disabled {
background: darkgrey; background: darkgrey;
color: lightgrey; color: lightgrey;
} }
/* ASYA: most the following code does not work*/
.onOffIndicatorWrapper input[type=checkbox] + label::after {
content: ' OFF';
}
.onOffIndicatorWrapper input[type=checkbox]:checked + label{
color: #1cba94;
}
.onOffIndicatorWrapper input[type=checkbox]:checked + label::after{
content: ' ON';
}
.onOffIndicatorWrapper {
width: auto;
}

View file

@ -1,26 +1,28 @@
import { import {
sanitizeTheatreKey, sanitizeTheatreKey,
arraysEqual, arraysEqual,
clone,
} from './utils.js'; } from './utils.js';
const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) { const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
// private // private
let props = { }; let props = { };
if (typeof values === 'string') { if (typeof values === 'string') {
const filename = sanitizeTheatreKey(values); const audioID = sanitizeTheatreKey(values);
values = {}; values = {};
values[filename] = false; values[audioID] = false;
} }
if (typeof values === 'object') { if (typeof values === 'object') {
props[Object.keys(values)[0]] = tp.core.types.boolean(false); props[Object.keys(values)[0]] = tp.core.types.boolean(false);
} }
const onValuesChangeCallbacks = []; const onValuesChangeCallbacks = [];
let hierarchyPanelButton = null;
let panelFinderTimeout = false;
// private functions // private functions
// //
const onValuesChange = (values) => { const onValuesChange = (values) => {
console.log(values);
const n_callbacks = onValuesChangeCallbacks.length; const n_callbacks = onValuesChangeCallbacks.length;
const successes = []; const successes = [];
if (n_callbacks > 0) { if (n_callbacks > 0) {
@ -38,18 +40,173 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
}); });
} }
}; };
const getHierarchyPanelButton = () => {
const findInjectPanel = () => { if (hierarchyPanelButton === null) {
console.log('AudioLayer::findInjectPanel'); hierarchyPanelButton = tp.shadowRoot.querySelector(`.layerMover${this.id()}`);
const sequencePanel = tp.getSequencePanel(); }
const sequencePanelLeft = tp.getSequencePanelLeft(); return hierarchyPanelButton;
}; };
const setTime = (filename, start, stop) => { const getPanelPropDiamond = (panelPropTitle) => {
filename = sanitizeTheatreKey(filename); return panelPropTitle.previousSibling;
};
const getPanelPropInput = (panelPropTitle) => {
return panelPropTitle
.parentElement
.nextSibling
.querySelector('input');
};
const findInjectPanel = () => {
let doItAgain = true;
console.log('AudioLayer::findInjectPanel');
const panel = tp.getPanel();
let panelSuccesses = 0;
const audioIDs = Object.keys(this.theatreObject.value);
{ // PANEL
for (let i = 0; i < audioIDs.length; i++) {
const audioID = audioIDs[i];
let panelPropTitle = tp.getPanelPropTitle(audioID);
const panelPropContainer = tp.getPanelPropContainer(panelPropTitle);
if (panelPropTitle === null || panelPropContainer == null) {
continue;
}
// Phase 1) prevent unwanted interaction
// remove theatrejs listeners
// such as contextmenu
// NOTE: this does not work with stop(Immediate)Propagation here
const tmp = panelPropTitle.cloneNode(true);
panelPropTitle.parentNode.replaceChild(tmp, panelPropTitle);
panelPropTitle = tmp;
// remove diamond
const diamond = getPanelPropDiamond(panelPropTitle);
if (diamond !== null) {
diamond.remove();
}
// unchangeable boolean
const boolean = getPanelPropInput(panelPropTitle);
boolean.disabled = true;
boolean.parentElement.classList.add('onOffIndicatorWrapper');
boolean.classList.add('onOffIndicator');
boolean.style.width = 'auto';
const container = document.createElement('div');
container.innerHTML = `
<div class="main_panel_button button delete${audioID}">
delete
</div>
`;
for (let i = 0; i < container.children.length; i++) {
panelPropContainer.append(container.children[i]);
};
panelPropContainer.querySelector(`.button.delete${audioID}`)
.addEventListener('click', () => {
this.removeFile(audioID);
});
panelSuccesses++;
};
}
if (panelSuccesses === audioIDs.length) {
doItAgain = false;
}
if (doItAgain) {
clearTimeout(panelFinderTimeout);
panelFinderTimeout = setTimeout(() => {
this.findInjectPanel();
}, 30);
}
}
const findInjectSequencePanel = () => {
let doItAgain = true;
let sequencePanelSuccess = 0;
const sequencePanel = tp.getSequencePanel();
const sequencePanelLeft = tp.getSequencePanelLeft();
if (sequencePanelLeft !== null) { // SEQUENCE PANEL LEFT
const propTitles = sequencePanelLeft.querySelectorAll('[data-testid="SequencePanel-PropTitle"]');
const audioLayerTitle = (() => {
const titles = sequencePanelLeft.querySelectorAll('[data-testid="SequencePanel-Title"]');
for (let i = 0; i < titles.length; i++) {
if (titles[i].innerHTML === this.id()) {
return titles[i];
}
}
return null;
})();
if (audioLayerTitle !== null) {
const audioSection = audioLayerTitle.closest('li');
if (audioSection !== null) {
const audioPropTitles = audioSection.querySelectorAll('[data-testid="SequencePanel-PropTitle"]');
window.audioPropTitles = audioPropTitles;
audioPropTitles.forEach((audioPropTitle) => {
const diamond = (() => {
const potential = audioPropTitle.nextSibling;
if (potential !== null
&& potential.nodeName.toLowerCase() === 'div'
&& potential.querySelectorAll(':scope > [data-pi-key]').length === 3) {
return potential;
}
return null;
})();
if (diamond !== null) {
diamond.style.display = 'none';
}
if (audioPropTitle.innerHTML.length > config.audio.maxFilenameLength) {
const file = audioPropTitle.innerHTML;
const m = (config.audio.maxFilenameLength / 2) - 2;
audioPropTitle.innerHTML = file.substr(0,m) + '..' + file.substr(file.length - m, m);
}
});
sequencePanelSuccess++;
}
}
}
if (sequencePanelLeft !== null) { // SEQUENCE PANEL RIGHT
const audioSectionAnchor = sequencePanelLeft
.nextSibling
.querySelector(`[data-pi-key*="${this.id()}"]`);
if (audioSectionAnchor !== null) {
const audioSection = audioSectionAnchor.closest('li');
if (audioSection !== null) {
audioSection.addEventListener('contextmenu', (e) => {
e.stopPropagation();
e.stopImmediatePropagation();
});
audioSection.querySelectorAll('*').forEach((element) => {
element.addEventListener('contextmenu', (e) => {
e.stopPropagation();
e.stopImmediatePropagation();
});
});
sequencePanelSuccess++;
}
}
}
if (sequencePanelSuccess === 2) {
doItAgain = false;
}
if (doItAgain) {
clearTimeout(panelFinderTimeout);
panelFinderTimeout = setTimeout(() => {
this.findInjectSequencePanel();
}, 30);
}
};
const setTime = (audioID, start, stop) => {
audioID = sanitizeTheatreKey(audioID);
return new Promise((resolve) => { return new Promise((resolve) => {
const keyframes = [{ const keyframes = [{
path: [filename], path: [audioID],
keyframes: [{ keyframes: [{
position: -1, position: -1,
value: false, value: false,
@ -67,11 +224,11 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
}, },
], ],
}]; }];
if (tp.getKeyframes(this, [filename]).length > 0) { if (tp.getKeyframes(this, [audioID]).length > 0) {
tp.studio.transaction(({ tp.studio.transaction(({
__experimental_deleteKeyframes __experimental_deleteKeyframes
}) => { }) => {
__experimental_deleteKeyframes(this.theatreObject.props[filename]); __experimental_deleteKeyframes(this.theatreObject.props[audioID]);
}); });
} }
tp.addKeyframes(this, keyframes).then(() => { tp.addKeyframes(this, keyframes).then(() => {
@ -80,6 +237,15 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
}); });
}; };
const getValue = (audioID) => {
const values = this.theatreObject.value;
if (typeof values[audioID] !== 'undefined') {
return values[audioID];
} else {
return null;
}
};
const init = () => { const init = () => {
return new Promise((resolve) => { return new Promise((resolve) => {
this.theatreObject = tp.addObject(audioLayerID, this.props, onValuesChange); this.theatreObject = tp.addObject(audioLayerID, this.props, onValuesChange);
@ -97,33 +263,21 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
}; };
const remove = () => { const remove = () => {
tp.removeObject(audioLayerID);
}; };
// public // public
this.props = props; this.props = props;
this.findInjectPanel = findInjectPanel; this.findInjectPanel = findInjectPanel;
this.findInjectSequencePanel = findInjectSequencePanel;
this.setFile = (filename) => { this.addFile = (audioID) => {
filename = sanitizeTheatreKey(filename);
const values = {};
values[filename] = false;
props = {};
props[filename] = tp.core.types.boolean(values[filename]);
this.props = props;
tp.changeObject(audioLayerID, this.props);
tp.studio.transaction(({
set
}) => {
set(this.theatreObject.props, values);
});
};
this.addFile = (filename) => {
return new Promise((resolve) => { return new Promise((resolve) => {
filename = sanitizeTheatreKey(filename); audioID = sanitizeTheatreKey(audioID);
const values = this.theatreObject.value; const values = this.theatreObject.value;
values[filename] = false; values[audioID] = false;
props[filename] = tp.core.types.boolean(values[filename]); props[audioID] = tp.core.types.boolean(values[audioID]);
this.props = props; this.props = props;
const setDummy = () => { const setDummy = () => {
@ -154,12 +308,12 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
setDummy(); setDummy();
}); });
}; };
this.removeFile = (filename) => { this.removeFile = (audioID) => {
return new Promise((resolve) => { return new Promise((resolve) => {
filename = sanitizeTheatreKey(filename); audioID = sanitizeTheatreKey(audioID);
const values = this.theatreObject.value; const values = clone(this.theatreObject.value);
delete values[filename]; delete values[audioID];
delete props[filename]; delete props[audioID];
this.props = props; this.props = props;
const setDummy = () => { const setDummy = () => {
tp.changeObject(audioLayerID, { tp.changeObject(audioLayerID, {
@ -175,16 +329,53 @@ const AudioLayer = function(tp, audioLayerID, values = false, autoInit = true) {
const givenValueKeys = Object.keys(againChangedValues); const givenValueKeys = Object.keys(againChangedValues);
if (arraysEqual(expectedValueKeys, givenValueKeys)) { if (arraysEqual(expectedValueKeys, givenValueKeys)) {
resolve(); resolve();
return true;
} else {
return false;
} }
}); });
tp.changeObject(audioLayerID, this.props); tp.changeObject(audioLayerID, this.props);
return true;
} else {
return false;
} }
}); });
setDummy(); setDummy();
if (!audio.audioPlayer.remove(audioID)) {
console.log('AudioLayer::remove', `could not remove ${audioID} from audioPlayer`);
}
}); });
}; };
this.setTime = setTime; this.setTime = setTime;
this.getValue = getValue;
this.isSelected = () => {
const panel = getHierarchyPanelButton();
if (panel === null) {
return false;
} else {
const notSelected = panel.querySelector('.not-selected');
return !notSelected;
}
};
this.select = () => {
const panel = getHierarchyPanelButton();
const selectables = panel.querySelector('.not-selected');
if (selectables !== null && typeof selectables.dispatchEvent === 'function') {
var clickEvent = new MouseEvent("click", {
"view": window,
"bubbles": true,
"cancelable": false
});
selectables.dispatchEvent(clickEvent);
} else {
window.debugElement = panel;
}
};
this.init = init; this.init = init;
this.id = () => { this.id = () => {

View file

@ -59,10 +59,20 @@ const AudioPlayer = function() {
startTime startTime
}); });
}; };
this.remove = (audioID) => {
const index = audioElements.findIndex((e) => { return e.audioID === audioID; });
if (index < 0) {
return false;
} else {
audioElements.splice(index, 1);
return true;
}
};
this.update = () => { this.update = () => {
audioElements.forEach((audioElement, i) => { audioElements.forEach((audioElement, i) => {
if (tp.isPlaying() && !record.isRecording()) { if (tp.isPlaying() && !record.isRecording()) {
const shouldBePlaying = getAudioLayer().theatreObject.value[audioElement.audioID]; const shouldBePlaying = getAudioLayer().getValue([audioElement.audioID]);
if (shouldBePlaying !== null) {
if (shouldBePlaying && audioElement.audioDomElement.paused) { if (shouldBePlaying && audioElement.audioDomElement.paused) {
// sequence position is always greater than startTime // sequence position is always greater than startTime
// this is true, as it is written // this is true, as it is written
@ -73,6 +83,9 @@ const AudioPlayer = function() {
audioElement.audioDomElement.pause(); audioElement.audioDomElement.pause();
audioElement.audioDomElement.currentTime = 0; audioElement.audioDomElement.currentTime = 0;
} }
} else {
console.log('AudioPlayer::update',`${audioElement.audioID} does not exist in audioLayer.`);
}
} else if (!audioElement.audioDomElement.paused) { } else if (!audioElement.audioDomElement.paused) {
audioElement.audioDomElement.pause(); audioElement.audioDomElement.pause();
audioElement.audioDomElement.currentTime = 0; audioElement.audioDomElement.currentTime = 0;

View file

@ -586,6 +586,9 @@ const deleteLayer = (id, saveProject = true) => {
const addAudioLayer = (filename = false) => { const addAudioLayer = (filename = false) => {
return new Promise((resolve) => { return new Promise((resolve) => {
const audioLayerID = (() => { const audioLayerID = (() => {
if (audioLayers.length === 0) {
return 'audio';
}
let index = 0; let index = 0;
for (let i = 0; i < audioLayers.length; i++) { for (let i = 0; i < audioLayers.length; i++) {
if (audioLayers.findIndex((audioLayer) => audioLayer.id() === `audio-${index}`) < 0) { if (audioLayers.findIndex((audioLayer) => audioLayer.id() === `audio-${index}`) < 0) {

View file

@ -284,6 +284,11 @@ const TheatrePlay = function(autoInit = false) {
friendlySequenceNames(); friendlySequenceNames();
}, 1000); }, 1000);
} }
// dirty, should be not in here:
if (getAudioLayers().length > 0) {
getAudioLayer().findInjectSequencePanel();
}
}; };
//public //public

View file

@ -372,6 +372,12 @@ function getParents(elem, until = null) {
return parents; return parents;
} }
function removeAllEventListeners(elem) {
const tmp = elem.cloneNode(true);
elem.parentNode.replaceChild(tmp, elem);
elem = tmp;
}
function arraysEqual(a, b, sortingMatters = false) { function arraysEqual(a, b, sortingMatters = false) {
if (a === b) return true; if (a === b) return true;
if (a == null || b == null) return false; if (a == null || b == null) return false;
@ -618,6 +624,7 @@ export {
mixObject, mixObject,
clone, clone,
getParents, getParents,
removeAllEventListeners,
arraysEqual, arraysEqual,
mapValue, mapValue,
smoothValue, smoothValue,