Aggiunge l'importazione da scheda di memoria e riordina l'interfaccia attorno a quello che ciascuna sezione serve a fare. L'importazione riconosce i supporti collegati, cerca nelle sottocartelle e prima di toccare il disco mostra il piano: quali cartelle nasceranno e che nome avranno i primi file. Un'importazione sbagliata su mille file non si annulla, e guardare prima costa un istante. Fa poi tre cose che a mano si sbagliano sempre: separa le sessioni sulla pausa fra due scatti, invece di lasciare piu' riprese mescolate in una cartella sola; costruisce i nomi da modelli con segnaposto, perche' un archivio si consulta anni dopo e il nome e' l'unica cosa leggibile senza aprire nulla; e rilegge quello che ha scritto confrontandone l'impronta, perche' una scheda che si scollega a meta' copia produce file della dimensione giusta e del contenuto troncato, e il danno si scopre mesi dopo. Sulla conversione in DNG va detto con precisione cosa si puo' e non si puo' fare. Un DNG vero contiene i valori del sensore prima dell'interpolazione cromatica; ottenerlo da un formato proprietario richiede la libreria del produttore, che il vincolo sulle dipendenze esclude. Quello che si ottiene in-house e' un DNG lineare - la specifica lo prevede, i pixel sono gia' interpolati, il file e' valido e apribile ovunque ma non restituisce la liberta' del grezzo. La copia resta quindi la scelta predefinita, e l'interfaccia lo dice invece di lasciarlo intuire. Il contenitore TIFF/DNG e' scritto a mano come il multiplexer MP4, e la verifica lo rilegge con il parser di questo stesso programma: due implementazioni indipendenti dello stesso formato, e al primo confronto e' saltato fuori un errore di dodici byte per voce nel calcolo degli scostamenti - la directory Exif finiva oltre il puntatore che la indicava. Le spiegazioni passano dalle note stampate ai suggerimenti a comparsa. Una nota sotto un cursore occupa spazio a chi la conosce gia', quindi deve restare corta; un suggerimento che appare solo quando serve non ha quel vincolo e puo' dire l'unica cosa che conta - perche' quel parametro esiste e cosa succede a spostarlo nel verso sbagliato. Ogni sezione guadagna un comando Ottimizza che rileva le impostazioni migliori per quella sola parte e riferisce cosa ha cambiato e perche'. Si distingue dal pilota automatico, che lavora di continuo sui parametri deducibili senza ambiguita': l'ottimizzazione si chiede a mano perche' accende e spegne interi moduli, e sostituire quelle scelte in silenzio sarebbe peggio che lasciarle sbagliate. Dove il dato manca non tira a indovinare: lo dice. L'uscita guadagna rapporto e ritaglio. Cambiare rapporto non deforma piu' l'immagine: il ritaglio viene preso con il nuovo rapporto dentro il fotogramma, il che ha anche corretto un difetto latente dello stadio geometrico, che con rapporti diversi fra sorgente e uscita stirava invece di tagliare. La zona da tenere si sceglie trascinandola. I comandi seguono la sezione: importazione e analisi compaiono solo dove servono. Un pulsante che non ha senso dove ci si trova non va disabilitato ma tolto, perche' disabilitato resta un ingombro che chiede perche' non funziona. Le preferenze dell'applicazione non mostrano piu' anteprima, riepilogo della sequenza ne' riga di stato che ne parli: non riguardano la sequenza caricata, e tenerle accanto confondeva due piani diversi. Via anche le descrizioni inutili: la finestra si chiama Titano e basta. Due difetti trovati durante la verifica a video. La barra di navigazione nasceva sulla prima voce, che ora e' Archivio, quindi il selettore usciva subito perche' l'indice coincideva e la sezione non veniva mai mostrata: barra su una voce, contenuto su un'altra. E il posizionamento dei pulsanti leggeva Visible, che in WinForms resta falso finche' la finestra non e' stata mostrata perche' riporta la visibilita' dell'intera catena: alla costruzione nessun pulsante veniva collocato e restavano tutti impilati sull'angolo. Verifica: da 54 a 60 controlli. I nuovi coprono i modelli di percorso, la sostituzione dei caratteri illegali, il rifiuto dei segnaposto inventati, il riconoscimento delle sessioni e la rilettura del DNG scritto - sia dal parser interno sia dal decodificatore di sistema. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
2.7 KiB
C#
73 lines
2.7 KiB
C#
using System.Drawing.Drawing2D;
|
|
|
|
namespace Titano.UI;
|
|
|
|
/// <summary>
|
|
/// Suggerimenti a comparsa, disegnati a mano nel tema scuro.
|
|
///
|
|
/// Le spiegazioni stanno qui invece che sotto ai controlli per un motivo pratico: una nota
|
|
/// stampata sotto un cursore deve essere corta, perché occupa spazio a chi la conosce già.
|
|
/// Un suggerimento che compare solo quando serve non ha quel vincolo, e può permettersi di
|
|
/// dire l'unica cosa che conta davvero — perché quel parametro esiste, e cosa succede se lo
|
|
/// si sposta nella direzione sbagliata.
|
|
///
|
|
/// Il suggerimento di sistema è disegnato dal tema di Windows, che qui sarebbe chiaro su
|
|
/// scuro: viene quindi disegnato per intero, con la stessa tavolozza del resto.
|
|
/// </summary>
|
|
internal static class Tips
|
|
{
|
|
private const int MaximumWidth = 380;
|
|
|
|
private static readonly ToolTip Instance = Create();
|
|
|
|
private static ToolTip Create()
|
|
{
|
|
var tip = new ToolTip
|
|
{
|
|
OwnerDraw = true,
|
|
InitialDelay = 380,
|
|
ReshowDelay = 120,
|
|
AutoPopDelay = 32000, // le spiegazioni lunghe devono restare leggibili
|
|
ShowAlways = true,
|
|
UseAnimation = false,
|
|
UseFading = false,
|
|
};
|
|
|
|
tip.Popup += (_, e) =>
|
|
{
|
|
var size = TextRenderer.MeasureText(tip.GetToolTip(e.AssociatedControl) ?? string.Empty,
|
|
Theme.Small, new Size(MaximumWidth, 0),
|
|
TextFormatFlags.WordBreak);
|
|
e.ToolTipSize = new Size(Math.Min(MaximumWidth, size.Width) + 22, size.Height + 18);
|
|
};
|
|
|
|
tip.Draw += (_, e) =>
|
|
{
|
|
var g = e.Graphics;
|
|
Theme.HighQuality(g);
|
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
|
|
|
var bounds = new RectangleF(0.5f, 0.5f, e.Bounds.Width - 1, e.Bounds.Height - 1);
|
|
Theme.FillAndStroke(g, bounds, 5f, Theme.SurfaceAlt, Theme.BorderStrong);
|
|
|
|
TextRenderer.DrawText(g, e.ToolTipText, Theme.Small,
|
|
Rectangle.Inflate(e.Bounds, -11, -9), Theme.Text,
|
|
TextFormatFlags.Left | TextFormatFlags.Top | TextFormatFlags.WordBreak);
|
|
};
|
|
|
|
return tip;
|
|
}
|
|
|
|
/// <summary>Associa una spiegazione a un controllo e a tutti i suoi figli.</summary>
|
|
public static void Set(Control control, string text)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(text)) return;
|
|
|
|
Instance.SetToolTip(control, text);
|
|
|
|
// Un LabeledCombo è un pannello con dentro etichetta e menu: senza propagare, il
|
|
// suggerimento comparirebbe solo sui pochi pixel di bordo fra i due.
|
|
foreach (Control child in control.Controls) Set(child, text);
|
|
}
|
|
}
|