diff --git a/Ganimede/Ganimede/MainWindow.xaml b/Ganimede/Ganimede/MainWindow.xaml
index f4c26b5..ef57ac9 100644
--- a/Ganimede/Ganimede/MainWindow.xaml
+++ b/Ganimede/Ganimede/MainWindow.xaml
@@ -5,127 +5,245 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Ganimede"
mc:Ignorable="d"
- Title="Ganimede - Frame Extractor" Height="800" Width="1200"
- Background="#222">
+ Title="Estrattore Frame Video" Height="800" Width="1250"
+ Background="#1E2228" WindowStartupLocation="CenterScreen">
+
+
+ #268BFF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/Ganimede/Ganimede/MainWindow.xaml.cs b/Ganimede/Ganimede/MainWindow.xaml.cs
index 001b9e2..8798120 100644
--- a/Ganimede/Ganimede/MainWindow.xaml.cs
+++ b/Ganimede/Ganimede/MainWindow.xaml.cs
@@ -19,9 +19,6 @@ using WpfButton = System.Windows.Controls.Button;
namespace Ganimede
{
- ///
- /// Interaction logic for MainWindow.xaml
- ///
public partial class MainWindow : Window
{
private string? outputFolder;
@@ -40,28 +37,41 @@ namespace Ganimede
{
ThumbnailsPanel.ItemsSource = thumbnails;
QueueItemsControl.ItemsSource = _processingService.JobQueue;
-
- // Load saved settings
+
outputFolder = Settings.Default.LastOutputFolder;
if (!string.IsNullOrEmpty(outputFolder))
- StatusText.Text = $"Output folder: {outputFolder}";
+ {
+ StatusText.Text = "Pronto";
+ GlobalOutputFolderTextBox.Text = outputFolder;
+ }
- // Subscribe to processing service events
_processingService.JobCompleted += OnJobCompleted;
_processingService.JobFailed += OnJobFailed;
_processingService.ProcessingStarted += OnProcessingStarted;
_processingService.ProcessingStopped += OnProcessingStopped;
_processingService.JobQueue.CollectionChanged += (s, e) => UpdateQueueCount();
- Debug.WriteLine("[INIT] MainWindow initialized with queue support.");
+ UpdateQueueCount();
}
private void UpdateQueueCount()
{
Dispatcher.Invoke(() =>
{
- var count = _processingService.JobQueue.Count;
- QueueCountText.Text = $"({count} elementi)";
+ QueueCountText.Text = $"({_processingService.JobQueue.Count})";
+ UpdateJobsSummary();
+ });
+ }
+
+ private void UpdateJobsSummary()
+ {
+ var pending = _processingService.JobQueue.Count(j => j.Status == JobStatus.Pending);
+ var processing = _processingService.JobQueue.Count(j => j.Status == JobStatus.Processing);
+ var completed = _processingService.JobQueue.Count(j => j.Status == JobStatus.Completed);
+ var failed = _processingService.JobQueue.Count(j => j.Status == JobStatus.Failed);
+ Dispatcher.Invoke(() =>
+ {
+ JobsSummaryText.Text = $"In attesa: {pending} | In corso: {processing} | Completati: {completed} | Falliti: {failed}";
});
}
@@ -71,7 +81,8 @@ namespace Ganimede
{
StartQueueButton.IsEnabled = false;
StopQueueButton.IsEnabled = true;
- StatusText.Text = "Elaborazione coda avviata...";
+ StatusText.Text = "Elaborazione coda...";
+ UpdateJobsSummary();
});
}
@@ -81,7 +92,8 @@ namespace Ganimede
{
StartQueueButton.IsEnabled = true;
StopQueueButton.IsEnabled = false;
- StatusText.Text = "Elaborazione coda fermata.";
+ StatusText.Text = "Coda fermata";
+ UpdateJobsSummary();
});
}
@@ -90,8 +102,8 @@ namespace Ganimede
Dispatcher.Invoke(() =>
{
StatusText.Text = $"โ Completato: {job.VideoName}";
- // Load thumbnails for the completed job
LoadThumbnailsFromFolder(job.OutputFolder);
+ UpdateJobsSummary();
});
}
@@ -99,7 +111,8 @@ namespace Ganimede
{
Dispatcher.Invoke(() =>
{
- StatusText.Text = $"โ Fallito: {job.VideoName} - {job.StatusMessage}";
+ StatusText.Text = $"โ Fallito: {job.VideoName}";
+ UpdateJobsSummary();
});
}
@@ -108,206 +121,125 @@ namespace Ganimede
try
{
if (!Directory.Exists(folder)) return;
-
- var imageFiles = Directory.GetFiles(folder, "*.png")
- .OrderBy(f => f)
- .Take(20) // Load max 20 thumbnails for preview
- .ToList();
-
+ var imageFiles = Directory.GetFiles(folder, "*.png").OrderBy(f => f).Take(60).ToList();
+ thumbnails.Clear();
foreach (var imagePath in imageFiles)
{
- var bitmap = new BitmapImage();
- bitmap.BeginInit();
- bitmap.UriSource = new Uri(imagePath);
- bitmap.CacheOption = BitmapCacheOption.OnLoad;
- bitmap.EndInit();
- thumbnails.Add(bitmap);
+ var bmp = new BitmapImage();
+ bmp.BeginInit();
+ bmp.UriSource = new Uri(imagePath);
+ bmp.CacheOption = BitmapCacheOption.OnLoad;
+ bmp.EndInit();
+ thumbnails.Add(bmp);
}
}
catch (Exception ex)
{
- Debug.WriteLine($"[ERROR] Failed to load thumbnails: {ex.Message}");
+ Debug.WriteLine($"[ERROR] Impossibile caricare thumbnails: {ex.Message}");
}
}
private void ConfigureFFMpeg()
{
var ffmpegBin = Settings.Default.FFmpegBinFolder;
-
if (!string.IsNullOrEmpty(ffmpegBin) && ValidateFFMpegBinaries(ffmpegBin))
- {
- FFMpegCore.GlobalFFOptions.Configure(options => options.BinaryFolder = ffmpegBin);
- Debug.WriteLine($"[CONFIG] FFMpeg bin folder set: {ffmpegBin}");
- }
- else if (TryUseSystemFFMpeg())
- {
- Debug.WriteLine("[CONFIG] Using system FFMpeg from PATH");
- }
+ FFMpegCore.GlobalFFOptions.Configure(o => o.BinaryFolder = ffmpegBin);
+ else if (TryUseSystemFFMpeg()) { }
else if (TryFixMissingFFMpeg(ffmpegBin))
- {
- FFMpegCore.GlobalFFOptions.Configure(options => options.BinaryFolder = ffmpegBin);
- Debug.WriteLine($"[CONFIG] FFMpeg fixed and configured: {ffmpegBin}");
- }
- else
- {
- Debug.WriteLine("[ERROR] FFMpeg configuration failed.");
- }
+ FFMpegCore.GlobalFFOptions.Configure(o => o.BinaryFolder = ffmpegBin);
}
- private bool ValidateFFMpegBinaries(string binFolder)
- {
- if (!Directory.Exists(binFolder))
- return false;
-
- var ffmpegPath = Path.Combine(binFolder, "ffmpeg.exe");
- var ffprobePath = Path.Combine(binFolder, "ffprobe.exe");
-
- return File.Exists(ffmpegPath) && File.Exists(ffprobePath);
- }
+ private bool ValidateFFMpegBinaries(string binFolder) =>
+ Directory.Exists(binFolder) &&
+ File.Exists(Path.Combine(binFolder, "ffmpeg.exe")) &&
+ File.Exists(Path.Combine(binFolder, "ffprobe.exe"));
private bool TryUseSystemFFMpeg()
{
try
{
- var processInfo = new ProcessStartInfo
- {
- FileName = "ffmpeg",
- Arguments = "-version",
- UseShellExecute = false,
- RedirectStandardOutput = true,
- CreateNoWindow = true
- };
-
- using var process = Process.Start(processInfo);
- return process != null && process.WaitForExit(5000) && process.ExitCode == 0;
- }
- catch
- {
- return false;
+ var psi = new ProcessStartInfo { FileName = "ffmpeg", Arguments = "-version", UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true };
+ using var p = Process.Start(psi);
+ return p != null && p.WaitForExit(4000) && p.ExitCode == 0;
}
+ catch { return false; }
}
private bool TryFixMissingFFMpeg(string binFolder)
{
- if (string.IsNullOrEmpty(binFolder) || !Directory.Exists(binFolder))
- return false;
-
+ if (string.IsNullOrEmpty(binFolder) || !Directory.Exists(binFolder)) return false;
var ffmpegPath = Path.Combine(binFolder, "ffmpeg.exe");
var ffprobePath = Path.Combine(binFolder, "ffprobe.exe");
-
if (!File.Exists(ffmpegPath) && File.Exists(ffprobePath))
{
- try
- {
- Debug.WriteLine("[FIX] Attempting to copy ffprobe.exe as ffmpeg.exe");
- File.Copy(ffprobePath, ffmpegPath, true);
- return File.Exists(ffmpegPath);
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"[ERROR] Failed to copy ffprobe as ffmpeg: {ex.Message}");
- return false;
- }
+ try { File.Copy(ffprobePath, ffmpegPath, true); return File.Exists(ffmpegPath); } catch { return false; }
}
-
return false;
}
private void BrowseVideoButton_Click(object sender, RoutedEventArgs e)
{
- Debug.WriteLine("[UI] BrowseVideoButton_Click invoked.");
- var dialog = new WpfOpenFileDialog
- {
- Filter = "Video files (*.mp4;*.avi;*.mov;*.mkv;*.wmv)|*.mp4;*.avi;*.mov;*.mkv;*.wmv|All files (*.*)|*.*",
- Multiselect = true
- };
-
- if (dialog.ShowDialog() == true)
- {
- AddVideosToQueue(dialog.FileNames);
- }
+ var dialog = new WpfOpenFileDialog { Filter = "Video (*.mp4;*.avi;*.mov;*.mkv;*.wmv)|*.mp4;*.avi;*.mov;*.mkv;*.wmv|Tutti i file (*.*)|*.*", Multiselect = true };
+ if (dialog.ShowDialog() == true) AddVideosToQueue(dialog.FileNames);
}
private void ImportFolderButton_Click(object sender, RoutedEventArgs e)
{
- using var dialog = new System.Windows.Forms.FolderBrowserDialog
- {
- Description = "Seleziona la cartella contenente i video da importare",
- ShowNewFolderButton = false
- };
+ using var dialog = new System.Windows.Forms.FolderBrowserDialog { Description = "Seleziona la cartella con i video", ShowNewFolderButton = false };
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
- var folder = dialog.SelectedPath;
try
{
- var videoFiles = Directory.EnumerateFiles(folder, "*.*", SearchOption.TopDirectoryOnly)
- .Where(IsVideoFile)
- .ToArray();
- if (videoFiles.Length == 0)
+ var files = Directory.EnumerateFiles(dialog.SelectedPath, "*.*", SearchOption.TopDirectoryOnly).Where(IsVideoFile).ToArray();
+ if (files.Length == 0)
{
- WpfMessageBox.Show("Nessun file video valido trovato nella cartella.", "Importa Cartella", MessageBoxButton.OK, MessageBoxImage.Information);
+ WpfMessageBox.Show("Nessun file video valido trovato.", "Importa Cartella", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
- AddVideosToQueue(videoFiles);
- StatusText.Text = $"Importati {videoFiles.Length} video dalla cartella.";
+ AddVideosToQueue(files);
+ StatusText.Text = $"Importati {files.Length} video.";
}
catch (Exception ex)
{
- WpfMessageBox.Show($"Errore durante l'importazione: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
+ WpfMessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
- private void AddVideosToQueue(string[] videoPaths)
+ private void AddVideosToQueue(string[] paths)
{
if (string.IsNullOrEmpty(outputFolder))
{
- WpfMessageBox.Show("Seleziona prima una cartella di output.", "Cartella Output Richiesta",
- MessageBoxButton.OK, MessageBoxImage.Warning);
+ WpfMessageBox.Show("Seleziona prima una cartella di output.", "Cartella Output Richiesta", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
-
- var createSubfolder = Settings.Default.CreateSubfolder;
-
- foreach (var videoPath in videoPaths)
- {
- _processingService.AddJob(videoPath, outputFolder, createSubfolder);
- Debug.WriteLine($"[QUEUE] Added video to queue: {Path.GetFileName(videoPath)}");
- }
-
- StatusText.Text = $"Aggiunti {videoPaths.Length} video in coda (Pending)";
- Settings.Default.LastVideoPath = videoPaths.FirstOrDefault();
+ var createSub = Settings.Default.CreateSubfolder;
+ foreach (var p in paths) _processingService.AddJob(p, outputFolder, createSub);
+ StatusText.Text = $"Aggiunti {paths.Length} video (In attesa)";
+ Settings.Default.LastVideoPath = paths.FirstOrDefault();
Settings.Default.Save();
+ UpdateQueueCount();
}
private void SelectOutputFolderButton_Click(object sender, RoutedEventArgs e)
{
- Debug.WriteLine("[UI] SelectOutputFolderButton_Click invoked.");
using var dialog = new System.Windows.Forms.FolderBrowserDialog();
-
- if (!string.IsNullOrEmpty(outputFolder))
- dialog.SelectedPath = outputFolder;
-
+ if (!string.IsNullOrEmpty(outputFolder)) dialog.SelectedPath = outputFolder;
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
outputFolder = dialog.SelectedPath;
- StatusText.Text = $"Output folder: {outputFolder}";
+ GlobalOutputFolderTextBox.Text = outputFolder;
+ StatusText.Text = "Cartella output aggiornata";
Settings.Default.LastOutputFolder = outputFolder;
Settings.Default.Save();
- Debug.WriteLine($"[INFO] Output folder selected: {outputFolder}");
}
}
private void SettingsButton_Click(object sender, RoutedEventArgs e)
{
- var settingsWindow = new SettingsWindow
+ var win = new SettingsWindow { Owner = this };
+ if (win.ShowDialog() == true)
{
- Owner = this
- };
-
- if (settingsWindow.ShowDialog() == true)
- {
- // Reconfigure FFMpeg if settings changed
ConfigureFFMpeg();
StatusText.Text = "Impostazioni aggiornate";
}
@@ -317,97 +249,59 @@ namespace Ganimede
{
if (_processingService.JobQueue.Count == 0)
{
- WpfMessageBox.Show("Nessun video in coda. Aggiungi prima dei video.", "Coda Vuota",
- MessageBoxButton.OK, MessageBoxImage.Information);
+ WpfMessageBox.Show("Nessun video in coda.", "Coda Vuota", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
-
- var pendingJobs = _processingService.JobQueue.Count(job => job.Status == JobStatus.Pending);
- if (pendingJobs == 0)
+ if (_processingService.JobQueue.All(j => j.Status != JobStatus.Pending))
{
- WpfMessageBox.Show("Nessun job in stato Pending.", "Nessun Job",
- MessageBoxButton.OK, MessageBoxImage.Information);
+ WpfMessageBox.Show("Nessun job in stato In attesa.", "Nessun Job", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
-
- Debug.WriteLine("[QUEUE] Starting queue processing manually");
await _processingService.StartProcessingAsync();
+ UpdateJobsSummary();
}
private void StopQueueButton_Click(object sender, RoutedEventArgs e)
{
_processingService.StopProcessing();
- StatusText.Text = "Arresto elaborazione in corso...";
- Debug.WriteLine("[QUEUE] Stop processing requested by user");
+ StatusText.Text = "Arresto in corso...";
+ UpdateJobsSummary();
}
- private void JobCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
- {
- UpdateSelectedJobs();
- }
+ private void JobCheckBox_CheckedChanged(object sender, RoutedEventArgs e) => UpdateSelectedJobs();
private void UpdateSelectedJobs()
{
_selectedJobs.Clear();
-
- // Find all checked checkboxes in the ItemsControl
- var checkBoxes = FindVisualChildren(QueueItemsControl).Where(cb => cb.Name == "JobCheckBox");
-
- foreach (var checkBox in checkBoxes)
- {
- if (checkBox.IsChecked == true && checkBox.Tag is VideoJob job)
- {
- _selectedJobs.Add(job);
- }
- }
-
- // Update configure button state
+ var boxes = FindVisualChildren(QueueItemsControl).Where(cb => cb.Name == "JobCheckBox");
+ foreach (var cb in boxes) if (cb.IsChecked == true && cb.Tag is VideoJob job) _selectedJobs.Add(job);
ConfigureSelectedButton.IsEnabled = _selectedJobs.Count > 0;
-
- Debug.WriteLine($"[SELECTION] {_selectedJobs.Count} jobs selected");
}
private void ConfigureSelectedButton_Click(object sender, RoutedEventArgs e)
{
- if (_selectedJobs.Count == 0)
- return;
-
- var configWindow = new JobConfigWindow(_selectedJobs.ToList())
+ if (_selectedJobs.Count == 0) return;
+ var cfg = new JobConfigWindow(_selectedJobs.ToList()) { Owner = this };
+ if (cfg.ShowDialog() == true)
{
- Owner = this
- };
-
- if (configWindow.ShowDialog() == true)
- {
- StatusText.Text = $"Configurazione applicata a {_selectedJobs.Count} job(s)";
-
- // Reset job output folders for those without custom settings
+ StatusText.Text = $"Configurazione applicata a {_selectedJobs.Count} job";
foreach (var job in _selectedJobs.Where(j => string.IsNullOrEmpty(j.CustomOutputFolder)))
{
- var createSubfolder = Settings.Default.CreateSubfolder;
- if (job.ExtractionMode == ExtractionMode.SingleFrame)
- {
- job.OutputFolder = outputFolder; // single frame directly
- }
- else
- {
- job.OutputFolder = createSubfolder
- ? Path.Combine(outputFolder, job.VideoName)
- : outputFolder;
- }
+ var createSub = Settings.Default.CreateSubfolder;
+ job.OutputFolder = job.ExtractionMode == ExtractionMode.SingleFrame ? outputFolder : (createSub ? Path.Combine(outputFolder, job.VideoName) : outputFolder);
}
+ UpdateJobsSummary();
}
}
private void RemoveQueueItem_Click(object sender, RoutedEventArgs e)
{
- if (sender is WpfButton button && button.Tag is VideoJob job)
+ if (sender is WpfButton btn && btn.Tag is VideoJob job)
{
_processingService.CancelJob(job);
if (job.Status == JobStatus.Cancelled || job.Status == JobStatus.Pending)
- {
_processingService.JobQueue.Remove(job);
- }
+ UpdateQueueCount();
}
}
@@ -415,83 +309,55 @@ namespace Ganimede
{
_processingService.RemoveCompletedJobs();
StatusText.Text = "Job completati rimossi";
+ UpdateQueueCount();
}
private void ClearAllButton_Click(object sender, RoutedEventArgs e)
{
- var processingJobs = _processingService.JobQueue.Where(j => j.Status == JobStatus.Processing).ToList();
-
- if (processingJobs.Count > 0)
+ var processing = _processingService.JobQueue.Any(j => j.Status == JobStatus.Processing);
+ if (processing)
{
- var result = WpfMessageBox.Show(
- $"Ci sono {processingJobs.Count} job in elaborazione.\n\n" +
- "Sรฌ: Ferma tutto e svuota la coda\n" +
- "No: Rimuovi solo job completati/pending\n" +
- "Annulla: Non fare nulla",
- "Job in corso",
- MessageBoxButton.YesNoCancel,
- MessageBoxImage.Question);
-
- switch (result)
+ var res = WpfMessageBox.Show("Ci sono job in elaborazione.\n\nSi: Ferma e svuota la coda\nNo: Rimuovi solo job non in elaborazione\nAnnulla: Annulla", "Conferma", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
+ if (res == MessageBoxResult.Cancel) return;
+ if (res == MessageBoxResult.Yes)
{
- case MessageBoxResult.Yes:
- _processingService.StopProcessing();
- _processingService.JobQueue.Clear();
- thumbnails.Clear();
- StatusText.Text = "Tutti i job rimossi e elaborazione fermata";
- break;
- case MessageBoxResult.No:
- for (int i = _processingService.JobQueue.Count - 1; i >= 0; i--)
- {
- if (_processingService.JobQueue[i].Status != JobStatus.Processing)
- {
- _processingService.JobQueue.RemoveAt(i);
- }
- }
- StatusText.Text = "Coda ripulita (job in corso mantenuti)";
- break;
- case MessageBoxResult.Cancel:
- return;
+ _processingService.StopProcessing();
+ _processingService.JobQueue.Clear();
+ thumbnails.Clear();
+ }
+ else if (res == MessageBoxResult.No)
+ {
+ for (int i = _processingService.JobQueue.Count - 1; i >= 0; i--)
+ if (_processingService.JobQueue[i].Status != JobStatus.Processing)
+ _processingService.JobQueue.RemoveAt(i);
}
}
else
{
- var result = WpfMessageBox.Show("Sicuro di voler rimuovere tutti i job?",
- "Pulisci Tutto", MessageBoxButton.YesNo, MessageBoxImage.Question);
-
- if (result == MessageBoxResult.Yes)
+ if (WpfMessageBox.Show("Rimuovere tutti i job?", "Conferma", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
_processingService.JobQueue.Clear();
thumbnails.Clear();
- StatusText.Text = "Tutti i job rimossi";
}
}
+ StatusText.Text = "Coda aggiornata";
+ UpdateQueueCount();
}
- private static bool IsVideoFile(string filePath)
+ private static bool IsVideoFile(string path)
{
- var extension = Path.GetExtension(filePath).ToLowerInvariant();
- return extension is ".mp4" or ".avi" or ".mov" or ".mkv" or ".wmv" or ".flv" or ".webm";
+ var ext = Path.GetExtension(path).ToLowerInvariant();
+ return ext is ".mp4" or ".avi" or ".mov" or ".mkv" or ".wmv" or ".flv" or ".webm";
}
- // Helper method to find visual children
- private static IEnumerable FindVisualChildren(DependencyObject depObj) where T : DependencyObject
+ private static IEnumerable FindVisualChildren(DependencyObject dep) where T : DependencyObject
{
- if (depObj != null)
+ if (dep == null) yield break;
+ for (int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(dep); i++)
{
- for (int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(depObj); i++)
- {
- DependencyObject child = System.Windows.Media.VisualTreeHelper.GetChild(depObj, i);
- if (child != null && child is T)
- {
- yield return (T)child;
- }
-
- foreach (T childOfChild in FindVisualChildren(child))
- {
- yield return childOfChild;
- }
- }
+ var child = System.Windows.Media.VisualTreeHelper.GetChild(dep, i);
+ if (child is T t) yield return t;
+ foreach (var c in FindVisualChildren(child)) yield return c;
}
}
}
diff --git a/Ganimede/Ganimede/Windows/JobConfigWindow.xaml b/Ganimede/Ganimede/Windows/JobConfigWindow.xaml
index 0c4f837..b715e41 100644
--- a/Ganimede/Ganimede/Windows/JobConfigWindow.xaml
+++ b/Ganimede/Ganimede/Windows/JobConfigWindow.xaml
@@ -4,131 +4,183 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
- Title="Configure Selected Jobs" Height="560" Width="600"
- Background="#222" WindowStartupLocation="CenterOwner">
-
+ Title="Configurazione Job" Height="640" Width="640"
+ Background="#1E2228" WindowStartupLocation="CenterOwner">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/Ganimede/Ganimede/Windows/JobConfigWindow.xaml.cs b/Ganimede/Ganimede/Windows/JobConfigWindow.xaml.cs
index 5a246a7..91fd72e 100644
--- a/Ganimede/Ganimede/Windows/JobConfigWindow.xaml.cs
+++ b/Ganimede/Ganimede/Windows/JobConfigWindow.xaml.cs
@@ -17,32 +17,21 @@ namespace Ganimede.Windows
{
InitializeComponent();
_selectedJobs = selectedJobs;
-
- SelectedJobsText.Text = $"{selectedJobs.Count} job(s) selected";
+ SelectedJobsText.Text = $"{selectedJobs.Count} job selezionati";
LoadCurrentSettings();
}
private void SetExtractionModeRadio(ExtractionMode mode)
{
- var fullObj = FindName("ExtractionFullRadio");
- if (fullObj is System.Windows.Controls.RadioButton fullRb)
- fullRb.IsChecked = mode == ExtractionMode.Full;
- var singleObj = FindName("ExtractionSingleRadio");
- if (singleObj is System.Windows.Controls.RadioButton singleRb)
- singleRb.IsChecked = mode == ExtractionMode.SingleFrame;
- var autoObj = FindName("ExtractionAutoRadio");
- if (autoObj is System.Windows.Controls.RadioButton autoRb)
- autoRb.IsChecked = mode == ExtractionMode.Auto;
+ if (FindName("ExtractionFullRadio") is System.Windows.Controls.RadioButton fullRb) fullRb.IsChecked = mode == ExtractionMode.Full;
+ if (FindName("ExtractionSingleRadio") is System.Windows.Controls.RadioButton singleRb) singleRb.IsChecked = mode == ExtractionMode.SingleFrame;
+ if (FindName("ExtractionAutoRadio") is System.Windows.Controls.RadioButton autoRb) autoRb.IsChecked = mode == ExtractionMode.Auto;
}
private ExtractionMode GetSelectedExtractionMode()
{
- var singleObj = FindName("ExtractionSingleRadio");
- if (singleObj is System.Windows.Controls.RadioButton singleRb && singleRb.IsChecked == true)
- return ExtractionMode.SingleFrame;
- var autoObj = FindName("ExtractionAutoRadio");
- if (autoObj is System.Windows.Controls.RadioButton autoRb && autoRb.IsChecked == true)
- return ExtractionMode.Auto;
+ if (FindName("ExtractionSingleRadio") is System.Windows.Controls.RadioButton singleRb && singleRb.IsChecked == true) return ExtractionMode.SingleFrame;
+ if (FindName("ExtractionAutoRadio") is System.Windows.Controls.RadioButton autoRb && autoRb.IsChecked == true) return ExtractionMode.Auto;
return ExtractionMode.Full;
}
@@ -52,8 +41,6 @@ namespace Ganimede.Windows
if (firstJob != null)
{
SetExtractionModeRadio(firstJob.ExtractionMode);
-
- // Output settings
if (!string.IsNullOrEmpty(firstJob.CustomOutputFolder))
{
UseCustomOutputCheckBox.IsChecked = true;
@@ -61,7 +48,6 @@ namespace Ganimede.Windows
}
CreateSubfolderCheckBox.IsChecked = firstJob.CustomCreateSubfolder;
- // Frame size settings
if (!string.IsNullOrEmpty(firstJob.CustomFrameSize))
{
UseCustomFrameSizeCheckBox.IsChecked = true;
@@ -75,7 +61,6 @@ namespace Ganimede.Windows
}
}
- // Overwrite settings
if (firstJob.CustomOverwriteMode.HasValue)
{
UseCustomOverwriteCheckBox.IsChecked = true;
@@ -89,7 +74,6 @@ namespace Ganimede.Windows
}
}
- // Naming settings
if (firstJob.CustomNamingPattern.HasValue)
{
UseCustomNamingCheckBox.IsChecked = true;
@@ -105,12 +89,9 @@ namespace Ganimede.Windows
}
}
- if (CustomFrameSizeComboBox.SelectedItem == null)
- CustomFrameSizeComboBox.SelectedIndex = 0;
- if (CustomOverwriteComboBox.SelectedItem == null)
- CustomOverwriteComboBox.SelectedIndex = 0;
- if (CustomNamingComboBox.SelectedItem == null)
- CustomNamingComboBox.SelectedIndex = 0;
+ if (CustomFrameSizeComboBox.SelectedItem == null) CustomFrameSizeComboBox.SelectedIndex = 0;
+ if (CustomOverwriteComboBox.SelectedItem == null) CustomOverwriteComboBox.SelectedIndex = 0;
+ if (CustomNamingComboBox.SelectedItem == null) CustomNamingComboBox.SelectedIndex = 0;
UpdateJobNamingPreview();
}
@@ -130,7 +111,7 @@ namespace Ganimede.Windows
}
else
{
- JobNamingPreviewText.Text = "Video1_000001.png (using default)";
+ JobNamingPreviewText.Text = "Video1_000001.png (default)";
}
}
catch
@@ -148,19 +129,9 @@ namespace Ganimede.Windows
private void BrowseCustomOutputButton_Click(object sender, RoutedEventArgs e)
{
- using var dialog = new System.Windows.Forms.FolderBrowserDialog
- {
- Description = "Select custom output folder for selected jobs",
- ShowNewFolderButton = true
- };
-
- if (!string.IsNullOrEmpty(CustomOutputTextBox.Text))
- dialog.SelectedPath = CustomOutputTextBox.Text;
-
- if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
- {
- CustomOutputTextBox.Text = dialog.SelectedPath;
- }
+ using var dialog = new System.Windows.Forms.FolderBrowserDialog { Description = "Seleziona cartella di output personalizzata", ShowNewFolderButton = true };
+ if (!string.IsNullOrEmpty(CustomOutputTextBox.Text)) dialog.SelectedPath = CustomOutputTextBox.Text;
+ if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) CustomOutputTextBox.Text = dialog.SelectedPath;
}
private void ApplyButton_Click(object sender, RoutedEventArgs e)
@@ -176,50 +147,28 @@ namespace Ganimede.Windows
{
job.CustomOutputFolder = CustomOutputTextBox.Text;
job.CustomCreateSubfolder = CreateSubfolderCheckBox.IsChecked ?? true;
- // Do NOT create per-video folder if SingleFrame
if (job.CustomCreateSubfolder && job.ExtractionMode != ExtractionMode.SingleFrame)
- {
job.OutputFolder = System.IO.Path.Combine(job.CustomOutputFolder, job.VideoName);
- }
else
- {
- job.OutputFolder = job.CustomOutputFolder; // single frame goes directly here
- }
+ job.OutputFolder = job.CustomOutputFolder;
}
else
{
job.CustomOutputFolder = string.Empty;
- // OutputFolder will be recalculated in MainWindow if needed
}
if (UseCustomFrameSizeCheckBox.IsChecked == true && CustomFrameSizeComboBox.SelectedItem is ComboBoxItem frameSizeItem)
- {
job.CustomFrameSize = frameSizeItem.Tag?.ToString() ?? string.Empty;
- }
- else
- {
- job.CustomFrameSize = string.Empty;
- }
+ else job.CustomFrameSize = string.Empty;
- if (UseCustomOverwriteCheckBox.IsChecked == true && CustomOverwriteComboBox.SelectedItem is ComboBoxItem overwriteItem)
- {
- if (Enum.TryParse(overwriteItem.Tag?.ToString(), out var overwriteMode))
- {
- job.CustomOverwriteMode = overwriteMode;
- }
- }
- else
- {
- job.CustomOverwriteMode = null;
- }
+ if (UseCustomOverwriteCheckBox.IsChecked == true && CustomOverwriteComboBox.SelectedItem is ComboBoxItem overwriteItem && Enum.TryParse(overwriteItem.Tag?.ToString(), out var overwriteMode))
+ job.CustomOverwriteMode = overwriteMode;
+ else job.CustomOverwriteMode = null;
- if (UseCustomNamingCheckBox.IsChecked == true && CustomNamingComboBox.SelectedItem is ComboBoxItem namingItem)
+ if (UseCustomNamingCheckBox.IsChecked == true && CustomNamingComboBox.SelectedItem is ComboBoxItem namingItem && Enum.TryParse(namingItem.Tag?.ToString(), out var namingPattern))
{
- if (Enum.TryParse(namingItem.Tag?.ToString(), out var namingPattern))
- {
- job.CustomNamingPattern = namingPattern;
- job.CustomPrefix = string.IsNullOrWhiteSpace(CustomNamingPrefixTextBox.Text) ? "custom" : CustomNamingPrefixTextBox.Text;
- }
+ job.CustomNamingPattern = namingPattern;
+ job.CustomPrefix = string.IsNullOrWhiteSpace(CustomNamingPrefixTextBox.Text) ? "custom" : CustomNamingPrefixTextBox.Text;
}
else
{
@@ -227,13 +176,12 @@ namespace Ganimede.Windows
job.CustomPrefix = string.Empty;
}
}
-
DialogResult = true;
Close();
}
catch (Exception ex)
{
- WpfMessageBox.Show($"Error applying settings: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
+ WpfMessageBox.Show($"Errore durante l'applicazione delle impostazioni: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
diff --git a/Ganimede/Ganimede/Windows/SettingsWindow.xaml b/Ganimede/Ganimede/Windows/SettingsWindow.xaml
index e47a0e5..dc8ad8a 100644
--- a/Ganimede/Ganimede/Windows/SettingsWindow.xaml
+++ b/Ganimede/Ganimede/Windows/SettingsWindow.xaml
@@ -4,9 +4,9 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
- Title="Settings" Height="560" Width="600"
- Background="#222" WindowStartupLocation="CenterOwner">
-
+ Title="Impostazioni" Height="600" Width="640"
+ Background="#1E2228" WindowStartupLocation="CenterOwner">
+
@@ -14,113 +14,102 @@
-
+
-
-
-
+
+
+
-
-
-
+
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
-
+
-
-
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -128,9 +117,9 @@
-
-
diff --git a/Ganimede/Ganimede/Windows/SettingsWindow.xaml.cs b/Ganimede/Ganimede/Windows/SettingsWindow.xaml.cs
index adcf44d..6a98641 100644
--- a/Ganimede/Ganimede/Windows/SettingsWindow.xaml.cs
+++ b/Ganimede/Ganimede/Windows/SettingsWindow.xaml.cs
@@ -24,9 +24,8 @@ namespace Ganimede.Windows
DefaultOutputTextBox.Text = Settings.Default.LastOutputFolder;
CreateSubfolderCheckBox.IsChecked = Settings.Default.CreateSubfolder;
var singleFrameChk = GetCheckBox("SingleFrameUseSubfolderCheckBox");
- if (singleFrameChk != null)
- singleFrameChk.IsChecked = Settings.Default.SingleFrameUseSubfolder;
-
+ if (singleFrameChk != null) singleFrameChk.IsChecked = Settings.Default.SingleFrameUseSubfolder;
+
var frameSize = Settings.Default.FrameSize;
foreach (System.Windows.Controls.ComboBoxItem item in FrameSizeComboBox.Items)
{
@@ -47,15 +46,14 @@ namespace Ganimede.Windows
}
}
- // Default extraction mode
switch (Settings.Default.DefaultExtractionMode)
{
case "SingleFrame":
- if (GetDefaultModeRadio("DefaultModeSingleRadio") is { } r1) r1.IsChecked = true; break;
+ GetDefaultModeRadio("DefaultModeSingleRadio")!.IsChecked = true; break;
case "Auto":
- if (GetDefaultModeRadio("DefaultModeAutoRadio") is { } r2) r2.IsChecked = true; break;
+ GetDefaultModeRadio("DefaultModeAutoRadio")!.IsChecked = true; break;
default:
- if (GetDefaultModeRadio("DefaultModeFullRadio") is { } r3) r3.IsChecked = true; break;
+ GetDefaultModeRadio("DefaultModeFullRadio")!.IsChecked = true; break;
}
UpdateFFmpegStatus();
@@ -68,53 +66,38 @@ namespace Ganimede.Windows
return "Full";
}
- private bool GetSingleFrameUseSubfolder()
- {
- return GetCheckBox("SingleFrameUseSubfolderCheckBox")?.IsChecked == true;
- }
+ private bool GetSingleFrameUseSubfolder() => GetCheckBox("SingleFrameUseSubfolderCheckBox")?.IsChecked == true;
private void UpdateFFmpegStatus()
{
var path = FFmpegPathTextBox.Text;
if (string.IsNullOrEmpty(path))
{
- FFmpegStatusText.Text = "No path specified";
+ FFmpegStatusText.Text = "Nessun percorso specificato";
FFmpegStatusText.Foreground = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Orange);
}
else if (ValidateFFMpegPath(path))
{
- FFmpegStatusText.Text = "? Valid FFmpeg installation found";
+ FFmpegStatusText.Text = "? FFmpeg valido";
FFmpegStatusText.Foreground = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.LightGreen);
}
else
{
- FFmpegStatusText.Text = "? FFmpeg binaries not found in specified path";
+ FFmpegStatusText.Text = "? Binari FFmpeg non trovati";
FFmpegStatusText.Foreground = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red);
}
}
private bool ValidateFFMpegPath(string path)
{
- if (!Directory.Exists(path))
- return false;
-
- var ffmpegPath = Path.Combine(path, "ffmpeg.exe");
- var ffprobePath = Path.Combine(path, "ffprobe.exe");
-
- return File.Exists(ffmpegPath) && File.Exists(ffprobePath);
+ if (!Directory.Exists(path)) return false;
+ return File.Exists(Path.Combine(path, "ffmpeg.exe")) && File.Exists(Path.Combine(path, "ffprobe.exe"));
}
private void BrowseFFmpegButton_Click(object sender, RoutedEventArgs e)
{
- using var dialog = new System.Windows.Forms.FolderBrowserDialog
- {
- Description = "Select FFmpeg binary folder",
- ShowNewFolderButton = false
- };
-
- if (!string.IsNullOrEmpty(FFmpegPathTextBox.Text))
- dialog.SelectedPath = FFmpegPathTextBox.Text;
-
+ using var dialog = new System.Windows.Forms.FolderBrowserDialog { Description = "Seleziona cartella binari FFmpeg", ShowNewFolderButton = false };
+ if (!string.IsNullOrEmpty(FFmpegPathTextBox.Text)) dialog.SelectedPath = FFmpegPathTextBox.Text;
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
FFmpegPathTextBox.Text = dialog.SelectedPath;
@@ -124,19 +107,9 @@ namespace Ganimede.Windows
private void BrowseOutputButton_Click(object sender, RoutedEventArgs e)
{
- using var dialog = new System.Windows.Forms.FolderBrowserDialog
- {
- Description = "Select default output folder",
- ShowNewFolderButton = true
- };
-
- if (!string.IsNullOrEmpty(DefaultOutputTextBox.Text))
- dialog.SelectedPath = DefaultOutputTextBox.Text;
-
- if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
- {
- DefaultOutputTextBox.Text = dialog.SelectedPath;
- }
+ using var dialog = new System.Windows.Forms.FolderBrowserDialog { Description = "Seleziona cartella output predefinita", ShowNewFolderButton = true };
+ if (!string.IsNullOrEmpty(DefaultOutputTextBox.Text)) dialog.SelectedPath = DefaultOutputTextBox.Text;
+ if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) DefaultOutputTextBox.Text = dialog.SelectedPath;
}
private void NamingPatternComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { }
@@ -156,13 +129,13 @@ namespace Ganimede.Windows
Settings.Default.DefaultExtractionMode = GetSelectedDefaultExtractionMode();
Settings.Default.SingleFrameUseSubfolder = GetSingleFrameUseSubfolder();
Settings.Default.Save();
- Debug.WriteLine("[SETTINGS] Settings saved successfully");
+ Debug.WriteLine("[SETTINGS] Salvate");
DialogResult = true;
Close();
}
catch (Exception ex)
{
- WpfMessageBox.Show($"Error saving settings: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
+ WpfMessageBox.Show($"Errore durante il salvataggio: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
Debug.WriteLine($"[ERROR] Failed to save settings: {ex.Message}");
}
}