Use file-scoped namespaces in forms

This commit is contained in:
Ben Olden-Cooligan 2022-07-02 16:12:34 -07:00
parent 6731df4789
commit d1e86b18e3
18 changed files with 2813 additions and 2831 deletions

View File

@ -1,11 +1,10 @@
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public abstract class DialogHelper
{
public abstract class DialogHelper
{
public abstract bool PromptToSavePdfOrImage(string defaultPath, out string savePath);
public abstract bool PromptToSavePdfOrImage(string defaultPath, out string savePath);
public abstract bool PromptToSavePdf(string defaultPath, out string savePath);
public abstract bool PromptToSavePdf(string defaultPath, out string savePath);
public abstract bool PromptToSaveImage(string defaultPath, out string savePath);
}
}
public abstract bool PromptToSaveImage(string defaultPath, out string savePath);
}

View File

@ -2,44 +2,43 @@
using System.Windows.Forms;
using NAPS2.ImportExport.Email;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class EmailProviderWidget : Button
{
public partial class EmailProviderWidget : Button
public EmailProviderWidget()
{
public EmailProviderWidget()
{
InitializeComponent();
}
public EmailProviderType ProviderType { get; set; }
public Image ProviderIcon
{
get => pboxIcon.Image;
set => pboxIcon.Image = value;
}
public string ProviderName
{
get => Text;
set => Text = value;
}
public Action? ClickAction { get; set; }
private void EmailProviderWidget_MouseEnter(object sender, EventArgs e)
{
BackColor = Color.FromArgb(229, 241, 251);
}
private void EmailProviderWidget_MouseLeave(object sender, EventArgs e)
{
BackColor = DefaultBackColor;
}
private void EmailProviderWidget_Click(object sender, EventArgs e)
{
ClickAction?.Invoke();
}
InitializeComponent();
}
}
public EmailProviderType ProviderType { get; set; }
public Image ProviderIcon
{
get => pboxIcon.Image;
set => pboxIcon.Image = value;
}
public string ProviderName
{
get => Text;
set => Text = value;
}
public Action? ClickAction { get; set; }
private void EmailProviderWidget_MouseEnter(object sender, EventArgs e)
{
BackColor = Color.FromArgb(229, 241, 251);
}
private void EmailProviderWidget_MouseLeave(object sender, EventArgs e)
{
BackColor = DefaultBackColor;
}
private void EmailProviderWidget_Click(object sender, EventArgs e)
{
ClickAction?.Invoke();
}
}

View File

@ -3,60 +3,59 @@ using System.Threading;
using System.Windows.Forms;
using NAPS2.ImportExport.Email.Oauth;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class FAuthorize : FormBase
{
public partial class FAuthorize : FormBase
private readonly ErrorOutput _errorOutput;
private CancellationTokenSource? _cancelTokenSource;
public FAuthorize(ErrorOutput errorOutput)
{
private readonly ErrorOutput _errorOutput;
private CancellationTokenSource? _cancelTokenSource;
public FAuthorize(ErrorOutput errorOutput)
{
_errorOutput = errorOutput;
RestoreFormState = false;
InitializeComponent();
}
public OauthProvider? OauthProvider { get; set; }
private void FAuthorize_Load(object sender, EventArgs e)
{
if (OauthProvider == null) throw new InvalidOperationException("OauthProvider must be specified");
MaximumSize = new Size(Math.Max(lblWaiting.Width + 142, 272), Height);
MinimumSize = new Size(Math.Max(lblWaiting.Width + 142, 272), Height);
_cancelTokenSource = new CancellationTokenSource();
Task.Run(() =>
{
try
{
OauthProvider.AcquireToken(_cancelTokenSource.Token);
Invoke(() =>
{
DialogResult = DialogResult.OK;
Close();
});
}
catch (OperationCanceledException)
{
}
catch (Exception ex)
{
_errorOutput.DisplayError(MiscResources.AuthError, ex);
Log.ErrorException("Error acquiring Oauth token", ex);
Invoke(() =>
{
DialogResult = DialogResult.Cancel;
Close();
});
}
});
}
private void FAuthorize_FormClosed(object sender, FormClosedEventArgs e)
{
_cancelTokenSource?.Cancel();
}
_errorOutput = errorOutput;
RestoreFormState = false;
InitializeComponent();
}
}
public OauthProvider? OauthProvider { get; set; }
private void FAuthorize_Load(object sender, EventArgs e)
{
if (OauthProvider == null) throw new InvalidOperationException("OauthProvider must be specified");
MaximumSize = new Size(Math.Max(lblWaiting.Width + 142, 272), Height);
MinimumSize = new Size(Math.Max(lblWaiting.Width + 142, 272), Height);
_cancelTokenSource = new CancellationTokenSource();
Task.Run(() =>
{
try
{
OauthProvider.AcquireToken(_cancelTokenSource.Token);
Invoke(() =>
{
DialogResult = DialogResult.OK;
Close();
});
}
catch (OperationCanceledException)
{
}
catch (Exception ex)
{
_errorOutput.DisplayError(MiscResources.AuthError, ex);
Log.ErrorException("Error acquiring Oauth token", ex);
Invoke(() =>
{
DialogResult = DialogResult.Cancel;
Close();
});
}
});
}
private void FAuthorize_FormClosed(object sender, FormClosedEventArgs e)
{
_cancelTokenSource?.Cancel();
}
}

View File

