diff --git a/.forgejo/workflows/build-windows-avalonia.yml b/.forgejo/workflows/build-windows-avalonia.yml
index 4666242..3d3c18e 100644
--- a/.forgejo/workflows/build-windows-avalonia.yml
+++ b/.forgejo/workflows/build-windows-avalonia.yml
@@ -14,15 +14,15 @@ env:
PROJECT_PATH: imagecatalog/ImageCatalog 2.csproj
PUBLISH_DIR: artifacts/publish/win-x64
ARTIFACT_NAME: imagecatalog-windows-avalonia
- NUGET_SOURCE_NAME: Nuget-Forgejo-AIFotoONLUS
- NUGET_SOURCE_URL: ${{ vars.AIFOTOONLUS_NUGET_SOURCE_URL || format('{0}/api/packages/{1}/nuget/index.json', github.server_url, vars.AIFOTOONLUS_PACKAGE_OWNER || github.repository_owner) }}
+ NUGET_SOURCE_NAME: Nuget-GitLab-AIFotoONLUS
+ NUGET_SOURCE_URL: https://gitlab.com/api/v4/projects/79509532/packages/nuget/index.json
jobs:
build:
runs-on: docker
env:
- FORGEJO_PACKAGE_USERNAME: ${{ secrets.FORGEJO_PACKAGE_USERNAME }}
- FORGEJO_PACKAGE_TOKEN: ${{ secrets.FORGEJO_PACKAGE_TOKEN }}
+ NUGET_USERNAME: ${{ secrets.NUGET_USERNAME }}
+ NUGET_PASSWORD: ${{ secrets.NUGET_PASSWORD }}
steps:
- name: Checkout
@@ -36,12 +36,12 @@ jobs:
- name: Validate NuGet secrets
run: |
set -eu
- if [ -z "${FORGEJO_PACKAGE_USERNAME}" ]; then
- echo "secrets.FORGEJO_PACKAGE_USERNAME is required"
+ if [ -z "${NUGET_USERNAME}" ]; then
+ echo "secrets.NUGET_USERNAME is required"
exit 1
fi
- if [ -z "${FORGEJO_PACKAGE_TOKEN}" ]; then
- echo "secrets.FORGEJO_PACKAGE_TOKEN is required"
+ if [ -z "${NUGET_PASSWORD}" ]; then
+ echo "secrets.NUGET_PASSWORD is required"
exit 1
fi
@@ -53,8 +53,8 @@ jobs:
dotnet nuget update source "${{ env.NUGET_SOURCE_NAME }}" \
--source "${{ env.NUGET_SOURCE_URL }}" \
- --username "${FORGEJO_PACKAGE_USERNAME}" \
- --password "${FORGEJO_PACKAGE_TOKEN}" \
+ --username "${NUGET_USERNAME}" \
+ --password "${NUGET_PASSWORD}" \
--store-password-in-clear-text \
--configfile "${temp_config}"
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 3ce4bbe..3734723 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -4,7 +4,7 @@
```powershell
# Build
-dotnet build Catalog.slnx
+dotnet build Catalog.sln
# Run all tests
dotnet test MaddoShared.Tests
@@ -21,13 +21,13 @@ dotnet publish "imagecatalog\ImageCatalog 2.csproj" -c Release -r win-x64 --self
## Architecture
-This is an Avalonia image cataloging application targeting .NET 10.0-windows.
+This is a WinForms/WPF image cataloging application targeting .NET 10.0-windows.
### Projects
| Project | Purpose |
|---------|---------|
-| **imagecatalog** | Main desktop application — Avalonia with Fluent theme (`AvaloniaMainWindow`) |
+| **imagecatalog** | Main desktop application — WinForms (default), WPF (`--wpf`), or Avalonia (`--avalonia`) |
| **MaddoShared** | Shared image processing library (the core) |
| **MaddoShared.Tests** | Unit tests for MaddoShared |
| **MaddoShared.Benchmarks** | BenchmarkDotNet performance benchmarks |
@@ -35,7 +35,12 @@ This is an Avalonia image cataloging application targeting .NET 10.0-windows.
| **ImageCatalogCS / ImageCatalogParallel** | Legacy/experimental variants |
| **CatalogLib / CatalogLibVb / CatalogVbLib** | Legacy VB.NET libraries |
-The main app launches Avalonia directly. Dialog events (`SelectSourceFolderRequested`, etc.) are subscribed in `AvaloniaMainWindow` code-behind. `DataModel.UiInvoker` must be set by the active UI to enable cross-thread UI updates (Avalonia sets this to `Dispatcher.UIThread.Invoke`).
+The main app selects its UI at startup via command-line flag:
+- *(default)* — WinForms (`MainForm`)
+- `--wpf` — WPF with MahApps.Metro (`MainWindow`)
+- `--avalonia` — Avalonia with Fluent theme (`AvaloniaMainWindow`)
+
+All three UIs bind to the same `DataModel`. Dialog events (`SelectSourceFolderRequested`, etc.) are subscribed in each window's code-behind. `DataModel.UiInvoker` must be set by the active UI to enable cross-thread UI updates (Avalonia sets this to `Dispatcher.UIThread.Invoke`; WPF uses `Application.Current.Dispatcher`).
### Core Flow
diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index 0af4af3..0000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "name": "ImageCatalog Avalonia",
- "type": "coreclr",
- "request": "launch",
- "preLaunchTask": "build ImageCatalog Avalonia",
- "program": "${workspaceFolder:Catalog}/imagecatalog/bin/Debug/net10.0-windows/win-x64/ImageCatalog.exe",
- "args": [],
- "cwd": "${workspaceFolder:Catalog}/imagecatalog",
- "stopAtEntry": false,
- "console": "internalConsole"
- }
- ]
-}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
deleted file mode 100644
index 22c598b..0000000
--- a/.vscode/tasks.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "build ImageCatalog Avalonia",
- "type": "process",
- "command": "dotnet",
- "args": [
- "build",
- "${workspaceFolder:Catalog}/imagecatalog/ImageCatalog 2.csproj",
- "--configuration",
- "Debug"
- ],
- "problemMatcher": "$msCompile",
- "group": "build"
- }
- ]
-}
\ No newline at end of file
diff --git a/Catalog.code-workspace b/Catalog.code-workspace
deleted file mode 100644
index 15ec3a0..0000000
--- a/Catalog.code-workspace
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "folders": [
- {
- "path": "."
- },
- {
- "path": "../AIFotoONLUS"
- },
- {
- "path": "../../various/regalamiunsorriso"
- }
- ],
- "settings": {
- "commentTranslate.hover.enabled": false
- }
-}
\ No newline at end of file
diff --git a/Catalog.sln b/Catalog.sln
new file mode 100644
index 0000000..5d1d09f
--- /dev/null
+++ b/Catalog.sln
@@ -0,0 +1,116 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 18
+VisualStudioVersion = 18.2.11415.280
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageCatalog 2", "imagecatalog\ImageCatalog 2.csproj", "{3F1E23DB-435E-0590-1EF5-735E898DBA3C}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{A3D50937-74F6-4DC8-8D89-B534B484C0F9}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaddoShared", "MaddoShared\MaddoShared.csproj", "{AEBFE9E3-277C-4A7B-8448-145D1B11998B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{5F0BEF23-B1EA-4100-A772-DC455D40B1C1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaddoShared.Tests", "MaddoShared.Tests\MaddoShared.Tests.csproj", "{59952BE8-20B4-4BF2-9367-705F41395265}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaddoShared.Benchmarks", "MaddoShared.Benchmarks\MaddoShared.Benchmarks.csproj", "{07499348-8C15-4DCC-8316-4AD121A43C38}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Catalog.Communication", "Catalog.Communication\Catalog.Communication.csproj", "{EF5D3B7E-F380-4976-A0A9-085FEA157F79}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaddoShared.ImageSharpTests", "MaddoShared.ImageSharpTests\MaddoShared.ImageSharpTests.csproj", "{1528903F-3BF9-599C-2DD0-0AF7B5706675}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Debug|x64.Build.0 = Debug|Any CPU
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Debug|x86.ActiveCfg = Debug|x86
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Debug|x86.Build.0 = Debug|x86
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Release|x64.ActiveCfg = Release|x64
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Release|x64.Build.0 = Release|x64
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Release|x86.ActiveCfg = Release|x86
+ {3F1E23DB-435E-0590-1EF5-735E898DBA3C}.Release|x86.Build.0 = Release|x86
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Debug|x64.Build.0 = Debug|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Debug|x86.Build.0 = Debug|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Release|x64.ActiveCfg = Release|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Release|x64.Build.0 = Release|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Release|x86.ActiveCfg = Release|Any CPU
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B}.Release|x86.Build.0 = Release|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Debug|x64.Build.0 = Debug|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Debug|x86.Build.0 = Debug|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Release|Any CPU.Build.0 = Release|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Release|x64.ActiveCfg = Release|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Release|x64.Build.0 = Release|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Release|x86.ActiveCfg = Release|Any CPU
+ {59952BE8-20B4-4BF2-9367-705F41395265}.Release|x86.Build.0 = Release|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Debug|x64.Build.0 = Debug|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Debug|x86.Build.0 = Debug|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Release|Any CPU.Build.0 = Release|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Release|x64.ActiveCfg = Release|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Release|x64.Build.0 = Release|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Release|x86.ActiveCfg = Release|Any CPU
+ {07499348-8C15-4DCC-8316-4AD121A43C38}.Release|x86.Build.0 = Release|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Debug|x64.Build.0 = Debug|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Debug|x86.Build.0 = Debug|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Release|x64.ActiveCfg = Release|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Release|x64.Build.0 = Release|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Release|x86.ActiveCfg = Release|Any CPU
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79}.Release|x86.Build.0 = Release|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Debug|x64.Build.0 = Debug|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Debug|x86.Build.0 = Debug|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Release|x64.ActiveCfg = Release|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Release|x64.Build.0 = Release|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Release|x86.ActiveCfg = Release|Any CPU
+ {1528903F-3BF9-599C-2DD0-0AF7B5706675}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {AEBFE9E3-277C-4A7B-8448-145D1B11998B} = {A3D50937-74F6-4DC8-8D89-B534B484C0F9}
+ {59952BE8-20B4-4BF2-9367-705F41395265} = {5F0BEF23-B1EA-4100-A772-DC455D40B1C1}
+ {EF5D3B7E-F380-4976-A0A9-085FEA157F79} = {A3D50937-74F6-4DC8-8D89-B534B484C0F9}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {0E3ABC63-8601-4DAC-AFEA-33F3E8E36757}
+ EndGlobalSection
+EndGlobal
diff --git a/Catalog.slnx b/Catalog.slnx
deleted file mode 100644
index 3c8cf36..0000000
--- a/Catalog.slnx
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MaddoShared.Tests/DataModelCharacterizationTests.cs b/MaddoShared.Tests/DataModelCharacterizationTests.cs
index cba6ce0..7ce601e 100644
--- a/MaddoShared.Tests/DataModelCharacterizationTests.cs
+++ b/MaddoShared.Tests/DataModelCharacterizationTests.cs
@@ -1,5 +1,4 @@
using System;
-using System.IO;
using System.Threading.Tasks;
using ImageCatalog_2;
using ImageCatalog_2.Services;
@@ -135,61 +134,6 @@ public class DataModelCharacterizationTests
model.FontSize.ShouldBe(42);
}
- [TestMethod]
- public void FaceExecutableFolder_EnablesGpuToggleWhenBothVariantsExist()
- {
- using var root = new TemporaryDirectory();
- CreateFaceEncoderExecutable(root.Path, "cpu");
- CreateFaceEncoderExecutable(root.Path, "gpu");
-
- var model = CreateModel();
-
- model.FaceExecutablePath = root.Path;
-
- model.FaceGpuOptionEnabled.ShouldBeTrue();
- model.UseFaceGpu.ShouldBeFalse();
- }
-
- [TestMethod]
- public void UseFaceGpu_UpdatesUpsampleWhenUsingRecommendedDefault()
- {
- using var root = new TemporaryDirectory();
- CreateFaceEncoderExecutable(root.Path, "cpu");
- CreateFaceEncoderExecutable(root.Path, "gpu");
-
- var model = CreateModel();
- model.FaceExecutablePath = root.Path;
- model.FaceUpsample.ShouldBeTrue();
-
- model.UseFaceGpu = true;
-
- model.FaceUpsample.ShouldBeFalse();
- }
-
- [TestMethod]
- public void ResolveConfiguredFaceEncoderExecutablePath_UsesFolderLayoutFromPowerShellScript()
- {
- using var root = new TemporaryDirectory();
- var cpuExecutable = CreateFaceEncoderExecutable(root.Path, "cpu");
- var gpuExecutable = CreateFaceEncoderExecutable(root.Path, "gpu");
-
- DataModel.ResolveConfiguredFaceEncoderExecutablePath(root.Path, useGpu: false).ShouldBe(cpuExecutable);
- DataModel.ResolveConfiguredFaceEncoderExecutablePath(root.Path, useGpu: true).ShouldBe(gpuExecutable);
- }
-
- [TestMethod]
- public void BuildFaceEncoderOutputPaths_UsesTimestampAndSanitizedFolderName()
- {
- var timestamp = new DateTime(2026, 5, 9, 14, 30, 45);
- var output = DataModel.BuildFaceEncoderOutputPaths(
- @"C:\out",
- @"C:\images\04 APRILE: gara?",
- timestamp);
-
- output.OutputFilePath.ShouldBe(@"C:\out\face_encodings_20260509_143045_04_APRILE_gara.pkl");
- output.LogFilePath.ShouldBe(@"C:\out\encoder_log_20260509_143045_04_APRILE_gara.txt");
- }
-
private static DataModel CreateModel(
ISettingsService? settingsService = null,
ITestService? testService = null)
@@ -225,33 +169,4 @@ public class DataModelCharacterizationTests
Substitute.For>(),
versionProvider: null);
}
-
- private static string CreateFaceEncoderExecutable(string rootPath, string variant)
- {
- var variantDirectory = Path.Combine(rootPath, $"face_encoder_{variant}");
- Directory.CreateDirectory(variantDirectory);
-
- var executablePath = Path.Combine(variantDirectory, $"face_encoder_{variant}.exe");
- File.WriteAllText(executablePath, "stub");
- return executablePath;
- }
-
- private sealed class TemporaryDirectory : IDisposable
- {
- public TemporaryDirectory()
- {
- Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
- Directory.CreateDirectory(Path);
- }
-
- public string Path { get; }
-
- public void Dispose()
- {
- if (Directory.Exists(Path))
- {
- Directory.Delete(Path, recursive: true);
- }
- }
- }
}
diff --git a/MaddoShared.Tests/MaddoShared.Tests.csproj b/MaddoShared.Tests/MaddoShared.Tests.csproj
index d8936a9..1d562c8 100644
--- a/MaddoShared.Tests/MaddoShared.Tests.csproj
+++ b/MaddoShared.Tests/MaddoShared.Tests.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/NuGet.Config b/NuGet.Config
index e0e2d2b..79cf275 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -1,25 +1,25 @@
-
+
-
+
-
-
+
+
diff --git a/imagecatalog/AvaloniaMainWindow.axaml.cs b/imagecatalog/AvaloniaMainWindow.axaml.cs
index 8ebe952..2de8d3f 100644
--- a/imagecatalog/AvaloniaMainWindow.axaml.cs
+++ b/imagecatalog/AvaloniaMainWindow.axaml.cs
@@ -3,7 +3,6 @@ using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.Styling;
using Avalonia.Threading;
-using System.ComponentModel;
using System.IO;
namespace ImageCatalog_2;
@@ -21,7 +20,6 @@ public partial class AvaloniaMainWindow : Window
DataContext = _model;
Opened += (_, _) => SyncThemeStateFromCurrentTheme();
- Closing += AvaloniaMainWindow_Closing;
// Let DataModel marshal callbacks onto Avalonia UI thread.
_model.UiInvoker = action => Dispatcher.UIThread.Invoke(action);
@@ -137,29 +135,6 @@ public partial class AvaloniaMainWindow : Window
};
}
- private bool _isStoppingFaceEncoderForClose;
-
- private async void AvaloniaMainWindow_Closing(object? sender, CancelEventArgs e)
- {
- if (_isStoppingFaceEncoderForClose || !_model.IsFaceEncoderRunning)
- {
- return;
- }
-
- e.Cancel = true;
- _isStoppingFaceEncoderForClose = true;
-
- try
- {
- await _model.StopFaceEncoderAsync("Arresto face encoder in chiusura...", waitForExit: true);
- }
- finally
- {
- _isStoppingFaceEncoderForClose = false;
- Close();
- }
- }
-
private void ToggleTheme_Click(object? sender, RoutedEventArgs e)
{
_isDarkTheme = !_isDarkTheme;
diff --git a/imagecatalog/AvaloniaViews/FaceAiTabView.axaml b/imagecatalog/AvaloniaViews/FaceAiTabView.axaml
index 134621c..7f7f3ae 100644
--- a/imagecatalog/AvaloniaViews/FaceAiTabView.axaml
+++ b/imagecatalog/AvaloniaViews/FaceAiTabView.axaml
@@ -5,16 +5,16 @@
-
-
+
-
-
+
+
@@ -26,26 +26,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -59,11 +39,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ MinHeight="180" />
diff --git a/imagecatalog/AvaloniaViews/FaceAiTabView.axaml.cs b/imagecatalog/AvaloniaViews/FaceAiTabView.axaml.cs
index 3057b02..98295dc 100644
--- a/imagecatalog/AvaloniaViews/FaceAiTabView.axaml.cs
+++ b/imagecatalog/AvaloniaViews/FaceAiTabView.axaml.cs
@@ -1,56 +1,25 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
-using Avalonia.Threading;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
using System;
-using System.ComponentModel;
using System.Diagnostics;
using System.IO;
+using System.Text;
+using System.Threading.Tasks;
namespace ImageCatalog_2.AvaloniaViews;
public partial class FaceAiTabView : Avalonia.Controls.UserControl
{
- private INotifyPropertyChanged? _faceAiPropertySource;
+ private readonly ILogger _logger;
public FaceAiTabView()
{
InitializeComponent();
- DataContextChanged += OnDataContextChanged;
- }
-
- private void OnDataContextChanged(object? sender, EventArgs e)
- {
- if (_faceAiPropertySource is not null)
- {
- _faceAiPropertySource.PropertyChanged -= OnFaceAiPropertyChanged;
- }
-
- _faceAiPropertySource = DataContext as INotifyPropertyChanged;
- if (_faceAiPropertySource is not null)
- {
- _faceAiPropertySource.PropertyChanged += OnFaceAiPropertyChanged;
- }
- }
-
- private void OnFaceAiPropertyChanged(object? sender, PropertyChangedEventArgs e)
- {
- if (!string.Equals(e.PropertyName, nameof(DataModel.FaceCommandOutput), StringComparison.Ordinal))
- {
- return;
- }
-
- var outputBox = this.FindControl("FaceOutputTextBox");
- if (outputBox is null)
- {
- return;
- }
-
- Dispatcher.UIThread.Post(() =>
- {
- var textLength = outputBox.Text?.Length ?? 0;
- outputBox.CaretIndex = textLength;
- });
+ _logger = Program.ServiceProvider.GetService(typeof(ILogger)) as ILogger
+ ?? NullLogger.Instance;
}
private async void SelectFaceExecutable_Click(object? sender, RoutedEventArgs e)
@@ -68,14 +37,19 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
return;
}
- var folders = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
+ var files = await storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
- Title = "Seleziona la cartella Face Recognition Windows"
+ Title = "Seleziona face_encoder.exe",
+ FileTypeFilter =
+ [
+ new FilePickerFileType("Eseguibile") { Patterns = ["*.exe"] },
+ new FilePickerFileType("Tutti i file") { Patterns = ["*.*"] }
+ ]
});
- if (folders.Count > 0)
+ if (files.Count > 0)
{
- executableBox.Text = folders[0].Path.LocalPath;
+ executableBox.Text = files[0].Path.LocalPath;
if (DataContext is DataModel model)
{
model.FaceExecutablePath = executableBox.Text;
@@ -83,7 +57,7 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
}
}
- private async void SelectFaceOutputFolder_Click(object? sender, RoutedEventArgs e)
+ private async void SelectFaceOutputFile_Click(object? sender, RoutedEventArgs e)
{
var outputBox = this.FindControl("FaceOutputFolderTextBox");
if (outputBox is null)
@@ -98,14 +72,21 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
return;
}
- var folders = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
+ var files = await storageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
{
- Title = "Seleziona la cartella output per encodings e log"
+ Title = "Seleziona file output encodings (.pkl)",
+ SuggestedFileName = "encodings.pkl",
+ DefaultExtension = "pkl",
+ FileTypeChoices =
+ [
+ new FilePickerFileType("Pickle file") { Patterns = ["*.pkl"] }
+ ],
+ ShowOverwritePrompt = true
});
- if (folders.Count > 0)
+ if (files is not null)
{
- outputBox.Text = folders[0].Path.LocalPath;
+ outputBox.Text = files.Path.LocalPath;
if (DataContext is DataModel model)
{
model.FaceOutputFolderPath = outputBox.Text;
@@ -127,12 +108,6 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
return;
}
- if (Directory.Exists(path))
- {
- OpenInExplorer(path);
- return;
- }
-
if (File.Exists(path))
{
OpenInExplorer(path);
@@ -157,12 +132,6 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
return;
}
- if (Directory.Exists(outputPath))
- {
- OpenInExplorer(outputPath);
- return;
- }
-
if (File.Exists(outputPath))
{
OpenInExplorer(outputPath);
@@ -187,14 +156,169 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
return;
}
- if (Directory.Exists(path))
+ var directory = Path.GetDirectoryName(path);
+ OpenInExplorer(string.IsNullOrWhiteSpace(directory) ? path : directory);
+ }
+
+ private async void RunFaceEncoder_Click(object? sender, RoutedEventArgs e)
+ {
+ var executableBox = this.FindControl("FaceExecutablePathTextBox");
+ var outputFolderBox = this.FindControl("FaceOutputFolderTextBox");
+ var outputLogBox = this.FindControl("FaceOutputTextBox");
+ var statusBlock = this.FindControl("FaceStatusTextBlock");
+ var runButton = this.FindControl("FaceRunButton");
+
+ if (executableBox is null || outputFolderBox is null || outputLogBox is null || statusBlock is null || runButton is null)
{
- OpenInExplorer(path);
return;
}
- var directory = Path.GetDirectoryName(path);
- OpenInExplorer(string.IsNullOrWhiteSpace(directory) ? path : directory);
+ if (DataContext is not DataModel model)
+ {
+ statusBlock.Text = "DataContext non valido.";
+ return;
+ }
+
+ var executablePath = executableBox.Text?.Trim().Trim('"') ?? string.Empty;
+ var outputFilePath = outputFolderBox.Text?.Trim().Trim('"') ?? string.Empty;
+ var imagesFolder = (model.DestinationPath ?? string.Empty).Trim().Trim('"');
+
+ model.FaceExecutablePath = executablePath;
+ model.FaceOutputFolderPath = outputFilePath;
+
+ if (string.IsNullOrWhiteSpace(executablePath) || !File.Exists(executablePath))
+ {
+ statusBlock.Text = "Percorso eseguibile non valido.";
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(imagesFolder) || !Directory.Exists(imagesFolder))
+ {
+ statusBlock.Text = "Cartella Destinazione non valida.";
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(outputFilePath))
+ {
+ statusBlock.Text = "Inserisci il file di output .pkl.";
+ return;
+ }
+
+ if (!string.Equals(Path.GetExtension(outputFilePath), ".pkl", StringComparison.OrdinalIgnoreCase))
+ {
+ statusBlock.Text = "Il file di output deve avere estensione .pkl.";
+ return;
+ }
+
+ try
+ {
+ var outputDirectory = Path.GetDirectoryName(outputFilePath);
+ if (!string.IsNullOrWhiteSpace(outputDirectory))
+ {
+ Directory.CreateDirectory(outputDirectory);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Unable to create face output directory for file: {OutputFilePath}", outputFilePath);
+ statusBlock.Text = "Impossibile creare la cartella del file di output.";
+ return;
+ }
+
+ runButton.IsEnabled = false;
+ statusBlock.Text = "Esecuzione face encoder in corso...";
+ outputLogBox.Text = string.Empty;
+
+ var outputLines = new StringBuilder();
+ var errorLines = new StringBuilder();
+
+ try
+ {
+ var imagesFolderArg = NormalizeDirectoryPathArgument(imagesFolder);
+ var outputFileArg = NormalizeFilePathArgument(outputFilePath);
+
+ var processStartInfo = new ProcessStartInfo
+ {
+ FileName = executablePath,
+ WorkingDirectory = Path.GetDirectoryName(executablePath) ?? Environment.CurrentDirectory,
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true,
+ };
+ processStartInfo.ArgumentList.Add("--images");
+ processStartInfo.ArgumentList.Add(imagesFolderArg);
+ processStartInfo.ArgumentList.Add("--out");
+ processStartInfo.ArgumentList.Add(outputFileArg);
+
+ using var process = new Process { StartInfo = processStartInfo, EnableRaisingEvents = true };
+ process.OutputDataReceived += (_, args) =>
+ {
+ if (string.IsNullOrWhiteSpace(args.Data))
+ {
+ return;
+ }
+
+ lock (outputLines)
+ {
+ outputLines.AppendLine(args.Data);
+ }
+ };
+
+ process.ErrorDataReceived += (_, args) =>
+ {
+ if (string.IsNullOrWhiteSpace(args.Data))
+ {
+ return;
+ }
+
+ lock (errorLines)
+ {
+ errorLines.AppendLine(args.Data);
+ }
+ };
+
+ if (!process.Start())
+ {
+ throw new InvalidOperationException("Avvio face_encoder.exe fallito.");
+ }
+
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+ await process.WaitForExitAsync().ConfigureAwait(true);
+
+ var summary = new StringBuilder();
+ summary.AppendLine($"Exit code: {process.ExitCode}");
+
+ if (outputLines.Length > 0)
+ {
+ summary.AppendLine();
+ summary.AppendLine("STDOUT:");
+ summary.Append(outputLines);
+ }
+
+ if (errorLines.Length > 0)
+ {
+ summary.AppendLine();
+ summary.AppendLine("STDERR:");
+ summary.Append(errorLines);
+ }
+
+ outputLogBox.Text = summary.ToString();
+ statusBlock.Text = process.ExitCode == 0
+ ? "Face encoder completato."
+ : $"Face encoder terminato con errore (code {process.ExitCode}).";
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Face encoder execution failed.");
+ outputLogBox.Text = ex.ToString();
+ statusBlock.Text = "Errore durante esecuzione face encoder.";
+ }
+ finally
+ {
+ runButton.IsEnabled = true;
+ }
}
private static void OpenInExplorer(string? path)
@@ -221,4 +345,31 @@ public partial class FaceAiTabView : Avalonia.Controls.UserControl
// Ignore failures when opening Explorer.
}
}
+
+ private static string NormalizeDirectoryPathArgument(string value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return string.Empty;
+ }
+
+ var normalized = value.Trim().Trim('"');
+ var root = Path.GetPathRoot(normalized);
+ if (!string.IsNullOrEmpty(root) && normalized.Length > root.Length)
+ {
+ normalized = normalized.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+ }
+
+ return normalized;
+ }
+
+ private static string NormalizeFilePathArgument(string value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return string.Empty;
+ }
+
+ return value.Trim().Trim('"');
+ }
}
diff --git a/imagecatalog/Commands/ButtonCommandBinder.cs b/imagecatalog/Commands/ButtonCommandBinder.cs
new file mode 100644
index 0000000..2fc301c
--- /dev/null
+++ b/imagecatalog/Commands/ButtonCommandBinder.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Windows.Forms;
+using System.Windows.Input;
+
+namespace ImageCatalog_2.Commands
+{
+ ///
+ /// Helper class to bind WinForms Button controls to ICommand implementations
+ ///
+ public static class ButtonCommandBinder
+ {
+ ///
+ /// Binds a Button's Click event to an ICommand
+ ///
+ /// The button to bind
+ /// The command to execute
+ /// Optional parameter to pass to the command
+ public static void BindCommand(this Button button, ICommand command, object commandParameter = null)
+ {
+ if (button == null) throw new ArgumentNullException(nameof(button));
+ if (command == null) throw new ArgumentNullException(nameof(command));
+
+ // Wire up the Click event to execute the command
+ button.Click += (sender, e) =>
+ {
+ if (command.CanExecute(commandParameter))
+ {
+ command.Execute(commandParameter);
+ }
+ };
+
+ // Wire up CanExecuteChanged to enable/disable the button
+ command.CanExecuteChanged += (sender, e) =>
+ {
+ button.Enabled = command.CanExecute(commandParameter);
+ };
+
+ // Set initial enabled state
+ button.Enabled = command.CanExecute(commandParameter);
+ }
+
+ ///
+ /// Binds multiple buttons to commands at once
+ ///
+ public static void BindCommands(params (Button button, ICommand command, object parameter)[] bindings)
+ {
+ foreach (var (button, command, parameter) in bindings)
+ {
+ button.BindCommand(command, parameter);
+ }
+ }
+ }
+}
diff --git a/imagecatalog/DataModel.cs b/imagecatalog/DataModel.cs
index 25e7041..206c602 100644
--- a/imagecatalog/DataModel.cs
+++ b/imagecatalog/DataModel.cs
@@ -9,12 +9,14 @@ using System.Diagnostics;
#if WINDOWS
using System.Drawing.Text;
#endif
-using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+#if WINDOWS
+using System.Windows.Forms;
+#endif
using System.Windows.Input;
using AutoMapper;
using MaddoShared;
@@ -38,8 +40,6 @@ namespace ImageCatalog_2
public ICommand SelectModelsFolderCommand { get; }
public ICommand SelectCsvOutputCommand { get; }
public ICommand StartAiCommand { get; }
- public ICommand StartFaceEncoderCommand { get; }
- public ICommand StopFaceEncoderCommand { get; }
private readonly ITestService _service;
private readonly ILogger _logger;
@@ -54,15 +54,6 @@ namespace ImageCatalog_2
private readonly VisualSettingsViewModel _visual;
private readonly PicSettings _picSettings;
private readonly IMapper _mapper;
- private readonly AsyncCommand _startFaceEncoderCommand;
- private readonly AsyncCommand _stopFaceEncoderCommand;
- private readonly object _faceEncoderProcessLock = new();
- private Process? _faceEncoderProcess;
- private CancellationTokenSource? _faceEncoderWatcherTokenSource;
- private Task? _faceEncoderWatcherTask;
- private CancellationTokenSource? _faceEncoderLogWatcherTokenSource;
- private Task? _faceEncoderLogWatcherTask;
- private bool _hasStartedFaceEncoderInSession;
// ComboBox collections
public List AvailableFonts { get; }
@@ -102,10 +93,6 @@ namespace ImageCatalog_2
SelectModelsFolderCommand = new RelayCommand(SelectModelsFolder);
SelectCsvOutputCommand = new RelayCommand(SelectCsvOutput);
StartAiCommand = new AsyncCommand(StartAiAsync);
- _startFaceEncoderCommand = new AsyncCommand(RunFaceEncoderAsync, CanRunFaceEncoder);
- _stopFaceEncoderCommand = new AsyncCommand(() => StopFaceEncoderAsync("Arresto richiesto dall'utente."), CanStopFaceEncoder);
- StartFaceEncoderCommand = _startFaceEncoderCommand;
- StopFaceEncoderCommand = _stopFaceEncoderCommand;
SelectSourceFolderCommand = new RelayCommand(SelectSourceFolder);
SelectDestinationFolderCommand = new RelayCommand(SelectDestinationFolder);
@@ -117,7 +104,6 @@ namespace ImageCatalog_2
// Load available fonts
AvailableFonts = LoadAvailableFonts();
- RefreshFaceExecutableCapabilities();
}
private async Task StartAiAsync()
@@ -165,7 +151,8 @@ namespace ImageCatalog_2
}
///
- /// Optional UI-thread invoker set by the active UI layer.
+ /// Optional UI-thread invoker set by the active UI layer (WPF, Avalonia, etc.).
+ /// When set, uses this delegate instead of the WPF dispatcher.
///
public Action? UiInvoker { get; set; }
@@ -176,7 +163,7 @@ namespace ImageCatalog_2
if (UiInvoker != null)
UiInvoker(action);
else
- action();
+ System.Windows.Application.Current?.Dispatcher.Invoke(action);
});
}
@@ -205,18 +192,7 @@ namespace ImageCatalog_2
public string FaceExecutablePath
{
get => _ai.FaceExecutablePath;
- set
- {
- var normalizedValue = value ?? string.Empty;
- if (string.Equals(_ai.FaceExecutablePath, normalizedValue, StringComparison.Ordinal))
- {
- RefreshFaceExecutableCapabilities();
- return;
- }
-
- _ai.FaceExecutablePath = normalizedValue;
- RefreshFaceExecutableCapabilities();
- }
+ set => _ai.FaceExecutablePath = value;
}
public string FaceOutputFolderPath
@@ -225,64 +201,6 @@ namespace ImageCatalog_2
set => _ai.FaceOutputFolderPath = value;
}
- public bool FaceRecursive
- {
- get => _ai.FaceRecursive;
- set => _ai.FaceRecursive = value;
- }
-
- public bool FaceIncludeThumbnails
- {
- get => _ai.FaceIncludeThumbnails;
- set => _ai.FaceIncludeThumbnails = value;
- }
-
- public IReadOnlyList FaceParallelismOptions { get; } = [1, 2, 3, 4, 5];
-
- public int FaceParallelism
- {
- get => _ai.FaceParallelism;
- set => _ai.FaceParallelism = value;
- }
-
- public int FaceMinSize
- {
- get => _ai.FaceMinSize;
- set => _ai.FaceMinSize = value;
- }
-
- public bool FaceUpsample
- {
- get => _ai.FaceUpsample;
- set => _ai.FaceUpsample = value;
- }
-
- public bool FaceGpuOptionEnabled => _ai.FaceGpuOptionEnabled;
-
- public bool UseFaceGpu
- {
- get => _ai.UseFaceGpu;
- set => SetUseFaceGpu(value);
- }
-
- public bool IsFaceEncoderRunning
- {
- get => _ai.IsFaceEncoderRunning;
- private set => _ai.IsFaceEncoderRunning = value;
- }
-
- public string FaceStatusMessage
- {
- get => _ai.FaceStatusMessage;
- private set => _ai.FaceStatusMessage = value;
- }
-
- public string FaceCommandOutput
- {
- get => _ai.FaceCommandOutput;
- private set => _ai.FaceCommandOutput = value;
- }
-
// Race upload settings
public string ApiLogin
{
@@ -475,7 +393,6 @@ namespace ImageCatalog_2
}
NotifyPropertyChanged(e.PropertyName);
- UpdateFaceEncoderCommandStates();
}
private void OnRaceUploadPropertyChanged(object? sender, PropertyChangedEventArgs e)
@@ -1355,785 +1272,6 @@ namespace ImageCatalog_2
}
}
- public async Task StopFaceEncoderAsync(string reason, bool waitForExit = true)
- {
- var trackedProcess = GetTrackedFaceEncoderProcess();
- var ownsProcess = false;
- var process = trackedProcess;
-
- if (process is null)
- {
- process = FindConfiguredFaceEncoderProcess();
- ownsProcess = process is not null;
- }
-
- if (process is null)
- {
- await InvokeOnUiThreadAsync(() =>
- {
- IsFaceEncoderRunning = false;
- FaceStatusMessage = "Face encoder non in esecuzione.";
- }).ConfigureAwait(false);
- return;
- }
-
- try
- {
- await InvokeOnUiThreadAsync(() => FaceStatusMessage = reason).ConfigureAwait(false);
-
- var gracefulStopRequested = TryRequestFaceEncoderStop(process);
- if (waitForExit)
- {
- var exited = await WaitForProcessExitAsync(process, TimeSpan.FromSeconds(5)).ConfigureAwait(false);
- if (!exited)
- {
- try
- {
- process.Kill(entireProcessTree: true);
- exited = await WaitForProcessExitAsync(process, TimeSpan.FromSeconds(5)).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.LogWarning(ex, "Unable to terminate face encoder process {ProcessId}", process.Id);
- }
- }
-
- await InvokeOnUiThreadAsync(() =>
- {
- IsFaceEncoderRunning = !exited && IsProcessAlive(process);
- FaceStatusMessage = exited
- ? "Face encoder arrestato."
- : gracefulStopRequested
- ? "Segnale di arresto inviato al face encoder."
- : "Arresto forzato del face encoder richiesto.";
- }).ConfigureAwait(false);
- }
- }
- finally
- {
- if (ownsProcess)
- {
- process.Dispose();
- }
- }
- }
-
- private bool CanRunFaceEncoder()
- {
- return !IsFaceEncoderRunning;
- }
-
- private bool CanStopFaceEncoder()
- {
- return IsFaceEncoderRunning;
- }
-
- private void UpdateFaceEncoderCommandStates()
- {
- _startFaceEncoderCommand?.RaiseCanExecuteChanged();
- _stopFaceEncoderCommand?.RaiseCanExecuteChanged();
- }
-
- private async Task RunFaceEncoderAsync()
- {
- if (IsFaceEncoderRunning)
- {
- FaceStatusMessage = "Face encoder gia in esecuzione.";
- return;
- }
-
- var executableRootPath = NormalizeFilePathArgument(FaceExecutablePath);
- var outputFolderPath = NormalizeDirectoryPathArgument(FaceOutputFolderPath);
- var imagesFolder = NormalizeDirectoryPathArgument(DestinationPath);
- var executablePath = ResolveConfiguredFaceEncoderExecutablePath(executableRootPath, UseFaceGpu);
-
- if (string.IsNullOrWhiteSpace(executableRootPath))
- {
- FaceStatusMessage = "Percorso cartella face encoder non valido.";
- return;
- }
-
- if (string.IsNullOrWhiteSpace(executablePath) || !File.Exists(executablePath))
- {
- FaceStatusMessage = UseFaceGpu
- ? "Impossibile trovare face_encoder_gpu.exe nella cartella selezionata."
- : "Impossibile trovare face_encoder_cpu.exe nella cartella selezionata.";
- return;
- }
-
- if (string.IsNullOrWhiteSpace(imagesFolder) || !Directory.Exists(imagesFolder))
- {
- FaceStatusMessage = "Cartella Destinazione non valida.";
- return;
- }
-
- if (string.IsNullOrWhiteSpace(outputFolderPath))
- {
- FaceStatusMessage = "Inserisci la cartella di output per encodings e log.";
- return;
- }
-
- try
- {
- Directory.CreateDirectory(outputFolderPath);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Unable to create face output directory: {OutputFolderPath}", outputFolderPath);
- FaceStatusMessage = "Impossibile creare la cartella di output.";
- return;
- }
-
- var parallelism = NormalizeFaceParallelism(FaceParallelism);
- var minSize = NormalizeFaceMinSize(FaceMinSize);
- var outputFiles = BuildFaceEncoderOutputPaths(outputFolderPath, imagesFolder, DateTime.Now);
-
- FaceExecutablePath = executableRootPath;
- FaceOutputFolderPath = outputFolderPath;
- FaceCommandOutput = string.Empty;
- FaceStatusMessage = "Esecuzione face encoder in corso...";
-
- var transcriptLines = new StringBuilder();
- var outputLines = new StringBuilder();
- var errorLines = new StringBuilder();
-
- try
- {
- var processStartInfo = new ProcessStartInfo
- {
- FileName = executablePath,
- WorkingDirectory = Path.GetDirectoryName(executablePath) ?? Environment.CurrentDirectory,
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- RedirectStandardInput = false,
- CreateNoWindow = false,
- };
-
- processStartInfo.ArgumentList.Add("--images");
- processStartInfo.ArgumentList.Add(imagesFolder);
- processStartInfo.ArgumentList.Add("--out");
- processStartInfo.ArgumentList.Add(outputFiles.OutputFilePath);
- processStartInfo.ArgumentList.Add("--log");
- processStartInfo.ArgumentList.Add(outputFiles.LogFilePath);
-
- if (FaceRecursive)
- {
- processStartInfo.ArgumentList.Add("--recursive");
- }
-
- if (FaceIncludeThumbnails)
- {
- processStartInfo.ArgumentList.Add("--include-tn");
- }
-
- processStartInfo.ArgumentList.Add(UseFaceGpu ? "--multiprocess" : "--multicore");
- processStartInfo.ArgumentList.Add(parallelism.ToString());
- processStartInfo.ArgumentList.Add("--min-size");
- processStartInfo.ArgumentList.Add(minSize.ToString());
-
- if (FaceUpsample)
- {
- processStartInfo.ArgumentList.Add("--upsample");
- }
-
- using var process = new Process { StartInfo = processStartInfo, EnableRaisingEvents = true };
- process.OutputDataReceived += (_, args) => AppendFaceProcessOutput(outputLines, transcriptLines, args.Data, isError: false);
- process.ErrorDataReceived += (_, args) => AppendFaceProcessOutput(errorLines, transcriptLines, args.Data, isError: true);
- process.Exited += (_, _) =>
- {
- _ = InvokeOnUiThreadAsync(() =>
- {
- if (!ComputeIsFaceEncoderRunning())
- {
- IsFaceEncoderRunning = false;
- }
- });
- };
-
- if (!process.Start())
- {
- throw new InvalidOperationException("Avvio face encoder fallito.");
- }
-
- _hasStartedFaceEncoderInSession = true;
- EnsureFaceEncoderWatcherStarted();
- TrackFaceEncoderProcess(process);
- await InvokeOnUiThreadAsync(() => IsFaceEncoderRunning = true).ConfigureAwait(false);
-
- if (UseFaceGpu)
- {
- StartFaceEncoderLogWatcher(outputFiles.LogFilePath, outputLines, transcriptLines);
- }
-
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- await process.WaitForExitAsync().ConfigureAwait(false);
-
- var summary = BuildFaceEncoderSummary(process.ExitCode, processStartInfo, outputFiles.OutputFilePath, outputFiles.LogFilePath, outputLines, errorLines);
- await InvokeOnUiThreadAsync(() =>
- {
- FaceCommandOutput = string.IsNullOrWhiteSpace(FaceCommandOutput)
- ? summary
- : $"{FaceCommandOutput.TrimEnd()}\n\n{summary}";
- FaceStatusMessage = process.ExitCode == 0
- ? "Face encoder completato."
- : $"Face encoder terminato con errore (code {process.ExitCode}).";
- }).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Console.Error.WriteLine(ex);
- _logger.LogError(ex, "Face encoder execution failed.");
- await InvokeOnUiThreadAsync(() =>
- {
- FaceCommandOutput = ex.ToString();
- FaceStatusMessage = "Errore durante esecuzione face encoder.";
- }).ConfigureAwait(false);
- }
- finally
- {
- await StopFaceEncoderLogWatcherAsync().ConfigureAwait(false);
- ClearTrackedFaceEncoderProcess();
- await InvokeOnUiThreadAsync(() => IsFaceEncoderRunning = ComputeIsFaceEncoderRunning()).ConfigureAwait(false);
- }
- }
-
- private async Task WatchFaceEncoderProcessAsync(CancellationToken token)
- {
- using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
-
- try
- {
- while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false))
- {
- if (!_hasStartedFaceEncoderInSession)
- {
- continue;
- }
-
- var isRunning = ComputeIsFaceEncoderRunning();
- if (isRunning != IsFaceEncoderRunning)
- {
- await InvokeOnUiThreadAsync(() => IsFaceEncoderRunning = isRunning).ConfigureAwait(false);
- }
- }
- }
- catch (OperationCanceledException)
- {
- // App shutdown.
- }
- }
-
- private void EnsureFaceEncoderWatcherStarted()
- {
- if (_faceEncoderWatcherTask is not null)
- {
- return;
- }
-
- _faceEncoderWatcherTokenSource = new CancellationTokenSource();
- _faceEncoderWatcherTask = WatchFaceEncoderProcessAsync(_faceEncoderWatcherTokenSource.Token);
- }
-
- private void StartFaceEncoderLogWatcher(string logFilePath, StringBuilder outputLines, StringBuilder transcriptLines)
- {
- _faceEncoderLogWatcherTokenSource?.Cancel();
- _faceEncoderLogWatcherTokenSource?.Dispose();
-
- _faceEncoderLogWatcherTokenSource = new CancellationTokenSource();
- _faceEncoderLogWatcherTask = WatchFaceEncoderLogFileAsync(logFilePath, outputLines, transcriptLines, _faceEncoderLogWatcherTokenSource.Token);
- }
-
- private async Task StopFaceEncoderLogWatcherAsync()
- {
- var tokenSource = _faceEncoderLogWatcherTokenSource;
- var task = _faceEncoderLogWatcherTask;
-
- _faceEncoderLogWatcherTokenSource = null;
- _faceEncoderLogWatcherTask = null;
-
- if (tokenSource is null)
- {
- return;
- }
-
- try
- {
- await tokenSource.CancelAsync().ConfigureAwait(false);
- if (task is not null)
- {
- await task.ConfigureAwait(false);
- }
- }
- catch (OperationCanceledException)
- {
- // Expected when shutting down the watcher.
- }
- finally
- {
- tokenSource.Dispose();
- }
- }
-
- private async Task WatchFaceEncoderLogFileAsync(string logFilePath, StringBuilder outputLines, StringBuilder transcriptLines, CancellationToken token)
- {
- long filePosition = 0;
-
- while (!token.IsCancellationRequested)
- {
- try
- {
- if (File.Exists(logFilePath))
- {
- using var stream = new FileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
- if (filePosition > stream.Length)
- {
- filePosition = 0;
- }
-
- stream.Seek(filePosition, SeekOrigin.Begin);
- using var reader = new StreamReader(stream);
- while (!reader.EndOfStream)
- {
- var line = await reader.ReadLineAsync(token).ConfigureAwait(false);
- AppendFaceProcessOutput(outputLines, transcriptLines, line, isError: false);
- }
-
- filePosition = stream.Position;
- }
- }
- catch (OperationCanceledException)
- {
- throw;
- }
- catch (IOException)
- {
- // Retry on the next polling interval while the encoder is still writing.
- }
- catch (UnauthorizedAccessException)
- {
- // Retry on the next polling interval if the log file is transiently locked.
- }
-
- await Task.Delay(TimeSpan.FromMilliseconds(250), token).ConfigureAwait(false);
- }
- }
-
- private void RefreshFaceExecutableCapabilities()
- {
- var executableRoot = NormalizeFilePathArgument(_ai.FaceExecutablePath);
- var hasCpu = !string.IsNullOrWhiteSpace(ResolveConfiguredFaceEncoderExecutablePath(executableRoot, useGpu: false));
- var hasGpu = !string.IsNullOrWhiteSpace(ResolveConfiguredFaceEncoderExecutablePath(executableRoot, useGpu: true));
-
- _ai.FaceGpuOptionEnabled = hasCpu && hasGpu;
-
- if (hasGpu && !hasCpu)
- {
- _ai.UseFaceGpu = true;
- }
- else if (!hasGpu)
- {
- _ai.UseFaceGpu = false;
- }
- }
-
- private void SetUseFaceGpu(bool value)
- {
- var currentValue = _ai.UseFaceGpu;
- if (!FaceGpuOptionEnabled)
- {
- return;
- }
-
- if (currentValue == value)
- {
- return;
- }
-
- _ai.UseFaceGpu = value;
-
- var previousRecommendedUpsample = GetRecommendedFaceUpsample(currentValue);
- if (_ai.FaceUpsample == previousRecommendedUpsample)
- {
- _ai.FaceUpsample = GetRecommendedFaceUpsample(value);
- }
- }
-
- private void TrackFaceEncoderProcess(Process process)
- {
- lock (_faceEncoderProcessLock)
- {
- _faceEncoderProcess = process;
- }
- }
-
- private void ClearTrackedFaceEncoderProcess()
- {
- lock (_faceEncoderProcessLock)
- {
- if (_faceEncoderProcess is not null && _faceEncoderProcess.HasExited)
- {
- _faceEncoderProcess = null;
- return;
- }
-
- _faceEncoderProcess = null;
- }
- }
-
- private Process? GetTrackedFaceEncoderProcess()
- {
- lock (_faceEncoderProcessLock)
- {
- if (_faceEncoderProcess is null)
- {
- return null;
- }
-
- if (_faceEncoderProcess.HasExited)
- {
- _faceEncoderProcess = null;
- return null;
- }
-
- return _faceEncoderProcess;
- }
- }
-
- private Process? FindConfiguredFaceEncoderProcess()
- {
- var configuredExecutablePath = ResolveConfiguredFaceEncoderExecutablePath(FaceExecutablePath, UseFaceGpu);
- if (string.IsNullOrWhiteSpace(configuredExecutablePath))
- {
- return null;
- }
-
- var processName = Path.GetFileNameWithoutExtension(configuredExecutablePath);
- foreach (var process in Process.GetProcessesByName(processName))
- {
- if (!IsProcessAlive(process))
- {
- process.Dispose();
- continue;
- }
-
- if (IsMatchingProcessPath(process, configuredExecutablePath))
- {
- return process;
- }
-
- process.Dispose();
- }
-
- return null;
- }
-
- private bool ComputeIsFaceEncoderRunning()
- {
- var trackedProcess = GetTrackedFaceEncoderProcess();
- if (trackedProcess is not null)
- {
- return true;
- }
-
- if (!_hasStartedFaceEncoderInSession)
- {
- return false;
- }
-
- using var discoveredProcess = FindConfiguredFaceEncoderProcess();
- return discoveredProcess is not null;
- }
-
- private static bool IsProcessAlive(Process process)
- {
- try
- {
- return !process.HasExited;
- }
- catch
- {
- return false;
- }
- }
-
- private static bool IsMatchingProcessPath(Process process, string configuredExecutablePath)
- {
- try
- {
- var processPath = process.MainModule?.FileName;
- return !string.IsNullOrWhiteSpace(processPath)
- && string.Equals(Path.GetFullPath(processPath), Path.GetFullPath(configuredExecutablePath), StringComparison.OrdinalIgnoreCase);
- }
- catch
- {
- return false;
- }
- }
-
- private bool TryRequestFaceEncoderStop(Process process)
- {
- if (!IsProcessAlive(process))
- {
- return true;
- }
-
-#if WINDOWS
- if (Program.TrySendConsoleInterrupt(process.Id))
- {
- return true;
- }
-#endif
-
- try
- {
- return process.CloseMainWindow();
- }
- catch (Exception ex)
- {
- _logger.LogWarning(ex, "Unable to request graceful stop for face encoder process {ProcessId}", process.Id);
- return false;
- }
- }
-
- private static async Task WaitForProcessExitAsync(Process process, TimeSpan timeout)
- {
- if (!IsProcessAlive(process))
- {
- return true;
- }
-
- using var cancellationTokenSource = new CancellationTokenSource(timeout);
- try
- {
- await process.WaitForExitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
- return true;
- }
- catch (OperationCanceledException)
- {
- return !IsProcessAlive(process);
- }
- }
-
- private void AppendFaceProcessOutput(StringBuilder builder, StringBuilder transcriptBuilder, string? line, bool isError)
- {
- if (string.IsNullOrWhiteSpace(line))
- {
- return;
- }
-
- lock (builder)
- {
- builder.AppendLine(line);
- }
-
- if (isError)
- {
- Console.Error.WriteLine(line);
- }
- else
- {
- Console.WriteLine(line);
- }
-
- string transcript;
- lock (transcriptBuilder)
- {
- if (isError)
- {
- transcriptBuilder.Append("[stderr] ");
- }
-
- transcriptBuilder.AppendLine(line);
- transcript = transcriptBuilder.ToString();
- }
-
- _ = InvokeOnUiThreadAsync(() => FaceCommandOutput = transcript);
- }
-
- internal static string? ResolveConfiguredFaceEncoderExecutablePath(string configuredPath, bool useGpu)
- {
- var variant = useGpu ? "gpu" : "cpu";
- foreach (var candidate in EnumerateFaceEncoderExecutableCandidates(configuredPath, variant))
- {
- if (File.Exists(candidate))
- {
- return candidate;
- }
- }
-
- return null;
- }
-
- internal static (string OutputFilePath, string LogFilePath) BuildFaceEncoderOutputPaths(string outputFolderPath, string imagesFolderPath, DateTime timestamp)
- {
- var safeRaceName = BuildSafeFaceEncoderRaceName(imagesFolderPath);
- var timestampToken = timestamp.ToString("yyyyMMdd_HHmmss");
-
- return (
- Path.Combine(outputFolderPath, $"face_encodings_{timestampToken}_{safeRaceName}.pkl"),
- Path.Combine(outputFolderPath, $"encoder_log_{timestampToken}_{safeRaceName}.txt"));
- }
-
- internal static string BuildSafeFaceEncoderRaceName(string imagesFolderPath)
- {
- var raceName = new DirectoryInfo(imagesFolderPath).Name;
- if (string.IsNullOrWhiteSpace(raceName))
- {
- return "race";
- }
-
- var invalidChars = Path.GetInvalidFileNameChars();
- var builder = new StringBuilder(raceName.Length);
- var previousWasSeparator = false;
-
- foreach (var currentChar in raceName)
- {
- if (char.IsWhiteSpace(currentChar) || invalidChars.Contains(currentChar))
- {
- if (!previousWasSeparator)
- {
- builder.Append('_');
- previousWasSeparator = true;
- }
-
- continue;
- }
-
- builder.Append(currentChar);
- previousWasSeparator = false;
- }
-
- return builder.ToString().Trim('_') switch
- {
- "" => "race",
- var sanitized => sanitized
- };
- }
-
- private static IEnumerable EnumerateFaceEncoderExecutableCandidates(string configuredPath, string variant)
- {
- var normalizedPath = NormalizeFilePathArgument(configuredPath);
- if (string.IsNullOrWhiteSpace(normalizedPath))
- {
- yield break;
- }
-
- var executableName = $"face_encoder_{variant}.exe";
-
- if (File.Exists(normalizedPath))
- {
- var fileDirectory = Path.GetDirectoryName(normalizedPath);
- if (!string.IsNullOrWhiteSpace(fileDirectory))
- {
- yield return Path.Combine(fileDirectory, executableName);
-
- var parentDirectory = Directory.GetParent(fileDirectory)?.FullName;
- if (!string.IsNullOrWhiteSpace(parentDirectory))
- {
- yield return Path.Combine(parentDirectory, $"face_encoder_{variant}", executableName);
- }
- }
-
- yield return normalizedPath;
- yield break;
- }
-
- yield return Path.Combine(normalizedPath, executableName);
- yield return Path.Combine(normalizedPath, $"face_encoder_{variant}", executableName);
-
- var leafName = Path.GetFileName(normalizedPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
- if (leafName.Equals("face_encoder_cpu", StringComparison.OrdinalIgnoreCase)
- || leafName.Equals("face_encoder_gpu", StringComparison.OrdinalIgnoreCase))
- {
- var parentDirectory = Directory.GetParent(normalizedPath)?.FullName;
- if (!string.IsNullOrWhiteSpace(parentDirectory))
- {
- yield return Path.Combine(parentDirectory, $"face_encoder_{variant}", executableName);
- }
- }
- }
-
- private static int NormalizeFaceParallelism(int value)
- {
- return value is >= 1 and <= 5 ? value : 3;
- }
-
- private static int NormalizeFaceMinSize(int value)
- {
- return value > 0 ? value : 35;
- }
-
- private static bool GetRecommendedFaceUpsample(bool useGpu)
- {
- return !useGpu;
- }
-
- private static string BuildFaceEncoderSummary(
- int exitCode,
- ProcessStartInfo processStartInfo,
- string outputFilePath,
- string logFilePath,
- StringBuilder outputLines,
- StringBuilder errorLines)
- {
- var summary = new StringBuilder();
- summary.AppendLine($"Exit code: {exitCode}");
- summary.AppendLine($"Command: {processStartInfo.FileName} {string.Join(" ", processStartInfo.ArgumentList)}");
- summary.AppendLine($"Output file: {outputFilePath}");
- summary.AppendLine($"Log file: {logFilePath}");
-
- lock (outputLines)
- {
- if (outputLines.Length > 0)
- {
- summary.AppendLine();
- summary.AppendLine("STDOUT:");
- summary.Append(outputLines);
- }
- }
-
- lock (errorLines)
- {
- if (errorLines.Length > 0)
- {
- summary.AppendLine();
- summary.AppendLine("STDERR:");
- summary.Append(errorLines);
- }
- }
-
- return summary.ToString();
- }
-
- private static string NormalizeDirectoryPathArgument(string value)
- {
- if (string.IsNullOrWhiteSpace(value))
- {
- return string.Empty;
- }
-
- var normalized = value.Trim().Trim('"');
- var root = Path.GetPathRoot(normalized);
- if (!string.IsNullOrEmpty(root) && normalized.Length > root.Length)
- {
- normalized = normalized.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
- }
-
- return normalized;
- }
-
- private static string NormalizeFilePathArgument(string value)
- {
- if (string.IsNullOrWhiteSpace(value))
- {
- return string.Empty;
- }
-
- return value.Trim().Trim('"');
- }
-
// Note: These commands will trigger events that the View will handle to show dialogs
// since dialogs require UI context
public event EventHandler? SelectSourceFolderRequested;
@@ -2145,7 +1283,11 @@ namespace ImageCatalog_2
public event EventHandler? LoadSettingsRequested;
public event EventHandler? SelectColorRequested;
// Request that the View shows a message to the user (message, caption, icon)
+#if WINDOWS
+ public event EventHandler>? ShowMessageRequested;
+#else
public event EventHandler>? ShowMessageRequested;
+#endif
public event EventHandler? SelectTransparentColorRequested;
private void SelectSourceFolder(object parameter)
diff --git a/imagecatalog/ImageCatalog 2.csproj b/imagecatalog/ImageCatalog 2.csproj
index 2749766..d10dce5 100644
--- a/imagecatalog/ImageCatalog 2.csproj
+++ b/imagecatalog/ImageCatalog 2.csproj
@@ -12,6 +12,8 @@
net10.0-windows
WinExe
+ true
+ true
win-x64
Logo.ico
@@ -29,7 +31,9 @@
false
-
+
true
true
@@ -61,9 +65,11 @@
+
+
@@ -75,7 +81,8 @@
+ with MinVer's computed Version to avoid mismatches embedded into generated XAML/BAML. The explicit
+ AssemblyVersion/FileVersion at the top of this file will be used for runtime identity. -->
True
@@ -83,6 +90,11 @@
Settings.settings
+
+
+ MainForm.cs
+
+
diff --git a/imagecatalog/MainForm.Designer.cs b/imagecatalog/MainForm.Designer.cs
new file mode 100644
index 0000000..a35536c
--- /dev/null
+++ b/imagecatalog/MainForm.Designer.cs
@@ -0,0 +1,2246 @@
+#if WINDOWS
+using System;
+using System.Diagnostics;
+using System.Drawing;
+using System.Runtime.CompilerServices;
+using System.Windows.Forms;
+using Microsoft.VisualBasic.CompilerServices;
+
+namespace ImageCatalog
+{
+ [DesignerGenerated()]
+ public partial class MainForm : Form
+ {
+
+ // Form overrides dispose to clean up the component list.
+ [DebuggerNonUserCode()]
+ protected override void Dispose(bool disposing)
+ {
+ try
+ {
+ if (disposing && components is object)
+ {
+ components.Dispose();
+ }
+ }
+ finally
+ {
+ base.Dispose(disposing);
+ }
+ }
+
+ // Required by the Windows Form Designer
+ private System.ComponentModel.IContainer components;
+
+ // NOTE: The following procedure is required by the Windows Form Designer
+ // It can be modified using the Windows Form Designer.
+ // Do not modify it using the code editor.
+ [DebuggerStepThrough()]
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ ProgressBar1 = new ProgressBar();
+ CheckBox22 = new CheckBox();
+ bindingSource1 = new BindingSource(components);
+ dataModelBindingSource = new BindingSource(components);
+ Label43 = new Label();
+ TabControl1 = new TabControl();
+ TabPage5 = new TabPage();
+ groupBox12 = new GroupBox();
+ rdbLibrary2 = new RadioButton();
+ rdbLibrary1 = new RadioButton();
+ GroupBox11 = new GroupBox();
+ numericUpDown2 = new NumericUpDown();
+ numericUpDown1 = new NumericUpDown();
+ Panel3 = new Panel();
+ rdbNuovoMetodo = new RadioButton();
+ rdbVecchioMetodo = new RadioButton();
+ Label8 = new Label();
+ Label7 = new Label();
+ GroupBox3 = new GroupBox();
+ btnOpenDestFolder = new Button();
+ btnOpenSourceFolder = new Button();
+ chkAggiornaSottodirectory = new CheckBox();
+ _Button3 = new Button();
+ _Button2 = new Button();
+ Label1 = new Label();
+ Label2 = new Label();
+ txtSorgente = new TextBox();
+ txtDestinazione = new TextBox();
+ GroupBox8 = new GroupBox();
+ rdbNumFiles = new RadioButton();
+ rdbNumProgressiva = new RadioButton();
+ txtCifreContatore = new TextBox();
+ Label34 = new Label();
+ txtSuffissoCartelle = new TextBox();
+ Label33 = new Label();
+ Label31 = new Label();
+ chkCreaSottocartelle = new CheckBox();
+ txtFilePerCartella = new TextBox();
+ Label32 = new Label();
+ GroupBox7 = new GroupBox();
+ chkSovrascriviFile = new CheckBox();
+ chkRotazioneAutomatica = new CheckBox();
+ chkForzaJpg = new CheckBox();
+ TabPage3 = new TabPage();
+ GroupBox10 = new GroupBox();
+ Label42 = new Label();
+ Label41 = new Label();
+ TextBox31 = new TextBox();
+ TextBox30 = new TextBox();
+ GroupBox9 = new GroupBox();
+ CheckBox17 = new CheckBox();
+ CheckBox16 = new CheckBox();
+ GroupBox5 = new GroupBox();
+ TextBox34 = new TextBox();
+ _Button8 = new Button();
+ Label36 = new Label();
+ TextBox25 = new TextBox();
+ Label35 = new Label();
+ ComboBox3 = new ComboBox();
+ TextBox11 = new TextBox();
+ Label12 = new Label();
+ Label11 = new Label();
+ CheckBox3 = new CheckBox();
+ GroupBox4 = new GroupBox();
+ Label40 = new Label();
+ TextBox29 = new TextBox();
+ TextBox18 = new TextBox();
+ Label26 = new Label();
+ DateTimePicker1 = new DateTimePicker();
+ CheckBox8 = new CheckBox();
+ TextBox9 = new TextBox();
+ CheckBox7 = new CheckBox();
+ Label4 = new Label();
+ TextBox4 = new TextBox();
+ Label9 = new Label();
+ Label13 = new Label();
+ ComboBox1 = new ComboBox();
+ ComboBox2 = new ComboBox();
+ Label14 = new Label();
+ TextBox12 = new TextBox();
+ Label15 = new Label();
+ TabPage2 = new TabPage();
+ GroupBox2 = new GroupBox();
+ Label45 = new Label();
+ TextBox32 = new TextBox();
+ TextBox26 = new TextBox();
+ Label37 = new Label();
+ Label38 = new Label();
+ TextBox27 = new TextBox();
+ Label39 = new Label();
+ TextBox28 = new TextBox();
+ CheckBox15 = new CheckBox();
+ TabPage1 = new TabPage();
+ Panel1 = new Panel();
+ _CheckBox18 = new CheckBox();
+ _CheckBox4 = new CheckBox();
+ _CheckBox12 = new CheckBox();
+ GroupBox1 = new GroupBox();
+ Label46 = new Label();
+ TextBox33 = new TextBox();
+ Label5 = new Label();
+ TextBox5 = new TextBox();
+ Label6 = new Label();
+ TextBox6 = new TextBox();
+ Label3 = new Label();
+ TextBox3 = new TextBox();
+ CheckBox1 = new CheckBox();
+ comboThumbnailOption = new ComboBox();
+ TabPage4 = new TabPage();
+ GroupBox6 = new GroupBox();
+ chkUseTransparentColor = new CheckBox();
+ btnSetTransparency = new Button();
+ _PictureBox1 = new PictureBox();
+ ComboBox5 = new ComboBox();
+ ComboBox4 = new ComboBox();
+ TextBox19 = new TextBox();
+ Label28 = new Label();
+ CheckBox5 = new CheckBox();
+ TextBox15 = new TextBox();
+ TextBox14 = new TextBox();
+ Label25 = new Label();
+ TextBox16 = new TextBox();
+ Label24 = new Label();
+ Label22 = new Label();
+ Label23 = new Label();
+ _Button4 = new Button();
+ TextBox10 = new TextBox();
+ Label29 = new Label();
+ PictureBox3 = new PictureBox();
+ versionLabel = new Label();
+ _Button7 = new Button();
+ _Button5 = new Button();
+ Label20 = new Label();
+ Label19 = new Label();
+ Label18 = new Label();
+ lblFotoTotaliNum = new Label();
+ Label10 = new Label();
+ _Button6 = new Button();
+ _btnCreaCatalogoAsync = new Button();
+ timer1 = new System.Windows.Forms.Timer(components);
+ dataModelBindingSource1 = new BindingSource(components);
+ colorDialog1 = new ColorDialog();
+ label16 = new Label();
+ ((System.ComponentModel.ISupportInitialize)bindingSource1).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)dataModelBindingSource).BeginInit();
+ TabControl1.SuspendLayout();
+ TabPage5.SuspendLayout();
+ groupBox12.SuspendLayout();
+ GroupBox11.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)numericUpDown2).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)numericUpDown1).BeginInit();
+ Panel3.SuspendLayout();
+ GroupBox3.SuspendLayout();
+ GroupBox8.SuspendLayout();
+ GroupBox7.SuspendLayout();
+ TabPage3.SuspendLayout();
+ GroupBox10.SuspendLayout();
+ GroupBox9.SuspendLayout();
+ GroupBox5.SuspendLayout();
+ GroupBox4.SuspendLayout();
+ TabPage2.SuspendLayout();
+ GroupBox2.SuspendLayout();
+ TabPage1.SuspendLayout();
+ Panel1.SuspendLayout();
+ GroupBox1.SuspendLayout();
+ TabPage4.SuspendLayout();
+ GroupBox6.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)_PictureBox1).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)PictureBox3).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)dataModelBindingSource1).BeginInit();
+ SuspendLayout();
+ //
+ // ProgressBar1
+ //
+ ProgressBar1.Location = new Point(1078, 561);
+ ProgressBar1.Margin = new Padding(6, 8, 6, 8);
+ ProgressBar1.Name = "ProgressBar1";
+ ProgressBar1.Size = new Size(384, 52);
+ ProgressBar1.TabIndex = 67;
+ //
+ // CheckBox22
+ //
+ CheckBox22.AutoSize = true;
+ CheckBox22.DataBindings.Add(new Binding("Checked", bindingSource1, "ShutdownSystem", true, DataSourceUpdateMode.OnPropertyChanged));
+ CheckBox22.Location = new Point(1078, 827);
+ CheckBox22.Margin = new Padding(6, 8, 6, 8);
+ CheckBox22.Name = "CheckBox22";
+ CheckBox22.Size = new Size(197, 34);
+ CheckBox22.TabIndex = 65;
+ CheckBox22.Text = "Arresta il sistema";
+ CheckBox22.UseVisualStyleBackColor = true;
+ //
+ // bindingSource1
+ //
+ bindingSource1.DataSource = dataModelBindingSource;
+ //
+ // dataModelBindingSource
+ //
+ dataModelBindingSource.DataSource = typeof(ImageCatalog_2.DataModel);
+ //
+ // Label43
+ //
+ Label43.AutoSize = true;
+ Label43.DataBindings.Add(new Binding("Text", bindingSource1, "SpeedCounter", true));
+ Label43.Location = new Point(1074, 725);
+ Label43.Margin = new Padding(6, 0, 6, 0);
+ Label43.Name = "Label43";
+ Label43.Size = new Size(46, 30);
+ Label43.TabIndex = 64;
+ Label43.Text = "000";
+ Label43.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // TabControl1
+ //
+ TabControl1.Controls.Add(TabPage5);
+ TabControl1.Controls.Add(TabPage3);
+ TabControl1.Controls.Add(TabPage2);
+ TabControl1.Controls.Add(TabPage1);
+ TabControl1.Controls.Add(TabPage4);
+ TabControl1.DataBindings.Add(new Binding("Enabled", bindingSource1, "UiEnabled", true));
+ TabControl1.Location = new Point(24, 22);
+ TabControl1.Margin = new Padding(6, 8, 6, 8);
+ TabControl1.Name = "TabControl1";
+ TabControl1.SelectedIndex = 0;
+ TabControl1.Size = new Size(1042, 870);
+ TabControl1.TabIndex = 63;
+ //
+ // TabPage5
+ //
+ TabPage5.Controls.Add(groupBox12);
+ TabPage5.Controls.Add(GroupBox11);
+ TabPage5.Controls.Add(GroupBox3);
+ TabPage5.Controls.Add(GroupBox8);
+ TabPage5.Controls.Add(GroupBox7);
+ TabPage5.Location = new Point(4, 39);
+ TabPage5.Margin = new Padding(6, 8, 6, 8);
+ TabPage5.Name = "TabPage5";
+ TabPage5.Padding = new Padding(6, 8, 6, 8);
+ TabPage5.Size = new Size(1034, 827);
+ TabPage5.TabIndex = 4;
+ TabPage5.Text = "Generale";
+ TabPage5.UseVisualStyleBackColor = true;
+ //
+ // groupBox12
+ //
+ groupBox12.Controls.Add(rdbLibrary2);
+ groupBox12.Controls.Add(rdbLibrary1);
+ groupBox12.Location = new Point(405, 625);
+ groupBox12.Name = "groupBox12";
+ groupBox12.Size = new Size(350, 175);
+ groupBox12.TabIndex = 49;
+ groupBox12.TabStop = false;
+ groupBox12.Text = "Libreria Manipolazione Grafica";
+ //
+ // rdbLibrary2
+ //
+ rdbLibrary2.AutoSize = true;
+ rdbLibrary2.DataBindings.Add(new Binding("Checked", bindingSource1, "UseImageSharp", true, DataSourceUpdateMode.OnPropertyChanged));
+ rdbLibrary2.Location = new Point(12, 77);
+ rdbLibrary2.Name = "rdbLibrary2";
+ rdbLibrary2.Size = new Size(149, 34);
+ rdbLibrary2.TabIndex = 1;
+ rdbLibrary2.TabStop = true;
+ rdbLibrary2.Text = "ImageSharp";
+ rdbLibrary2.UseVisualStyleBackColor = true;
+ //
+ // rdbLibrary1
+ //
+ rdbLibrary1.AutoSize = true;
+ rdbLibrary1.DataBindings.Add(new Binding("Checked", bindingSource1, "UseSystemGraphics", true, DataSourceUpdateMode.OnPropertyChanged));
+ rdbLibrary1.Location = new Point(12, 37);
+ rdbLibrary1.Name = "rdbLibrary1";
+ rdbLibrary1.Size = new Size(188, 34);
+ rdbLibrary1.TabIndex = 0;
+ rdbLibrary1.TabStop = true;
+ rdbLibrary1.Text = "System.Graphics";
+ rdbLibrary1.UseVisualStyleBackColor = true;
+ //
+ // GroupBox11
+ //
+ GroupBox11.Controls.Add(numericUpDown2);
+ GroupBox11.Controls.Add(numericUpDown1);
+ GroupBox11.Controls.Add(Panel3);
+ GroupBox11.Controls.Add(Label8);
+ GroupBox11.Controls.Add(Label7);
+ GroupBox11.Location = new Point(14, 483);
+ GroupBox11.Margin = new Padding(6, 8, 6, 8);
+ GroupBox11.Name = "GroupBox11";
+ GroupBox11.Padding = new Padding(6, 8, 6, 8);
+ GroupBox11.Size = new Size(382, 305);
+ GroupBox11.TabIndex = 48;
+ GroupBox11.TabStop = false;
+ GroupBox11.Text = "Avanzate (ATTENZIONE)";
+ //
+ // numericUpDown2
+ //
+ numericUpDown2.DataBindings.Add(new Binding("Value", bindingSource1, "ThreadsCount", true, DataSourceUpdateMode.OnPropertyChanged));
+ numericUpDown2.Location = new Point(14, 111);
+ numericUpDown2.Maximum = new decimal(new int[] { 10000, 0, 0, 0 });
+ numericUpDown2.Name = "numericUpDown2";
+ numericUpDown2.Size = new Size(105, 35);
+ numericUpDown2.TabIndex = 52;
+ //
+ // numericUpDown1
+ //
+ numericUpDown1.DataBindings.Add(new Binding("Value", bindingSource1, "ChunkSize", true, DataSourceUpdateMode.OnPropertyChanged));
+ numericUpDown1.Location = new Point(14, 58);
+ numericUpDown1.Maximum = new decimal(new int[] { 10000, 0, 0, 0 });
+ numericUpDown1.Name = "numericUpDown1";
+ numericUpDown1.Size = new Size(105, 35);
+ numericUpDown1.TabIndex = 51;
+ //
+ // Panel3
+ //
+ Panel3.Controls.Add(rdbNuovoMetodo);
+ Panel3.Controls.Add(rdbVecchioMetodo);
+ Panel3.Location = new Point(14, 168);
+ Panel3.Margin = new Padding(6, 8, 6, 8);
+ Panel3.Name = "Panel3";
+ Panel3.Size = new Size(355, 123);
+ Panel3.TabIndex = 4;
+ //
+ // rdbNuovoMetodo
+ //
+ rdbNuovoMetodo.AutoSize = true;
+ rdbNuovoMetodo.Checked = true;
+ rdbNuovoMetodo.DataBindings.Add(new Binding("Checked", bindingSource1, "UseParallelProcessing", true, DataSourceUpdateMode.OnPropertyChanged));
+ rdbNuovoMetodo.Location = new Point(17, 65);
+ rdbNuovoMetodo.Margin = new Padding(6, 8, 6, 8);
+ rdbNuovoMetodo.Name = "rdbNuovoMetodo";
+ rdbNuovoMetodo.Size = new Size(116, 34);
+ rdbNuovoMetodo.TabIndex = 1;
+ rdbNuovoMetodo.TabStop = true;
+ rdbNuovoMetodo.Text = "Parallelo";
+ rdbNuovoMetodo.UseVisualStyleBackColor = true;
+ //
+ // rdbVecchioMetodo
+ //
+ rdbVecchioMetodo.AutoSize = true;
+ rdbVecchioMetodo.DataBindings.Add(new Binding("Checked", bindingSource1, "UseSequentialProcessing", true, DataSourceUpdateMode.OnPropertyChanged));
+ rdbVecchioMetodo.Location = new Point(17, 9);
+ rdbVecchioMetodo.Margin = new Padding(6, 8, 6, 8);
+ rdbVecchioMetodo.Name = "rdbVecchioMetodo";
+ rdbVecchioMetodo.Size = new Size(105, 34);
+ rdbVecchioMetodo.TabIndex = 0;
+ rdbVecchioMetodo.Text = "Lineare";
+ rdbVecchioMetodo.UseVisualStyleBackColor = true;
+ //
+ // Label8
+ //
+ Label8.AutoSize = true;
+ Label8.Location = new Point(127, 60);
+ Label8.Margin = new Padding(6, 0, 6, 0);
+ Label8.Name = "Label8";
+ Label8.Size = new Size(215, 30);
+ Label8.TabIndex = 3;
+ Label8.Text = "Chunk Size (0 = MAX)";
+ //
+ // Label7
+ //
+ Label7.AutoSize = true;
+ Label7.Location = new Point(127, 112);
+ Label7.Margin = new Padding(6, 0, 6, 0);
+ Label7.Name = "Label7";
+ Label7.Size = new Size(186, 30);
+ Label7.TabIndex = 1;
+ Label7.Text = "Threads (0 = Auto)";
+ //
+ // GroupBox3
+ //
+ GroupBox3.Controls.Add(btnOpenDestFolder);
+ GroupBox3.Controls.Add(btnOpenSourceFolder);
+ GroupBox3.Controls.Add(chkAggiornaSottodirectory);
+ GroupBox3.Controls.Add(_Button3);
+ GroupBox3.Controls.Add(_Button2);
+ GroupBox3.Controls.Add(Label1);
+ GroupBox3.Controls.Add(Label2);
+ GroupBox3.Controls.Add(txtSorgente);
+ GroupBox3.Controls.Add(txtDestinazione);
+ GroupBox3.ForeColor = Color.FromArgb(0, 0, 192);
+ GroupBox3.Location = new Point(12, 13);
+ GroupBox3.Margin = new Padding(6, 8, 6, 8);
+ GroupBox3.Name = "GroupBox3";
+ GroupBox3.Padding = new Padding(6, 8, 6, 8);
+ GroupBox3.Size = new Size(991, 232);
+ GroupBox3.TabIndex = 35;
+ GroupBox3.TabStop = false;
+ GroupBox3.Text = "Directory";
+ //
+ // btnOpenDestFolder
+ //
+ btnOpenDestFolder.Location = new Point(939, 97);
+ btnOpenDestFolder.Margin = new Padding(6, 8, 6, 8);
+ btnOpenDestFolder.Name = "btnOpenDestFolder";
+ btnOpenDestFolder.Size = new Size(48, 35);
+ btnOpenDestFolder.TabIndex = 27;
+ btnOpenDestFolder.Text = "Apri";
+ //
+ // btnOpenSourceFolder
+ //
+ btnOpenSourceFolder.Location = new Point(939, 38);
+ btnOpenSourceFolder.Margin = new Padding(6, 8, 6, 8);
+ btnOpenSourceFolder.Name = "btnOpenSourceFolder";
+ btnOpenSourceFolder.Size = new Size(48, 35);
+ btnOpenSourceFolder.TabIndex = 26;
+ btnOpenSourceFolder.Text = "Apri";
+ //
+ // chkAggiornaSottodirectory
+ //
+ chkAggiornaSottodirectory.DataBindings.Add(new Binding("Checked", bindingSource1, "UpdateSubdirectories", true, DataSourceUpdateMode.OnPropertyChanged));
+ chkAggiornaSottodirectory.ForeColor = Color.Black;
+ chkAggiornaSottodirectory.Location = new Point(161, 147);
+ chkAggiornaSottodirectory.Margin = new Padding(6, 8, 6, 8);
+ chkAggiornaSottodirectory.Name = "chkAggiornaSottodirectory";
+ chkAggiornaSottodirectory.Size = new Size(475, 55);
+ chkAggiornaSottodirectory.TabIndex = 25;
+ chkAggiornaSottodirectory.Text = "aggiorna le sottodirectory";
+ //
+ // _Button3
+ //
+ _Button3.Location = new Point(879, 96);
+ _Button3.Margin = new Padding(6, 8, 6, 8);
+ _Button3.Name = "_Button3";
+ _Button3.Size = new Size(48, 36);
+ _Button3.TabIndex = 6;
+ _Button3.Text = "...";
+ //
+ // _Button2
+ //
+ _Button2.Location = new Point(879, 38);
+ _Button2.Margin = new Padding(6, 8, 6, 8);
+ _Button2.Name = "_Button2";
+ _Button2.Size = new Size(48, 35);
+ _Button2.TabIndex = 5;
+ _Button2.Text = "...";
+ //
+ // Label1
+ //
+ Label1.AutoSize = true;
+ Label1.ForeColor = Color.Black;
+ Label1.Location = new Point(12, 43);
+ Label1.Margin = new Padding(6, 0, 6, 0);
+ Label1.Name = "Label1";
+ Label1.Size = new Size(96, 30);
+ Label1.TabIndex = 3;
+ Label1.Text = "Sorgente";
+ //
+ // Label2
+ //
+ Label2.AutoSize = true;
+ Label2.ForeColor = Color.Black;
+ Label2.Location = new Point(12, 96);
+ Label2.Margin = new Padding(6, 0, 6, 0);
+ Label2.Name = "Label2";
+ Label2.Size = new Size(133, 30);
+ Label2.TabIndex = 4;
+ Label2.Text = "Destinazione";
+ //
+ // txtSorgente
+ //
+ txtSorgente.DataBindings.Add(new Binding("Text", bindingSource1, "SourcePath", true, DataSourceUpdateMode.OnPropertyChanged));
+ txtSorgente.Location = new Point(161, 38);
+ txtSorgente.Margin = new Padding(6, 8, 6, 8);
+ txtSorgente.Name = "txtSorgente";
+ txtSorgente.Size = new Size(706, 35);
+ txtSorgente.TabIndex = 0;
+ //
+ // txtDestinazione
+ //
+ txtDestinazione.DataBindings.Add(new Binding("Text", bindingSource1, "DestinationPath", true, DataSourceUpdateMode.OnPropertyChanged));
+ txtDestinazione.Location = new Point(161, 93);
+ txtDestinazione.Margin = new Padding(6, 8, 6, 8);
+ txtDestinazione.Name = "txtDestinazione";
+ txtDestinazione.Size = new Size(706, 35);
+ txtDestinazione.TabIndex = 1;
+ txtDestinazione.Text = "TextBox2";
+ //
+ // GroupBox8
+ //
+ GroupBox8.Controls.Add(rdbNumFiles);
+ GroupBox8.Controls.Add(rdbNumProgressiva);
+ GroupBox8.Controls.Add(txtCifreContatore);
+ GroupBox8.Controls.Add(Label34);
+ GroupBox8.Controls.Add(txtSuffissoCartelle);
+ GroupBox8.Controls.Add(Label33);
+ GroupBox8.Controls.Add(Label31);
+ GroupBox8.Controls.Add(chkCreaSottocartelle);
+ GroupBox8.Controls.Add(txtFilePerCartella);
+ GroupBox8.Controls.Add(Label32);
+ GroupBox8.ForeColor = Color.FromArgb(0, 0, 192);
+ GroupBox8.Location = new Point(408, 261);
+ GroupBox8.Margin = new Padding(6, 8, 6, 8);
+ GroupBox8.Name = "GroupBox8";
+ GroupBox8.Padding = new Padding(6, 8, 6, 8);
+ GroupBox8.Size = new Size(384, 351);
+ GroupBox8.TabIndex = 47;
+ GroupBox8.TabStop = false;
+ GroupBox8.Text = "Sottocartelle";
+ //
+ // rdbNumFiles
+ //
+ rdbNumFiles.DataBindings.Add(new Binding("Checked", bindingSource1, "UseFileNumbering", true, DataSourceUpdateMode.OnPropertyChanged));
+ rdbNumFiles.ForeColor = Color.Black;
+ rdbNumFiles.Location = new Point(65, 295);
+ rdbNumFiles.Margin = new Padding(6, 8, 6, 8);
+ rdbNumFiles.Name = "rdbNumFiles";
+ rdbNumFiles.Size = new Size(271, 38);
+ rdbNumFiles.TabIndex = 38;
+ rdbNumFiles.Text = "Numerazione files";
+ //
+ // rdbNumProgressiva
+ //
+ rdbNumProgressiva.Checked = true;
+ rdbNumProgressiva.DataBindings.Add(new Binding("Checked", bindingSource1, "UseProgressiveNumbering", true, DataSourceUpdateMode.OnPropertyChanged));
+ rdbNumProgressiva.ForeColor = Color.Black;
+ rdbNumProgressiva.Location = new Point(65, 258);
+ rdbNumProgressiva.Margin = new Padding(6, 8, 6, 8);
+ rdbNumProgressiva.Name = "rdbNumProgressiva";
+ rdbNumProgressiva.Size = new Size(305, 38);
+ rdbNumProgressiva.TabIndex = 37;
+ rdbNumProgressiva.TabStop = true;
+ rdbNumProgressiva.Text = "Numerazione progressiva";
+ //
+ // txtCifreContatore
+ //
+ txtCifreContatore.DataBindings.Add(new Binding("Text", bindingSource1, "CounterDigits", true, DataSourceUpdateMode.OnPropertyChanged));
+ txtCifreContatore.Location = new Point(257, 202);
+ txtCifreContatore.Margin = new Padding(6, 8, 6, 8);
+ txtCifreContatore.Name = "txtCifreContatore";
+ txtCifreContatore.Size = new Size(107, 35);
+ txtCifreContatore.TabIndex = 34;
+ txtCifreContatore.Text = "4";
+ //
+ // Label34
+ //
+ Label34.ForeColor = Color.Black;
+ Label34.Location = new Point(17, 202);
+ Label34.Margin = new Padding(6, 0, 6, 0);
+ Label34.Name = "Label34";
+ Label34.Size = new Size(223, 38);
+ Label34.TabIndex = 33;
+ Label34.Text = "Num. cifre contatore";
+ Label34.TextAlign = ContentAlignment.MiddleRight;
+ //
+ // txtSuffissoCartelle
+ //
+ txtSuffissoCartelle.DataBindings.Add(new Binding("Text", bindingSource1, "FolderSuffix", true, DataSourceUpdateMode.OnPropertyChanged));
+ txtSuffissoCartelle.Location = new Point(113, 147);
+ txtSuffissoCartelle.Margin = new Padding(6, 8, 6, 8);
+ txtSuffissoCartelle.Name = "txtSuffissoCartelle";
+ txtSuffissoCartelle.Size = new Size(251, 35);
+ txtSuffissoCartelle.TabIndex = 32;
+ txtSuffissoCartelle.Text = "TextBox20";
+ //
+ // Label33
+ //
+ Label33.ForeColor = Color.Black;
+ Label33.Location = new Point(12, 155);
+ Label33.Margin = new Padding(6, 0, 6, 0);
+ Label33.Name = "Label33";
+ Label33.Size = new Size(96, 38);
+ Label33.TabIndex = 31;
+ Label33.Text = "Suffisso";
+ //
+ // Label31
+ //
+ Label31.ForeColor = Color.Black;
+ Label31.Location = new Point(48, 93);
+ Label31.Margin = new Padding(6, 0, 6, 0);
+ Label31.Name = "Label31";
+ Label31.Size = new Size(65, 38);
+ Label31.TabIndex = 30;
+ Label31.Text = "ogni";
+ //
+ // chkCreaSottocartelle
+ //
+ chkCreaSottocartelle.DataBindings.Add(new Binding("Checked", bindingSource1, "CreateSubfolders", true, DataSourceUpdateMode.OnPropertyChanged));
+ chkCreaSottocartelle.ForeColor = Color.Black;
+ chkCreaSottocartelle.Location = new Point(113, 38);
+ chkCreaSottocartelle.Margin = new Padding(6, 8, 6, 8);
+ chkCreaSottocartelle.Name = "chkCreaSottocartelle";
+ chkCreaSottocartelle.Size = new Size(223, 38);
+ chkCreaSottocartelle.TabIndex = 29;
+ chkCreaSottocartelle.Text = "crea sottocartelle";
+ //
+ // txtFilePerCartella
+ //
+ txtFilePerCartella.DataBindings.Add(new Binding("Text", bindingSource1, "FilesPerFolder", true, DataSourceUpdateMode.OnPropertyChanged));
+ txtFilePerCartella.Location = new Point(113, 93);
+ txtFilePerCartella.Margin = new Padding(6, 8, 6, 8);
+ txtFilePerCartella.Name = "txtFilePerCartella";
+ txtFilePerCartella.Size = new Size(124, 35);
+ txtFilePerCartella.TabIndex = 27;
+ txtFilePerCartella.Text = "99";
+ //
+ // Label32
+ //
+ Label32.ForeColor = Color.Black;
+ Label32.Location = new Point(257, 93);
+ Label32.Margin = new Padding(6, 0, 6, 0);
+ Label32.Name = "Label32";
+ Label32.Size = new Size(48, 38);
+ Label32.TabIndex = 28;
+ Label32.Text = "file";
+ //
+ // GroupBox7
+ //
+ GroupBox7.Controls.Add(chkSovrascriviFile);
+ GroupBox7.Controls.Add(chkRotazioneAutomatica);
+ GroupBox7.Controls.Add(chkForzaJpg);
+ GroupBox7.ForeColor = Color.FromArgb(0, 0, 192);
+ GroupBox7.Location = new Point(12, 261);
+ GroupBox7.Margin = new Padding(6, 8, 6, 8);
+ GroupBox7.Name = "GroupBox7";
+ GroupBox7.Padding = new Padding(6, 8, 6, 8);
+ GroupBox7.Size = new Size(384, 202);
+ GroupBox7.TabIndex = 45;
+ GroupBox7.TabStop = false;
+ GroupBox7.Text = "Generale";
+ //
+ // chkSovrascriviFile
+ //
+ chkSovrascriviFile.AutoSize = true;
+ chkSovrascriviFile.DataBindings.Add(new Binding("Checked", bindingSource1, "OverwriteImages", true, DataSourceUpdateMode.OnPropertyChanged));
+ chkSovrascriviFile.Location = new Point(31, 141);
+ chkSovrascriviFile.Margin = new Padding(6, 8, 6, 8);
+ chkSovrascriviFile.Name = "chkSovrascriviFile";
+ chkSovrascriviFile.Size = new Size(170, 34);
+ chkSovrascriviFile.TabIndex = 2;
+ chkSovrascriviFile.Text = "Sovrascrivi file";
+ chkSovrascriviFile.UseVisualStyleBackColor = true;
+ //
+ // chkRotazioneAutomatica
+ //
+ chkRotazioneAutomatica.DataBindings.Add(new Binding("Checked", bindingSource1, "AutomaticRotation", true, DataSourceUpdateMode.OnPropertyChanged));
+ chkRotazioneAutomatica.ForeColor = Color.Black;
+ chkRotazioneAutomatica.Location = new Point(31, 90);
+ chkRotazioneAutomatica.Margin = new Padding(6, 8, 6, 8);
+ chkRotazioneAutomatica.Name = "chkRotazioneAutomatica";
+ chkRotazioneAutomatica.Size = new Size(271, 38);
+ chkRotazioneAutomatica.TabIndex = 1;
+ chkRotazioneAutomatica.Text = "Rotazione automatica";
+ //
+ // chkForzaJpg
+ //
+ chkForzaJpg.Checked = true;
+ chkForzaJpg.CheckState = CheckState.Checked;
+ chkForzaJpg.DataBindings.Add(new Binding("Checked", bindingSource1, "ForceJpeg", true, DataSourceUpdateMode.OnPropertyChanged));
+ chkForzaJpg.ForeColor = Color.Black;
+ chkForzaJpg.Location = new Point(31, 42);
+ chkForzaJpg.Margin = new Padding(6, 8, 6, 8);
+ chkForzaJpg.Name = "chkForzaJpg";
+ chkForzaJpg.Size = new Size(161, 38);
+ chkForzaJpg.TabIndex = 0;
+ chkForzaJpg.Text = "Forza Jpg";
+ //
+ // TabPage3
+ //
+ TabPage3.Controls.Add(GroupBox10);
+ TabPage3.Controls.Add(GroupBox9);
+ TabPage3.Controls.Add(GroupBox5);
+ TabPage3.Controls.Add(GroupBox4);
+ TabPage3.Location = new Point(4, 39);
+ TabPage3.Margin = new Padding(6, 8, 6, 8);
+ TabPage3.Name = "TabPage3";
+ TabPage3.Padding = new Padding(6, 8, 6, 8);
+ TabPage3.Size = new Size(1034, 827);
+ TabPage3.TabIndex = 2;
+ TabPage3.Text = "Testo";
+ TabPage3.UseVisualStyleBackColor = true;
+ //
+ // GroupBox10
+ //
+ GroupBox10.Controls.Add(Label42);
+ GroupBox10.Controls.Add(Label41);
+ GroupBox10.Controls.Add(TextBox31);
+ GroupBox10.Controls.Add(TextBox30);
+ GroupBox10.Location = new Point(631, 180);
+ GroupBox10.Margin = new Padding(6, 8, 6, 8);
+ GroupBox10.Name = "GroupBox10";
+ GroupBox10.Padding = new Padding(6, 8, 6, 8);
+ GroupBox10.Size = new Size(372, 168);
+ GroupBox10.TabIndex = 39;
+ GroupBox10.TabStop = false;
+ GroupBox10.Text = "Testo foto verticali";
+ //
+ // Label42
+ //
+ Label42.AutoSize = true;
+ Label42.Location = new Point(14, 107);
+ Label42.Margin = new Padding(6, 0, 6, 0);
+ Label42.Name = "Label42";
+ Label42.Size = new Size(90, 30);
+ Label42.TabIndex = 3;
+ Label42.Text = "Margine";
+ //
+ // Label41
+ //
+ Label41.AutoSize = true;
+ Label41.Location = new Point(14, 57);
+ Label41.Margin = new Padding(6, 0, 6, 0);
+ Label41.Name = "Label41";
+ Label41.Size = new Size(214, 30);
+ Label41.TabIndex = 2;
+ Label41.Text = "Dimensione Carattere";
+ //
+ // TextBox31
+ //
+ TextBox31.DataBindings.Add(new Binding("Text", bindingSource1, "VerticalTextMargin", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox31.Location = new Point(262, 107);
+ TextBox31.Margin = new Padding(6, 8, 6, 8);
+ TextBox31.Name = "TextBox31";
+ TextBox31.Size = new Size(74, 35);
+ TextBox31.TabIndex = 1;
+ //
+ // TextBox30
+ //
+ TextBox30.DataBindings.Add(new Binding("Text", bindingSource1, "VerticalTextSize", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox30.Location = new Point(262, 51);
+ TextBox30.Margin = new Padding(6, 8, 6, 8);
+ TextBox30.Name = "TextBox30";
+ TextBox30.Size = new Size(74, 35);
+ TextBox30.TabIndex = 0;
+ //
+ // GroupBox9
+ //
+ GroupBox9.Controls.Add(CheckBox17);
+ GroupBox9.Controls.Add(CheckBox16);
+ GroupBox9.Location = new Point(631, 72);
+ GroupBox9.Margin = new Padding(6, 8, 6, 8);
+ GroupBox9.Name = "GroupBox9";
+ GroupBox9.Padding = new Padding(6, 8, 6, 8);
+ GroupBox9.Size = new Size(372, 103);
+ GroupBox9.TabIndex = 38;
+ GroupBox9.TabStop = false;
+ GroupBox9.Text = "Slide show";
+ //
+ // CheckBox17
+ //
+ CheckBox17.AutoSize = true;
+ CheckBox17.DataBindings.Add(new Binding("Checked", bindingSource1, "ShowPhotoNumber", true, DataSourceUpdateMode.OnPropertyChanged));
+ CheckBox17.Location = new Point(192, 42);
+ CheckBox17.Margin = new Padding(6, 8, 6, 8);
+ CheckBox17.Name = "CheckBox17";
+ CheckBox17.Size = new Size(159, 34);
+ CheckBox17.TabIndex = 1;
+ CheckBox17.Text = "Numero foto";
+ CheckBox17.UseVisualStyleBackColor = true;
+ //
+ // CheckBox16
+ //
+ CheckBox16.AutoSize = true;
+ CheckBox16.DataBindings.Add(new Binding("Checked", bindingSource1, "ShowDate", true, DataSourceUpdateMode.OnPropertyChanged));
+ CheckBox16.Location = new Point(12, 43);
+ CheckBox16.Margin = new Padding(6, 8, 6, 8);
+ CheckBox16.Name = "CheckBox16";
+ CheckBox16.Size = new Size(83, 34);
+ CheckBox16.TabIndex = 0;
+ CheckBox16.Text = "Data";
+ CheckBox16.UseVisualStyleBackColor = true;
+ //
+ // GroupBox5
+ //
+ GroupBox5.Controls.Add(TextBox34);
+ GroupBox5.Controls.Add(_Button8);
+ GroupBox5.Controls.Add(Label36);
+ GroupBox5.Controls.Add(TextBox25);
+ GroupBox5.Controls.Add(Label35);
+ GroupBox5.Controls.Add(ComboBox3);
+ GroupBox5.Controls.Add(TextBox11);
+ GroupBox5.Controls.Add(Label12);
+ GroupBox5.Controls.Add(Label11);
+ GroupBox5.Controls.Add(CheckBox3);
+ GroupBox5.ForeColor = Color.FromArgb(0, 0, 192);
+ GroupBox5.Location = new Point(12, 72);
+ GroupBox5.Margin = new Padding(6, 8, 6, 8);
+ GroupBox5.Name = "GroupBox5";
+ GroupBox5.Padding = new Padding(6, 8, 6, 8);
+ GroupBox5.Size = new Size(607, 278);
+ GroupBox5.TabIndex = 37;
+ GroupBox5.TabStop = false;
+ GroupBox5.Text = "Carattere";
+ //
+ // TextBox34
+ //
+ TextBox34.DataBindings.Add(new Binding("Text", bindingSource1, "TextColorRGB", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox34.Location = new Point(319, 210);
+ TextBox34.Margin = new Padding(6, 8, 6, 8);
+ TextBox34.Name = "TextBox34";
+ TextBox34.Size = new Size(107, 35);
+ TextBox34.TabIndex = 36;
+ TextBox34.TextAlign = HorizontalAlignment.Right;
+ //
+ // _Button8
+ //
+ _Button8.ForeColor = Color.Black;
+ _Button8.Location = new Point(444, 205);
+ _Button8.Margin = new Padding(6, 8, 6, 8);
+ _Button8.Name = "_Button8";
+ _Button8.Size = new Size(149, 55);
+ _Button8.TabIndex = 35;
+ _Button8.Text = "Scegli...";
+ //
+ // Label36
+ //
+ Label36.ForeColor = Color.Black;
+ Label36.Location = new Point(17, 138);
+ Label36.Margin = new Padding(6, 0, 6, 0);
+ Label36.Name = "Label36";
+ Label36.Size = new Size(240, 43);
+ Label36.TabIndex = 34;
+ Label36.Text = "Dimensione miniatura";
+ Label36.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // TextBox25
+ //
+ TextBox25.DataBindings.Add(new Binding("Text", bindingSource1, "FontSizeThumbnail", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox25.Location = new Point(319, 137);
+ TextBox25.Margin = new Padding(6, 8, 6, 8);
+ TextBox25.Name = "TextBox25";
+ TextBox25.Size = new Size(107, 35);
+ TextBox25.TabIndex = 33;
+ TextBox25.Text = "TextBox25";
+ //
+ // Label35
+ //
+ Label35.ForeColor = Color.Black;
+ Label35.Location = new Point(17, 215);
+ Label35.Margin = new Padding(6, 0, 6, 0);
+ Label35.Name = "Label35";
+ Label35.Size = new Size(144, 38);
+ Label35.TabIndex = 32;
+ Label35.Text = "Colore RGB";
+ Label35.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // ComboBox3
+ //
+ ComboBox3.DataBindings.Add(new Binding("Text", bindingSource1, "FontName", true, DataSourceUpdateMode.OnPropertyChanged));
+ ComboBox3.Location = new Point(192, 18);
+ ComboBox3.Margin = new Padding(6, 8, 6, 8);
+ ComboBox3.Name = "ComboBox3";
+ ComboBox3.Size = new Size(237, 38);
+ ComboBox3.TabIndex = 28;
+ ComboBox3.Text = "ComboBox3";
+ //
+ // TextBox11
+ //
+ TextBox11.DataBindings.Add(new Binding("Text", bindingSource1, "FontSize", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox11.Location = new Point(319, 81);
+ TextBox11.Margin = new Padding(6, 8, 6, 8);
+ TextBox11.Name = "TextBox11";
+ TextBox11.Size = new Size(107, 35);
+ TextBox11.TabIndex = 27;
+ TextBox11.Text = "TextBox11";
+ //
+ // Label12
+ //
+ Label12.AutoSize = true;
+ Label12.ForeColor = Color.Black;
+ Label12.Location = new Point(17, 87);
+ Label12.Margin = new Padding(6, 0, 6, 0);
+ Label12.Name = "Label12";
+ Label12.Size = new Size(123, 30);
+ Label12.TabIndex = 26;
+ Label12.Text = "Dimensione";
+ Label12.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // Label11
+ //
+ Label11.AutoSize = true;
+ Label11.ForeColor = Color.Black;
+ Label11.Location = new Point(113, 18);
+ Label11.Margin = new Padding(6, 0, 6, 0);
+ Label11.Name = "Label11";
+ Label11.Size = new Size(54, 30);
+ Label11.TabIndex = 22;
+ Label11.Text = "Font";
+ //
+ // CheckBox3
+ //
+ CheckBox3.DataBindings.Add(new Binding("Checked", bindingSource1, "FontBold", true, DataSourceUpdateMode.OnPropertyChanged));
+ CheckBox3.ForeColor = Color.Black;
+ CheckBox3.Location = new Point(449, 18);
+ CheckBox3.Margin = new Padding(6, 8, 6, 8);
+ CheckBox3.Name = "CheckBox3";
+ CheckBox3.Size = new Size(144, 55);
+ CheckBox3.TabIndex = 24;
+ CheckBox3.Text = "Grassetto";
+ //
+ // GroupBox4
+ //
+ GroupBox4.Controls.Add(Label40);
+ GroupBox4.Controls.Add(TextBox29);
+ GroupBox4.Controls.Add(TextBox18);
+ GroupBox4.Controls.Add(Label26);
+ GroupBox4.Controls.Add(DateTimePicker1);
+ GroupBox4.Controls.Add(CheckBox8);
+ GroupBox4.Controls.Add(TextBox9);
+ GroupBox4.Controls.Add(CheckBox7);
+ GroupBox4.Controls.Add(Label4);
+ GroupBox4.Controls.Add(TextBox4);
+ GroupBox4.Controls.Add(Label9);
+ GroupBox4.Controls.Add(Label13);
+ GroupBox4.Controls.Add(ComboBox1);
+ GroupBox4.Controls.Add(ComboBox2);
+ GroupBox4.Controls.Add(Label14);
+ GroupBox4.Controls.Add(TextBox12);
+ GroupBox4.Controls.Add(Label15);
+ GroupBox4.ForeColor = Color.FromArgb(0, 0, 192);
+ GroupBox4.Location = new Point(12, 363);
+ GroupBox4.Margin = new Padding(6, 8, 6, 8);
+ GroupBox4.Name = "GroupBox4";
+ GroupBox4.Padding = new Padding(6, 8, 6, 8);
+ GroupBox4.Size = new Size(991, 429);
+ GroupBox4.TabIndex = 36;
+ GroupBox4.TabStop = false;
+ GroupBox4.Text = "Testo da applicare";
+ //
+ // Label40
+ //
+ Label40.AutoSize = true;
+ Label40.Location = new Point(17, 120);
+ Label40.Margin = new Padding(6, 0, 6, 0);
+ Label40.Name = "Label40";
+ Label40.Size = new Size(92, 30);
+ Label40.TabIndex = 40;
+ Label40.Text = "Verticale";
+ //
+ // TextBox29
+ //
+ TextBox29.DataBindings.Add(new Binding("Text", bindingSource1, "VerticalText", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox29.Location = new Point(144, 112);
+ TextBox29.Margin = new Padding(6, 8, 6, 8);
+ TextBox29.Multiline = true;
+ TextBox29.Name = "TextBox29";
+ TextBox29.Size = new Size(813, 97);
+ TextBox29.TabIndex = 39;
+ //
+ // TextBox18
+ //
+ TextBox18.DataBindings.Add(new Binding("Text", bindingSource1, "TimeLabel", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox18.Location = new Point(463, 360);
+ TextBox18.Margin = new Padding(6, 8, 6, 8);
+ TextBox18.Name = "TextBox18";
+ TextBox18.Size = new Size(196, 35);
+ TextBox18.TabIndex = 38;
+ //
+ // Label26
+ //
+ Label26.AutoSize = true;
+ Label26.ForeColor = Color.Black;
+ Label26.Location = new Point(689, 360);
+ Label26.Margin = new Padding(6, 0, 6, 0);
+ Label26.Name = "Label26";
+ Label26.Size = new Size(94, 30);
+ Label26.TabIndex = 37;
+ Label26.Text = "partenza";
+ //
+ // DateTimePicker1
+ //
+ DateTimePicker1.DataBindings.Add(new Binding("Value", bindingSource1, "RaceStartDate", true, DataSourceUpdateMode.OnPropertyChanged));
+ DateTimePicker1.Format = DateTimePickerFormat.Time;
+ DateTimePicker1.Location = new Point(785, 360);
+ DateTimePicker1.Margin = new Padding(6, 8, 6, 8);
+ DateTimePicker1.Name = "DateTimePicker1";
+ DateTimePicker1.Size = new Size(172, 35);
+ DateTimePicker1.TabIndex = 36;
+ //
+ // CheckBox8
+ //
+ CheckBox8.DataBindings.Add(new Binding("Checked", bindingSource1, "AddTime", true, DataSourceUpdateMode.OnPropertyChanged));
+ CheckBox8.ForeColor = Color.Black;
+ CheckBox8.Location = new Point(144, 360);
+ CheckBox8.Margin = new Padding(6, 8, 6, 8);
+ CheckBox8.Name = "CheckBox8";
+ CheckBox8.Size = new Size(113, 38);
+ CheckBox8.TabIndex = 35;
+ CheckBox8.Text = "Orario";
+ //
+ // TextBox9
+ //
+ TextBox9.DataBindings.Add(new Binding("Text", bindingSource1, "TextTransparency", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox9.Location = new Point(240, 249);
+ TextBox9.Margin = new Padding(6, 8, 6, 8);
+ TextBox9.Name = "TextBox9";
+ TextBox9.Size = new Size(107, 35);
+ TextBox9.TabIndex = 20;
+ TextBox9.Text = "TextBox9";
+ //
+ // CheckBox7
+ //
+ CheckBox7.DataBindings.Add(new Binding("Checked", bindingSource1, "AddRaceTime", true, DataSourceUpdateMode.OnPropertyChanged));
+ CheckBox7.ForeColor = Color.Black;
+ CheckBox7.Location = new Point(271, 360);
+ CheckBox7.Margin = new Padding(6, 8, 6, 8);
+ CheckBox7.Name = "CheckBox7";
+ CheckBox7.Size = new Size(175, 38);
+ CheckBox7.TabIndex = 34;
+ CheckBox7.Text = "Tempo gara";
+ //
+ // Label4
+ //
+ Label4.AutoSize = true;
+ Label4.ForeColor = Color.Black;
+ Label4.Location = new Point(17, 55);
+ Label4.Margin = new Padding(6, 0, 6, 0);
+ Label4.Name = "Label4";
+ Label4.Size = new Size(119, 30);
+ Label4.TabIndex = 9;
+ Label4.Text = "Orizzontale";
+ //
+ // TextBox4
+ //
+ TextBox4.DataBindings.Add(new Binding("Text", bindingSource1, "HorizontalText", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox4.Location = new Point(144, 55);
+ TextBox4.Margin = new Padding(6, 8, 6, 8);
+ TextBox4.Name = "TextBox4";
+ TextBox4.Size = new Size(813, 35);
+ TextBox4.TabIndex = 8;
+ //
+ // Label9
+ //
+ Label9.AutoSize = true;
+ Label9.ForeColor = Color.Black;
+ Label9.Location = new Point(17, 249);
+ Label9.Margin = new Padding(6, 0, 6, 0);
+ Label9.Name = "Label9";
+ Label9.Size = new Size(210, 30);
+ Label9.TabIndex = 19;
+ Label9.Text = "Trasparenza (0-100%)";
+ //
+ // Label13
+ //
+ Label13.AutoSize = true;
+ Label13.ForeColor = Color.Black;
+ Label13.Location = new Point(31, 305);
+ Label13.Margin = new Padding(6, 0, 6, 0);
+ Label13.Name = "Label13";
+ Label13.Size = new Size(100, 30);
+ Label13.TabIndex = 29;
+ Label13.Text = "Posizione";
+ //
+ // ComboBox1
+ //
+ ComboBox1.DataBindings.Add(new Binding("Text", bindingSource1, "VerticalPosition", true, DataSourceUpdateMode.OnPropertyChanged));
+ ComboBox1.Location = new Point(144, 305);
+ ComboBox1.Margin = new Padding(6, 8, 6, 8);
+ ComboBox1.Name = "ComboBox1";
+ ComboBox1.Size = new Size(203, 38);
+ ComboBox1.TabIndex = 28;
+ ComboBox1.Text = "ComboBox1";
+ //
+ // ComboBox2
+ //
+ ComboBox2.DataBindings.Add(new Binding("Text", bindingSource1, "HorizontalAlignment", true, DataSourceUpdateMode.OnPropertyChanged));
+ ComboBox2.Location = new Point(751, 305);
+ ComboBox2.Margin = new Padding(6, 8, 6, 8);
+ ComboBox2.Name = "ComboBox2";
+ ComboBox2.Size = new Size(203, 38);
+ ComboBox2.TabIndex = 31;
+ ComboBox2.Text = "ComboBox2";
+ //
+ // Label14
+ //
+ Label14.AutoSize = true;
+ Label14.ForeColor = Color.Black;
+ Label14.Location = new Point(607, 305);
+ Label14.Margin = new Padding(6, 0, 6, 0);
+ Label14.Name = "Label14";
+ Label14.Size = new Size(136, 30);
+ Label14.TabIndex = 30;
+ Label14.Text = "Allineamento";
+ //
+ // TextBox12
+ //
+ TextBox12.DataBindings.Add(new Binding("Text", bindingSource1, "TextMargin", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox12.Location = new Point(751, 249);
+ TextBox12.Margin = new Padding(6, 8, 6, 8);
+ TextBox12.Name = "TextBox12";
+ TextBox12.Size = new Size(203, 35);
+ TextBox12.TabIndex = 33;
+ TextBox12.Text = "TextBox12";
+ //
+ // Label15
+ //
+ Label15.AutoSize = true;
+ Label15.ForeColor = Color.Black;
+ Label15.Location = new Point(593, 249);
+ Label15.Margin = new Padding(6, 0, 6, 0);
+ Label15.Name = "Label15";
+ Label15.Size = new Size(151, 30);
+ Label15.TabIndex = 32;
+ Label15.Text = "Margine (pixel)";
+ //
+ // TabPage2
+ //
+ TabPage2.Controls.Add(GroupBox2);
+ TabPage2.Location = new Point(4, 39);
+ TabPage2.Margin = new Padding(6, 8, 6, 8);
+ TabPage2.Name = "TabPage2";
+ TabPage2.Padding = new Padding(6, 8, 6, 8);
+ TabPage2.Size = new Size(1034, 827);
+ TabPage2.TabIndex = 5;
+ TabPage2.Text = "Foto";
+ TabPage2.UseVisualStyleBackColor = true;
+ //
+ // GroupBox2
+ //
+ GroupBox2.Controls.Add(Label45);
+ GroupBox2.Controls.Add(TextBox32);
+ GroupBox2.Controls.Add(TextBox26);
+ GroupBox2.Controls.Add(Label37);
+ GroupBox2.Controls.Add(Label38);
+ GroupBox2.Controls.Add(TextBox27);
+ GroupBox2.Controls.Add(Label39);
+ GroupBox2.Controls.Add(TextBox28);
+ GroupBox2.Controls.Add(CheckBox15);
+ GroupBox2.ForeColor = Color.FromArgb(0, 0, 192);
+ GroupBox2.Location = new Point(6, 13);
+ GroupBox2.Margin = new Padding(6, 8, 6, 8);
+ GroupBox2.Name = "GroupBox2";
+ GroupBox2.Padding = new Padding(6, 8, 6, 8);
+ GroupBox2.Size = new Size(607, 360);
+ GroupBox2.TabIndex = 36;
+ GroupBox2.TabStop = false;
+ GroupBox2.Text = "Foto grande";
+ //
+ // Label45
+ //
+ Label45.AutoSize = true;
+ Label45.Location = new Point(22, 198);
+ Label45.Margin = new Padding(6, 0, 6, 0);
+ Label45.Name = "Label45";
+ Label45.Size = new Size(80, 30);
+ Label45.TabIndex = 22;
+ Label45.Text = "Qualità";
+ //
+ // TextBox32
+ //
+ TextBox32.DataBindings.Add(new Binding("Text", bindingSource1, "JpegQuality", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox32.Location = new Point(144, 185);
+ TextBox32.Margin = new Padding(6, 8, 6, 8);
+ TextBox32.Name = "TextBox32";
+ TextBox32.Size = new Size(141, 35);
+ TextBox32.TabIndex = 21;
+ TextBox32.Text = "100";
+ //
+ // TextBox26
+ //
+ TextBox26.DataBindings.Add(new Binding("Text", bindingSource1, "BigPhotoSuffix", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox26.Location = new Point(449, 111);
+ TextBox26.Margin = new Padding(6, 8, 6, 8);
+ TextBox26.Name = "TextBox26";
+ TextBox26.Size = new Size(107, 35);
+ TextBox26.TabIndex = 20;
+ //
+ // Label37
+ //
+ Label37.ForeColor = Color.Black;
+ Label37.Location = new Point(336, 111);
+ Label37.Margin = new Padding(6, 0, 6, 0);
+ Label37.Name = "Label37";
+ Label37.Size = new Size(96, 38);
+ Label37.TabIndex = 19;
+ Label37.Text = "Suffisso";
+ Label37.TextAlign = ContentAlignment.MiddleRight;
+ //
+ // Label38
+ //
+ Label38.AutoSize = true;
+ Label38.ForeColor = Color.Black;
+ Label38.Location = new Point(48, 55);
+ Label38.Margin = new Padding(6, 0, 6, 0);
+ Label38.Name = "Label38";
+ Label38.Size = new Size(81, 30);
+ Label38.TabIndex = 16;
+ Label38.Text = "Altezza";
+ //
+ // TextBox27
+ //
+ TextBox27.DataBindings.Add(new Binding("Text", bindingSource1, "PhotoBigWidth", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox27.Location = new Point(144, 55);
+ TextBox27.Margin = new Padding(6, 8, 6, 8);
+ TextBox27.Name = "TextBox27";
+ TextBox27.Size = new Size(141, 35);
+ TextBox27.TabIndex = 14;
+ TextBox27.Text = "TextBox27";
+ //
+ // Label39
+ //
+ Label39.AutoSize = true;
+ Label39.ForeColor = Color.Black;
+ Label39.Location = new Point(17, 111);
+ Label39.Margin = new Padding(6, 0, 6, 0);
+ Label39.Name = "Label39";
+ Label39.Size = new Size(107, 30);
+ Label39.TabIndex = 17;
+ Label39.Text = "Larghezza";
+ //
+ // TextBox28
+ //
+ TextBox28.DataBindings.Add(new Binding("Text", bindingSource1, "PhotoBigHeight", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox28.Location = new Point(144, 111);
+ TextBox28.Margin = new Padding(6, 8, 6, 8);
+ TextBox28.Name = "TextBox28";
+ TextBox28.Size = new Size(141, 35);
+ TextBox28.TabIndex = 15;
+ TextBox28.Text = "TextBox28";
+ //
+ // CheckBox15
+ //
+ CheckBox15.Checked = true;
+ CheckBox15.CheckState = CheckState.Checked;
+ CheckBox15.DataBindings.Add(new Binding("Checked", bindingSource1, "KeepOriginalDimensions", true, DataSourceUpdateMode.OnPropertyChanged));
+ CheckBox15.ForeColor = Color.Black;
+ CheckBox15.Location = new Point(336, 38);
+ CheckBox15.Margin = new Padding(6, 8, 6, 8);
+ CheckBox15.Name = "CheckBox15";
+ CheckBox15.Size = new Size(240, 73);
+ CheckBox15.TabIndex = 18;
+ CheckBox15.Text = "Mantieni dimensioni originali";
+ //
+ // TabPage1
+ //
+ TabPage1.Controls.Add(Panel1);
+ TabPage1.Controls.Add(GroupBox1);
+ TabPage1.Location = new Point(4, 39);
+ TabPage1.Margin = new Padding(6, 8, 6, 8);
+ TabPage1.Name = "TabPage1";
+ TabPage1.Padding = new Padding(6, 8, 6, 8);
+ TabPage1.Size = new Size(1034, 827);
+ TabPage1.TabIndex = 0;
+ TabPage1.Text = "Miniature";
+ TabPage1.UseVisualStyleBackColor = true;
+ //
+ // Panel1
+ //
+ Panel1.Controls.Add(_CheckBox18);
+ Panel1.Controls.Add(_CheckBox4);
+ Panel1.Controls.Add(_CheckBox12);
+ Panel1.Location = new Point(103, 545);
+ Panel1.Margin = new Padding(6, 8, 6, 8);
+ Panel1.Name = "Panel1";
+ Panel1.Size = new Size(607, 168);
+ Panel1.TabIndex = 26;
+ Panel1.Visible = false;
+ //
+ // _CheckBox18
+ //
+ _CheckBox18.AutoSize = true;
+ _CheckBox18.Location = new Point(281, 8);
+ _CheckBox18.Margin = new Padding(6, 8, 6, 8);
+ _CheckBox18.Name = "_CheckBox18";
+ _CheckBox18.Size = new Size(159, 34);
+ _CheckBox18.TabIndex = 36;
+ _CheckBox18.Text = "Numero foto";
+ _CheckBox18.UseVisualStyleBackColor = true;
+ //
+ // _CheckBox4
+ //
+ _CheckBox4.ForeColor = Color.Black;
+ _CheckBox4.Location = new Point(19, 8);
+ _CheckBox4.Margin = new Padding(6, 8, 6, 8);
+ _CheckBox4.Name = "_CheckBox4";
+ _CheckBox4.Size = new Size(209, 39);
+ _CheckBox4.TabIndex = 34;
+ _CheckBox4.Text = "Aggiungi scritta";
+ //
+ // _CheckBox12
+ //
+ _CheckBox12.ForeColor = Color.Black;
+ _CheckBox12.Location = new Point(19, 43);
+ _CheckBox12.Margin = new Padding(6, 8, 6, 8);
+ _CheckBox12.Name = "_CheckBox12";
+ _CheckBox12.Size = new Size(209, 48);
+ _CheckBox12.TabIndex = 35;
+ _CheckBox12.Text = "Aggiungi orario";
+ //
+ // GroupBox1
+ //
+ GroupBox1.Controls.Add(label16);
+ GroupBox1.Controls.Add(Label46);
+ GroupBox1.Controls.Add(TextBox33);
+ GroupBox1.Controls.Add(Label5);
+ GroupBox1.Controls.Add(TextBox5);
+ GroupBox1.Controls.Add(Label6);
+ GroupBox1.Controls.Add(TextBox6);
+ GroupBox1.Controls.Add(Label3);
+ GroupBox1.Controls.Add(TextBox3);
+ GroupBox1.Controls.Add(CheckBox1);
+ GroupBox1.Controls.Add(comboThumbnailOption);
+ GroupBox1.ForeColor = Color.FromArgb(0, 0, 192);
+ GroupBox1.Location = new Point(12, 12);
+ GroupBox1.Margin = new Padding(6, 8, 6, 8);
+ GroupBox1.Name = "GroupBox1";
+ GroupBox1.Padding = new Padding(6, 8, 6, 8);
+ GroupBox1.Size = new Size(701, 485);
+ GroupBox1.TabIndex = 25;
+ GroupBox1.TabStop = false;
+ GroupBox1.Text = "Miniature";
+ //
+ // Label46
+ //
+ Label46.AutoSize = true;
+ Label46.Location = new Point(396, 99);
+ Label46.Margin = new Padding(6, 0, 6, 0);
+ Label46.Name = "Label46";
+ Label46.Size = new Size(80, 30);
+ Label46.TabIndex = 21;
+ Label46.Text = "Qualità";
+ //
+ // TextBox33
+ //
+ TextBox33.DataBindings.Add(new Binding("Text", bindingSource1, "JpegQualityThumbnail", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox33.Location = new Point(487, 93);
+ TextBox33.Margin = new Padding(6, 8, 6, 8);
+ TextBox33.Name = "TextBox33";
+ TextBox33.Size = new Size(196, 35);
+ TextBox33.TabIndex = 20;
+ //
+ // Label5
+ //
+ Label5.AutoSize = true;
+ Label5.ForeColor = Color.Black;
+ Label5.Location = new Point(48, 202);
+ Label5.Margin = new Padding(6, 0, 6, 0);
+ Label5.Name = "Label5";
+ Label5.Size = new Size(81, 30);
+ Label5.TabIndex = 12;
+ Label5.Text = "Altezza";
+ //
+ // TextBox5
+ //
+ TextBox5.DataBindings.Add(new Binding("Text", bindingSource1, "ThumbnailWidth", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox5.Location = new Point(144, 147);
+ TextBox5.Margin = new Padding(6, 8, 6, 8);
+ TextBox5.Name = "TextBox5";
+ TextBox5.Size = new Size(172, 35);
+ TextBox5.TabIndex = 10;
+ TextBox5.Text = "TextBox5";
+ //
+ // Label6
+ //
+ Label6.AutoSize = true;
+ Label6.ForeColor = Color.Black;
+ Label6.Location = new Point(17, 147);
+ Label6.Margin = new Padding(6, 0, 6, 0);
+ Label6.Name = "Label6";
+ Label6.Size = new Size(107, 30);
+ Label6.TabIndex = 13;
+ Label6.Text = "Larghezza";
+ //
+ // TextBox6
+ //
+ TextBox6.DataBindings.Add(new Binding("Text", bindingSource1, "ThumbnailHeight", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox6.Location = new Point(144, 202);
+ TextBox6.Margin = new Padding(6, 8, 6, 8);
+ TextBox6.Name = "TextBox6";
+ TextBox6.Size = new Size(172, 35);
+ TextBox6.TabIndex = 11;
+ TextBox6.Text = "TextBox6";
+ //
+ // Label3
+ //
+ Label3.AutoSize = true;
+ Label3.ForeColor = Color.Black;
+ Label3.Location = new Point(48, 93);
+ Label3.Margin = new Padding(6, 0, 6, 0);
+ Label3.Name = "Label3";
+ Label3.Size = new Size(85, 30);
+ Label3.TabIndex = 7;
+ Label3.Text = "Suffisso";
+ //
+ // TextBox3
+ //
+ TextBox3.DataBindings.Add(new Binding("Text", bindingSource1, "ThumbnailPrefix", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox3.Location = new Point(144, 93);
+ TextBox3.Margin = new Padding(6, 8, 6, 8);
+ TextBox3.Name = "TextBox3";
+ TextBox3.Size = new Size(172, 35);
+ TextBox3.TabIndex = 6;
+ TextBox3.Text = "TextBox3";
+ //
+ // CheckBox1
+ //
+ CheckBox1.DataBindings.Add(new Binding("Checked", bindingSource1, "CreateThumbnails", true, DataSourceUpdateMode.OnPropertyChanged));
+ CheckBox1.ForeColor = Color.Black;
+ CheckBox1.Location = new Point(144, 38);
+ CheckBox1.Margin = new Padding(6, 8, 6, 8);
+ CheckBox1.Name = "CheckBox1";
+ CheckBox1.Size = new Size(209, 55);
+ CheckBox1.TabIndex = 5;
+ CheckBox1.Text = "Crea miniature";
+ //
+ // comboThumbnailOption
+ //
+ comboThumbnailOption.DropDownStyle = ComboBoxStyle.DropDownList;
+ comboThumbnailOption.Location = new Point(204, 262);
+ comboThumbnailOption.Margin = new Padding(6, 8, 6, 8);
+ comboThumbnailOption.Name = "comboThumbnailOption";
+ comboThumbnailOption.Size = new Size(470, 38);
+ comboThumbnailOption.TabIndex = 18;
+ //
+ // TabPage4
+ //
+ TabPage4.Controls.Add(GroupBox6);
+ TabPage4.Location = new Point(4, 39);
+ TabPage4.Margin = new Padding(6, 8, 6, 8);
+ TabPage4.Name = "TabPage4";
+ TabPage4.Padding = new Padding(6, 8, 6, 8);
+ TabPage4.Size = new Size(1034, 827);
+ TabPage4.TabIndex = 3;
+ TabPage4.Text = "Logo";
+ TabPage4.UseVisualStyleBackColor = true;
+ //
+ // GroupBox6
+ //
+ GroupBox6.Controls.Add(chkUseTransparentColor);
+ GroupBox6.Controls.Add(btnSetTransparency);
+ GroupBox6.Controls.Add(_PictureBox1);
+ GroupBox6.Controls.Add(ComboBox5);
+ GroupBox6.Controls.Add(ComboBox4);
+ GroupBox6.Controls.Add(TextBox19);
+ GroupBox6.Controls.Add(Label28);
+ GroupBox6.Controls.Add(CheckBox5);
+ GroupBox6.Controls.Add(TextBox15);
+ GroupBox6.Controls.Add(TextBox14);
+ GroupBox6.Controls.Add(Label25);
+ GroupBox6.Controls.Add(TextBox16);
+ GroupBox6.Controls.Add(Label24);
+ GroupBox6.Controls.Add(Label22);
+ GroupBox6.Controls.Add(Label23);
+ GroupBox6.Controls.Add(_Button4);
+ GroupBox6.Controls.Add(TextBox10);
+ GroupBox6.Controls.Add(Label29);
+ GroupBox6.Controls.Add(PictureBox3);
+ GroupBox6.ForeColor = Color.FromArgb(0, 0, 192);
+ GroupBox6.Location = new Point(12, 13);
+ GroupBox6.Margin = new Padding(6, 8, 6, 8);
+ GroupBox6.Name = "GroupBox6";
+ GroupBox6.Padding = new Padding(6, 8, 6, 8);
+ GroupBox6.Size = new Size(991, 593);
+ GroupBox6.TabIndex = 42;
+ GroupBox6.TabStop = false;
+ GroupBox6.Text = "Logo";
+ //
+ // chkUseTransparentColor
+ //
+ chkUseTransparentColor.AutoSize = true;
+ chkUseTransparentColor.Location = new Point(39, 461);
+ chkUseTransparentColor.Name = "chkUseTransparentColor";
+ chkUseTransparentColor.Size = new Size(210, 34);
+ chkUseTransparentColor.TabIndex = 46;
+ chkUseTransparentColor.Text = "Colore trasparente";
+ chkUseTransparentColor.UseVisualStyleBackColor = true;
+ //
+ // btnSetTransparency
+ //
+ btnSetTransparency.Location = new Point(288, 455);
+ btnSetTransparency.Name = "btnSetTransparency";
+ btnSetTransparency.Size = new Size(131, 40);
+ btnSetTransparency.TabIndex = 45;
+ btnSetTransparency.Text = "Imposta";
+ btnSetTransparency.UseVisualStyleBackColor = true;
+ //
+ // _PictureBox1
+ //
+ _PictureBox1.Cursor = Cursors.Cross;
+ _PictureBox1.Location = new Point(511, 129);
+ _PictureBox1.Margin = new Padding(6, 8, 6, 8);
+ _PictureBox1.Name = "_PictureBox1";
+ _PictureBox1.Size = new Size(449, 369);
+ _PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
+ _PictureBox1.TabIndex = 43;
+ _PictureBox1.TabStop = false;
+ //
+ // ComboBox5
+ //
+ ComboBox5.DataBindings.Add(new Binding("Text", bindingSource1, "LogoVerticalPosition", true, DataSourceUpdateMode.OnPropertyChanged));
+ ComboBox5.Location = new Point(288, 387);
+ ComboBox5.Margin = new Padding(6, 8, 6, 8);
+ ComboBox5.Name = "ComboBox5";
+ ComboBox5.Size = new Size(189, 38);
+ ComboBox5.TabIndex = 42;
+ ComboBox5.Text = "ComboBox5";
+ //
+ // ComboBox4
+ //
+ ComboBox4.DataBindings.Add(new Binding("Text", bindingSource1, "LogoHorizontalPosition", true, DataSourceUpdateMode.OnPropertyChanged));
+ ComboBox4.Location = new Point(288, 333);
+ ComboBox4.Margin = new Padding(6, 8, 6, 8);
+ ComboBox4.Name = "ComboBox4";
+ ComboBox4.Size = new Size(189, 38);
+ ComboBox4.TabIndex = 41;
+ ComboBox4.Text = "ComboBox4";
+ //
+ // TextBox19
+ //
+ TextBox19.DataBindings.Add(new Binding("Text", bindingSource1, "LogoTransparency", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox19.Location = new Point(288, 222);
+ TextBox19.Margin = new Padding(6, 8, 6, 8);
+ TextBox19.Name = "TextBox19";
+ TextBox19.Size = new Size(189, 35);
+ TextBox19.TabIndex = 40;
+ TextBox19.Text = "TextBox19";
+ //
+ // Label28
+ //
+ Label28.ForeColor = Color.Black;
+ Label28.Location = new Point(38, 222);
+ Label28.Margin = new Padding(6, 0, 6, 0);
+ Label28.Name = "Label28";
+ Label28.Size = new Size(240, 38);
+ Label28.TabIndex = 39;
+ Label28.Text = "Trasparenza (0-100%)";
+ Label28.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // CheckBox5
+ //
+ CheckBox5.DataBindings.Add(new Binding("Checked", bindingSource1, "AddLogo", true, DataSourceUpdateMode.OnPropertyChanged));
+ CheckBox5.ForeColor = Color.Black;
+ CheckBox5.Location = new Point(12, 56);
+ CheckBox5.Margin = new Padding(6, 8, 6, 8);
+ CheckBox5.Name = "CheckBox5";
+ CheckBox5.Size = new Size(144, 47);
+ CheckBox5.TabIndex = 38;
+ CheckBox5.Text = "Aggiungi";
+ //
+ // TextBox15
+ //
+ TextBox15.DataBindings.Add(new Binding("Text", bindingSource1, "LogoHeight", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox15.Location = new Point(288, 167);
+ TextBox15.Margin = new Padding(6, 8, 6, 8);
+ TextBox15.Name = "TextBox15";
+ TextBox15.Size = new Size(189, 35);
+ TextBox15.TabIndex = 19;
+ TextBox15.Text = "TextBox15";
+ //
+ // TextBox14
+ //
+ TextBox14.DataBindings.Add(new Binding("Text", bindingSource1, "LogoWidth", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox14.Location = new Point(288, 111);
+ TextBox14.Margin = new Padding(6, 8, 6, 8);
+ TextBox14.Name = "TextBox14";
+ TextBox14.Size = new Size(189, 35);
+ TextBox14.TabIndex = 18;
+ TextBox14.Text = "TextBox14";
+ //
+ // Label25
+ //
+ Label25.AutoSize = true;
+ Label25.ForeColor = Color.Black;
+ Label25.Location = new Point(39, 390);
+ Label25.Margin = new Padding(6, 0, 6, 0);
+ Label25.Name = "Label25";
+ Label25.Size = new Size(183, 30);
+ Label25.TabIndex = 36;
+ Label25.Text = "Posizione verticale";
+ Label25.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // TextBox16
+ //
+ TextBox16.DataBindings.Add(new Binding("Text", bindingSource1, "LogoMargin", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox16.Location = new Point(288, 278);
+ TextBox16.Margin = new Padding(6, 8, 6, 8);
+ TextBox16.Name = "TextBox16";
+ TextBox16.Size = new Size(189, 35);
+ TextBox16.TabIndex = 35;
+ TextBox16.Text = "TextBox16";
+ //
+ // Label24
+ //
+ Label24.AutoSize = true;
+ Label24.ForeColor = Color.Black;
+ Label24.Location = new Point(38, 283);
+ Label24.Margin = new Padding(6, 0, 6, 0);
+ Label24.Name = "Label24";
+ Label24.Size = new Size(176, 30);
+ Label24.TabIndex = 34;
+ Label24.Text = "Margine (pixel/%)";
+ Label24.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // Label22
+ //
+ Label22.AutoSize = true;
+ Label22.ForeColor = Color.Black;
+ Label22.Location = new Point(38, 117);
+ Label22.Margin = new Padding(6, 0, 6, 0);
+ Label22.Name = "Label22";
+ Label22.Size = new Size(81, 30);
+ Label22.TabIndex = 20;
+ Label22.Text = "Altezza";
+ Label22.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // Label23
+ //
+ Label23.AutoSize = true;
+ Label23.ForeColor = Color.Black;
+ Label23.Location = new Point(38, 172);
+ Label23.Margin = new Padding(6, 0, 6, 0);
+ Label23.Name = "Label23";
+ Label23.Size = new Size(107, 30);
+ Label23.TabIndex = 21;
+ Label23.Text = "Larghezza";
+ Label23.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // _Button4
+ //
+ _Button4.Location = new Point(929, 55);
+ _Button4.Margin = new Padding(6, 8, 6, 8);
+ _Button4.Name = "_Button4";
+ _Button4.Size = new Size(48, 47);
+ _Button4.TabIndex = 8;
+ _Button4.Text = "...";
+ //
+ // TextBox10
+ //
+ TextBox10.DataBindings.Add(new Binding("Text", bindingSource1, "LogoFile", true, DataSourceUpdateMode.OnPropertyChanged));
+ TextBox10.Location = new Point(288, 55);
+ TextBox10.Margin = new Padding(6, 8, 6, 8);
+ TextBox10.Name = "TextBox10";
+ TextBox10.Size = new Size(621, 35);
+ TextBox10.TabIndex = 6;
+ TextBox10.Text = "TextBox10";
+ //
+ // Label29
+ //
+ Label29.AutoSize = true;
+ Label29.ForeColor = Color.Black;
+ Label29.Location = new Point(38, 341);
+ Label29.Margin = new Padding(6, 0, 6, 0);
+ Label29.Name = "Label29";
+ Label29.Size = new Size(208, 30);
+ Label29.TabIndex = 36;
+ Label29.Text = "Posizione orizzontale";
+ Label29.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // PictureBox3
+ //
+ PictureBox3.BorderStyle = BorderStyle.FixedSingle;
+ PictureBox3.Location = new Point(432, 442);
+ PictureBox3.Margin = new Padding(6, 8, 6, 8);
+ PictureBox3.Name = "PictureBox3";
+ PictureBox3.Size = new Size(45, 53);
+ PictureBox3.TabIndex = 44;
+ PictureBox3.TabStop = false;
+ PictureBox3.Visible = false;
+ //
+ // versionLabel
+ //
+ versionLabel.DataBindings.Add(new Binding("Text", bindingSource1, "AppVersion", true));
+ versionLabel.Location = new Point(1182, 873);
+ versionLabel.Margin = new Padding(6, 0, 6, 0);
+ versionLabel.Name = "versionLabel";
+ versionLabel.Size = new Size(281, 47);
+ versionLabel.TabIndex = 62;
+ versionLabel.Text = "Versione 2.2 2021";
+ versionLabel.TextAlign = ContentAlignment.MiddleRight;
+ //
+ // _Button7
+ //
+ _Button7.DataBindings.Add(new Binding("Enabled", bindingSource1, "UiDisabled", true, DataSourceUpdateMode.OnPropertyChanged));
+ _Button7.DataBindings.Add(new Binding("Command", bindingSource1, "AsyncCancelOperationCommand", true));
+ _Button7.Font = new Font("Microsoft Sans Serif", 14.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
+ _Button7.Location = new Point(1078, 278);
+ _Button7.Margin = new Padding(6, 8, 6, 8);
+ _Button7.Name = "_Button7";
+ _Button7.Size = new Size(384, 93);
+ _Button7.TabIndex = 61;
+ _Button7.Text = "STOP";
+ //
+ // _Button5
+ //
+ _Button5.DataBindings.Add(new Binding("Enabled", bindingSource1, "UiEnabled", true));
+ _Button5.Font = new Font("Microsoft Sans Serif", 11F, FontStyle.Bold, GraphicsUnit.Point, 0);
+ _Button5.Location = new Point(1078, 95);
+ _Button5.Margin = new Padding(6, 8, 6, 8);
+ _Button5.Name = "_Button5";
+ _Button5.Size = new Size(384, 73);
+ _Button5.TabIndex = 60;
+ _Button5.Text = "Salva impostazioni";
+ //
+ // Label20
+ //
+ Label20.AutoSize = true;
+ Label20.Font = new Font("Microsoft Sans Serif", 9.75F, FontStyle.Bold, GraphicsUnit.Point, 0);
+ Label20.Location = new Point(1078, 678);
+ Label20.Margin = new Padding(6, 0, 6, 0);
+ Label20.Name = "Label20";
+ Label20.Size = new Size(175, 29);
+ Label20.TabIndex = 59;
+ Label20.Text = "foto generate:";
+ //
+ // Label19
+ //
+ Label19.AutoSize = true;
+ Label19.Font = new Font("Microsoft Sans Serif", 9.75F, FontStyle.Bold, GraphicsUnit.Point, 0);
+ Label19.Location = new Point(1078, 635);
+ Label19.Margin = new Padding(6, 0, 6, 0);
+ Label19.Name = "Label19";
+ Label19.Size = new Size(135, 29);
+ Label19.TabIndex = 58;
+ Label19.Text = "foto totali: ";
+ //
+ // Label18
+ //
+ Label18.AutoSize = true;
+ Label18.Font = new Font("Microsoft Sans Serif", 12F, FontStyle.Bold, GraphicsUnit.Point, 0);
+ Label18.Location = new Point(1286, 678);
+ Label18.Margin = new Padding(6, 0, 6, 0);
+ Label18.Name = "Label18";
+ Label18.Size = new Size(31, 32);
+ Label18.TabIndex = 57;
+ Label18.Text = "0";
+ //
+ // lblFotoTotaliNum
+ //
+ lblFotoTotaliNum.AutoSize = true;
+ lblFotoTotaliNum.Font = new Font("Microsoft Sans Serif", 12F, FontStyle.Bold, GraphicsUnit.Point, 0);
+ lblFotoTotaliNum.Location = new Point(1286, 635);
+ lblFotoTotaliNum.Margin = new Padding(6, 0, 6, 0);
+ lblFotoTotaliNum.Name = "lblFotoTotaliNum";
+ lblFotoTotaliNum.Size = new Size(31, 32);
+ lblFotoTotaliNum.TabIndex = 56;
+ lblFotoTotaliNum.Text = "0";
+ //
+ // Label10
+ //
+ Label10.Font = new Font("Microsoft Sans Serif", 14.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
+ Label10.Location = new Point(1078, 377);
+ Label10.Margin = new Padding(6, 0, 6, 0);
+ Label10.Name = "Label10";
+ Label10.Size = new Size(384, 167);
+ Label10.TabIndex = 55;
+ Label10.Text = "file";
+ //
+ // _Button6
+ //
+ _Button6.DataBindings.Add(new Binding("Enabled", bindingSource1, "UiEnabled", true));
+ _Button6.Font = new Font("Microsoft Sans Serif", 11F, FontStyle.Bold, GraphicsUnit.Point, 0);
+ _Button6.Location = new Point(1078, 22);
+ _Button6.Margin = new Padding(6, 8, 6, 8);
+ _Button6.Name = "_Button6";
+ _Button6.Size = new Size(384, 73);
+ _Button6.TabIndex = 54;
+ _Button6.Text = "Carica impostazioni";
+ //
+ // _btnCreaCatalogoAsync
+ //
+ _btnCreaCatalogoAsync.DataBindings.Add(new Binding("Enabled", bindingSource1, "UiEnabled", true));
+ _btnCreaCatalogoAsync.Font = new Font("Microsoft Sans Serif", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
+ _btnCreaCatalogoAsync.Location = new Point(1078, 175);
+ _btnCreaCatalogoAsync.Margin = new Padding(6, 8, 6, 8);
+ _btnCreaCatalogoAsync.Name = "_btnCreaCatalogoAsync";
+ _btnCreaCatalogoAsync.Size = new Size(384, 87);
+ _btnCreaCatalogoAsync.TabIndex = 68;
+ _btnCreaCatalogoAsync.Text = "CREA";
+ _btnCreaCatalogoAsync.UseVisualStyleBackColor = true;
+ //
+ // dataModelBindingSource1
+ //
+ dataModelBindingSource1.DataSource = typeof(ImageCatalog_2.DataModel);
+ //
+ // label16
+ //
+ label16.AutoSize = true;
+ label16.Location = new Point(39, 262);
+ label16.Name = "label16";
+ label16.Size = new Size(156, 30);
+ label16.TabIndex = 22;
+ label16.Text = "Testo Miniature";
+ //
+ // MainForm
+ //
+ AutoScaleDimensions = new SizeF(12F, 30F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(1478, 925);
+ Controls.Add(_btnCreaCatalogoAsync);
+ Controls.Add(ProgressBar1);
+ Controls.Add(CheckBox22);
+ Controls.Add(Label43);
+ Controls.Add(TabControl1);
+ Controls.Add(versionLabel);
+ Controls.Add(_Button7);
+ Controls.Add(_Button5);
+ Controls.Add(Label20);
+ Controls.Add(Label19);
+ Controls.Add(Label18);
+ Controls.Add(lblFotoTotaliNum);
+ Controls.Add(Label10);
+ Controls.Add(_Button6);
+ Margin = new Padding(6, 8, 6, 8);
+ MaximizeBox = false;
+ Name = "MainForm";
+ Text = "Image Catalog";
+ Load += Form1_Load;
+ ((System.ComponentModel.ISupportInitialize)bindingSource1).EndInit();
+ ((System.ComponentModel.ISupportInitialize)dataModelBindingSource).EndInit();
+ TabControl1.ResumeLayout(false);
+ TabPage5.ResumeLayout(false);
+ groupBox12.ResumeLayout(false);
+ groupBox12.PerformLayout();
+ GroupBox11.ResumeLayout(false);
+ GroupBox11.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)numericUpDown2).EndInit();
+ ((System.ComponentModel.ISupportInitialize)numericUpDown1).EndInit();
+ Panel3.ResumeLayout(false);
+ Panel3.PerformLayout();
+ GroupBox3.ResumeLayout(false);
+ GroupBox3.PerformLayout();
+ GroupBox8.ResumeLayout(false);
+ GroupBox8.PerformLayout();
+ GroupBox7.ResumeLayout(false);
+ GroupBox7.PerformLayout();
+ TabPage3.ResumeLayout(false);
+ GroupBox10.ResumeLayout(false);
+ GroupBox10.PerformLayout();
+ GroupBox9.ResumeLayout(false);
+ GroupBox9.PerformLayout();
+ GroupBox5.ResumeLayout(false);
+ GroupBox5.PerformLayout();
+ GroupBox4.ResumeLayout(false);
+ GroupBox4.PerformLayout();
+ TabPage2.ResumeLayout(false);
+ GroupBox2.ResumeLayout(false);
+ GroupBox2.PerformLayout();
+ TabPage1.ResumeLayout(false);
+ Panel1.ResumeLayout(false);
+ Panel1.PerformLayout();
+ GroupBox1.ResumeLayout(false);
+ GroupBox1.PerformLayout();
+ TabPage4.ResumeLayout(false);
+ GroupBox6.ResumeLayout(false);
+ GroupBox6.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)_PictureBox1).EndInit();
+ ((System.ComponentModel.ISupportInitialize)PictureBox3).EndInit();
+ ((System.ComponentModel.ISupportInitialize)dataModelBindingSource1).EndInit();
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ internal ProgressBar ProgressBar1;
+ internal CheckBox CheckBox22;
+ internal Label Label43;
+ internal TabControl TabControl1;
+ internal TabPage TabPage5;
+ internal GroupBox GroupBox3;
+ internal CheckBox chkAggiornaSottodirectory;
+ private Button _Button3;
+
+ internal Button Button3
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _Button3;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _Button3 = value;
+ }
+ }
+
+ private Button _Button2;
+
+ internal Button Button2
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _Button2;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _Button2 = value;
+ }
+ }
+
+ internal Label Label1;
+ internal Label Label2;
+ internal TextBox txtSorgente;
+ internal TextBox txtDestinazione;
+ internal GroupBox GroupBox8;
+ internal RadioButton rdbNumFiles;
+ internal RadioButton rdbNumProgressiva;
+ internal TextBox txtCifreContatore;
+ internal Label Label34;
+ internal TextBox txtSuffissoCartelle;
+ internal Label Label33;
+ internal Label Label31;
+ internal CheckBox chkCreaSottocartelle;
+ internal TextBox txtFilePerCartella;
+ internal Label Label32;
+ internal GroupBox GroupBox7;
+ internal CheckBox chkRotazioneAutomatica;
+ internal CheckBox chkForzaJpg;
+ internal TabPage TabPage3;
+ internal GroupBox GroupBox10;
+ internal Label Label42;
+ internal Label Label41;
+ internal TextBox TextBox31;
+ internal TextBox TextBox30;
+ internal Label versionLabel;
+ internal GroupBox GroupBox9;
+ internal CheckBox CheckBox17;
+ internal CheckBox CheckBox16;
+ internal GroupBox GroupBox5;
+ internal TextBox TextBox34;
+ private Button _Button8;
+
+ internal Button Button8
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _Button8;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _Button8 = value;
+ }
+ }
+
+ internal Label Label36;
+ internal TextBox TextBox25;
+ internal Label Label35;
+ internal ComboBox ComboBox3;
+ internal TextBox TextBox11;
+ internal Label Label12;
+ internal Label Label11;
+ internal CheckBox CheckBox3;
+ internal GroupBox GroupBox4;
+ internal Label Label40;
+ internal TextBox TextBox29;
+ internal TextBox TextBox18;
+ internal Label Label26;
+ internal DateTimePicker DateTimePicker1;
+ internal CheckBox CheckBox8;
+ internal TextBox TextBox9;
+ internal CheckBox CheckBox7;
+ internal Label Label4;
+ internal TextBox TextBox4;
+ internal Label Label9;
+ internal Label Label13;
+ internal ComboBox ComboBox1;
+ internal ComboBox ComboBox2;
+ internal Label Label14;
+ internal TextBox TextBox12;
+ internal Label Label15;
+ internal TabPage TabPage2;
+ internal GroupBox GroupBox2;
+ internal Label Label45;
+ internal TextBox TextBox32;
+ internal TextBox TextBox26;
+ internal Label Label37;
+ internal Label Label38;
+ internal TextBox TextBox27;
+ internal Label Label39;
+ internal TextBox TextBox28;
+ internal CheckBox CheckBox15;
+ internal TabPage TabPage1;
+ internal Panel Panel1;
+ private CheckBox _CheckBox18;
+
+ internal CheckBox CheckBox18
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _CheckBox18;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _CheckBox18 = value;
+ }
+ }
+
+ private CheckBox _CheckBox4;
+
+ internal CheckBox CheckBox4
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _CheckBox4;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _CheckBox4 = value;
+ }
+ }
+
+ private CheckBox _CheckBox12;
+
+ internal CheckBox CheckBox12
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _CheckBox12;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _CheckBox12 = value;
+ }
+ }
+
+ internal GroupBox GroupBox1;
+ internal Label Label46;
+ internal TextBox TextBox33;
+ private ComboBox comboThumbnailOption;
+ internal Label Label5;
+ internal TextBox TextBox5;
+ internal Label Label6;
+ internal TextBox TextBox6;
+ internal Label Label3;
+ internal TextBox TextBox3;
+ internal CheckBox CheckBox1;
+ internal TabPage TabPage4;
+ internal GroupBox GroupBox6;
+ private PictureBox _PictureBox1;
+
+ internal PictureBox PictureBox1
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _PictureBox1;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _PictureBox1 = value;
+ }
+ }
+
+ internal ComboBox ComboBox5;
+ internal ComboBox ComboBox4;
+ internal TextBox TextBox19;
+ internal Label Label28;
+ internal CheckBox CheckBox5;
+ internal TextBox TextBox15;
+ internal TextBox TextBox14;
+ internal Label Label25;
+ internal TextBox TextBox16;
+ internal Label Label24;
+ internal Label Label22;
+ internal Label Label23;
+ private Button _Button4;
+
+ internal Button Button4
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _Button4;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _Button4 = value;
+ }
+ }
+
+ internal TextBox TextBox10;
+ internal Label Label29;
+ private Label _Label27;
+
+ internal Label Label27
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _Label27;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _Label27 = value;
+ }
+ }
+
+ private Button _Button7;
+
+ private Button _Button5;
+
+ internal Button Button5
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _Button5;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _Button5 = value;
+ }
+ }
+
+ internal Label Label20;
+ internal Label Label19;
+ internal Label Label18;
+ internal Label lblFotoTotaliNum;
+ internal Label Label10;
+
+ //internal Button btnCreaCatalogo
+ //{
+ // [MethodImpl(MethodImplOptions.Synchronized)]
+ // get
+ // {
+ // return _btnCreaCatalogo;
+ // }
+
+ // [MethodImpl(MethodImplOptions.Synchronized)]
+ // set
+ // {
+ // if (_btnCreaCatalogo != null)
+ // {
+ // _btnCreaCatalogo.Click -= btnCreaCatalogo_Click;
+ // }
+
+ // _btnCreaCatalogo = value;
+ // if (_btnCreaCatalogo != null)
+ // {
+ // _btnCreaCatalogo.Click += btnCreaCatalogo_Click;
+ // }
+ // }
+ //}
+
+ private Button _Button6;
+
+ internal Button Button6
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _Button6;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _Button6 = value;
+ }
+ }
+
+ internal GroupBox GroupBox11;
+ internal Label Label7;
+ internal Label Label8;
+ internal Panel Panel3;
+ internal RadioButton rdbNuovoMetodo;
+ internal RadioButton rdbVecchioMetodo;
+ internal CheckBox chkSovrascriviFile;
+ private Button _btnCreaCatalogoAsync;
+ private System.Windows.Forms.Timer timer1;
+ private BindingSource dataModelBindingSource;
+ private BindingSource dataModelBindingSource1;
+ private BindingSource bindingSource1;
+ private NumericUpDown numericUpDown1;
+ private NumericUpDown numericUpDown2;
+ private Button btnOpenDestFolder;
+ private Button btnOpenSourceFolder;
+ private GroupBox groupBox12;
+ private RadioButton rdbLibrary2;
+ private RadioButton rdbLibrary1;
+ internal PictureBox PictureBox3;
+ private ColorDialog colorDialog1;
+ private Button btnSetTransparency;
+ private CheckBox chkUseTransparentColor;
+ private Label label16;
+
+ internal Button btnCreaCatalogoAsync
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ get
+ {
+ return _btnCreaCatalogoAsync;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ set
+ {
+ _btnCreaCatalogoAsync = value;
+ }
+ }
+ }
+}
+#endif
diff --git a/imagecatalog/MainForm.cs b/imagecatalog/MainForm.cs
new file mode 100644
index 0000000..92604d9
--- /dev/null
+++ b/imagecatalog/MainForm.cs
@@ -0,0 +1,842 @@
+#if WINDOWS
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Text;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using ImageCatalog_2;
+using ImageCatalog_2.Commands;
+using ImageCatalog_2.Services;
+using MaddoShared;
+using Microsoft.Extensions.Logging;
+
+namespace ImageCatalog;
+
+public partial class MainForm
+{
+ private readonly DataModel Model;
+
+ private readonly ILogger _logger;
+
+ private readonly ParametriSetup _parametriSetup;
+ private readonly PicSettings _picSettings;
+ // Prevent re-entrant updates between UI events and model PropertyChanged handling
+ private bool _suppressRadioUpdates = false;
+ private bool _transparentDialogOpen = false;
+
+ public MainForm(DataModel model, ImageCreationService imageCreationStuff, PicSettings picSettings,
+ ParametriSetup parametriSetup, ILogger logger)
+ {
+ Model = model;
+ _parametriSetup = parametriSetup;
+ _picSettings = picSettings;
+ _logger = logger;
+
+ _logger.LogDebug("Start");
+
+ InitializeComponent();
+ // Set this form as the control for thread marshalling in the DataModel
+ Model.SetControl(this);
+
+ // Ensure the designer data bindings have a concrete DataSource immediately so
+ // that UI controls (radio buttons) reflect the ViewModel state and propagate
+ // user changes back to the ViewModel.
+ bindingSource1.DataSource = Model;
+
+ BindControls();
+
+ // The designer originally bound the radio buttons to boolean helpers on the ViewModel.
+ // Those two separate bindings can fight with each other. Clear designer bindings and
+ // wire explicit Click handlers that update the single authoritative property
+ // `Model.ImageLibrary`. Also keep a PropertyChanged listener to reflect external
+ // changes back into the radio buttons.
+ rdbLibrary1.DataBindings.Clear();
+ rdbLibrary2.DataBindings.Clear();
+
+ // Initialize radio state from model
+ rdbLibrary1.Checked = Model.UseSystemGraphics;
+ rdbLibrary2.Checked = Model.UseImageSharp;
+
+ // Use Click handlers (not CheckedChanged) to avoid competing binding updates
+ rdbLibrary1.Click += (_, _) =>
+ {
+ if (_suppressRadioUpdates) return;
+ if (Model.ImageLibrary != "System.Graphics")
+ Model.ImageLibrary = "System.Graphics";
+ };
+ rdbLibrary2.Click += (_, _) =>
+ {
+ if (_suppressRadioUpdates) return;
+ if (Model.ImageLibrary != "ImageSharp")
+ Model.ImageLibrary = "ImageSharp";
+ };
+
+ // Watch for model changes so we can reflect external updates
+ Model.PropertyChanged += Model_PropertyChanged;
+
+ // Thumbnail options moved to ComboBox to avoid conflicting bindings with multiple radio buttons
+
+ // Initialize ComboBox with Italian descriptions
+ comboThumbnailOption.Items.Clear();
+ comboThumbnailOption.Items.AddRange(new object[] {
+ "Nessuna",
+ "Aggiungi scritta",
+ "Nome file",
+ "Aggiungi orario",
+ "Nome+Orario",
+ "Tempo gara"
+ });
+
+ // Bind to model via helper index property ThumbnailOptionIndex
+ comboThumbnailOption.DataBindings.Add(new Binding("SelectedIndex", bindingSource1, "ThumbnailOptionIndex", true, DataSourceUpdateMode.OnPropertyChanged));
+
+ // Save user preferences on form close instead of immediately when dialogs are used
+ this.FormClosing += MainForm_FormClosing;
+
+ // Wire up 'Open folder in Explorer' buttons
+ btnOpenSourceFolder.Click += BtnOpenSourceFolder_Click;
+ btnOpenDestFolder.Click += BtnOpenDestFolder_Click;
+
+ // Show currently selected color in small PictureBox3
+ PictureBox3.BackColor = ColorTranslator.FromHtml(Model.TransparentColor);
+
+ // Version label is data-bound to DataModel.AppVersion; DataModel is populated with the version via DI
+ }
+
+
+
+ private void RdbLibrary_CheckedChanged(object? sender, EventArgs e)
+ {
+ // Keep behavior simple: when a radio button becomes checked, update the ViewModel
+ // so that the designer binding and PicSettings stay in sync.
+ if (sender is RadioButton rb && rb.Checked)
+ {
+ _logger?.LogDebug("Radio library changed: {RadioName}", rb.Name);
+ if (rb == rdbLibrary2)
+ {
+ Model.ImageLibrary = "ImageSharp";
+ }
+ else if (rb == rdbLibrary1)
+ {
+ Model.ImageLibrary = "System.Graphics";
+ }
+ }
+ }
+
+ private void Model_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName is null) return;
+ if (e.PropertyName == nameof(Model.ImageLibrary) || e.PropertyName == nameof(Model.UseImageSharp) || e.PropertyName == nameof(Model.UseSystemGraphics))
+ {
+ _logger?.LogDebug("Model property changed: {Property} => ImageLibrary={ImageLibrary}, PicSettings.Provider={Provider}", e.PropertyName, Model.ImageLibrary, _picSettings.ImageCreatorProvider);
+
+ // Reflect authoritative model value into the radio buttons in a thread-safe, re-entrancy-safe way
+ try
+ {
+ _suppressRadioUpdates = true;
+ rdbLibrary1.Checked = Model.UseSystemGraphics;
+ rdbLibrary2.Checked = Model.UseImageSharp;
+ }
+ finally
+ {
+ _suppressRadioUpdates = false;
+ }
+ }
+
+ // Thumbnail mode changes - reflect back to combo box index
+ if (e.PropertyName == nameof(Model.ThumbnailMode) ||
+ e.PropertyName == nameof(Model.ThumbnailOption) ||
+ e.PropertyName == nameof(Model.ThumbnailOptionIndex))
+ {
+ try
+ {
+ _suppressRadioUpdates = true;
+ comboThumbnailOption.SelectedIndex = Model.ThumbnailOptionIndex;
+ }
+ finally
+ {
+ _suppressRadioUpdates = false;
+ }
+ }
+ }
+
+ protected void BindControls()
+ {
+ // Bind buttons to ViewModel commands using command binding
+ _btnCreaCatalogoAsync.BindCommand(Model.ProcessImagesCommand);
+ // Note: `button1` control does not exist in the designer. Use the primary create button only.
+ _Button2.BindCommand(Model.SelectSourceFolderCommand);
+ _Button3.BindCommand(Model.SelectDestinationFolderCommand);
+ _Button4.BindCommand(Model.SelectLogoFileCommand);
+ _Button5.BindCommand(Model.SaveSettingsCommand);
+ _Button6.BindCommand(Model.LoadSettingsCommand);
+ _Button8.BindCommand(Model.SelectColorCommand);
+ // Bind the transparency chooser button/command
+ btnSetTransparency.BindCommand(Model.SelectTransparentColorCommand);
+
+ // Subscribe to ViewModel events for UI dialogs (these need UI context)
+ Model.SelectSourceFolderRequested += OnSelectSourceFolderRequested;
+ Model.SelectDestinationFolderRequested += OnSelectDestinationFolderRequested;
+ Model.SelectLogoFileRequested += OnSelectLogoFileRequested;
+ Model.SaveSettingsRequested += OnSaveSettingsRequested;
+ Model.LoadSettingsRequested += OnLoadSettingsRequested;
+ Model.SelectColorRequested += OnSelectColorRequested;
+ Model.SelectTransparentColorRequested += OnSelectTransparentColorRequested;
+ // Show message requests (from ViewModel validation)
+ Model.ShowMessageRequested += OnShowMessageRequested;
+ }
+
+ private void OnSelectTransparentColorRequested(object? sender, EventArgs e)
+ {
+ // Ensure UI thread
+ if (InvokeRequired)
+ {
+ Invoke(new Action