Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/SightAdapt/ConfigurationForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ internal sealed class ConfigurationForm : Form
{
private readonly SettingsCoordinator _settingsCoordinator;
private readonly Func<ApplicationIdentity?> _getCurrentApplication;
private readonly Action<IWin32Window, SettingsCoordinator>
_showVisualProfileManager;
private readonly ToggleSwitch _automaticModeSwitch;
private readonly Label _automaticModeStateLabel;
private readonly Label _profileCountLabel;
Expand All @@ -17,12 +19,16 @@ internal sealed class ConfigurationForm : Form

public ConfigurationForm(
SettingsCoordinator settingsCoordinator,
Func<ApplicationIdentity?> getCurrentApplication)
Func<ApplicationIdentity?> getCurrentApplication,
Action<IWin32Window, SettingsCoordinator>?
showVisualProfileManager = null)
{
_settingsCoordinator = settingsCoordinator ??
throw new ArgumentNullException(nameof(settingsCoordinator));
_getCurrentApplication = getCurrentApplication ??
throw new ArgumentNullException(nameof(getCurrentApplication));
_showVisualProfileManager = showVisualProfileManager ??
VisualProfileManagerForm.ShowManager;

Text = ProductInfo.WindowTitle;
StartPosition = FormStartPosition.CenterScreen;
Expand Down Expand Up @@ -62,6 +68,8 @@ public ConfigurationForm(

private SightAdaptSettings Settings => _settingsCoordinator.Current;

internal int RefreshGeneration { get; private set; }

public void RefreshProfiles()
{
if (IsDisposed)
Expand All @@ -88,6 +96,8 @@ public void RefreshProfiles()
{
_refreshing = false;
}

RefreshGeneration++;
}

private Control CreateRootLayout()
Expand Down Expand Up @@ -628,10 +638,9 @@ private void EditSelectedVisualProfile()
}
}

private void ManageVisualProfiles()
internal void ManageVisualProfiles()
{
VisualProfileManagerForm.ShowManager(this, _settingsCoordinator);
RefreshProfiles();
_showVisualProfileManager(this, _settingsCoordinator);
}

private ApplicationProfile? GetSelectedApplicationProfile()
Expand Down
25 changes: 20 additions & 5 deletions src/SightAdapt/ModernSelectorComboBoxColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,20 +155,32 @@ protected override void Paint(
graphics,
Rectangle.Inflate(cellBounds, -7, -6),
formattedValue?.ToString() ?? string.Empty,
cellStyle.Font ?? AppTheme.CreateUiFont(9.5f),
ResolvePaintFont(
cellStyle.Font,
DataGridView?.Font),
foreground,
selected,
focused:
selected &&
DataGridView?.CurrentCellAddress.X == ColumnIndex &&
DataGridView.CurrentCellAddress.Y == rowIndex);
}

internal static Font ResolvePaintFont(
Font? cellStyleFont,
Font? gridFont)
{
return cellStyleFont ??
gridFont ??
Control.DefaultFont;
}
}