@ -7,367 +7,366 @@ using NAPS2.Scan;
using NAPS2.Scan.Batch;
using NAPS2.Scan.Exceptions;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class FBatchScan : FormBase
{
public partial class FBatchScan : FormBase
{
public const string PATCH_CODE_INFO_URL = "http://www.naps2.com/doc-batch-scan.html#patch-t";
public const string PATCH_CODE_INFO_URL = "http://www.naps2.com/doc-batch-scan.html#patch-t";
private readonly IBatchScanPerformer _batchScanPerformer;
private readonly ErrorOutput _errorOutput;
private readonly DialogHelper _dialogHelper;
private readonly IProfileManager _profileManager;
private TransactionConfigScope<CommonConfig> _userTransact;
private Naps2Config _transactionConfig;
private readonly IBatchScanPerformer _batchScanPerformer;
private readonly ErrorOutput _errorOutput;
private readonly DialogHelper _dialogHelper;
private readonly IProfileManager _profileManager;
private TransactionConfigScope<CommonConfig> _userTransact;
private Naps2Config _transactionConfig;
private bool _batchRunning;
private CancellationTokenSource _cts = new CancellationTokenSource();
private bool _batchRunning;
private CancellationTokenSource _cts = new CancellationTokenSource();
public FBatchScan(IBatchScanPerformer batchScanPerformer, ErrorOutput errorOutput, DialogHelper dialogHelper, IProfileManager profileManager)
public FBatchScan(IBatchScanPerformer batchScanPerformer, ErrorOutput errorOutput, DialogHelper dialogHelper, IProfileManager profileManager)
{
_batchScanPerformer = batchScanPerformer;
_errorOutput = errorOutput;
_dialogHelper = dialogHelper;
_profileManager = profileManager;
InitializeComponent();
RestoreFormState = false;
}
public Action<ProcessedImage> ImageCallback { get; set; }
protected override void OnLoad(object sender, EventArgs eventArgs)
{
new LayoutManager(this)
.Bind(groupboxScanConfig, groupboxOutput,
panelSaveSeparator, panelSaveTo, panelSaveType, panelScanDetails, panelScanType,
comboProfile, txtFilePath, lblStatus)
.WidthToForm()
.Bind(btnEditProfile, btnAddProfile, btnStart, btnCancel, btnChooseFolder)
.RightToForm()
.Activate();
btnAddProfile.Enabled = !(Config.Get(c => c.NoUserProfiles) && _profileManager.Profiles.Any(x => x.IsLocked));
ConditionalControls.LockHeight(this);
// TODO: Granular
_userTransact = Config.User.BeginTransaction();
_transactionConfig = Config.WithTransaction(_userTransact);
UpdateUIFromSettings();
}
private void UpdateUIFromSettings()
{
UpdateProfiles();
rdSingleScan.Checked = _transactionConfig.Get(c => c.BatchSettings.ScanType) == BatchScanType.Single;
rdMultipleScansPrompt.Checked = _transactionConfig.Get(c => c.BatchSettings.ScanType) == BatchScanType.MultipleWithPrompt;
rdMultipleScansDelay.Checked = _transactionConfig.Get(c => c.BatchSettings.ScanType) == BatchScanType.MultipleWithDelay;
// TODO: Verify culture (+ vaildation ofc)
txtNumberOfScans.Text = _transactionConfig.Get(c => c.BatchSettings.ScanCount).ToString(CultureInfo.CurrentCulture);
txtTimeBetweenScans.Text = _transactionConfig.Get(c => c.BatchSettings.ScanIntervalSeconds).ToString(CultureInfo.CurrentCulture);
rdLoadIntoNaps2.Checked = _transactionConfig.Get(c => c.BatchSettings.OutputType) == BatchOutputType.Load;
rdSaveToSingleFile.Checked = _transactionConfig.Get(c => c.BatchSettings.OutputType) == BatchOutputType.SingleFile;
rdSaveToMultipleFiles.Checked = _transactionConfig.Get(c => c.BatchSettings.OutputType) == BatchOutputType.MultipleFiles;
rdFilePerScan.Checked = _transactionConfig.Get(c => c.BatchSettings.SaveSeparator) == SaveSeparator.FilePerScan;
rdFilePerPage.Checked = _transactionConfig.Get(c => c.BatchSettings.SaveSeparator) == SaveSeparator.FilePerPage;
rdSeparateByPatchT.Checked = _transactionConfig.Get(c => c.BatchSettings.SaveSeparator) == SaveSeparator.PatchT;
txtFilePath.Text = _transactionConfig.Get(c => c.BatchSettings.SavePath);
}
private bool ValidateSettings()
{
bool ok = true;
_userTransact.Set(c => c.BatchSettings.ProfileDisplayName, comboProfile.Text);
if (comboProfile.SelectedIndex == -1)
{
_batchScanPerformer = batchScanPerformer;
_errorOutput = errorOutput;
_dialogHelper = dialogHelper;
_profileManager = profileManager;
InitializeComponent();
RestoreFormState = false;
ok = false;
comboProfile.Focus();
}
public Action<ProcessedImage> ImageCallback { get; set; }
_userTransact.Set(c => c.BatchSettings.ScanType, rdMultipleScansPrompt.Checked ? BatchScanType.MultipleWithPrompt
: rdMultipleScansDelay.Checked ? BatchScanType.MultipleWithDelay
: BatchScanType.Single);
protected override void OnLoad(object sender, EventArgs eventArgs)
if (rdMultipleScansDelay.Checked)
{
new LayoutManager(this)
.Bind(groupboxScanConfig, groupboxOutput,
panelSaveSeparator, panelSaveTo, panelSaveType, panelScanDetails, panelScanType,
comboProfile, txtFilePath, lblStatus)
.WidthToForm()
.Bind(btnEditProfile, btnAddProfile, btnStart, btnCancel, btnChooseFolder)
.RightToForm()
.Activate();
btnAddProfile.Enabled = !(Config.Get(c => c.NoUserProfiles) && _profileManager.Profiles.Any(x => x.IsLocked));
ConditionalControls.LockHeight(this);
// TODO: Granular
_userTransact = Config.User.BeginTransaction();
_transactionConfig = Config.WithTransaction(_userTransact);
UpdateUIFromSettings();
}
private void UpdateUIFromSettings()
{
UpdateProfiles();
rdSingleScan.Checked = _transactionConfig.Get(c => c.BatchSettings.ScanType) == BatchScanType.Single;
rdMultipleScansPrompt.Checked = _transactionConfig.Get(c => c.BatchSettings.ScanType) == BatchScanType.MultipleWithPrompt;
rdMultipleScansDelay.Checked = _transactionConfig.Get(c => c.BatchSettings.ScanType) == BatchScanType.MultipleWithDelay;
// TODO: Verify culture (+ vaildation ofc)
txtNumberOfScans.Text = _transactionConfig.Get(c => c.BatchSettings.ScanCount).ToString(CultureInfo.CurrentCulture);
txtTimeBetweenScans.Text = _transactionConfig.Get(c => c.BatchSettings.ScanIntervalSeconds).ToString(CultureInfo.CurrentCulture);
rdLoadIntoNaps2.Checked = _transactionConfig.Get(c => c.BatchSettings.OutputType) == BatchOutputType.Load;
rdSaveToSingleFile.Checked = _transactionConfig.Get(c => c.BatchSettings.OutputType) == BatchOutputType.SingleFile;
rdSaveToMultipleFiles.Checked = _transactionConfig.Get(c => c.BatchSettings.OutputType) == BatchOutputType.MultipleFiles;
rdFilePerScan.Checked = _transactionConfig.Get(c => c.BatchSettings.SaveSeparator) == SaveSeparator.FilePerScan;
rdFilePerPage.Checked = _transactionConfig.Get(c => c.BatchSettings.SaveSeparator) == SaveSeparator.FilePerPage;
rdSeparateByPatchT.Checked = _transactionConfig.Get(c => c.BatchSettings.SaveSeparator) == SaveSeparator.PatchT;
txtFilePath.Text = _transactionConfig.Get(c => c.BatchSettings.SavePath);
}
private bool ValidateSettings()
{
bool ok = true;
_userTransact.Set(c => c.BatchSettings.ProfileDisplayName, comboProfile.Text);
if (comboProfile.SelectedIndex == -1)
if (!int.TryParse(txtNumberOfScans.Text, out int scanCount) || scanCount <= 0)
{
ok = false;
comboProfile.Focus();
scanCount = 0;
txtNumberOfScans.Focus();
}
_userTransact.Set(c => c.BatchSettings.ScanCount, scanCount);
_userTransact.Set(c => c.BatchSettings.ScanType, rdMultipleScansPrompt.Checked ? BatchScanType.MultipleWithPrompt
: rdMultipleScansDelay.Checked ? BatchScanType.MultipleWithDelay
: BatchScanType.Single);
if (rdMultipleScansDelay.Checked)
{
if (!int.TryParse(txtNumberOfScans.Text, out int scanCount) || scanCount <= 0)
{
ok = false;
scanCount = 0;
txtNumberOfScans.Focus();
}
_userTransact.Set(c => c.BatchSettings.ScanCount, scanCount);
if (!double.TryParse(txtTimeBetweenScans.Text, out double scanInterval) || scanInterval < 0)
{
ok = false;
scanInterval = 0;
txtTimeBetweenScans.Focus();
}
_userTransact.Set(c => c.BatchSettings.ScanIntervalSeconds, scanInterval);
}
_userTransact.Set(c => c.BatchSettings.OutputType, rdSaveToSingleFile.Checked ? BatchOutputType.SingleFile
: rdSaveToMultipleFiles.Checked ? BatchOutputType.MultipleFiles
: BatchOutputType.Load);
_userTransact.Set(c => c.BatchSettings.SaveSeparator, rdFilePerScan.Checked ? SaveSeparator.FilePerScan
: rdSeparateByPatchT.Checked ? SaveSeparator.PatchT
: SaveSeparator.FilePerPage);
_userTransact.Set(c => c.BatchSettings.SavePath, txtFilePath.Text);
if (_transactionConfig.Get(c => c.BatchSettings.OutputType) != BatchOutputType.Load && string.IsNullOrWhiteSpace(_transactionConfig.Get(c => c.BatchSettings.SavePath)))
if (!double.TryParse(txtTimeBetweenScans.Text, out double scanInterval) || scanInterval < 0)
{
ok = false;
txtFilePath.Focus();
scanInterval = 0;
txtTimeBetweenScans.Focus();
}
return ok;
_userTransact.Set(c => c.BatchSettings.ScanIntervalSeconds, scanInterval);
}
private void UpdateProfiles()
_userTransact.Set(c => c.BatchSettings.OutputType, rdSaveToSingleFile.Checked ? BatchOutputType.SingleFile
: rdSaveToMultipleFiles.Checked ? BatchOutputType.MultipleFiles
: BatchOutputType.Load);
_userTransact.Set(c => c.BatchSettings.SaveSeparator, rdFilePerScan.Checked ? SaveSeparator.FilePerScan
: rdSeparateByPatchT.Checked ? SaveSeparator.PatchT
: SaveSeparator.FilePerPage);
_userTransact.Set(c => c.BatchSettings.SavePath, txtFilePath.Text);
if (_transactionConfig.Get(c => c.BatchSettings.OutputType) != BatchOutputType.Load && string.IsNullOrWhiteSpace(_transactionConfig.Get(c => c.BatchSettings.SavePath)))
{
comboProfile.Items.Clear();
comboProfile.Items.AddRange(_profileManager.Profiles.Cast<object>().ToArray());
if (!string.IsNullOrEmpty(_transactionConfig.Get(c => c.BatchSettings.ProfileDisplayName)) &&
_profileManager.Profiles.Any(x => x.DisplayName == _transactionConfig.Get(c => c.BatchSettings.ProfileDisplayName)))
{
comboProfile.Text = _transactionConfig.Get(c => c.BatchSettings.ProfileDisplayName);
}
else if (_profileManager.DefaultProfile != null)
{
comboProfile.Text = _profileManager.DefaultProfile.DisplayName;
}
else
{
comboProfile.Text = "";
}
ok = false;
txtFilePath.Focus();
}
private void rdSingleScan_CheckedChanged(object sender, EventArgs e)
{
ConditionalControls.UnlockHeight(this);
ConditionalControls.SetVisible(rdFilePerScan, !rdSingleScan.Checked && rdSaveToMultipleFiles.Checked);
ConditionalControls.LockHeight(this);
}
return ok;
}
private void rdMultipleScansDelay_CheckedChanged(object sender, EventArgs e)
private void UpdateProfiles()
{
comboProfile.Items.Clear();
comboProfile.Items.AddRange(_profileManager.Profiles.Cast<object>().ToArray());
if (!string.IsNullOrEmpty(_transactionConfig.Get(c => c.BatchSettings.ProfileDisplayName)) &&
_profileManager.Profiles.Any(x => x.DisplayName == _transactionConfig.Get(c => c.BatchSettings.ProfileDisplayName)))
{
ConditionalControls.UnlockHeight(this);
ConditionalControls.SetVisible(panelScanDetails, rdMultipleScansDelay.Checked);
ConditionalControls.LockHeight(this);
comboProfile.Text = _transactionConfig.Get(c => c.BatchSettings.ProfileDisplayName);
}
private void rdLoadIntoNaps2_CheckedChanged(object sender, EventArgs e)
else if (_profileManager.DefaultProfile != null)
{
ConditionalControls.UnlockHeight(this);
ConditionalControls.SetVisible(panelSaveTo, !rdLoadIntoNaps2.Checked);
ConditionalControls.LockHeight(this);
comboProfile.Text = _profileManager.DefaultProfile.DisplayName;
}
private void rdSaveToMultipleFiles_CheckedChanged(object sender, EventArgs e)
else
{
ConditionalControls.UnlockHeight(this);
ConditionalControls.SetVisible(panelSaveSeparator, rdSaveToMultipleFiles.Checked);
ConditionalControls.SetVisible(rdFilePerScan, !rdSingleScan.Checked && rdSaveToMultipleFiles.Checked);
ConditionalControls.LockHeight(this);
comboProfile.Text = "";
}
}
private void btnChooseFolder_Click(object sender, EventArgs e)
private void rdSingleScan_CheckedChanged(object sender, EventArgs e)
{
ConditionalControls.UnlockHeight(this);
ConditionalControls.SetVisible(rdFilePerScan, !rdSingleScan.Checked && rdSaveToMultipleFiles.Checked);
ConditionalControls.LockHeight(this);
}
private void rdMultipleScansDelay_CheckedChanged(object sender, EventArgs e)
{
ConditionalControls.UnlockHeight(this);
ConditionalControls.SetVisible(panelScanDetails, rdMultipleScansDelay.Checked);
ConditionalControls.LockHeight(this);
}
private void rdLoadIntoNaps2_CheckedChanged(object sender, EventArgs e)
{
ConditionalControls.UnlockHeight(this);
ConditionalControls.SetVisible(panelSaveTo, !rdLoadIntoNaps2.Checked);
ConditionalControls.LockHeight(this);
}
private void rdSaveToMultipleFiles_CheckedChanged(object sender, EventArgs e)
{
ConditionalControls.UnlockHeight(this);
ConditionalControls.SetVisible(panelSaveSeparator, rdSaveToMultipleFiles.Checked);
ConditionalControls.SetVisible(rdFilePerScan, !rdSingleScan.Checked && rdSaveToMultipleFiles.Checked);
ConditionalControls.LockHeight(this);
}
private void btnChooseFolder_Click(object sender, EventArgs e)
{
if (_dialogHelper.PromptToSavePdfOrImage(null, out string savePath))
{
if (_dialogHelper.PromptToSavePdfOrImage(null, out string savePath))
txtFilePath.Text = savePath;
}
}
private void linkPatchCodeInfo_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
Process.Start(PATCH_CODE_INFO_URL);
}
private void comboProfile_Format(object sender, ListControlConvertEventArgs e)
{
e.Value = ((ScanProfile)e.ListItem).DisplayName;
}
private void btnEditProfile_Click(object sender, EventArgs e)
{
var originalProfile = (ScanProfile) comboProfile.SelectedItem;
if (originalProfile != null)
{
var fedit = FormFactory.Create<FEditProfile>();
fedit.ScanProfile = originalProfile;
fedit.ShowDialog();
if (fedit.Result)
{
txtFilePath.Text = savePath;
}
}
private void linkPatchCodeInfo_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
Process.Start(PATCH_CODE_INFO_URL);
}
private void comboProfile_Format(object sender, ListControlConvertEventArgs e)
{
e.Value = ((ScanProfile)e.ListItem).DisplayName;
}
private void btnEditProfile_Click(object sender, EventArgs e)
{
var originalProfile = (ScanProfile) comboProfile.SelectedItem;
if (originalProfile != null)
{
var fedit = FormFactory.Create<FEditProfile>();
fedit.ScanProfile = originalProfile;
fedit.ShowDialog();
if (fedit.Result)
{
_profileManager.Mutate(new ListMutation<ScanProfile>.ReplaceWith(fedit.ScanProfile), ListSelection.Of(originalProfile));
_userTransact.Set(c => c.BatchSettings.ProfileDisplayName, fedit.ScanProfile.DisplayName);
UpdateProfiles();
}
}
}
private void btnAddProfile_Click(object sender, EventArgs e)
{
if (!(Config.Get(c => c.NoUserProfiles) && _profileManager.Profiles.Any(x => x.IsLocked)))
{
var fedit = FormFactory.Create<FEditProfile>();
fedit.ScanProfile = Config.Get(c => c.DefaultProfileSettings);
fedit.ShowDialog();
if (fedit.Result)
{
_profileManager.Mutate(new ListMutation<ScanProfile>.Append(fedit.ScanProfile), ListSelection.Empty<ScanProfile>());
_userTransact.Set(c => c.BatchSettings.ProfileDisplayName, fedit.ScanProfile.DisplayName);
UpdateProfiles();
}
}
}
private void btnStart_Click(object sender, EventArgs e)
{
if (_batchRunning)
{
return;
}
if (!ValidateSettings())
{
return;
}
// Update state
_batchRunning = true;
_cts = new CancellationTokenSource();
// Update UI
btnStart.Enabled = false;
btnCancel.Enabled = true;
btnCancel.Text = MiscResources.Cancel;
EnableDisableSettings(false);
// Start the batch
DoBatchScan().AssertNoAwait();
// Save settings for next time (could also do on form close)
_userTransact.Commit();
}
private void EnableDisableSettings(bool enabled)
{
EnableDisable(groupboxScanConfig, enabled);
EnableDisable(groupboxOutput, enabled);
}
private void EnableDisable(Control root, bool enabled)
{
foreach (Control control in root.Controls)
{
if (control.Controls.Count > 0)
{
EnableDisable(control, enabled);
}
else
{
control.Enabled = enabled;
}
}
}
private async Task DoBatchScan()
{
try
{
await _batchScanPerformer.PerformBatchScan(Config.Get(c => c.BatchSettings), this,
image => SafeInvoke(() => ImageCallback(image)), ProgressCallback, _cts.Token);
SafeInvoke(() =>
{
lblStatus.Text = _cts.IsCancellationRequested
? MiscResources.BatchStatusCancelled
: MiscResources.BatchStatusComplete;
});
}
catch (ScanDriverException ex)
{
if (ex is ScanDriverUnknownException)
{
Log.ErrorException("Error in batch scan", ex);
_errorOutput.DisplayError(ex.Message, ex);
}
else
{
_errorOutput.DisplayError(ex.Message);
}
}
catch (Exception ex)
{
Log.ErrorException("Error in batch scan", ex);
_errorOutput.DisplayError(MiscResources.BatchError, ex);
SafeInvoke(() =>
{
lblStatus.Text = MiscResources.BatchStatusError;
});
}
SafeInvoke(() =>
{
_batchRunning = false;
_cts = new CancellationTokenSource();
btnStart.Enabled = true;
btnCancel.Enabled = true;
btnCancel.Text = MiscResources.Close;
EnableDisableSettings(true);
Activate();
});
}
private void ProgressCallback(string status)
{
SafeInvoke(() =>
{
lblStatus.Text = status;
});
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (_batchRunning)
{
if (MessageBox.Show(MiscResources.ConfirmCancelBatch, MiscResources.CancelBatch, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
_cts.Cancel();
btnCancel.Enabled = false;
lblStatus.Text = MiscResources.BatchStatusCancelling;
}
}
else
{
Close();
}
}
private void FBatchScan_FormClosing(object sender, FormClosingEventArgs e)
{
if (_cts.IsCancellationRequested)
{
// Keep dialog open while cancel is in progress to avoid concurrency issues
e.Cancel = true;
}
}
private void linkPlaceholders_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var form = FormFactory.Create<FPlaceholders>();
form.FileName = txtFilePath.Text;
if (form.ShowDialog() == DialogResult.OK)
{
txtFilePath.Text = form.FileName;
_profileManager.Mutate(new ListMutation<ScanProfile>.ReplaceWith(fedit.ScanProfile), ListSelection.Of(originalProfile));
_userTransact.Set(c => c.BatchSettings.ProfileDisplayName, fedit.ScanProfile.DisplayName);
UpdateProfiles();
}
}
}
}
private void btnAddProfile_Click(object sender, EventArgs e)
{
if (!(Config.Get(c => c.NoUserProfiles) && _profileManager.Profiles.Any(x => x.IsLocked)))
{
var fedit = FormFactory.Create<FEditProfile>();
fedit.ScanProfile = Config.Get(c => c.DefaultProfileSettings);
fedit.ShowDialog();
if (fedit.Result)
{
_profileManager.Mutate(new ListMutation<ScanProfile>.Append(fedit.ScanProfile), ListSelection.Empty<ScanProfile>());
_userTransact.Set(c => c.BatchSettings.ProfileDisplayName, fedit.ScanProfile.DisplayName);
UpdateProfiles();
}
}
}
private void btnStart_Click(object sender, EventArgs e)
{
if (_batchRunning)
{
return;
}
if (!ValidateSettings())
{
return;
}
// Update state
_batchRunning = true;
_cts = new CancellationTokenSource();
// Update UI
btnStart.Enabled = false;
btnCancel.Enabled = true;
btnCancel.Text = MiscResources.Cancel;
EnableDisableSettings(false);
// Start the batch
DoBatchScan().AssertNoAwait();
// Save settings for next time (could also do on form close)
_userTransact.Commit();
}
private void EnableDisableSettings(bool enabled)
{
EnableDisable(groupboxScanConfig, enabled);
EnableDisable(groupboxOutput, enabled);
}
private void EnableDisable(Control root, bool enabled)
{
foreach (Control control in root.Controls)
{
if (control.Controls.Count > 0)
{
EnableDisable(control, enabled);
}
else
{
control.Enabled = enabled;
}
}
}
private async Task DoBatchScan()
{
try
{
await _batchScanPerformer.PerformBatchScan(Config.Get(c => c.BatchSettings), this,
image => SafeInvoke(() => ImageCallback(image)), ProgressCallback, _cts.Token);
SafeInvoke(() =>
{
lblStatus.Text = _cts.IsCancellationRequested
? MiscResources.BatchStatusCancelled
: MiscResources.BatchStatusComplete;
});
}
catch (ScanDriverException ex)
{
if (ex is ScanDriverUnknownException)
{
Log.ErrorException("Error in batch scan", ex);
_errorOutput.DisplayError(ex.Message, ex);
}
else
{
_errorOutput.DisplayError(ex.Message);
}
}
catch (Exception ex)
{
Log.ErrorException("Error in batch scan", ex);
_errorOutput.DisplayError(MiscResources.BatchError, ex);
SafeInvoke(() =>
{
lblStatus.Text = MiscResources.BatchStatusError;
});
}
SafeInvoke(() =>
{
_batchRunning = false;
_cts = new CancellationTokenSource();
btnStart.Enabled = true;
btnCancel.Enabled = true;
btnCancel.Text = MiscResources.Close;
EnableDisableSettings(true);
Activate();
});
}
private void ProgressCallback(string status)
{
SafeInvoke(() =>
{
lblStatus.Text = status;
});
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (_batchRunning)
{
if (MessageBox.Show(MiscResources.ConfirmCancelBatch, MiscResources.CancelBatch, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
_cts.Cancel();
btnCancel.Enabled = false;
lblStatus.Text = MiscResources.BatchStatusCancelling;
}
}
else
{
Close();
}
}
private void FBatchScan_FormClosing(object sender, FormClosingEventArgs e)
{
if (_cts.IsCancellationRequested)
{
// Keep dialog open while cancel is in progress to avoid concurrency issues
e.Cancel = true;
}
}
private void linkPlaceholders_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var form = FormFactory.Create<FPlaceholders>();
form.FileName = txtFilePath.Text;
if (form.ShowDialog() == DialogResult.OK)
{
txtFilePath.Text = form.FileName;
}
}
}

