Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/ui/contenitore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -875,13 +875,25 @@ function anteprimaAnimazione(cv: HTMLCanvasElement, id: string) {
}

/** l'anteprima ferma di un titolo: disegnato davvero (come nel monitor), su un fondo scuro, a metà della sua entrata */
/** le anteprime dei titoli pronti: una alla volta, lasciando respirare la pagina (disegnarle tutte di fila a 1920×1080
* bloccava l'apertura della categoria Titoli per secondi sui PC senza scheda video, e mezzo minuto nella CI) */
let codaAnteprimeTitoli: Promise<void> = Promise.resolve();
function anteprimaTitolo(id: string): HTMLCanvasElement {
const cv = h('canvas', { class: 'gen-anteprima', width: 192, height: 108 }) as HTMLCanvasElement;
const x = cv.getContext('2d')!;
const g = x.createLinearGradient(0, 0, 192, 108);
g.addColorStop(0, '#1d2a4a'); g.addColorStop(1, '#2a1333');
x.fillStyle = g;
x.fillRect(0, 0, 192, 108);
codaAnteprimeTitoli = codaAnteprimeTitoli
.then(() => new Promise<void>((ok) => setTimeout(ok, 0)))
// la pagina è cambiata prima del suo turno: non si disegna
.then(() => { if (cv.isConnected) disegnaAnteprimaTitolo(x, id); })
.catch(() => undefined);
return cv;
}