internal sealed class ModernSelectorEditingControl :
Control,
IDataGridViewEditingControl
{
private readonly Font _defaultFont;
private readonly ListBox _list;
private readonly ToolStripDropDown _dropDown;
private ModernSelectorOption[] _options = [];
Expand All @@ -177,10 +189,12 @@ internal sealed class ModernSelectorEditingControl :

public ModernSelectorEditingControl()
{
_defaultFont = AppTheme.CreateUiFont(9.5f);

AccessibleRole = AccessibleRole.ComboBox;
BackColor = AppTheme.SurfaceRaised;
Cursor = Cursors.Hand;
Font = AppTheme.CreateUiFont(9.5f);
Font = _defaultFont;
ForeColor = AppTheme.TextPrimary;
TabStop = true;
SetStyle(
Expand All @@ -196,7 +210,7 @@ public ModernSelectorEditingControl()
BackColor = AppTheme.SurfaceRaised,
BorderStyle = BorderStyle.None,
DrawMode = DrawMode.OwnerDrawFixed,
Font = AppTheme.CreateUiFont(9.5f),
Font = _defaultFont,
ForeColor = AppTheme.TextPrimary,
IntegralHeight = false,
ItemHeight = 34,
Expand Down Expand Up @@ -248,7 +262,7 @@ public void Configure(
{
_options = options.ToArray();
EditingControlValueChanged = false;
Font = style.Font ?? AppTheme.CreateUiFont(9.5f);
Font = style.Font ?? _defaultFont;
ForeColor = AppTheme.TextPrimary;
BackColor = AppTheme.SurfaceRaised;
SelectByValue(selectedId);
Expand All @@ -261,7 +275,7 @@ public void Configure(
public void ApplyCellStyleToEditingControl(
DataGridViewCellStyle dataGridViewCellStyle)
{
Font = dataGridViewCellStyle.Font ?? AppTheme.CreateUiFont(9.5f);
Font = dataGridViewCellStyle.Font ?? _defaultFont;
ForeColor = AppTheme.TextPrimary;
BackColor = AppTheme.SurfaceRaised;
}
Expand Down Expand Up @@ -397,6 +411,7 @@ protected override void Dispose(bool disposing)
{
_dropDown.Dispose();
_list.Dispose();
_defaultFont.Dispose();
}

base.Dispose(disposing);
Expand Down
73 changes: 60 additions & 13 deletions src/SightAdapt/ModernTheme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal static class AppTheme
public static readonly Color WindowBackground = Color.FromArgb(20, 23, 31);
public static readonly Color HeaderBackground = Color.FromArgb(24, 28, 38);
public static readonly Color Surface = Color.FromArgb(29, 34, 45);
public static readonly Color SurfaceAlternate = Color.FromArgb(32, 38, 50);
public static readonly Color SurfaceRaised = Color.FromArgb(36, 42, 55);
public static readonly Color SurfaceHover = Color.FromArgb(45, 53, 69);
public static readonly Color Border = Color.FromArgb(54, 63, 81);
Expand All @@ -28,6 +29,9 @@ internal static class AppTheme
public static readonly Color SuccessSoft = Color.FromArgb(30, 76, 67);
public static readonly Color Danger = Color.FromArgb(255, 111, 128);
public static readonly Color DangerSoft = Color.FromArgb(84, 43, 54);
public static readonly Color DangerHover = Color.FromArgb(96, 47, 59);
public static readonly Color DangerPressed = Color.FromArgb(105, 47, 60);
public static readonly Color DangerBorder = Color.FromArgb(120, 58, 70);
public static readonly Color Selection = Color.FromArgb(52, 67, 105);

public static Font CreateUiFont(float size = 9.5f, FontStyle style = FontStyle.Regular)
Expand Down Expand Up @@ -109,7 +113,7 @@ public static void StyleGrid(DataGridView grid)

grid.AlternatingRowsDefaultCellStyle = new DataGridViewCellStyle
{
BackColor = Color.FromArgb(32, 38, 50),
BackColor = SurfaceAlternate,
ForeColor = TextPrimary,
SelectionBackColor = Selection,
SelectionForeColor = TextPrimary,
Expand Down Expand Up @@ -243,28 +247,71 @@ protected override void OnPaint(PaintEventArgs eventArgs)

private (Color Background, Color Border, Color Foreground) ResolveColors()
{
if (!Enabled)
return ResolveColors(
VisualStyle,
Enabled,
_hovered,
_pressed);
}

internal static (
Color Background,
Color Border,
Color Foreground) ResolveColors(
ModernButtonStyle visualStyle,
bool enabled,
bool hovered,
bool pressed)
{
if (!enabled)
{
return (AppTheme.Surface, AppTheme.Border, AppTheme.TextMuted);
return (
AppTheme.Surface,
AppTheme.Border,
AppTheme.TextMuted);
}

return VisualStyle switch
return visualStyle switch
{
ModernButtonStyle.Primary => (
_pressed ? AppTheme.AccentPressed : _hovered ? AppTheme.AccentHover : AppTheme.Accent,
_pressed ? AppTheme.AccentPressed : AppTheme.AccentHover,
pressed
? AppTheme.AccentPressed
: hovered
? AppTheme.AccentHover
: AppTheme.Accent,
pressed
? AppTheme.AccentPressed
: AppTheme.AccentHover,
Color.White),
ModernButtonStyle.Danger => (
_pressed ? Color.FromArgb(105, 47, 60) : _hovered ? Color.FromArgb(96, 47, 59) : AppTheme.DangerSoft,
_hovered ? AppTheme.Danger : Color.FromArgb(120, 58, 70),
_hovered ? Color.White : AppTheme.Danger),
pressed
? AppTheme.DangerPressed
: hovered
? AppTheme.DangerHover
: AppTheme.DangerSoft,
hovered
? AppTheme.Danger
: AppTheme.DangerBorder,
hovered
? Color.White
: AppTheme.Danger),
ModernButtonStyle.Ghost => (
_pressed ? AppTheme.SurfaceRaised : _hovered ? AppTheme.SurfaceHover : AppTheme.WindowBackground,
_hovered ? AppTheme.Border : AppTheme.WindowBackground,
pressed
? AppTheme.SurfaceRaised
: hovered
? AppTheme.SurfaceHover
: AppTheme.WindowBackground,
hovered
? AppTheme.Border
: AppTheme.WindowBackground,
AppTheme.TextSecondary),
_ => (
_pressed ? AppTheme.SurfaceHover : _hovered ? AppTheme.SurfaceHover : AppTheme.SurfaceRaised,
_hovered ? AppTheme.Accent : AppTheme.Border,
pressed || hovered
? AppTheme.SurfaceHover
: AppTheme.SurfaceRaised,
hovered
? AppTheme.Accent
: AppTheme.Border,
AppTheme.TextPrimary),
};
}
Expand Down
6 changes: 3 additions & 3 deletions src/SightAdapt/SightAdapt.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
<Copyright>Copyright © $(Company)</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/KeyffMS/SightAdapt</RepositoryUrl>
<Version>0.5.0.33</Version>
<Version>0.5.0.34</Version>
<AssemblyVersion>0.5.0.0</AssemblyVersion>
<FileVersion>0.5.0.33</FileVersion>
<InformationalVersion>0.5.0.33</InformationalVersion>
<FileVersion>0.5.0.34</FileVersion>
<InformationalVersion>0.5.0.34</InformationalVersion>
<PlatformTarget>x64</PlatformTarget>
<Platforms>x64</Platforms>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
Expand Down
133 changes: 133 additions & 0 deletions tests/SightAdapt.Tests/ConfigurationProfileManagerRefreshTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using System.Windows.Forms;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace SightAdapt.Tests;

[TestClass]
public sealed class ConfigurationProfileManagerRefreshTests
{
[TestMethod]
public void ClosingManagerWithoutChangesDoesNotRefreshConfiguration()
{
RunOnSta(() =>
{
using var temporaryDirectory =
new TemporaryDirectory();
var coordinator = CreateCoordinator(
temporaryDirectory.Path);
var managerCalls = 0;
using var form = new ConfigurationForm(
coordinator,
() => null,
(_, receivedCoordinator) =>
{
Assert.AreSame(
coordinator,
receivedCoordinator);
managerCalls++;
});
var generation = form.RefreshGeneration;

form.ManageVisualProfiles();

Assert.AreEqual(1, managerCalls);
Assert.AreEqual(
generation,
form.RefreshGeneration);
});
}

[TestMethod]
public void ManagerMutationRefreshesConfigurationExactlyOnce()
{
RunOnSta(() =>
{
using var temporaryDirectory =
new TemporaryDirectory();
var coordinator = CreateCoordinator(
temporaryDirectory.Path);
using var form = new ConfigurationForm(
coordinator,
() => null,
(_, receivedCoordinator) =>
{
var result =
receivedCoordinator.Commit(settings =>
VisualProfileManagementService.Create(
settings,
"Reader").Id);
Assert.IsTrue(result.Succeeded);
});
var generation = form.RefreshGeneration;

form.ManageVisualProfiles();

Assert.AreEqual(
generation + 1,
form.RefreshGeneration);
Assert.IsTrue(
coordinator.Current.VisualProfiles.Any(
profile => profile.Name == "Reader"));
});
}

private static SettingsCoordinator CreateCoordinator(
string directory)
{
return new SettingsCoordinator(
new SettingsStore(
Path.Combine(
directory,
"settings.json")));
}

private static void RunOnSta(Action action)
{
Exception? failure = null;
var thread = new Thread(() =>
{
try
{
action();
}
catch (Exception exception)
{
failure = exception;
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

Assert.IsTrue(
thread.Join(TimeSpan.FromSeconds(10)),
"The configuration refresh test did not finish in time.");
if (failure is not null)
{
Assert.Fail(failure.ToString());
}
}

private sealed class TemporaryDirectory : IDisposable
{
public TemporaryDirectory()
{
Path = System.IO.Path.Combine(
System.IO.Path.GetTempPath(),
"SightAdapt.Tests",
Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(Path);
}

public string Path { get; }

public void Dispose()
{
if (Directory.Exists(Path))
{
Directory.Delete(
Path,
recursive: true);
}
}
}
}
Loading
Loading