View File

@ -2,230 +2,229 @@ using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
partial class FCrop : ImageForm
{
partial class FCrop : ImageForm
private static CropTransform _lastTransform;
private static Size _lastSize;
private Point _dragStartCoords;
private LayoutManager _lm;
private int _originalWidth, _originalHeight;
public FCrop(ImageContext imageContext)
: base(imageContext)
{
private static CropTransform _lastTransform;
private static Size _lastSize;
InitializeComponent();
private Point _dragStartCoords;
private LayoutManager _lm;
_lm = new LayoutManager(this)
.Bind(tbLeft, tbRight)
.WidthTo(() => (int)(GetImageWidthRatio() * pictureBox.Width))
.LeftTo(() => (int)((1 - GetImageWidthRatio()) * pictureBox.Width / 2))
.Bind(tbTop, tbBottom)
.HeightTo(() => (int)(GetImageHeightRatio() * pictureBox.Height))
.TopTo(() => (int)((1 - GetImageHeightRatio()) * pictureBox.Height / 2))
.Activate();
private int _originalWidth, _originalHeight;
_originalWidth = _originalHeight = 1000;
}
public FCrop(ImageContext imageContext)
: base(imageContext)
public CropTransform CropTransform { get; private set; }
protected override IEnumerable<Transform> Transforms => new[] { CropTransform };
protected override PictureBox PictureBox => pictureBox;
protected override Bitmap RenderPreview()
{
var bitmap = new Bitmap(_originalWidth, _originalHeight);
using (var g = Graphics.FromImage(bitmap))
{
InitializeComponent();
_lm = new LayoutManager(this)
.Bind(tbLeft, tbRight)
.WidthTo(() => (int)(GetImageWidthRatio() * pictureBox.Width))
.LeftTo(() => (int)((1 - GetImageWidthRatio()) * pictureBox.Width / 2))
.Bind(tbTop, tbBottom)
.HeightTo(() => (int)(GetImageHeightRatio() * pictureBox.Height))
.TopTo(() => (int)((1 - GetImageHeightRatio()) * pictureBox.Height / 2))
.Activate();
_originalWidth = _originalHeight = 1000;
}
public CropTransform CropTransform { get; private set; }
protected override IEnumerable<Transform> Transforms => new[] { CropTransform };
protected override PictureBox PictureBox => pictureBox;
protected override Bitmap RenderPreview()
{
var bitmap = new Bitmap(_originalWidth, _originalHeight);
using (var g = Graphics.FromImage(bitmap))
{
g.Clear(Color.Transparent);
var attrs = new ImageAttributes();
attrs.SetColorMatrix(new ColorMatrix { Matrix33 = 0.5f });
g.DrawImage(workingImage2,
new Rectangle(0, 0, _originalWidth, _originalHeight),
0,
0,
_originalWidth,
_originalHeight,
GraphicsUnit.Pixel,
attrs);
var cropBorderRect = new Rectangle(CropTransform.Left, CropTransform.Top,
_originalWidth - CropTransform.Left - CropTransform.Right,
_originalHeight - CropTransform.Top - CropTransform.Bottom);
g.SetClip(cropBorderRect);
g.DrawImage(workingImage2, new Rectangle(0, 0, _originalWidth, _originalHeight));
g.ResetClip();
g.DrawRectangle(new Pen(Color.Black, 2.0f), cropBorderRect);
}
return bitmap;
}
protected override void InitTransform()
{
_originalWidth = workingImage.Width;
_originalHeight = workingImage.Height;
if (_lastTransform != null && _lastSize == workingImage.Size)
{
CropTransform = _lastTransform;
}
else
{
ResetTransform();
}
UpdateCropBounds();
_lm.UpdateLayout();
}
protected override void ResetTransform()
{
CropTransform = new CropTransform(0, 0, 0, 0, _originalWidth, _originalHeight);
}
protected override void TransformSaved()
{
_lastTransform = CropTransform;
_lastSize = workingImage.Size;
}
private double GetImageWidthRatio()
{
if (workingImage == null)
{
return 1;
}
double imageAspect = _originalWidth / (double)_originalHeight;
double pboxAspect = pictureBox.Width / (double)pictureBox.Height;
if (imageAspect > pboxAspect)
{
return 1;
}
return imageAspect / pboxAspect;
}
private double GetImageHeightRatio()
{
if (workingImage == null)
{
return 1;
}
double imageAspect = _originalWidth / (double)_originalHeight;
double pboxAspect = pictureBox.Width / (double)pictureBox.Height;
if (pboxAspect > imageAspect)
{
return 1;
}
return pboxAspect / imageAspect;
}
private void UpdateCropBounds()
{
tbLeft.Maximum = tbRight.Maximum = _originalWidth;
tbTop.Maximum = tbBottom.Maximum = _originalHeight;
tbLeft.Value = CropTransform.Left;
tbRight.Value = _originalWidth - CropTransform.Right;
tbTop.Value = _originalHeight - CropTransform.Top;
tbBottom.Value = CropTransform.Bottom;
}
private void UpdateTransform()
{
CropTransform = new CropTransform
(
Math.Min(tbLeft.Value, tbRight.Value),
_originalWidth - Math.Max(tbLeft.Value, tbRight.Value),
_originalHeight - Math.Max(tbTop.Value, tbBottom.Value),
Math.Min(tbTop.Value, tbBottom.Value),
g.Clear(Color.Transparent);
var attrs = new ImageAttributes();
attrs.SetColorMatrix(new ColorMatrix { Matrix33 = 0.5f });
g.DrawImage(workingImage2,
new Rectangle(0, 0, _originalWidth, _originalHeight),
0,
0,
_originalWidth,
_originalHeight
);
UpdatePreviewBox();
_originalHeight,
GraphicsUnit.Pixel,
attrs);
var cropBorderRect = new Rectangle(CropTransform.Left, CropTransform.Top,
_originalWidth - CropTransform.Left - CropTransform.Right,
_originalHeight - CropTransform.Top - CropTransform.Bottom);
g.SetClip(cropBorderRect);
g.DrawImage(workingImage2, new Rectangle(0, 0, _originalWidth, _originalHeight));
g.ResetClip();
g.DrawRectangle(new Pen(Color.Black, 2.0f), cropBorderRect);
}
private void tbLeft_Scroll(object sender, EventArgs e)
{
UpdateTransform();
}
return bitmap;
}
private void tbRight_Scroll(object sender, EventArgs e)
protected override void InitTransform()
{
_originalWidth = workingImage.Width;
_originalHeight = workingImage.Height;
if (_lastTransform != null && _lastSize == workingImage.Size)
{
UpdateTransform();
CropTransform = _lastTransform;
}
private void tbBottom_Scroll(object sender, EventArgs e)
else
{
UpdateTransform();
ResetTransform();
}
UpdateCropBounds();
_lm.UpdateLayout();
}
private void tbTop_Scroll(object sender, EventArgs e)
protected override void ResetTransform()
{
CropTransform = new CropTransform(0, 0, 0, 0, _originalWidth, _originalHeight);
}
protected override void TransformSaved()
{
_lastTransform = CropTransform;
_lastSize = workingImage.Size;
}
private double GetImageWidthRatio()
{
if (workingImage == null)
{
UpdateTransform();
return 1;
}
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
double imageAspect = _originalWidth / (double)_originalHeight;
double pboxAspect = pictureBox.Width / (double)pictureBox.Height;
if (imageAspect > pboxAspect)
{
_dragStartCoords = TranslatePboxCoords(e.Location);
return 1;
}
return imageAspect / pboxAspect;
}
private void pictureBox_MouseMove(object sender, MouseEventArgs e)
private double GetImageHeightRatio()
{
if (workingImage == null)
{
if (e.Button == MouseButtons.Left)
return 1;
}
double imageAspect = _originalWidth / (double)_originalHeight;
double pboxAspect = pictureBox.Width / (double)pictureBox.Height;
if (pboxAspect > imageAspect)
{
return 1;
}
return pboxAspect / imageAspect;
}
private void UpdateCropBounds()
{
tbLeft.Maximum = tbRight.Maximum = _originalWidth;
tbTop.Maximum = tbBottom.Maximum = _originalHeight;
tbLeft.Value = CropTransform.Left;
tbRight.Value = _originalWidth - CropTransform.Right;
tbTop.Value = _originalHeight - CropTransform.Top;
tbBottom.Value = CropTransform.Bottom;
}
private void UpdateTransform()
{
CropTransform = new CropTransform
(
Math.Min(tbLeft.Value, tbRight.Value),
_originalWidth - Math.Max(tbLeft.Value, tbRight.Value),
_originalHeight - Math.Max(tbTop.Value, tbBottom.Value),
Math.Min(tbTop.Value, tbBottom.Value),
_originalWidth,
_originalHeight
);
UpdatePreviewBox();
}
private void tbLeft_Scroll(object sender, EventArgs e)
{
UpdateTransform();
}
private void tbRight_Scroll(object sender, EventArgs e)
{
UpdateTransform();
}
private void tbBottom_Scroll(object sender, EventArgs e)
{
UpdateTransform();
}
private void tbTop_Scroll(object sender, EventArgs e)
{
UpdateTransform();
}
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
_dragStartCoords = TranslatePboxCoords(e.Location);
}
private void pictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var dragEndCoords = TranslatePboxCoords(e.Location);
if (dragEndCoords.X > _dragStartCoords.X)
{
var dragEndCoords = TranslatePboxCoords(e.Location);
if (dragEndCoords.X > _dragStartCoords.X)
{
tbLeft.Value = _dragStartCoords.X;
tbRight.Value = dragEndCoords.X;
}
else
{
tbLeft.Value = dragEndCoords.X;
tbRight.Value = _dragStartCoords.X;
}
if (dragEndCoords.Y > _dragStartCoords.Y)
{
tbTop.Value = _originalHeight - _dragStartCoords.Y;
tbBottom.Value = _originalHeight - dragEndCoords.Y;
}
else
{
tbTop.Value = _originalHeight - dragEndCoords.Y;
tbBottom.Value = _originalHeight - _dragStartCoords.Y;
}
UpdateTransform();
}
}
private Point TranslatePboxCoords(Point point)
{
double px = point.X - 1;
double py = point.Y - 1;
double imageAspect = _originalWidth / (double)_originalHeight;
double pboxWidth = (pictureBox.Width - 2);
double pboxHeight = (pictureBox.Height - 2);
double pboxAspect = pboxWidth / pboxHeight;
if (pboxAspect > imageAspect)
{
// Empty space on left/right
var emptyWidth = ((1 - imageAspect / pboxAspect) / 2 * pboxWidth);
px = (pboxAspect / imageAspect * (px - emptyWidth));
tbLeft.Value = _dragStartCoords.X;
tbRight.Value = dragEndCoords.X;
}
else
{
// Empty space on top/bottom
var emptyHeight = ((1 - pboxAspect / imageAspect) / 2 * pboxHeight);
py = (imageAspect / pboxAspect * (py - emptyHeight));
tbLeft.Value = dragEndCoords.X;
tbRight.Value = _dragStartCoords.X;
}
double x = px / pboxWidth * _originalWidth;
double y = py / pboxHeight * _originalHeight;
x = Math.Max(Math.Min(x, _originalWidth), 0);
y = Math.Max(Math.Min(y, _originalHeight), 0);
return new Point((int)Math.Round(x), (int)Math.Round(y));
if (dragEndCoords.Y > _dragStartCoords.Y)
{
tbTop.Value = _originalHeight - _dragStartCoords.Y;
tbBottom.Value = _originalHeight - dragEndCoords.Y;
}
else
{
tbTop.Value = _originalHeight - dragEndCoords.Y;
tbBottom.Value = _originalHeight - _dragStartCoords.Y;
}
UpdateTransform();
}
}
}
private Point TranslatePboxCoords(Point point)
{
double px = point.X - 1;
double py = point.Y - 1;
double imageAspect = _originalWidth / (double)_originalHeight;
double pboxWidth = (pictureBox.Width - 2);
double pboxHeight = (pictureBox.Height - 2);
double pboxAspect = pboxWidth / pboxHeight;
if (pboxAspect > imageAspect)
{
// Empty space on left/right
var emptyWidth = ((1 - imageAspect / pboxAspect) / 2 * pboxWidth);
px = (pboxAspect / imageAspect * (px - emptyWidth));
}
else
{
// Empty space on top/bottom
var emptyHeight = ((1 - pboxAspect / imageAspect) / 2 * pboxHeight);
py = (imageAspect / pboxAspect * (py - emptyHeight));
}
double x = px / pboxWidth * _originalWidth;
double y = py / pboxHeight * _originalHeight;
x = Math.Max(Math.Min(x, _originalWidth), 0);
y = Math.Max(Math.Min(y, _originalHeight), 0);
return new Point((int)Math.Round(x), (int)Math.Round(y));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -5,147 +5,146 @@ using NAPS2.ImportExport.Email.Mapi;
using NAPS2.ImportExport.Email.Oauth;
using NAPS2.Scan;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class FEmailProvider : FormBase
{
public partial class FEmailProvider : FormBase
private readonly GmailOauthProvider _gmailOauthProvider;
private readonly OutlookWebOauthProvider _outlookWebOauthProvider;
private readonly SystemEmailClients _systemEmailClients;
private List<EmailProviderWidget> _providerWidgets;
private string[] _systemClientNames;
private string _defaultSystemClientName;
public FEmailProvider(GmailOauthProvider gmailOauthProvider, OutlookWebOauthProvider outlookWebOauthProvider, SystemEmailClients systemEmailClients)
{
private readonly GmailOauthProvider _gmailOauthProvider;
private readonly OutlookWebOauthProvider _outlookWebOauthProvider;
private readonly SystemEmailClients _systemEmailClients;
_gmailOauthProvider = gmailOauthProvider;
_outlookWebOauthProvider = outlookWebOauthProvider;
_systemEmailClients = systemEmailClients;
private List<EmailProviderWidget> _providerWidgets;
private string[] _systemClientNames;
private string _defaultSystemClientName;
InitializeComponent();
}
public FEmailProvider(GmailOauthProvider gmailOauthProvider, OutlookWebOauthProvider outlookWebOauthProvider, SystemEmailClients systemEmailClients)
private void FEmailProvider_Load(object sender, EventArgs e)
{
_providerWidgets = new List<EmailProviderWidget>();
_systemClientNames = _systemEmailClients.GetNames();
_defaultSystemClientName = _systemEmailClients.GetDefaultName();
foreach (var clientName in _systemClientNames.OrderBy(x => x == _defaultSystemClientName ? 0 : 1))
{
_gmailOauthProvider = gmailOauthProvider;
_outlookWebOauthProvider = outlookWebOauthProvider;
_systemEmailClients = systemEmailClients;
InitializeComponent();
_providerWidgets.Add(new EmailProviderWidget
{
ProviderType = EmailProviderType.System,
ProviderIcon = _systemEmailClients.GetIcon(clientName) ?? Icons.mail_yellow,
ProviderName = clientName,
ClickAction = () => ChooseSystem(clientName)
});
}
private void FEmailProvider_Load(object sender, EventArgs e)
if (_gmailOauthProvider.HasClientCreds)
{
_providerWidgets = new List<EmailProviderWidget>();
_systemClientNames = _systemEmailClients.GetNames();
_defaultSystemClientName = _systemEmailClients.GetDefaultName();
foreach (var clientName in _systemClientNames.OrderBy(x => x == _defaultSystemClientName ? 0 : 1))
_providerWidgets.Add(new EmailProviderWidget
{
_providerWidgets.Add(new EmailProviderWidget
{
ProviderType = EmailProviderType.System,
ProviderIcon = _systemEmailClients.GetIcon(clientName) ?? Icons.mail_yellow,
ProviderName = clientName,
ClickAction = () => ChooseSystem(clientName)
});
}
if (_gmailOauthProvider.HasClientCreds)
{
_providerWidgets.Add(new EmailProviderWidget
{
ProviderType = EmailProviderType.Gmail,
ProviderIcon = Icons.gmail,
ProviderName = EmailProviderType.Gmail.Description(),
ClickAction = () => ChooseOauth(_gmailOauthProvider)
});
}
if (_outlookWebOauthProvider.HasClientCreds)
{
_providerWidgets.Add(new EmailProviderWidget
{
ProviderType = EmailProviderType.OutlookWeb,
ProviderIcon = Icons.outlookweb,
ProviderName = EmailProviderType.OutlookWeb.Description(),
ClickAction = () => ChooseOauth(_outlookWebOauthProvider)
});
}
//providerWidgets.Add(new EmailProviderWidget
//{
// ProviderType = EmailProviderType.CustomSmtp,
// ProviderIcon = Icons.email_setting,
// ProviderName = EmailProviderType.CustomSmtp.Description(),
// ClickAction = ChooseCustomSmtp
//});
// Put the configured provider at the top
var defaultWidget = GetDefaultWidget();
if (defaultWidget != null)
{
_providerWidgets.Remove(defaultWidget);
_providerWidgets.Insert(0, defaultWidget);
}
ShowWidgets();
ProviderType = EmailProviderType.Gmail,
ProviderIcon = Icons.gmail,
ProviderName = EmailProviderType.Gmail.Description(),
ClickAction = () => ChooseOauth(_gmailOauthProvider)
});
}
private void ChooseSystem(string clientName)
if (_outlookWebOauthProvider.HasClientCreds)
{
_providerWidgets.Add(new EmailProviderWidget
{
ProviderType = EmailProviderType.OutlookWeb,
ProviderIcon = Icons.outlookweb,
ProviderName = EmailProviderType.OutlookWeb.Description(),
ClickAction = () => ChooseOauth(_outlookWebOauthProvider)
});
}
//providerWidgets.Add(new EmailProviderWidget
//{
// ProviderType = EmailProviderType.CustomSmtp,
// ProviderIcon = Icons.email_setting,
// ProviderName = EmailProviderType.CustomSmtp.Description(),
// ClickAction = ChooseCustomSmtp
//});
// Put the configured provider at the top
var defaultWidget = GetDefaultWidget();
if (defaultWidget != null)
{
_providerWidgets.Remove(defaultWidget);
_providerWidgets.Insert(0, defaultWidget);
}
ShowWidgets();
}
private void ChooseSystem(string clientName)
{
var emailSetup = Config.Get(c => c.EmailSetup);
emailSetup.SystemProviderName = clientName == _defaultSystemClientName ? null : clientName;
emailSetup.ProviderType = EmailProviderType.System;
Config.User.Set(c => c.EmailSetup, emailSetup);
DialogResult = DialogResult.OK;
Close();
}
private void ChooseOauth(OauthProvider provider)
{
var authForm = FormFactory.Create<FAuthorize>();
authForm.OauthProvider = provider;
if (authForm.ShowDialog() == DialogResult.OK)
{
var emailSetup = Config.Get(c => c.EmailSetup);
emailSetup.SystemProviderName = clientName == _defaultSystemClientName ? null : clientName;
emailSetup.ProviderType = EmailProviderType.System;
Config.User.Set(c => c.EmailSetup, emailSetup);
DialogResult = DialogResult.OK;
Close();
}
}
private void ChooseOauth(OauthProvider provider)
private void ShowWidgets()
{
int heightDiff = Height - panel1.Height;
panel1.Height = 0;
foreach (var widget in _providerWidgets)
{
var authForm = FormFactory.Create<FAuthorize>();
authForm.OauthProvider = provider;
if (authForm.ShowDialog() == DialogResult.OK)
{
DialogResult = DialogResult.OK;
Close();
}
panel1.Controls.Add(widget);
widget.Top = panel1.Height;
widget.Width = panel1.Width;
widget.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
panel1.Height += widget.Height - 1;
}
private void ShowWidgets()
{
int heightDiff = Height - panel1.Height;
panel1.Height = 0;
foreach (var widget in _providerWidgets)
{
panel1.Controls.Add(widget);
widget.Top = panel1.Height;
widget.Width = panel1.Width;
widget.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
panel1.Height += widget.Height - 1;
}
panel1.Height += 1;
MaximumSize = new Size(MaximumSize.Width, panel1.Height + heightDiff);
MinimumSize = new Size(MinimumSize.Width, panel1.Height + heightDiff);
}
panel1.Height += 1;
MaximumSize = new Size(MaximumSize.Width, panel1.Height + heightDiff);
MinimumSize = new Size(MinimumSize.Width, panel1.Height + heightDiff);
}
private EmailProviderWidget GetDefaultWidget()
private EmailProviderWidget GetDefaultWidget()
{
var emailSetup = Config.Get(c => c.EmailSetup);
foreach (var widget in _providerWidgets)
{
var emailSetup = Config.Get(c => c.EmailSetup);
foreach (var widget in _providerWidgets)
if (widget.ProviderType == emailSetup.ProviderType)
{
if (widget.ProviderType == emailSetup.ProviderType)
if (widget.ProviderType == EmailProviderType.System)
{
if (widget.ProviderType == EmailProviderType.System)
{
// System providers need additional logic since there may be more than one
if (widget.ProviderName == emailSetup.SystemProviderName
|| string.IsNullOrEmpty(emailSetup.SystemProviderName) && widget.ProviderName == _defaultSystemClientName)
{
return widget;
}
}
else
// System providers need additional logic since there may be more than one
if (widget.ProviderName == emailSetup.SystemProviderName
|| string.IsNullOrEmpty(emailSetup.SystemProviderName) && widget.ProviderName == _defaultSystemClientName)
{
return widget;
}
}
else
{
return widget;
}
}
return null;
}
return null;
}
}
}

