diff --git a/src/control.js b/src/control.js index 133fabb..9f3d4e6 100644 --- a/src/control.js +++ b/src/control.js @@ -353,6 +353,30 @@ function defaultCue(time) { return { time, effectIndex: null, effectName: '', text: '', textStyle: null, image: null, imageSize: 60, imagePos: 'center' }; } +// Build the '; + EFFECTS.families.forEach((name, i) => { + s += ''; + }); + return s; +} +// Build the '; + let s = ''; + for (let i = 0; i < EFFECTS.list.length; i++) { + if (EFFECTS.list[i].family !== fam) continue; + s += ''; + } + return s; +} +// First preset index of a family (used when a family is chosen). +function firstPresetOfFamily(fam) { + for (let i = 0; i < EFFECTS.list.length; i++) if (EFFECTS.list[i].family === fam) return i; + return -1; +} + // Build the per-track scene editor (timeline of cues with text + image styling). function buildSceneEditor(tr, i, li) { const cues = tr.cues || (tr.cues = []); @@ -364,14 +388,26 @@ function buildSceneEditor(tr, i, li) { const posLabels = { center: 'Centro', top: 'Alto', bottom: 'Basso', left: 'Sinistra', right: 'Destra' }; let html = '
🎬 Scene a tempo — la cue @00:00 parte col brano, le altre scattano al loro tempo
'; cues.forEach((c, ci) => { + const ce = (c.effectIndex != null && EFFECTS.list[c.effectIndex]) ? EFFECTS.list[c.effectIndex] : null; + const cFam = ce ? ce.family : -1; html += '
' + '
' + '@' + '' + - '' + (ci > 0 ? '' : 'base') + '
' + + '
' + + '
🌀 Effetto
' + + '
' + + '' + + '' + + '
' + + '
' + + '' + + '' + (ce ? ce.name : 'nessuno') + '' + + '
' + + '
' + '
' + '
🔤 Testo
' + '' + @@ -404,7 +440,17 @@ function buildSceneEditor(tr, i, li) { const c = cues[ci]; cueEl.querySelector('.cue-text').value = c.text || ''; cueEl.querySelector('.cue-time').addEventListener('change', (e) => { c.time = parseTime(e.target.value); savePlaylistState(); renderPlaylist(); }); - cueEl.querySelector('.cue-eff').addEventListener('click', () => { c.effectIndex = EFFECTS.list.indexOf(currentEffect); c.effectName = currentEffect.name; savePlaylistState(); renderPlaylist(); }); + cueEl.querySelector('.cue-eff-fam').addEventListener('change', (e) => { + const fam = parseInt(e.target.value, 10); + if (fam < 0) { c.effectIndex = null; c.effectName = ''; } + else { const idx = firstPresetOfFamily(fam); c.effectIndex = idx; c.effectName = idx >= 0 ? EFFECTS.list[idx].name : ''; } + savePlaylistState(); renderPlaylist(); + }); + cueEl.querySelector('.cue-eff-pre').addEventListener('change', (e) => { + const idx = parseInt(e.target.value, 10); + if (idx >= 0 && EFFECTS.list[idx]) { c.effectIndex = idx; c.effectName = EFFECTS.list[idx].name; savePlaylistState(); renderPlaylist(); } + }); + cueEl.querySelector('.cue-eff-cur').addEventListener('click', () => { c.effectIndex = EFFECTS.list.indexOf(currentEffect); c.effectName = currentEffect.name; savePlaylistState(); renderPlaylist(); }); cueEl.querySelector('.cue-text').addEventListener('input', (e) => { c.text = e.target.value; li.querySelector('.scene-btn').classList.toggle('active', hasScene(tr)); savePlaylistState(); }); cueEl.querySelector('.cue-tstyle').addEventListener('click', () => { c.textStyle = captureTextStyle(); savePlaylistState(); renderPlaylist(); }); const tsc = cueEl.querySelector('.cue-tstyle-clear'); diff --git a/src/output.js b/src/output.js index bf7a714..b321af9 100644 --- a/src/output.js +++ b/src/output.js @@ -332,10 +332,14 @@ djv.onControl(async (m) => { case 'playVideoTrack': try { audio.onEnded = () => djv.report({ type: 'trackEnded' }); - trackVideo.loop = false; trackVideo.muted = false; - trackVideo.src = toFileURL(m.path); - trackVideo.classList.add('show'); audio.attachVideo(trackVideo); + trackVideo.loop = false; trackVideo.muted = false; + // Force a fresh start even when re-selecting the same file: + // reassigning the same src may not reload, so pause + load() resets it. + trackVideo.pause(); + trackVideo.src = toFileURL(m.path); + trackVideo.load(); + trackVideo.classList.add('show'); await trackVideo.play(); hideHint(); djv.report({ type: 'playState', playing: true }); diff --git a/src/style.css b/src/style.css index 1cfe070..df30f14 100644 --- a/src/style.css +++ b/src/style.css @@ -372,8 +372,10 @@ textarea.textarea-lg { .scene-editor .cue-head { display: flex; align-items: center; gap: 6px; } .scene-editor .cue-at { opacity: 0.5; flex: 0 0 auto; } .scene-editor .cue-time { width: 60px; flex: 0 0 auto; text-align: center; padding: 6px 4px; font-variant-numeric: tabular-nums; } -.scene-editor .cue-eff { flex: 1; min-width: 0; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.scene-editor .cue-del { flex: 0 0 auto; color: #ff9a9a; } +.scene-editor .cue-del { flex: 0 0 auto; color: #ff9a9a; margin-left: auto; } +.scene-editor .cue-eff-fam, .scene-editor .cue-eff-pre { flex: 1; min-width: 0; } +.scene-editor .cue-eff-cur { flex: 0 0 auto; } +.scene-editor .cue-eff-name { flex: 1; min-width: 0; font-size: 10px; opacity: 0.72; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .scene-editor .cue-base { flex: 0 0 auto; font-size: 9px; opacity: 0.45; padding: 0 4px; } .scene-editor .cue-block { background: rgba(255,255,255,0.035); border-radius: 8px; padding: 7px 8px; margin-top: 7px; }