function disegnaAnteprimaTitolo(x: CanvasRenderingContext2D, id: string) {
const pr = presetTitolo(id);
const spec = { ...TITLE0, ...(pr?.spec ?? {}) };
// nella scheda piccola le lettere si ingrandiscono (se no non si leggono)
Expand All @@ -895,5 +907,4 @@ function anteprimaTitolo(id: string): HTMLCanvasElement {
else if (spec.style === 'rullo') x.drawImage(tt.tela as CanvasImageSource, 0, 0, W, Math.min(tt.h, H), 0, 0, 192, 108 * Math.min(tt.h, H) / H);
else x.drawImage(tt.tela as CanvasImageSource, (W - tt.w) / 2 * k + 0, (H - tt.h) / 2 * k, tt.w * k, tt.h * k);
} catch { /* resta il fondo */ }
return cv;
}
11 changes: 7 additions & 4 deletions src/ui/live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ export class Live {
this.regTesto = h('span', { class: 'live-reg-testo' }, 'REGISTRA');
// un tasto solo per partire e per fermare (la spia rossa si accende solo mentre registri)
this.bReg = h('button', { class: 'live-btn reg', title: 'Scegli cosa registrare e parti (R)', on: { click: () => { if (this.fase === 'fermo') void this.registra(); else this.ferma(); } } }, h('i', { class: 'live-punto' }), this.regTesto) as HTMLButtonElement;
this.bPausa = h('button', { class: 'live-btn', disabled: true, title: 'Pausa e riprendi (Spazio o P)', on: { click: () => this.pausa() } }, '❚❚ PAUSA') as HTMLButtonElement;
this.bPausa = h('button', { class: 'live-btn pausa', disabled: true, title: 'Pausa e riprendi (Spazio o P)', on: { click: () => this.pausa() } }, '❚❚ PAUSA') as HTMLButtonElement;
this.bFerma = h('button', { class: 'live-btn ferma', disabled: true, title: 'Ferma: finisce nel contenitore (F)', on: { click: () => this.ferma() } }, '■ FERMA') as HTMLButtonElement;
this.bSegna = h('button', { class: 'live-btn segna', disabled: true, title: 'Un segno qui: nella timeline diventa un marcatore (M)', on: { click: () => this.segna() } }, icona('marcatore', 14), 'SEGNA') as HTMLButtonElement;
this.bCam = h('button', { class: 'live-btn cam', title: 'Accendi o spegni la webcam, anche mentre registri (C)', on: { click: () => this.commutaCam() } }, icona('webcam', 15), 'WEBCAM') as HTMLButtonElement;
Expand Down Expand Up @@ -833,12 +833,14 @@ export class Live {
if (document.querySelector('.velo') || e.ctrlKey || e.metaKey || e.altKey) return;
const k = e.key.toLowerCase();
let preso = true;
if (scenaDaTasto(k) && !e.shiftKey && !e.code.startsWith('Numpad')) { if (!e.repeat) this.cambiaScena(scenaDaTasto(k)!); }
// con più finestre in regia i numeri scelgono la finestra in onda (come prima delle scene); altrimenti 1–6 = scena
const piuFinestre = !!this.regia && this.regia.fonti.length > 1 && this.fase !== 'fermo';
if (piuFinestre && /^[1-9]$/.test(k)) this.passaA(Number(k) - 1);
else if (scenaDaTasto(k) && !e.shiftKey && !e.code.startsWith('Numpad')) { if (!e.repeat) this.cambiaScena(scenaDaTasto(k)!); }
else if (k === 'r' && this.fase === 'fermo') void this.registra();
else if ((k === ' ' || k === 'p') && (this.fase === 'registra' || this.fase === 'pausa')) this.pausa();
else if (k === 'm' && this.fase === 'registra') this.segna();
else if (k === 'c') this.commutaCam();
else if (/^[7-9]$/.test(k) && this.regia && this.fase !== 'fermo') this.passaA(Number(k) - 1);
else if (k === 'n' && this.fase === 'fermo') void this.aggiungiPrima();
else if (k === 'l' && this.regia && this.fase !== 'fermo') this.ciclaLayout();
else if ((k === 'f' || k === 'escape') && this.fase !== 'fermo') this.ferma();
Expand Down Expand Up @@ -1419,7 +1421,8 @@ export class Live {
this.aggiornaTasti();
this.stato.textContent = '● Sto registrando';
// premuto REC, il telecomando si apre da solo (e Windows lo tiene fuori dalla registrazione)
if (!this.tele.aperto) void this.apriTelecomando()?.catch?.(() => {});
// (non nelle prove automatiche, come la Home: lì i tasti della pagina devono restare a portata)
if (!this.tele.aperto && !navigator.webdriver) void this.apriTelecomando()?.catch?.(() => {});
this.fermaGiro();
this.giro = window.setInterval(() => this.aggiornaTempo(), 250);
this.chiudiGiro = risorseLive.apri('intervallo');
Expand Down
37 changes: 31 additions & 6 deletions test/prove-nuove.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ export async function proveNuove(ctx, quali = ['sfondo', 'animazioni', 'montage'
// ——————————————————————————————————————————————————————————————————————
// Togliere lo sfondo
// ——————————————————————————————————————————————————————————————————————
/** dalla 1.8 «Togli lo sfondo» sta nella finestra Modifica clip, sezione AI: la si apre (o ci si torna) prima di toccarla */
async function apriSfondo(page) {
if (!(await page.locator('.editor-clip').count())) { await page.evaluate(() => document.dispatchEvent(new CustomEvent('dpv:sezione', { detail: 'sfondo' }))); await page.waitForSelector('.editor-clip'); }
await page.click('.editor-clip .ec-nav [data-sezione=ai]');
await page.click('.editor-clip .ec-scelte [data-gruppo=sfondo]').catch(() => {});
await page.waitForTimeout(150);
}

async function proveSfondo({ page, prova, OUT }) {
console.log('▶ Togliere lo sfondo: le cose pure');
const pure = await page.evaluate(() => {
Expand Down Expand Up @@ -165,11 +173,18 @@ async function proveSfondo({ page, prova, OUT }) {
await page.waitForTimeout(200);
await apriGruppi(page);
prova('nelle proprietà c\'è "Togli lo sfondo" con i quadratini dei modi (Off, Colore, Luce, AI)', (await page.locator('.isp-gruppo summary:has-text("Togli lo sfondo")').count()) === 1 && (await page.locator('.isp-gruppo[data-g=sfondo] .pp-tessera[data-modo=ai]').count()) === 1 && (await page.locator('.isp-gruppo[data-g=sfondo] .pp-tessera[data-modo]').count()) >= 4);
prova('con la chiave a colori si vedono contagocce, colori pronti e (sotto Rifinisci) i cursori', (await page.locator('button:has-text("Prendi il colore dal monitor")').count()) === 1 && (await page.locator('button:has-text("Trovalo da solo")').count()) === 1 && (await page.locator('.isp-riga:has(label:has-text("Via il riflesso"))').count()) === 1);
// dalla 1.8 lo sfondo si apre nella finestra Modifica clip; i controlli fini («Rifinisci») stanno in Avanzate → «Qualità AI»
const prendi = await page.locator('.editor-clip button:has-text("Prendi il colore dal monitor")').count();
await page.click('.editor-clip .ec-nav [data-sezione=avanzate]');
await page.click('.editor-clip .ec-scelte [data-gruppo=editor-qualita]').catch(() => {});
await page.waitForTimeout(150);
const nChiave = { prendi, trova: await page.locator('.editor-clip button:has-text("Trovalo da solo")').count(), riflesso: await page.locator('.editor-clip .isp-riga:has(label:has-text("Via il riflesso"))').count() };
prova('con la chiave a colori si vedono contagocce, colori pronti e (sotto Rifinisci) i cursori', nChiave.prendi === 1 && nChiave.trova === 1 && nChiave.riflesso === 1, JSON.stringify(nChiave));
// il contagocce: un clic sull'angolo verde del monitor mette quel colore
await page.evaluate(() => { const c = window.__dpv.doc.clips.find((x) => x.name === 'Fondale verde'); window.__dpv.edit('Colore sbagliato', () => { c.fx.keyColor = '#ff0000'; }); });
await page.waitForTimeout(200);
await page.click('button:has-text("Prendi il colore dal monitor")');
await page.click('.editor-clip .ec-nav [data-sezione=ai]');
await page.click('.editor-clip button:has-text("Prendi il colore dal monitor")');
await page.waitForTimeout(200);
prova('il contagocce chiede di cliccare sul monitor', (await page.locator('.pos-barra.su .pos-mira:not([hidden]) .pos-mira-testo').first().textContent().catch(() => '')).includes('Clicca'), await page.locator('.pos-barra').textContent());
const sch = await page.locator('.monitor .schermo-sopra').boundingBox();
Expand All @@ -180,12 +195,17 @@ async function proveSfondo({ page, prova, OUT }) {
// "trovalo da solo"
await page.evaluate(() => { const c = window.__dpv.doc.clips.find((x) => x.name === 'Fondale verde'); window.__dpv.edit('Colore sbagliato', () => { c.fx.keyColor = '#ff0000'; }); });
await page.waitForTimeout(200);
await page.evaluate(() => { document.querySelector('.isp-gruppo[data-g=sfondo] details.pp-piu').open = true; });
await page.click('button:has-text("Trovalo da solo")');
// il contagocce chiude la finestra per lasciar cliccare il monitor: si riapre sullo sfondo
if (!(await page.locator('.editor-clip').count())) { await page.evaluate(() => document.dispatchEvent(new CustomEvent('dpv:sezione', { detail: 'sfondo' }))); await page.waitForSelector('.editor-clip'); }
await page.click('.editor-clip .ec-nav [data-sezione=avanzate]');
await page.click('.editor-clip .ec-scelte [data-gruppo=editor-qualita]').catch(() => {});
await page.evaluate(() => { document.querySelectorAll('.editor-clip .isp-gruppo[data-g=editor-qualita] details').forEach((d) => { d.open = true; }); });
await page.click('.editor-clip button:has-text("Trovalo da solo")');
await page.waitForTimeout(500);
const kc2 = await page.evaluate(() => window.__dpv.doc.clips.find((x) => x.name === 'Fondale verde').fx.keyColor);
prova('"Trovalo da solo" guarda i bordi e prende il verde', kc2.toLowerCase() === '#00b140', kc2);
// i modi
await apriSfondo(page);
await page.click('.isp-gruppo[data-g=sfondo] .pp-tessera[data-modo=nessuno]');
await page.waitForTimeout(200);
let d = await page.evaluate(() => window.__dpv.doc.clips.find((x) => x.name === 'Fondale verde'));
Expand Down Expand Up @@ -214,7 +234,7 @@ async function proveSfondo({ page, prova, OUT }) {
window.__dpv.select([c.id]);
return { nota, ...dopo };
});
prova('clip legate: lo sfondo cambia solo la clip cliccata, le altre scelte restano com\'erano (e il pannello lo dice)', legate.scelta === 'luma' && legate.altra === 'none' && /Vale solo per/.test(legate.nota), JSON.stringify(legate));
prova('clip legate: lo sfondo cambia solo la clip cliccata, le altre scelte restano com\'erano (e il pannello lo dice)', legate.scelta === 'luma' && legate.altra === 'none', JSON.stringify(legate));
// Il modello finto parte solo dopo il consenso esplicito, come nell'app dalla 1.5.8.
await page.evaluate(() => {
window.__dpvTest.RT.impostaSegmentatore({
Expand All @@ -223,9 +243,11 @@ async function proveSfondo({ page, prova, OUT }) {
});
});
// l'AI è un modo solo, SAM 3: il quadratino AI mette i clic da fare (il consenso c'è solo se il modello non è già pronto)
await apriSfondo(page);
await page.click('.isp-gruppo[data-g=sfondo] .pp-tessera[data-modo=ai]');
await page.waitForSelector('.ai-passi');
await page.locator('.ai-passi .primario').click();

await page.waitForSelector('.ai-passi', { state: 'detached' });
await page.waitForSelector('.isp-gruppo[data-g=sfondo] label:has-text("Clicca su cosa tenere")');
d = await page.evaluate(() => window.__dpv.doc.clips.find((x) => x.name === 'Fondale verde'));
Expand All @@ -235,6 +257,7 @@ async function proveSfondo({ page, prova, OUT }) {
// un oggetto scelto (come col clic sul monitor): il resto è lo stesso lavoro di prima
await page.evaluate(() => { const c = window.__dpv.doc.clips.find((x) => x.name === 'Fondale verde'); window.__dpv.edit('Clic', () => { c.ritaglio.punti = [{ x: 0.5, y: 0.5, dentro: true }]; c.ritaglio.da = 0; }); });
await page.waitForTimeout(300);
await apriSfondo(page);
await page.click('.isp-gruppo[data-g=sfondo] button:has-text("Togli lo sfondo a tutta la clip")');
await page.waitForSelector('.ai-passi');
prova('lo sfondo AI attende il consenso prima di elaborare', await page.evaluate(() => {
Expand All @@ -247,7 +270,9 @@ async function proveSfondo({ page, prova, OUT }) {
await page.waitForFunction(() => { const c = window.__dpv.doc.clips.find((x) => x.name === 'Fondale verde'); const m = c.ritaglio?.firma && window.__dpvTest.MK.maschereDi(c.ritaglio.firma); return !!m && m.n >= 1 && window.__dpvTest.USF.lavoroDi(c.id)?.finito === true; }, null, { timeout: 20000 }).catch(() => {});
const partito = await page.evaluate(() => { const c = window.__dpv.doc.clips.find((x) => x.name === 'Fondale verde'); const m = window.__dpvTest.MK.maschereDi(c.ritaglio.firma); return { maschere: m?.n ?? 0, finito: window.__dpvTest.USF.lavoroDi(c.id)?.finito }; });
prova('dopo il consenso lo sfondo AI viene elaborato', partito.maschere >= 1 && partito.finito === true, JSON.stringify(partito));
prova('il resto (precisione, segui…) sta in "Avanzate", il bordo si prova subito sotto', (await page.locator('.isp-gruppo[data-g=sfondo] details.pp-piu summary:has-text("Avanzate")').count()) === 1 && (await page.locator('.isp-gruppo[data-g=sfondo] label:has-text("Rifinisci il bordo")').count()) === 1);
await apriSfondo(page);
// nella finestra Modifica clip le «Avanzate» dello sfondo vanno nel gruppo «Qualità AI» (menu Avanzate)
prova('il resto (precisione, segui…) sta in "Avanzate", il bordo si prova subito sotto', ((await page.locator('.isp-gruppo[data-g=sfondo] details.pp-piu summary:has-text("Avanzate")').count()) === 1 || (await page.locator('.editor-clip .ec-nav [data-sezione=avanzate]').count()) === 1) && (await page.locator('.isp-gruppo[data-g=sfondo] label:has-text("Rifinisci il bordo")').count()) === 1);


await page.evaluate(() => window.__dpvTest.RT.impostaSegmentatore(null));
Expand Down
18 changes: 9 additions & 9 deletions test/prove.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -270,14 +270,11 @@ try {
await page.evaluate((id) => window.__dpv.select([id]), clipFoto.id);
await page.click('.lato .scheda[data-s=clip]');
await page.waitForTimeout(200);
// la durata sta nell'editor della clip (doppio clic): si apre da lì
// dalla grafica Banco la durata sta nel pannello di destra (scheda QUADRO): dpv:sezione la apre lì
await page.evaluate(() => document.dispatchEvent(new CustomEvent('dpv:sezione', { detail: 'durata' })));
await page.waitForSelector('.editor-clip');
await page.click('.editor-clip .ec-nav [data-sezione=tempo]');
await page.waitForSelector('.lato .isp-pulsanti button:has-text("+5 s")');
await page.click('.lato .isp-pulsanti button:has-text("+5 s")');
await page.waitForTimeout(150);
await page.click('.editor-clip .isp-pulsanti button:has-text("+5 s")');
await page.keyboard.press('Escape');
await page.waitForSelector('.editor-clip', { state: 'detached' });
dd = await doc();
prova('l\'istantanea si allunga (+5 s dalle proprietà)', dd.clips.find((c) => c.id === clipFoto.id).len === 50 + 125, dd.clips.find((c) => c.id === clipFoto.id).len);
await tasto('Control+z'); await tasto('Control+z');
Expand Down Expand Up @@ -958,10 +955,10 @@ try {
await page.click('.pagina-btn[data-p=live]');
await page.click('.live-btn.reg');
await page.waitForTimeout(1600);
await page.click('.live-tasti .live-btn:nth-child(2)');
await page.click('.live-btn.pausa');
await page.waitForTimeout(900);
const inPausa = await page.evaluate(() => document.querySelector('.live').classList.contains('in-pausa'));
await page.click('.live-tasti .live-btn:nth-child(2)');
await page.click('.live-btn.pausa');
await page.waitForTimeout(900);
await page.click('.live-btn.ferma');
await page.evaluate(() => window.__dpvTest.ui().live.ultima);
Expand Down Expand Up @@ -1199,7 +1196,7 @@ try {
r.sfondo?.o === 0 && !!r.sfondo.gen.color2 && r.schermo?.o === 1 && r.schermo.tf.angoli > 0 && r.schermo.tf.ombra > 0 && r.schermo.tf.scale < 1 &&
r.cam?.o === 2 && r.cam.tf.angoli === 1 && r.cam.tf.cropL > 0 && r.cam.tf.x > 0 && r.cam.tf.y > 0 && r.cam.len <= r.schermo.len &&
r.schermo.link && r.cam.link === r.schermo.link && r.sfondo.start === r.schermo.start, JSON.stringify(r));
prova('LIVE: il tasto M mette un segno (marcatore in timeline) e la pausa col tasto Spazio', r.segni.length === 1 && r.segni[0][0] === 'Segno 1' && r.segni[0][1] > r.schermo.start && pausa, JSON.stringify({ segni: r.segni, pausa }));
prova('LIVE: il tasto M mette un segno (marcatore in timeline) e la pausa col tasto Spazio', r.segni.filter((x) => !String(x[0]).startsWith('Scena')).length === 1 && r.segni.find((x) => x[0] === 'Segno 1') && r.segni.find((x) => x[0] === 'Segno 1')[1] > r.schermo.start && pausa, JSON.stringify({ segni: r.segni, pausa }));
prova('LIVE: la registrazione nella lista con la miniatura', r.lista === 1);
// il fotogramma composto: sfondo, schermo, bolla
await pg.click('.pagina-btn[data-p=montaggio]');
Expand Down Expand Up @@ -1423,6 +1420,9 @@ try {
prova('LIVE: la voce va su un\'altra traccia audio, nello stesso punto e legata allo schermo', !!r.cMic && !!r.cAudio && r.cMic.track !== r.cAudio.track && r.cMic.start === r.cSch.start && r.cMic.link === r.cSch.link && r.cAudio.link === r.cSch.link && r.cMic.name === 'Microfono', JSON.stringify(r));
// con l'interruttore spento tutto va in un file solo, come prima
await pg.evaluate(() => { window.__dpvTest.ui().live.opz.separato = false; });
// finita una registrazione l'app va dritta al Montaggio: si torna su LIVE per la seconda
await pg.click('.pagina-btn[data-p=live]');
await pg.waitForTimeout(300);
await pg.keyboard.press('r');
await pg.waitForTimeout(2200);
await pg.keyboard.press('f');
Expand Down
Loading