View File

@ -1,75 +1,74 @@
using System.Windows.Forms;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
partial class FHueSaturation : ImageForm
{
partial class FHueSaturation : ImageForm
public FHueSaturation(ImageContext imageContext)
: base(imageContext)
{
public FHueSaturation(ImageContext imageContext)
: base(imageContext)
{
InitializeComponent();
ActiveControl = txtHue;
}
public HueTransform HueTransform { get; private set; } = new HueTransform();
public SaturationTransform SaturationTransform { get; private set; } = new SaturationTransform();
protected override IEnumerable<Transform> Transforms => new Transform[] { HueTransform, SaturationTransform };
protected override PictureBox PictureBox => pictureBox;
protected override void ResetTransform()
{
HueTransform = new HueTransform();
SaturationTransform = new SaturationTransform();
tbHue.Value = 0;
tbSaturation.Value = 0;
txtHue.Text = tbHue.Value.ToString("G");
txtSaturation.Text = tbSaturation.Value.ToString("G");
}
private void UpdateTransform()
{
HueTransform = new HueTransform(tbHue.Value);
SaturationTransform = new SaturationTransform(tbSaturation.Value);
UpdatePreviewBox();
}
private void txtHue_TextChanged(object sender, EventArgs e)
{
if (int.TryParse(txtHue.Text, out int value))
{
if (value >= tbHue.Minimum && value <= tbHue.Maximum)
{
tbHue.Value = value;
}
}
UpdateTransform();
}
private void tbHue_Scroll(object sender, EventArgs e)
{
txtHue.Text = tbHue.Value.ToString("G");
UpdateTransform();
}
private void txtSaturation_TextChanged(object sender, EventArgs e)
{
if (int.TryParse(txtSaturation.Text, out int value))
{
if (value >= tbSaturation.Minimum && value <= tbSaturation.Maximum)
{
tbSaturation.Value = value;
}
}
UpdateTransform();
}
private void tbSaturation_Scroll(object sender, EventArgs e)
{
txtSaturation.Text = tbSaturation.Value.ToString("G");
UpdateTransform();
}
InitializeComponent();
ActiveControl = txtHue;
}
}
public HueTransform HueTransform { get; private set; } = new HueTransform();
public SaturationTransform SaturationTransform { get; private set; } = new SaturationTransform();
protected override IEnumerable<Transform> Transforms => new Transform[] { HueTransform, SaturationTransform };
protected override PictureBox PictureBox => pictureBox;
protected override void ResetTransform()
{
HueTransform = new HueTransform();
SaturationTransform = new SaturationTransform();
tbHue.Value = 0;
tbSaturation.Value = 0;
txtHue.Text = tbHue.Value.ToString("G");
txtSaturation.Text = tbSaturation.Value.ToString("G");
}
private void UpdateTransform()
{
HueTransform = new HueTransform(tbHue.Value);
SaturationTransform = new SaturationTransform(tbSaturation.Value);
UpdatePreviewBox();
}
private void txtHue_TextChanged(object sender, EventArgs e)
{
if (int.TryParse(txtHue.Text, out int value))
{
if (value >= tbHue.Minimum && value <= tbHue.Maximum)
{
tbHue.Value = value;
}
}
UpdateTransform();
}
private void tbHue_Scroll(object sender, EventArgs e)
{
txtHue.Text = tbHue.Value.ToString("G");
UpdateTransform();
}
private void txtSaturation_TextChanged(object sender, EventArgs e)
{
if (int.TryParse(txtSaturation.Text, out int value))
{
if (value >= tbSaturation.Minimum && value <= tbSaturation.Maximum)
{
tbSaturation.Value = value;
}
}
UpdateTransform();
}
private void tbSaturation_Scroll(object sender, EventArgs e)
{
txtSaturation.Text = tbSaturation.Value.ToString("G");
UpdateTransform();
}
}

