acquisitore: «Attiva calibrazione» con scelta e CONFERMA sotto l'immagine calibrata (Refs #93)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,8 @@ PAGINA = r"""<!doctype html>
|
|||||||
select:focus, input:focus, button:focus-visible { outline: 2px solid var(--accento); outline-offset: 1px; }
|
select:focus, input:focus, button:focus-visible { outline: 2px solid var(--accento); outline-offset: 1px; }
|
||||||
input[type=range] { width: 100%; accent-color: var(--accento); }
|
input[type=range] { width: 100%; accent-color: var(--accento); }
|
||||||
input[type=checkbox] { accent-color: var(--accento); }
|
input[type=checkbox] { accent-color: var(--accento); }
|
||||||
|
.scelta-cal { margin-top: 8px; align-items: center; } /* #93 */
|
||||||
|
.scelta-cal select { flex: 1 1 200px; min-width: 0; } /* #93: nessuno scorrimento a 400 px */
|
||||||
.riga { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
|
.riga { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
|
||||||
.nota { font-size: .82rem; color: var(--secondario); margin: 8px 0 0; }
|
.nota { font-size: .82rem; color: var(--secondario); margin: 8px 0 0; }
|
||||||
button { padding: 7px 13px; font-size: .95rem; border: 0; border-radius: 6px; background: var(--accento); color: #fff;
|
button { padding: 7px 13px; font-size: .95rem; border: 0; border-radius: 6px; background: var(--accento); color: #fff;
|
||||||
@@ -156,7 +158,7 @@ PAGINA = r"""<!doctype html>
|
|||||||
<button id="avvia">Avvia anteprima</button>
|
<button id="avvia">Avvia anteprima</button>
|
||||||
<button id="ferma" class="secondario" disabled>Ferma anteprima</button>
|
<button id="ferma" class="secondario" disabled>Ferma anteprima</button>
|
||||||
<button id="scatta" class="secondario">Scatta</button>
|
<button id="scatta" class="secondario">Scatta</button>
|
||||||
<label style="margin:0 0 6px"><input id="mostraCal" type="checkbox"> Mostra immagine calibrata</label>
|
<label style="margin:0 0 6px"><input id="mostraCal" type="checkbox"> Attiva calibrazione</label>
|
||||||
<label style="margin:0 0 6px"><input id="mirinoCasella" type="checkbox"> Mirino centrale</label>
|
<label style="margin:0 0 6px"><input id="mirinoCasella" type="checkbox"> Mirino centrale</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="riquadri" id="riquadri">
|
<div class="riquadri" id="riquadri">
|
||||||
@@ -179,6 +181,12 @@ PAGINA = r"""<!doctype html>
|
|||||||
<div id="mirinoCal" class="mirino" hidden></div>
|
<div id="mirinoCal" class="mirino" hidden></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- #93: scelta della calibrazione da attivare sulla sorgente, con CONFERMA -->
|
||||||
|
<div class="riga scelta-cal">
|
||||||
|
<select id="sceltaCal" aria-label="Calibrazione da attivare" disabled></select>
|
||||||
|
<button id="confermaCal" type="button" disabled>CONFERMA</button>
|
||||||
|
</div>
|
||||||
|
<div id="msgSceltaCal" class="messaggio"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="indicatori">
|
<div class="indicatori">
|
||||||
@@ -618,7 +626,7 @@ $("avvia").onclick = avviaAnteprima;
|
|||||||
$("ferma").onclick = fermaAnteprima;
|
$("ferma").onclick = fermaAnteprima;
|
||||||
$("scatta").onclick = scatta;
|
$("scatta").onclick = scatta;
|
||||||
$("azzeraMax").onclick = function () { A.nitMax = 0; $("nitidezzaMax").textContent = "-"; $("barraNitidezza").style.width = "0"; };
|
$("azzeraMax").onclick = function () { A.nitMax = 0; $("nitidezzaMax").textContent = "-"; $("barraNitidezza").style.width = "0"; };
|
||||||
// #92: il mirino vale per entrambi i riquadri; la casella «Mostra immagine calibrata» apre il riquadro e raddrizza il frame gia' tenuto
|
// #92: il mirino vale per entrambi i riquadri; #93: la casella «Attiva calibrazione» apre il riquadro e raddrizza il frame gia' tenuto
|
||||||
$("mirinoCasella").onchange = function () { $("mirino").hidden = $("mirinoCal").hidden = !$("mirinoCasella").checked; };
|
$("mirinoCasella").onchange = function () { $("mirino").hidden = $("mirinoCal").hidden = !$("mirinoCasella").checked; };
|
||||||
function mostraRiquadroCal() {
|
function mostraRiquadroCal() {
|
||||||
var si = $("mostraCal").checked;
|
var si = $("mostraCal").checked;
|
||||||
@@ -995,6 +1003,7 @@ function disegnaElenco() {
|
|||||||
annullaConferma();
|
annullaConferma();
|
||||||
t.textContent = "";
|
t.textContent = "";
|
||||||
C.celle = [];
|
C.celle = [];
|
||||||
|
disegnaSceltaCal(); // #93: la combo sotto la calibrata segue l'elenco, anche se vuoto
|
||||||
if (!C.elenco.length) {
|
if (!C.elenco.length) {
|
||||||
var vuota = document.createElement("div");
|
var vuota = document.createElement("div");
|
||||||
vuota.className = "nota";
|
vuota.className = "nota";
|
||||||
@@ -1035,7 +1044,7 @@ function disegnaElenco() {
|
|||||||
var bc = bottone("Carica", "", function () { caricaNome(c.nome); });
|
var bc = bottone("Carica", "", function () { caricaNome(c.nome); });
|
||||||
bc.disabled = !$("sorgente").value;
|
bc.disabled = !$("sorgente").value;
|
||||||
az.appendChild(bc);
|
az.appendChild(bc);
|
||||||
if (attiva) az.appendChild(bottone("Scollega", "secondario", scollega));
|
if (attiva) az.appendChild(bottone("Scollega", "secondario", function () { scollega("msgElenco"); })); // #93: senza l'evento come parametro
|
||||||
az.appendChild(bottone("Elimina", "secondario", function (e) { eliminaNome(c.nome, e.currentTarget); }));
|
az.appendChild(bottone("Elimina", "secondario", function (e) { eliminaNome(c.nome, e.currentTarget); }));
|
||||||
sc.appendChild(riga1);
|
sc.appendChild(riga1);
|
||||||
sc.appendChild(riga2);
|
sc.appendChild(riga2);
|
||||||
@@ -1050,41 +1059,80 @@ function segnaRisoluzioni() {
|
|||||||
(C.celle || []).forEach(function (c) {
|
(C.celle || []).forEach(function (c) {
|
||||||
c.span.hidden = !(A.ris && c.w > 0 && c.h > 0 && (A.ris.w !== c.w || A.ris.h !== c.h));
|
c.span.hidden = !(A.ris && c.w > 0 && c.h > 0 && (A.ris.w !== c.w || A.ris.h !== c.h));
|
||||||
});
|
});
|
||||||
|
// #93: stesso avviso nelle voci della combo; si cambia solo il testo, cosi' scelta e menu aperto restano
|
||||||
|
var sel = $("sceltaCal");
|
||||||
|
for (var i = 0; i < sel.options.length; i++) if (sel.options[i].value) sel.options[i].textContent = testoVoceCal(sel.options[i].dataset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #93: testo di una voce della combo: «nome · W×H · px/mm», con «risoluzione diversa» se il frame noto non combacia
|
||||||
|
function testoVoceCal(d) {
|
||||||
|
var w = Number(d.w), h = Number(d.h);
|
||||||
|
var t = d.nome + " · " + (w && h ? fmt(w, 0) + "×" + fmt(h, 0) : "-") + " · " + fmt(Number(d.px), 3) + " px/mm";
|
||||||
|
if (A.ris && w > 0 && h > 0 && (A.ris.w !== w || A.ris.h !== h)) t += " — risoluzione diversa";
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
// #93: ridisegna la combo (ogni ricarica dell'elenco); preselezionata la calibrazione attiva, senza sorgente tutto spento
|
||||||
|
function disegnaSceltaCal() {
|
||||||
|
var sel = $("sceltaCal");
|
||||||
|
sel.textContent = "";
|
||||||
|
var nessuna = document.createElement("option");
|
||||||
|
nessuna.value = "";
|
||||||
|
nessuna.textContent = "— nessuna (non calibrata) —";
|
||||||
|
sel.appendChild(nessuna);
|
||||||
|
(C.elenco || []).forEach(function (c) {
|
||||||
|
var o = document.createElement("option");
|
||||||
|
o.value = c.nome;
|
||||||
|
o.dataset.nome = c.nome; o.dataset.w = c.image_width || 0; o.dataset.h = c.image_height || 0; o.dataset.px = c.px_per_mm || 0;
|
||||||
|
o.textContent = testoVoceCal(o.dataset);
|
||||||
|
sel.appendChild(o);
|
||||||
|
});
|
||||||
|
sel.value = C.attiva !== null && C.attiva !== undefined ? C.attiva : "";
|
||||||
|
if (sel.selectedIndex < 0) sel.selectedIndex = 0;
|
||||||
|
sel.disabled = $("confermaCal").disabled = !$("sorgente").value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// «Carica»: la calibrazione diventa quella attiva della sorgente. Un errore (es. risoluzione diversa) non ferma l'anteprima.
|
// «Carica»: la calibrazione diventa quella attiva della sorgente. Un errore (es. risoluzione diversa) non ferma l'anteprima.
|
||||||
async function caricaNome(nome) {
|
async function caricaNome(nome, idMsg) {
|
||||||
|
idMsg = idMsg || "msgElenco"; // #93: il messaggio puo' stare sotto la calibrata (msgSceltaCal)
|
||||||
var sorgente = $("sorgente").value;
|
var sorgente = $("sorgente").value;
|
||||||
if (!sorgente) { dire("msgElenco", "Scegliere una sorgente nella tab Acquisizione.", "errore"); return; }
|
if (!sorgente) { dire(idMsg, "Scegliere una sorgente nella tab Acquisizione.", "errore"); return; }
|
||||||
dire("msgElenco", "Caricamento di «" + nome + "»...", "");
|
dire(idMsg, "Caricamento di «" + nome + "»...", "");
|
||||||
try {
|
try {
|
||||||
var r = await fetch("/camera/calibrazione-attiva", { method: "PUT", headers: JSON_H, body: JSON.stringify({ source: sorgente, nome: nome }) });
|
var r = await fetch("/camera/calibrazione-attiva", { method: "PUT", headers: JSON_H, body: JSON.stringify({ source: sorgente, nome: nome }) });
|
||||||
if (sorgente !== $("sorgente").value) return;
|
if (sorgente !== $("sorgente").value) return;
|
||||||
if (!r.ok) { dire("msgElenco", await dettaglio(r), "errore"); return; }
|
if (!r.ok) { dire(idMsg, await dettaglio(r), "errore"); disegnaSceltaCal(); return; } // #93: la combo torna sull'attiva
|
||||||
dire("msgElenco", "Calibrazione «" + nome + "» caricata sulla sorgente.", "ok");
|
dire(idMsg, "Calibrazione «" + nome + "» caricata sulla sorgente.", "ok");
|
||||||
A.bloccoCal = false; // #92
|
A.bloccoCal = false; // #92
|
||||||
await aggiornaStato(); // prima lo stato nuovo, poi il riquadro calibrata con la nuova calibrazione
|
await aggiornaStato(); // prima lo stato nuovo (rilegge anche l'elenco, #93: schede e combo allineate), poi il riquadro calibrata
|
||||||
aggiornaCalibrata();
|
aggiornaCalibrata();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dire("msgElenco", "Servizio non raggiungibile.", "errore");
|
dire(idMsg, "Servizio non raggiungibile.", "errore");
|
||||||
|
disegnaSceltaCal(); // #93
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// «Scollega»: la sorgente torna senza calibrazione, la libreria resta
|
// «Scollega»: la sorgente torna senza calibrazione, la libreria resta
|
||||||
async function scollega() {
|
async function scollega(idMsg) {
|
||||||
|
idMsg = idMsg || "msgElenco"; // #93
|
||||||
var sorgente = $("sorgente").value;
|
var sorgente = $("sorgente").value;
|
||||||
if (!sorgente) return;
|
if (!sorgente) return;
|
||||||
try {
|
try {
|
||||||
var r = await fetch("/camera/calibration?source=" + encodeURIComponent(sorgente), { method: "DELETE" });
|
var r = await fetch("/camera/calibration?source=" + encodeURIComponent(sorgente), { method: "DELETE" });
|
||||||
dire("msgElenco", r.ok ? "Calibrazione scollegata dalla sorgente (resta fra le salvate)." : await dettaglio(r), r.ok ? "ok" : "errore");
|
dire(idMsg, r.ok ? "Calibrazione scollegata dalla sorgente (resta fra le salvate)." : await dettaglio(r), r.ok ? "ok" : "errore");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dire("msgElenco", "Servizio non raggiungibile.", "errore");
|
dire(idMsg, "Servizio non raggiungibile.", "errore");
|
||||||
}
|
}
|
||||||
A.bloccoCal = false; // #92
|
A.bloccoCal = false; // #92
|
||||||
await aggiornaStato();
|
await aggiornaStato(); // #93: rilegge anche l'elenco, quindi la combo torna sull'attiva anche dopo un errore
|
||||||
aggiornaCalibrata(); // #92: senza calibrazione il riquadro dice che non c'e'
|
aggiornaCalibrata(); // #92: senza calibrazione il riquadro dice che non c'e'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #93: CONFERMA sotto la calibrata: voce scelta -> PUT calibrazione-attiva, «nessuna» -> DELETE calibration
|
||||||
|
$("confermaCal").onclick = function () {
|
||||||
|
var nome = $("sceltaCal").value;
|
||||||
|
if (nome) caricaNome(nome, "msgSceltaCal"); else scollega("msgSceltaCal");
|
||||||
|
};
|
||||||
|
|
||||||
// «Elimina» di una riga: conferma in pagina con un secondo clic entro 4 s (niente finestre del browser)
|
// «Elimina» di una riga: conferma in pagina con un secondo clic entro 4 s (niente finestre del browser)
|
||||||
function annullaConferma() {
|
function annullaConferma() {
|
||||||
clearTimeout(C.confermaTimer);
|
clearTimeout(C.confermaTimer);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ def test_id_principali():
|
|||||||
def test_sezioni_e_testi_italiani():
|
def test_sezioni_e_testi_italiani():
|
||||||
for testo in ("Sorgente", "Anteprima", "Parametri camera", "Calibrazione",
|
for testo in ("Sorgente", "Anteprima", "Parametri camera", "Calibrazione",
|
||||||
"Salva come predefiniti", "Carica immagine da file...", "Questa sorgente non ha parametri regolabili",
|
"Salva come predefiniti", "Carica immagine da file...", "Questa sorgente non ha parametri regolabili",
|
||||||
"Mostra immagine calibrata"): # #92
|
"Attiva calibrazione"): # #92 #93
|
||||||
assert testo in PAGINA, testo
|
assert testo in PAGINA, testo
|
||||||
assert "it-IT" in PAGINA # numeri con la virgola
|
assert "it-IT" in PAGINA # numeri con la virgola
|
||||||
assert "Choose File" not in PAGINA
|
assert "Choose File" not in PAGINA
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ def test_sorgente_in_cima_poi_riquadri():
|
|||||||
assert i_acq < i_sorg < i_ant < i_riq < PAGINA.index('id="sezioneParametri"') < i_cal
|
assert i_acq < i_sorg < i_ant < i_riq < PAGINA.index('id="sezioneParametri"') < i_cal
|
||||||
assert PAGINA.index('id="sezioneCalibrazione"') > i_cal
|
assert PAGINA.index('id="sezioneCalibrazione"') > i_cal
|
||||||
# barra: casella calibrata e mirino; la vecchia casella «Immagine grezza» non c'e' piu'
|
# barra: casella calibrata e mirino; la vecchia casella «Immagine grezza» non c'e' piu'
|
||||||
assert 'id="mostraCal"' in PAGINA and "Mostra immagine calibrata" in PAGINA
|
assert 'id="mostraCal"' in PAGINA and "Attiva calibrazione" in PAGINA
|
||||||
assert 'id="grezzo"' not in PAGINA and "Immagine grezza (senza correzione)" not in PAGINA
|
assert 'id="grezzo"' not in PAGINA and "Immagine grezza (senza correzione)" not in PAGINA
|
||||||
# riquadri: «Immagine» sempre visibile, «Calibrata» nascosta finche' la casella e' spenta
|
# riquadri: «Immagine» sempre visibile, «Calibrata» nascosta finche' la casella e' spenta
|
||||||
assert re.search(r'<div class="riquadro" id="riquadroCal" hidden>', PAGINA)
|
assert re.search(r'<div class="riquadro" id="riquadroCal" hidden>', PAGINA)
|
||||||
@@ -124,3 +124,21 @@ def test_elenco_sorgenti_senza_attese_e_calibrata_solo_se_serve():
|
|||||||
assert "nessuna calibrazione attiva su questa sorgente" in PAGINA
|
assert "nessuna calibrazione attiva su questa sorgente" in PAGINA
|
||||||
assert "if (r.status === 409) A.bloccoCal = true;" in PAGINA and "if (A.bloccoCal) return;" in PAGINA
|
assert "if (r.status === 409) A.bloccoCal = true;" in PAGINA and "if (A.bloccoCal) return;" in PAGINA
|
||||||
assert PAGINA.count("A.bloccoCal = false;") >= 3 # cambio sorgente, Carica, Scollega
|
assert PAGINA.count("A.bloccoCal = false;") >= 3 # cambio sorgente, Carica, Scollega
|
||||||
|
|
||||||
|
|
||||||
|
def test_attiva_calibrazione_con_scelta_e_conferma():
|
||||||
|
# #93: sotto la calibrata una combo e CONFERMA; la casella cambia nome
|
||||||
|
for i in ('id="sceltaCal"', 'id="confermaCal"', 'id="msgSceltaCal"'):
|
||||||
|
assert i in PAGINA, i
|
||||||
|
assert "Attiva calibrazione" in PAGINA and ">CONFERMA</button>" in PAGINA
|
||||||
|
assert "Mostra immagine calibrata" not in PAGINA
|
||||||
|
assert PAGINA.index('id="riquadroCal"') < PAGINA.index('id="sceltaCal"') < PAGINA.index('id="confermaCal"') < PAGINA.index('id="msgSceltaCal"')
|
||||||
|
# il gestore di CONFERMA usa PUT calibrazione-attiva (via caricaNome) o DELETE calibration (via scollega), messaggio sotto la calibrata
|
||||||
|
gestore = PAGINA[PAGINA.index('$("confermaCal").onclick'):]
|
||||||
|
gestore = gestore[:gestore.index("};")]
|
||||||
|
assert 'caricaNome(nome, "msgSceltaCal")' in gestore and 'scollega("msgSceltaCal")' in gestore
|
||||||
|
assert 'method: "PUT"' in PAGINA and "/camera/calibrazione-attiva" in PAGINA
|
||||||
|
assert 'method: "DELETE"' in PAGINA and '"/camera/calibration?source="' in PAGINA
|
||||||
|
# voce vuota «nessuna», suffisso di risoluzione, combo ridisegnata con l'elenco e spenta senza sorgente
|
||||||
|
assert "— nessuna (non calibrata) —" in PAGINA and "— risoluzione diversa" in PAGINA
|
||||||
|
assert "disegnaSceltaCal();" in PAGINA and "= !$(\"sorgente\").value" in PAGINA
|
||||||
|
|||||||
Reference in New Issue
Block a user