From 214e54017007cef6e7129caaf6c3ac7dcf7db8e5 Mon Sep 17 00:00:00 2001 From: MaddoScientisto Date: Mon, 16 Feb 2026 18:58:15 +0100 Subject: [PATCH] Mutually exclusive thumbnail mode selection in UI Implement mutually exclusive logic for thumbnail display modes in DataModel and MainForm. Add ThumbnailMode property for authoritative state. Replace radio button bindings with event handlers. Synchronize UI with model changes. Explicitly map thumbnail flags to PicSettings. Force WinForms startup, disabling WPF branch. --- imagecatalog/DataModel.cs | 139 ++++++++++++++++++++++++++++++ imagecatalog/MainForm.Designer.cs | 2 + imagecatalog/MainForm.cs | 72 ++++++++++++++++ imagecatalog/Program.cs | 32 +++---- 4 files changed, 229 insertions(+), 16 deletions(-) diff --git a/imagecatalog/DataModel.cs b/imagecatalog/DataModel.cs index 683d296..a138109 100644 --- a/imagecatalog/DataModel.cs +++ b/imagecatalog/DataModel.cs @@ -836,8 +836,22 @@ namespace ImageCatalog_2 get => _showPhotoNumber; set { + if (_showPhotoNumber == value) return; _showPhotoNumber = value; + if (value) + { + // ensure mutually exclusive choices + _addTimeToThumbnails = false; + _addTextToThumbnails = false; + _addNumberAndTimeToThumbnails = false; + _addRaceTimeToThumbnails = false; + NotifyPropertyChanged(nameof(AddTimeToThumbnails)); + NotifyPropertyChanged(nameof(AddTextToThumbnails)); + NotifyPropertyChanged(nameof(AddNumberAndTimeToThumbnails)); + NotifyPropertyChanged(nameof(AddRaceTimeToThumbnails)); + } NotifyPropertyChanged(); + NotifyPropertyChanged(nameof(ThumbnailMode)); } } @@ -949,7 +963,20 @@ namespace ImageCatalog_2 get => _addTimeToThumbnails; set { + if (_addTimeToThumbnails == value) return; _addTimeToThumbnails = value; + if (value) + { + // ensure mutually exclusive choices + _addTextToThumbnails = false; + _showPhotoNumber = false; + _addNumberAndTimeToThumbnails = false; + _addRaceTimeToThumbnails = false; + NotifyPropertyChanged(nameof(AddTextToThumbnails)); + NotifyPropertyChanged(nameof(ShowPhotoNumber)); + NotifyPropertyChanged(nameof(AddNumberAndTimeToThumbnails)); + NotifyPropertyChanged(nameof(AddRaceTimeToThumbnails)); + } NotifyPropertyChanged(); } } @@ -1004,7 +1031,20 @@ namespace ImageCatalog_2 get => _addTextToThumbnails; set { + if (_addTextToThumbnails == value) return; _addTextToThumbnails = value; + if (value) + { + // ensure mutually exclusive choices + _addTimeToThumbnails = false; + _showPhotoNumber = false; + _addNumberAndTimeToThumbnails = false; + _addRaceTimeToThumbnails = false; + NotifyPropertyChanged(nameof(AddTimeToThumbnails)); + NotifyPropertyChanged(nameof(ShowPhotoNumber)); + NotifyPropertyChanged(nameof(AddNumberAndTimeToThumbnails)); + NotifyPropertyChanged(nameof(AddRaceTimeToThumbnails)); + } NotifyPropertyChanged(); } } @@ -1015,7 +1055,20 @@ namespace ImageCatalog_2 get => _addRaceTimeToThumbnails; set { + if (_addRaceTimeToThumbnails == value) return; _addRaceTimeToThumbnails = value; + if (value) + { + // ensure mutually exclusive choices + _addTimeToThumbnails = false; + _addTextToThumbnails = false; + _showPhotoNumber = false; + _addNumberAndTimeToThumbnails = false; + NotifyPropertyChanged(nameof(AddTimeToThumbnails)); + NotifyPropertyChanged(nameof(AddTextToThumbnails)); + NotifyPropertyChanged(nameof(ShowPhotoNumber)); + NotifyPropertyChanged(nameof(AddNumberAndTimeToThumbnails)); + } NotifyPropertyChanged(); } } @@ -1026,11 +1079,79 @@ namespace ImageCatalog_2 get => _addNumberAndTimeToThumbnails; set { + if (_addNumberAndTimeToThumbnails == value) return; _addNumberAndTimeToThumbnails = value; + if (value) + { + // ensure mutually exclusive choices + _addTimeToThumbnails = false; + _addTextToThumbnails = false; + _showPhotoNumber = false; + _addRaceTimeToThumbnails = false; + NotifyPropertyChanged(nameof(AddTimeToThumbnails)); + NotifyPropertyChanged(nameof(AddTextToThumbnails)); + NotifyPropertyChanged(nameof(ShowPhotoNumber)); + NotifyPropertyChanged(nameof(AddRaceTimeToThumbnails)); + } NotifyPropertyChanged(); } } + // Single authoritative thumbnail mode string to avoid conflicting bindings + // Possible values: "None", "Text", "Time", "Number", "NumberAndTime", "RaceTime" + public string ThumbnailMode + { + get + { + if (AddTextToThumbnails) return "Text"; + if (AddTimeToThumbnails) return "Time"; + if (ShowPhotoNumber) return "Number"; + if (AddNumberAndTimeToThumbnails) return "NumberAndTime"; + if (AddRaceTimeToThumbnails) return "RaceTime"; + return "None"; + } + set + { + var current = ThumbnailMode; + if (string.Equals(current, value, StringComparison.OrdinalIgnoreCase)) return; + + // Set the boolean flags via their public setters so mutual-exclusion logic runs + switch ((value ?? string.Empty).ToLowerInvariant()) + { + case "text": + AddTextToThumbnails = true; + break; + case "time": + AddTimeToThumbnails = true; + break; + case "number": + ShowPhotoNumber = true; + break; + case "numberandtime": + AddNumberAndTimeToThumbnails = true; + break; + case "racetime": + AddRaceTimeToThumbnails = true; + break; + default: + // clear all + _addTimeToThumbnails = false; + _addTextToThumbnails = false; + _showPhotoNumber = false; + _addRaceTimeToThumbnails = false; + _addNumberAndTimeToThumbnails = false; + NotifyPropertyChanged(nameof(AddTimeToThumbnails)); + NotifyPropertyChanged(nameof(AddTextToThumbnails)); + NotifyPropertyChanged(nameof(ShowPhotoNumber)); + NotifyPropertyChanged(nameof(AddRaceTimeToThumbnails)); + NotifyPropertyChanged(nameof(AddNumberAndTimeToThumbnails)); + break; + } + + NotifyPropertyChanged(nameof(ThumbnailMode)); + } + } + // Image processing progress and status private string _processingStatus = ""; public string ProcessingStatus @@ -1132,6 +1253,24 @@ namespace ImageCatalog_2 // Update PicSettings from DataModel using AutoMapper _mapper.Map(this, _picSettings); + // Explicitly ensure thumbnail-related flags are applied to PicSettings + // because AutoMapper may not map differently-named properties. + try + { + _picSettings.AggiungiScritteMiniature = this.AddTextToThumbnails; + _picSettings.UsaOrarioMiniatura = this.AddTimeToThumbnails; + _picSettings.AggNumTempMin = this.AddNumberAndTimeToThumbnails; + _picSettings.AggTempoGaraMin = this.AddRaceTimeToThumbnails; + _picSettings.CreaMiniature = this.CreateThumbnails; + _picSettings.LarghezzaSmall = this.ThumbnailWidth; + _picSettings.AltezzaSmall = this.ThumbnailHeight; + _picSettings.DimMin = this.FontSizeThumbnail; + _picSettings.JpegQualityMin = this.JpegQualityThumbnail; + } + catch + { + // Best-effort; do not fail processing on mapping issues + } var imageCreationOptions = new ImageCreationStuff.Options { diff --git a/imagecatalog/MainForm.Designer.cs b/imagecatalog/MainForm.Designer.cs index edb3bb1..136241c 100644 --- a/imagecatalog/MainForm.Designer.cs +++ b/imagecatalog/MainForm.Designer.cs @@ -1404,6 +1404,7 @@ namespace ImageCatalog // RadioButton4 // RadioButton4.AutoSize = true; + RadioButton4.DataBindings.Add(new Binding("Checked", bindingSource1, "AddTimeToThumbnails", true, DataSourceUpdateMode.OnPropertyChanged)); RadioButton4.Location = new Point(30, 93); RadioButton4.Margin = new Padding(6, 8, 6, 8); RadioButton4.Name = "RadioButton4"; @@ -1416,6 +1417,7 @@ namespace ImageCatalog // RadioButton6 // RadioButton6.AutoSize = true; + RadioButton6.DataBindings.Add(new Binding("Checked", bindingSource1, "ShowPhotoNumber", true, DataSourceUpdateMode.OnPropertyChanged)); RadioButton6.Location = new Point(258, 38); RadioButton6.Margin = new Padding(6, 8, 6, 8); RadioButton6.Name = "RadioButton6"; diff --git a/imagecatalog/MainForm.cs b/imagecatalog/MainForm.cs index 684a60c..674f29d 100644 --- a/imagecatalog/MainForm.cs +++ b/imagecatalog/MainForm.cs @@ -83,6 +83,55 @@ public partial class MainForm // Watch for model changes so we can reflect external updates Model.PropertyChanged += Model_PropertyChanged; + // Fix thumbnail radio buttons: clear designer bindings to avoid binding vs click conflicts + RadioButton3.DataBindings.Clear(); + RadioButton4.DataBindings.Clear(); + RadioButton5.DataBindings.Clear(); + RadioButton6.DataBindings.Clear(); + RadioButton7.DataBindings.Clear(); + + // Initialize radio state from model (thumbnail options) + try + { + _suppressRadioUpdates = true; + RadioButton3.Checked = Model.AddTextToThumbnails; + RadioButton4.Checked = Model.AddTimeToThumbnails; + RadioButton6.Checked = Model.ShowPhotoNumber; + RadioButton7.Checked = Model.AddNumberAndTimeToThumbnails; + RadioButton5.Checked = Model.AddRaceTimeToThumbnails; + } + finally + { + _suppressRadioUpdates = false; + } + + // Use CheckedChanged handlers to set the authoritative ThumbnailMode on the model + RadioButton3.CheckedChanged += (s, ev) => + { + if (_suppressRadioUpdates) return; + if (RadioButton3.Checked) Model.ThumbnailMode = "Text"; + }; + RadioButton4.CheckedChanged += (s, ev) => + { + if (_suppressRadioUpdates) return; + if (RadioButton4.Checked) Model.ThumbnailMode = "Time"; + }; + RadioButton6.CheckedChanged += (s, ev) => + { + if (_suppressRadioUpdates) return; + if (RadioButton6.Checked) Model.ThumbnailMode = "Number"; + }; + RadioButton7.CheckedChanged += (s, ev) => + { + if (_suppressRadioUpdates) return; + if (RadioButton7.Checked) Model.ThumbnailMode = "NumberAndTime"; + }; + RadioButton5.CheckedChanged += (s, ev) => + { + if (_suppressRadioUpdates) return; + if (RadioButton5.Checked) Model.ThumbnailMode = "RaceTime"; + }; + // Save user preferences on form close instead of immediately when dialogs are used this.FormClosing += MainForm_FormClosing; @@ -135,6 +184,29 @@ public partial class MainForm _suppressRadioUpdates = false; } } + + // Thumbnail mode changes - reflect back to radio buttons + if (e.PropertyName == nameof(Model.ThumbnailMode) || + e.PropertyName == nameof(Model.AddTextToThumbnails) || + e.PropertyName == nameof(Model.AddTimeToThumbnails) || + e.PropertyName == nameof(Model.ShowPhotoNumber) || + e.PropertyName == nameof(Model.AddNumberAndTimeToThumbnails) || + e.PropertyName == nameof(Model.AddRaceTimeToThumbnails)) + { + try + { + _suppressRadioUpdates = true; + RadioButton3.Checked = Model.AddTextToThumbnails; + RadioButton4.Checked = Model.AddTimeToThumbnails; + RadioButton6.Checked = Model.ShowPhotoNumber; + RadioButton7.Checked = Model.AddNumberAndTimeToThumbnails; + RadioButton5.Checked = Model.AddRaceTimeToThumbnails; + } + finally + { + _suppressRadioUpdates = false; + } + } } protected void BindControls() diff --git a/imagecatalog/Program.cs b/imagecatalog/Program.cs index 067acb5..678864c 100644 --- a/imagecatalog/Program.cs +++ b/imagecatalog/Program.cs @@ -79,24 +79,24 @@ static class Program // the block below and comment out the WPF branch. // ----------------------------------------------------------------------------- // // Force WinForms UI (uncomment to enable) - // var mainForm = serviceProvider.GetRequiredService(); - // // If you want to set the DataModel explicitly on the WinForms form use the lines below - // // var mainViewModel = serviceProvider.GetRequiredService(); - // // mainForm.Model = mainViewModel; - // Application.Run(mainForm); + var mainForm = serviceProvider.GetRequiredService(); + // If you want to set the DataModel explicitly on the WinForms form use the lines below + // var mainViewModel = serviceProvider.GetRequiredService(); + // mainForm.Model = mainViewModel; + Application.Run(mainForm); // ----------------------------------------------------------------------------- - if (serviceProvider.GetService(typeof(ImageCatalog_2.MainWindow)) is ImageCatalog_2.MainWindow wpfMain) - { - // Start WPF app - var app = new System.Windows.Application(); - app.Run(wpfMain); - } - else - { - var mainForm = serviceProvider.GetRequiredService(); - Application.Run(mainForm); - } + //if (serviceProvider.GetService(typeof(ImageCatalog_2.MainWindow)) is ImageCatalog_2.MainWindow wpfMain) + //{ + // // Start WPF app + // var app = new System.Windows.Application(); + // app.Run(wpfMain); + //} + //else + //{ + // var mainForm = serviceProvider.GetRequiredService(); + // Application.Run(mainForm); + //} } private static void ConfigureServices(ServiceCollection services)