View File

@ -1,92 +1,91 @@
using System.Windows.Forms;
using NAPS2.Ocr;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class FOcrLanguageDownload : FormBase
{
public partial class FOcrLanguageDownload : FormBase
private readonly TesseractLanguageManager _tesseractLanguageManager;
public FOcrLanguageDownload(TesseractLanguageManager tesseractLanguageManager)
{
private readonly TesseractLanguageManager _tesseractLanguageManager;
_tesseractLanguageManager = tesseractLanguageManager;
InitializeComponent();
public FOcrLanguageDownload(TesseractLanguageManager tesseractLanguageManager)
var initialSelection = new HashSet<string>();
// TODO: We used to select old installed languages here, maybe we could do it again if we get new lang data
if (!_tesseractLanguageManager.InstalledLanguages.Any())
{
_tesseractLanguageManager = tesseractLanguageManager;
InitializeComponent();
// Fresh install, so pre-select English as a sensible default
initialSelection.Add("ocr-eng");
}
var initialSelection = new HashSet<string>();
// TODO: We used to select old installed languages here, maybe we could do it again if we get new lang data
if (!_tesseractLanguageManager.InstalledLanguages.Any())
// Populate the list of language options
// Special case for English: sorted to the top of the list
var languageOptions = _tesseractLanguageManager.NotInstalledLanguages
.OrderBy(x => x.Code == "eng" ? "AAA" : x.Name);
foreach (var languageOption in languageOptions)
{
var item = new ListViewItem { Text = languageOption.Name, Tag = languageOption.Code };
if (initialSelection.Contains($"ocr-{languageOption.Code}"))
{
// Fresh install, so pre-select English as a sensible default
initialSelection.Add("ocr-eng");
item.Checked = true;
}
// Populate the list of language options
// Special case for English: sorted to the top of the list
var languageOptions = _tesseractLanguageManager.NotInstalledLanguages
.OrderBy(x => x.Code == "eng" ? "AAA" : x.Name);
foreach (var languageOption in languageOptions)
{
var item = new ListViewItem { Text = languageOption.Name, Tag = languageOption.Code };
if (initialSelection.Contains($"ocr-{languageOption.Code}"))
{
item.Checked = true;
}
lvLanguages.Items.Add(item);
}
UpdateView();
lvLanguages.Items.Add(item);
}
protected override void OnLoad(object sender, EventArgs eventArgs)
{
new LayoutManager(this)
.Bind(lvLanguages)
.WidthToForm()
.HeightToForm()
.Bind(labelSizeEstimate, btnCancel, btnDownload)
.BottomToForm()
.Bind(btnCancel, btnDownload)
.RightToForm()
.Activate();
}
private void UpdateView()
{
var selectedLanguages = SelectedLanguages;
double downloadSize = _tesseractLanguageManager.LanguageComponents.Where(x => selectedLanguages.Contains(x.Id)).Select(x => x.DownloadInfo.Size).Sum();
labelSizeEstimate.Text = string.Format(MiscResources.EstimatedDownloadSize, downloadSize.ToString("f1"));
btnDownload.Enabled = lvLanguages.Items.Cast<ListViewItem>().Any(x => x.Checked);
}
private HashSet<string> SelectedLanguages
{
get { return new HashSet<string>(lvLanguages.Items.Cast<ListViewItem>().Where(x => x.Checked).Select(x => $"ocr-{x.Tag}")); }
}
private void lvLanguages_ItemChecked(object sender, ItemCheckedEventArgs e)
{
UpdateView();
}
private void btnCancel_Click(object sender, EventArgs e)
{
Close();
}
private void btnDownload_Click(object sender, EventArgs e)
{
var progressForm = FormFactory.Create<FDownloadProgress>();
var selectedLanguages = SelectedLanguages;
foreach (var langComponent in _tesseractLanguageManager.LanguageComponents.Where(x => selectedLanguages.Contains(x.Id)))
{
progressForm.QueueFile(langComponent);
}
Close();
progressForm.ShowDialog();
}
UpdateView();
}
}
protected override void OnLoad(object sender, EventArgs eventArgs)
{
new LayoutManager(this)
.Bind(lvLanguages)
.WidthToForm()
.HeightToForm()
.Bind(labelSizeEstimate, btnCancel, btnDownload)
.BottomToForm()
.Bind(btnCancel, btnDownload)
.RightToForm()
.Activate();
}
private void UpdateView()
{
var selectedLanguages = SelectedLanguages;
double downloadSize = _tesseractLanguageManager.LanguageComponents.Where(x => selectedLanguages.Contains(x.Id)).Select(x => x.DownloadInfo.Size).Sum();
labelSizeEstimate.Text = string.Format(MiscResources.EstimatedDownloadSize, downloadSize.ToString("f1"));
btnDownload.Enabled = lvLanguages.Items.Cast<ListViewItem>().Any(x => x.Checked);
}
private HashSet<string> SelectedLanguages
{
get { return new HashSet<string>(lvLanguages.Items.Cast<ListViewItem>().Where(x => x.Checked).Select(x => $"ocr-{x.Tag}")); }
}
private void lvLanguages_ItemChecked(object sender, ItemCheckedEventArgs e)
{
UpdateView();
}
private void btnCancel_Click(object sender, EventArgs e)
{
Close();
}
private void btnDownload_Click(object sender, EventArgs e)
{
var progressForm = FormFactory.Create<FDownloadProgress>();
var selectedLanguages = SelectedLanguages;
foreach (var langComponent in _tesseractLanguageManager.LanguageComponents.Where(x => selectedLanguages.Contains(x.Id)))
{
progressForm.QueueFile(langComponent);
}
Close();
progressForm.ShowDialog();
}
}

View File

@ -1,37 +1,36 @@
using System.Windows.Forms;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class FPdfPassword : FormBase
{
public partial class FPdfPassword : FormBase
public FPdfPassword()
{
public FPdfPassword()
{
RestoreFormState = false;
InitializeComponent();
AcceptButton = btnOK;
CancelButton = btnCancel;
}
public string FileName { get; set; }
public string Password { get; private set; }
protected override void OnLoad(object sender, EventArgs eventArgs)
{
lblPrompt.Text = string.Format(lblPrompt.Text, FileName);
}
private void btnOK_Click(object sender, EventArgs e)
{
Password = txtPassword.Text;
DialogResult = DialogResult.OK;
Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
RestoreFormState = false;
InitializeComponent();
AcceptButton = btnOK;
CancelButton = btnCancel;
}
}
public string FileName { get; set; }
public string Password { get; private set; }
protected override void OnLoad(object sender, EventArgs eventArgs)
{
lblPrompt.Text = string.Format(lblPrompt.Text, FileName);
}
private void btnOK_Click(object sender, EventArgs e)
{
Password = txtPassword.Text;
DialogResult = DialogResult.OK;
Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
}

View File

@ -1,98 +1,97 @@
using System.Windows.Forms;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class FProgress : FormBase
{
public partial class FProgress : FormBase
private readonly ErrorOutput _errorOutput;
private readonly OperationProgress _operationProgress;
private volatile bool _loaded;
private volatile bool _background;
private IOperation _operation;
public FProgress(ErrorOutput errorOutput, OperationProgress operationProgress)
{
private readonly ErrorOutput _errorOutput;
private readonly OperationProgress _operationProgress;
_errorOutput = errorOutput;
_operationProgress = operationProgress;
InitializeComponent();
private volatile bool _loaded;
private volatile bool _background;
private IOperation _operation;
RestoreFormState = false;
}
public FProgress(ErrorOutput errorOutput, OperationProgress operationProgress)
public IOperation Operation
{
get => _operation;
set
{
_errorOutput = errorOutput;
_operationProgress = operationProgress;
InitializeComponent();
RestoreFormState = false;
_operation = value;
_operation.StatusChanged += operation_StatusChanged;
_operation.Finished += operation_Finished;
btnCancel.Visible = _operation.AllowCancel;
}
}
public IOperation Operation
void operation_StatusChanged(object sender, EventArgs e)
{
if (_loaded && !_background)
{
get => _operation;
set
{
_operation = value;
_operation.StatusChanged += operation_StatusChanged;
_operation.Finished += operation_Finished;
btnCancel.Visible = _operation.AllowCancel;
}
SafeInvoke(DisplayProgress);
}
}
void operation_StatusChanged(object sender, EventArgs e)
void operation_Finished(object sender, EventArgs e)
{
if (_loaded && !_background)
{
if (_loaded && !_background)
{
SafeInvoke(DisplayProgress);
}
SafeInvoke(Close);
}
}
void operation_Finished(object sender, EventArgs e)
protected override void OnLoad(object sender, EventArgs eventArgs)
{
_loaded = true;
Text = _operation.ProgressTitle;
btnRunInBG.Visible = _operation.AllowBackground;
DisplayProgress();
if (_operation.IsFinished)
{
if (_loaded && !_background)
{
SafeInvoke(Close);
}
}
protected override void OnLoad(object sender, EventArgs eventArgs)
{
_loaded = true;
Text = _operation.ProgressTitle;
btnRunInBG.Visible = _operation.AllowBackground;
DisplayProgress();
if (_operation.IsFinished)
{
Close();
}
}
private void DisplayProgress()
{
WinFormsOperationProgress.RenderStatus(Operation, labelStatus, labelNumber, progressBar);
}
private void btnCancel_Click(object sender, EventArgs e)
{
TryCancelOp();
}
private void FDownloadProgress_FormClosing(object sender, FormClosingEventArgs e)
{
if (!_operation.IsFinished && !_background)
{
TryCancelOp();
e.Cancel = true;
}
}
private void TryCancelOp()
{
if (Operation.AllowCancel)
{
Operation.Cancel();
btnCancel.Enabled = false;
}
}
private void btnRunInBG_Click(object sender, EventArgs e)
{
_background = true;
Close();
}
}
}
private void DisplayProgress()
{
WinFormsOperationProgress.RenderStatus(Operation, labelStatus, labelNumber, progressBar);
}
private void btnCancel_Click(object sender, EventArgs e)
{
TryCancelOp();
}
private void FDownloadProgress_FormClosing(object sender, FormClosingEventArgs e)
{
if (!_operation.IsFinished && !_background)
{
TryCancelOp();
e.Cancel = true;
}
}
private void TryCancelOp()
{
if (Operation.AllowCancel)
{
Operation.Cancel();
btnCancel.Enabled = false;
}
}
private void btnRunInBG_Click(object sender, EventArgs e)
{
_background = true;
Close();
}
}

View File

@ -1,38 +1,37 @@
using System.Windows.Forms;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class FRecover : FormBase
{
public partial class FRecover : FormBase
public FRecover()
{
public FRecover()
{
RestoreFormState = false;
InitializeComponent();
AcceptButton = btnRecover;
CancelButton = btnCancel;
}
public void SetData(int imageCount, DateTime scannedDateTime)
{
lblPrompt.Text = string.Format(lblPrompt.Text, imageCount, scannedDateTime.ToShortDateString(), scannedDateTime.ToShortTimeString());
}
private void btnDelete_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.No;
Close();
}
private void btnRecover_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Yes;
Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
RestoreFormState = false;
InitializeComponent();
AcceptButton = btnRecover;
CancelButton = btnCancel;
}
}
public void SetData(int imageCount, DateTime scannedDateTime)
{
lblPrompt.Text = string.Format(lblPrompt.Text, imageCount, scannedDateTime.ToShortDateString(), scannedDateTime.ToShortTimeString());
}
private void btnDelete_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.No;
Close();
}
private void btnRecover_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Yes;
Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
}

View File

@ -1,64 +1,63 @@
using System.Windows.Forms;
using NAPS2.Scan;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class FSelectDevice : FormBase
{
public partial class FSelectDevice : FormBase
public FSelectDevice()
{
public FSelectDevice()
SaveFormState = false;
RestoreFormState = false;
InitializeComponent();
AcceptButton = btnSelect;
CancelButton = btnCancel;
}
public List<ScanDevice> DeviceList { get; set; }
public ScanDevice? SelectedDevice { get; private set; }
protected override void OnLoad(object sender, EventArgs eventArgs)
{
new LayoutManager(this)
.Bind(listboxDevices)
.WidthToForm()
.HeightToForm()
.Bind(btnSelect, btnCancel)
.RightToForm()
.Activate();
foreach (var device in DeviceList)
{
SaveFormState = false;
RestoreFormState = false;
InitializeComponent();
AcceptButton = btnSelect;
CancelButton = btnCancel;
listboxDevices.Items.Add(device);
}
public List<ScanDevice> DeviceList { get; set; }
public ScanDevice? SelectedDevice { get; private set; }
protected override void OnLoad(object sender, EventArgs eventArgs)
if (listboxDevices.Items.Count > 0)
{
new LayoutManager(this)
.Bind(listboxDevices)
.WidthToForm()
.HeightToForm()
.Bind(btnSelect, btnCancel)
.RightToForm()
.Activate();
foreach (var device in DeviceList)
{
listboxDevices.Items.Add(device);
}
if (listboxDevices.Items.Count > 0)
{
listboxDevices.SelectedIndex = 0;
}
}
private void listboxDevices_Format(object sender, ListControlConvertEventArgs e)
{
e.Value = ((ScanDevice)e.ListItem).Name;
}
private void btnSelect_Click(object sender, EventArgs e)
{
if (listboxDevices.SelectedItem == null)
{
listboxDevices.Focus();
return;
}
DialogResult = DialogResult.OK;
SelectedDevice = ((ScanDevice) listboxDevices.SelectedItem);
Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
listboxDevices.SelectedIndex = 0;
}
}
}
private void listboxDevices_Format(object sender, ListControlConvertEventArgs e)
{
e.Value = ((ScanDevice)e.ListItem).Name;
}
private void btnSelect_Click(object sender, EventArgs e)
{
if (listboxDevices.SelectedItem == null)
{
listboxDevices.Focus();
return;
}
DialogResult = DialogResult.OK;
SelectedDevice = ((ScanDevice) listboxDevices.SelectedItem);
Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,18 @@
using System.ComponentModel;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class ILProfileIcons : Component
{
public partial class ILProfileIcons : Component
public ILProfileIcons()
{
public ILProfileIcons()
{
InitializeComponent();
}
public ILProfileIcons(IContainer container)
{
container.Add(this);
InitializeComponent();
}
InitializeComponent();
}
}
public ILProfileIcons(IContainer container)
{
container.Add(this);
InitializeComponent();
}
}

View File

@ -3,180 +3,179 @@ using System.Windows.Forms;
using NAPS2.Images.Gdi;
using Timer = System.Threading.Timer;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class ImageForm : FormBase
{
public partial class ImageForm : FormBase
private readonly ImageContext _imageContext;
protected Bitmap workingImage, workingImage2;
private bool _initComplete;
private bool _previewOutOfDate;
private bool _working;
private Timer _previewTimer;
private bool _closed;
private ImageForm()
{
private readonly ImageContext _imageContext;
// For the designer only
InitializeComponent();
}
protected Bitmap workingImage, workingImage2;
private bool _initComplete;
private bool _previewOutOfDate;
private bool _working;
private Timer _previewTimer;
private bool _closed;
protected ImageForm(ImageContext imageContext)
{
_imageContext = imageContext;
InitializeComponent();
}
private ImageForm()
public UiImage Image { get; set; }
public List<UiImage> SelectedImages { get; set; }
protected virtual IEnumerable<Transform> Transforms => throw new NotImplementedException();
protected virtual PictureBox PictureBox => throw new NotImplementedException();
private bool TransformMultiple => SelectedImages != null && checkboxApplyToSelected.Checked;
private IEnumerable<UiImage> ImagesToTransform => TransformMultiple ? SelectedImages : Enumerable.Repeat(Image, 1);
protected virtual Bitmap RenderPreview()
{
var result = (Bitmap)workingImage.Clone();
foreach (var transform in Transforms)
{
// For the designer only
InitializeComponent();
}
protected ImageForm(ImageContext imageContext)
{
_imageContext = imageContext;
InitializeComponent();
}
public UiImage Image { get; set; }
public List<UiImage> SelectedImages { get; set; }
protected virtual IEnumerable<Transform> Transforms => throw new NotImplementedException();
protected virtual PictureBox PictureBox => throw new NotImplementedException();
private bool TransformMultiple => SelectedImages != null && checkboxApplyToSelected.Checked;
private IEnumerable<UiImage> ImagesToTransform => TransformMultiple ? SelectedImages : Enumerable.Repeat(Image, 1);
protected virtual Bitmap RenderPreview()
{
var result = (Bitmap)workingImage.Clone();
foreach (var transform in Transforms)
if (!transform.IsNull)
{
if (!transform.IsNull)
{
// TODO: Maybe the working images etc. should be storage
result = ((GdiImage)_imageContext.PerformTransform(new GdiImage(result), transform)).Bitmap;
}
}
return result;
}
protected virtual void InitTransform()
{
}
protected virtual void ResetTransform()
{
}
protected virtual void TransformSaved()
{
}
private async void ImageForm_Load(object sender, EventArgs e)
{
checkboxApplyToSelected.BringToFront();
btnRevert.BringToFront();
btnCancel.BringToFront();
btnOK.BringToFront();
if (SelectedImages != null && SelectedImages.Count > 1)
{
checkboxApplyToSelected.Text = string.Format(checkboxApplyToSelected.Text, SelectedImages.Count);
}
else
{
ConditionalControls.Hide(checkboxApplyToSelected, 6);
}
Size = new Size(600, 600);
var maxDimen = Screen.AllScreens.Max(s => Math.Max(s.WorkingArea.Height, s.WorkingArea.Width));
// TODO: Limit to maxDimen * 2
using var imageToRender = Image.GetClonedImage();
// TODO: More generic or avoid the cast somehow? In general how do we integrate with eto?
workingImage = ((GdiImageContext)_imageContext).RenderToBitmap(imageToRender);
if (_closed)
{
workingImage?.Dispose();
return;
}
workingImage2 = (Bitmap)workingImage.Clone();
InitTransform();
lock (this)
{
_initComplete = true;
}
UpdatePreviewBox();
}
protected void UpdatePreviewBox()
{
if (_previewTimer == null)
{
_previewTimer = new Timer(_ =>
{
lock (this)
{
if (!_initComplete || !IsHandleCreated || !_previewOutOfDate || _working) return;
_working = true;
_previewOutOfDate = false;
}
var bitmap = RenderPreview();
SafeInvoke(() =>
{
PictureBox.Image?.Dispose();
PictureBox.Image = bitmap;
});
lock (this)
{
_working = false;
}
}, null, 0, 100);
}
lock (this)
{
_previewOutOfDate = true;
// TODO: Maybe the working images etc. should be storage
result = ((GdiImage)_imageContext.PerformTransform(new GdiImage(result), transform)).Bitmap;
}
}
return result;
}
private void btnCancel_Click(object sender, EventArgs e)
protected virtual void InitTransform()
{
}
protected virtual void ResetTransform()
{
}
protected virtual void TransformSaved()
{
}
private async void ImageForm_Load(object sender, EventArgs e)
{
checkboxApplyToSelected.BringToFront();
btnRevert.BringToFront();
btnCancel.BringToFront();
btnOK.BringToFront();
if (SelectedImages != null && SelectedImages.Count > 1)
{
Close();
checkboxApplyToSelected.Text = string.Format(checkboxApplyToSelected.Text, SelectedImages.Count);
}
else
{
ConditionalControls.Hide(checkboxApplyToSelected, 6);
}
private void btnOK_Click(object sender, EventArgs e)
{
if (Transforms.Any(x => !x.IsNull))
{
foreach (var img in ImagesToTransform)
{
lock (img)
{
foreach (var t in Transforms)
{
img.AddTransform(t);
}
// Optimize thumbnail rendering for the first (or only) image since we already have it loaded into memory
if (img == Image)
{
var transformed = _imageContext.PerformAllTransforms(new GdiImage(workingImage).Clone(), Transforms);
img.SetThumbnail(_imageContext.PerformTransform(transformed, new ThumbnailTransform(Config.Get(c => c.ThumbnailSize))));
}
}
}
}
TransformSaved();
Close();
}
Size = new Size(600, 600);
private void btnRevert_Click(object sender, EventArgs e)
{
ResetTransform();
UpdatePreviewBox();
}
private void ImageForm_FormClosed(object sender, FormClosedEventArgs e)
var maxDimen = Screen.AllScreens.Max(s => Math.Max(s.WorkingArea.Height, s.WorkingArea.Width));
// TODO: Limit to maxDimen * 2
using var imageToRender = Image.GetClonedImage();
// TODO: More generic or avoid the cast somehow? In general how do we integrate with eto?
workingImage = ((GdiImageContext)_imageContext).RenderToBitmap(imageToRender);
if (_closed)
{
workingImage?.Dispose();
workingImage2?.Dispose();
PictureBox.Image?.Dispose();
_previewTimer?.Dispose();
_closed = true;
return;
}
workingImage2 = (Bitmap)workingImage.Clone();
InitTransform();
lock (this)
{
_initComplete = true;
}
UpdatePreviewBox();
}
protected void UpdatePreviewBox()
{
if (_previewTimer == null)
{
_previewTimer = new Timer(_ =>
{
lock (this)
{
if (!_initComplete || !IsHandleCreated || !_previewOutOfDate || _working) return;
_working = true;
_previewOutOfDate = false;
}
var bitmap = RenderPreview();
SafeInvoke(() =>
{
PictureBox.Image?.Dispose();
PictureBox.Image = bitmap;
});
lock (this)
{
_working = false;
}
}, null, 0, 100);
}
lock (this)
{
_previewOutOfDate = true;
}
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
Close();
}
private void btnOK_Click(object sender, EventArgs e)
{
if (Transforms.Any(x => !x.IsNull))
{
foreach (var img in ImagesToTransform)
{
lock (img)
{
foreach (var t in Transforms)
{
img.AddTransform(t);
}
// Optimize thumbnail rendering for the first (or only) image since we already have it loaded into memory
if (img == Image)
{
var transformed = _imageContext.PerformAllTransforms(new GdiImage(workingImage).Clone(), Transforms);
img.SetThumbnail(_imageContext.PerformTransform(transformed, new ThumbnailTransform(Config.Get(c => c.ThumbnailSize))));
}
}
}
}
TransformSaved();
Close();
}
private void btnRevert_Click(object sender, EventArgs e)
{
ResetTransform();
UpdatePreviewBox();
}
private void ImageForm_FormClosed(object sender, FormClosedEventArgs e)
{
workingImage?.Dispose();
workingImage2?.Dispose();
PictureBox.Image?.Dispose();
_previewTimer?.Dispose();
_closed = true;
}
}

View File

@ -1,74 +1,73 @@
using System.Windows.Forms;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public partial class OperationProgressNotifyWidget : NotifyWidgetBase
{
public partial class OperationProgressNotifyWidget : NotifyWidgetBase
private readonly OperationProgress _operationProgress;
private readonly IOperation _op;
public OperationProgressNotifyWidget(OperationProgress operationProgress, IOperation op)
{
private readonly OperationProgress _operationProgress;
private readonly IOperation _op;
InitializeComponent();
public OperationProgressNotifyWidget(OperationProgress operationProgress, IOperation op)
_operationProgress = operationProgress;
_op = op;
cancelToolStripMenuItem.Visible = op.AllowCancel;
op.StatusChanged += Op_StatusChanged;
op.Finished += Op_Finished;
}
public override void ShowNotify() => DisplayProgress();
public override NotifyWidgetBase Clone() => new OperationProgressNotifyWidget(_operationProgress, _op);
private void DisplayProgress()
{
var lblNumberRight = lblNumber.Right;
WinFormsOperationProgress.RenderStatus(_op, lblTitle, lblNumber, progressBar);
if (_op.Status?.IndeterminateProgress != true)
{
InitializeComponent();
_operationProgress = operationProgress;
_op = op;
cancelToolStripMenuItem.Visible = op.AllowCancel;
op.StatusChanged += Op_StatusChanged;
op.Finished += Op_Finished;
// Don't display the number if the progress bar is precise
// Otherwise, the widget will be too cluttered
// The number is only shown for OcrOperation at the moment
lblNumber.Text = "";
}
lblNumber.Left = lblNumberRight - lblNumber.Width;
Width = Math.Max(Width, lblTitle.Width + lblNumber.Width + 22);
Height = Math.Max(Height, lblTitle.Height + 35);
}
public override void ShowNotify() => DisplayProgress();
private void DoHideNotify()
{
_op.StatusChanged -= Op_StatusChanged;
_op.Finished -= Op_Finished;
InvokeHideNotify();
}
public override NotifyWidgetBase Clone() => new OperationProgressNotifyWidget(_operationProgress, _op);
private void Op_StatusChanged(object sender, EventArgs e)
{
SafeInvoke(DisplayProgress);
}
private void DisplayProgress()
{
var lblNumberRight = lblNumber.Right;
WinFormsOperationProgress.RenderStatus(_op, lblTitle, lblNumber, progressBar);
if (_op.Status?.IndeterminateProgress != true)
{
// Don't display the number if the progress bar is precise
// Otherwise, the widget will be too cluttered
// The number is only shown for OcrOperation at the moment
lblNumber.Text = "";
}
lblNumber.Left = lblNumberRight - lblNumber.Width;
Width = Math.Max(Width, lblTitle.Width + lblNumber.Width + 22);
Height = Math.Max(Height, lblTitle.Height + 35);
}
private void Op_Finished(object sender, EventArgs e)
{
DoHideNotify();
}
private void DoHideNotify()
{
_op.StatusChanged -= Op_StatusChanged;
_op.Finished -= Op_Finished;
InvokeHideNotify();
}
private void cancelToolStripMenuItem_Click(object sender, EventArgs e)
{
_op.Cancel();
cancelToolStripMenuItem.Enabled = false;
}
private void Op_StatusChanged(object sender, EventArgs e)
{
SafeInvoke(DisplayProgress);
}
private void Op_Finished(object sender, EventArgs e)
private void OperationProgressNotifyWidget_Click(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DoHideNotify();
}
private void cancelToolStripMenuItem_Click(object sender, EventArgs e)
{
_op.Cancel();
cancelToolStripMenuItem.Enabled = false;
}
private void OperationProgressNotifyWidget_Click(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DoHideNotify();
_operationProgress.ShowModalProgress(_op);
}
_operationProgress.ShowModalProgress(_op);
}
}
}
}

View File

@ -2,173 +2,172 @@ using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace NAPS2.WinForms
namespace NAPS2.WinForms;
public class TiffViewer : UserControl
{
public class TiffViewer : UserControl
private readonly Container _components = null;
private Image _image;
private PictureBox _pbox;
private double _xzoom;
public TiffViewer()
{
private readonly Container _components = null;
InitializeComponent();
}
private Image _image;
private PictureBox _pbox;
private double _xzoom;
public TiffViewer()
public Image Image
{
set
{
InitializeComponent();
}
public Image Image
{
set
if (value != null)
{
if (value != null)
{
_image = value;
Zoom = 100;
}
else
{
ClearImage();
_image = null;
}
}
}
public int ImageWidth => _image?.Width ?? 0;
public int ImageHeight => _image?.Height ?? 0;
public double Zoom
{
set
{
if (_image != null)
{
double maxZoom = Math.Sqrt(1e8 / (_image.Width * (double) _image.Height)) * 100;
_xzoom = Math.Max(Math.Min(value, maxZoom), 10);
double displayWidth = _image.Width * (_xzoom / 100);
double displayHeight = _image.Height * (_xzoom / 100);
if (_image.HorizontalResolution > 0 && _image.VerticalResolution > 0)
{
displayHeight *= _image.HorizontalResolution / (double)_image.VerticalResolution;
}
_pbox.Image = _image;
_pbox.BorderStyle = BorderStyle.FixedSingle;
_pbox.Width = (int)displayWidth;
_pbox.Height = (int)displayHeight;
if (ZoomChanged != null)
{
_pbox.Cursor = HorizontalScroll.Visible || VerticalScroll.Visible ? Cursors.Hand : Cursors.Default;
ZoomChanged.Invoke(this, new EventArgs());
}
}
}
get => _xzoom;
}
public event EventHandler<EventArgs> ZoomChanged;
private void ClearImage()
{
_pbox.Image = Icons.hourglass_grey;
_pbox.BorderStyle = BorderStyle.None;
_pbox.Width = 32;
_pbox.Height = 32;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_components?.Dispose();
}
base.Dispose(disposing);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
if (ModifierKeys.HasFlag(Keys.Control))
{
StepZoom(e.Delta / (double)SystemInformation.MouseWheelScrollDelta);
_image = value;
Zoom = 100;
}
else
{
base.OnMouseWheel(e);
ClearImage();
_image = null;
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
switch (e.KeyCode)
{
case Keys.OemMinus:
if (e.Control)
{
StepZoom(-1);
}
break;
case Keys.Oemplus:
if (e.Control)
{
StepZoom(1);
}
break;
}
}
public void StepZoom(double steps)
{
Zoom = Math.Round(Zoom * Math.Pow(1.2, steps));
}
private Point _mousePos;
private void pbox_MouseDown(object sender, MouseEventArgs e)
{
_mousePos = e.Location;
}
private void pbox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
AutoScrollPosition = new Point(-AutoScrollPosition.X + _mousePos.X - e.X, -AutoScrollPosition.Y + _mousePos.Y - e.Y);
}
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TiffViewer));
this._pbox = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this._pbox)).BeginInit();
this.SuspendLayout();
//
// pbox
//
resources.ApplyResources(this._pbox, "_pbox");
this._pbox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._pbox.Name = "_pbox";
this._pbox.TabStop = false;
this._pbox.SizeMode = PictureBoxSizeMode.Zoom;
this._pbox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pbox_MouseDown);
this._pbox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pbox_MouseMove);
//
// TiffViewer
//
resources.ApplyResources(this, "$this");
this.BackColor = System.Drawing.Color.LightGray;
this.Controls.Add(this._pbox);
this.Name = "TiffViewer";
((System.ComponentModel.ISupportInitialize)(this._pbox)).EndInit();
this.ResumeLayout(false);
}
#endregion
}
}
public int ImageWidth => _image?.Width ?? 0;
public int ImageHeight => _image?.Height ?? 0;
public double Zoom
{
set
{
if (_image != null)
{
double maxZoom = Math.Sqrt(1e8 / (_image.Width * (double) _image.Height)) * 100;
_xzoom = Math.Max(Math.Min(value, maxZoom), 10);
double displayWidth = _image.Width * (_xzoom / 100);
double displayHeight = _image.Height * (_xzoom / 100);
if (_image.HorizontalResolution > 0 && _image.VerticalResolution > 0)
{
displayHeight *= _image.HorizontalResolution / (double)_image.VerticalResolution;
}
_pbox.Image = _image;
_pbox.BorderStyle = BorderStyle.FixedSingle;
_pbox.Width = (int)displayWidth;
_pbox.Height = (int)displayHeight;
if (ZoomChanged != null)
{
_pbox.Cursor = HorizontalScroll.Visible || VerticalScroll.Visible ? Cursors.Hand : Cursors.Default;
ZoomChanged.Invoke(this, new EventArgs());
}
}
}
get => _xzoom;
}
public event EventHandler<EventArgs> ZoomChanged;
private void ClearImage()
{
_pbox.Image = Icons.hourglass_grey;
_pbox.BorderStyle = BorderStyle.None;
_pbox.Width = 32;
_pbox.Height = 32;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_components?.Dispose();
}
base.Dispose(disposing);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
if (ModifierKeys.HasFlag(Keys.Control))
{
StepZoom(e.Delta / (double)SystemInformation.MouseWheelScrollDelta);
}
else
{
base.OnMouseWheel(e);
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
switch (e.KeyCode)
{
case Keys.OemMinus:
if (e.Control)
{
StepZoom(-1);
}
break;
case Keys.Oemplus:
if (e.Control)
{
StepZoom(1);
}
break;
}
}
public void StepZoom(double steps)
{
Zoom = Math.Round(Zoom * Math.Pow(1.2, steps));
}
private Point _mousePos;
private void pbox_MouseDown(object sender, MouseEventArgs e)
{
_mousePos = e.Location;
}
private void pbox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
AutoScrollPosition = new Point(-AutoScrollPosition.X + _mousePos.X - e.X, -AutoScrollPosition.Y + _mousePos.Y - e.Y);
}
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TiffViewer));
this._pbox = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this._pbox)).BeginInit();
this.SuspendLayout();
//
// pbox
//
resources.ApplyResources(this._pbox, "_pbox");
this._pbox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._pbox.Name = "_pbox";
this._pbox.TabStop = false;
this._pbox.SizeMode = PictureBoxSizeMode.Zoom;
this._pbox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pbox_MouseDown);
this._pbox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pbox_MouseMove);
//
// TiffViewer
//
resources.ApplyResources(this, "$this");
this.BackColor = System.Drawing.Color.LightGray;
this.Controls.Add(this._pbox);
this.Name = "TiffViewer";
((System.ComponentModel.ISupportInitialize)(this._pbox)).EndInit();
this.ResumeLayout(false);
}
#endregion
}