Skip to content

Commit

Permalink
WinForms: Dark mode
Browse files Browse the repository at this point in the history
  • Loading branch information
cyanfish committed Aug 31, 2024
1 parent 11f3dad commit 67e17ee
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 24 deletions.
2 changes: 1 addition & 1 deletion NAPS2.Lib.Gtk/EtoForms/Gtk/GtkEtoPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ public override Control AccessibleImageButton(Image image, string text, Action o
return button.ToEto();
}

public override void ConfigureZoomButton(Button button, string icon)
public override void ConfigureZoomButton(Button button, string icon, ColorScheme colorScheme)
{
var gtkButton = button.ToNative();
button.Text = "";
Expand Down
15 changes: 15 additions & 0 deletions NAPS2.Lib.WinForms/EtoForms/Ui/WinFormsDesktopForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ public WinFormsDesktopForm(

// TODO: Remove this if https://github.com/picoe/Eto/issues/2601 is fixed
NativeListView.KeyDown += (_, e) => OnKeyDown(new KeyEventArgs(e.KeyData.ToEto(), KeyEventType.KeyDown));

Load += (_, _) => colorScheme.ColorSchemeChanged += ColorSchemeChanged;
UnLoad += (_, _) => colorScheme.ColorSchemeChanged -= ColorSchemeChanged;
}

private void ColorSchemeChanged(object? sender, EventArgs e)
{
Invoker.Current.InvokeDispatch(() =>
{
if (WF.Application.OpenForms.Count == 1)
{
// Reload the form as WinForms dark mode doesn't dynamically switch everything
SetCulture(Config.Get(c => c.Culture) ?? "en");
}
});
}

protected override void OnClosing(CancelEventArgs e)
Expand Down
21 changes: 10 additions & 11 deletions NAPS2.Lib.WinForms/EtoForms/WinForms/WinFormsDarkModeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@

namespace NAPS2.EtoForms.WinForms;

public class WinFormsDarkModeProvider : IDarkModeProvider, IMessageFilter
public class WinFormsDarkModeProvider : IDarkModeProvider
{
private const int WM_SETTINGCHANGE = 0x1A;
private const int WM_REFLECT = 0x2000;

private bool? _value;

public WinFormsDarkModeProvider()
{
Application.AddMessageFilter(this);
SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged;
}

public bool IsDarkModeEnabled => _value ??= ReadDarkMode();
Expand All @@ -33,15 +30,17 @@ private bool ReadDarkMode()

public event EventHandler? DarkModeChanged;

public bool PreFilterMessage(ref Message m)
private void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
if (m.Msg is WM_SETTINGCHANGE or (WM_SETTINGCHANGE | WM_REFLECT))
var newValue = ReadDarkMode();
if (newValue != _value)
{
// TODO: Maybe we can narrow down the changed setting based on lParam?
// https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-settingchange
_value = null;
_value = newValue;
// WinForms dark mode is experimental
#pragma warning disable WFO5001
Application.SetColorMode(newValue ? SystemColorMode.Dark : SystemColorMode.Classic);
#pragma warning restore WFO5001
DarkModeChanged?.Invoke(this, EventArgs.Empty);
}
return false;
}
}
8 changes: 6 additions & 2 deletions NAPS2.Lib.WinForms/EtoForms/WinForms/WinFormsEtoPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public override Application CreateApplication()
WF.Application.EnableVisualStyles();
WF.Application.SetCompatibleTextRenderingDefault(false);
WF.Application.SetHighDpiMode(WF.HighDpiMode.PerMonitorV2);
// WinForms dark mode is experimental
#pragma warning disable WFO5001
WF.Application.SetColorMode(WF.SystemColorMode.System);
#pragma warning restore WFO5001
return new Application(Eto.Platforms.WinForms);
}

Expand Down Expand Up @@ -279,7 +283,7 @@ public override void SetImageSize(ButtonToolItem menuItem, int size)
handler.ImageSize = size;
}

public override void ConfigureZoomButton(Button button, string icon)
public override void ConfigureZoomButton(Button button, string icon, ColorScheme colorScheme)
{
AttachDpiDependency(button, scale =>
{
Expand All @@ -289,7 +293,7 @@ public override void ConfigureZoomButton(Button button, string icon)
var wfButton = (WF.Button) button.ToNative();
wfButton.AccessibleName = button.Text;
wfButton.Text = "";
wfButton.BackColor = SD.Color.White;
wfButton.BackColor = colorScheme.BackgroundColor.ToSD();
wfButton.FlatStyle = WF.FlatStyle.Flat;
}

Expand Down
8 changes: 4 additions & 4 deletions NAPS2.Lib.WinForms/EtoForms/WinForms/WinFormsListView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ namespace NAPS2.EtoForms.WinForms;

public class WinFormsListView<T> : IListView<T> where T : notnull
{
private static readonly Pen DefaultPen = new(Color.Black, 1);
private Pen DefaultPen => new(_behavior.ColorScheme.ForegroundColor.ToSD(), 1);
private static readonly Pen BasicSelectionPen = new(Color.FromArgb(0x60, 0xa0, 0xe8), 3);
private const int PageNumberTextPadding = 6;
private const int PageNumberSelectionPadding = 3;
private static readonly SolidBrush PageNumberOutlineBrush = new(Color.FromArgb(0x60, 0xa0, 0xe8));
private static readonly SolidBrush PageNumberSelectionBrush = new(Color.FromArgb(0xcc, 0xe8, 0xff));
private SolidBrush PageNumberOutlineBrush => new(_behavior.ColorScheme.HighlightBorderColor.ToSD());
private SolidBrush PageNumberSelectionBrush => new(_behavior.ColorScheme.HighlightBackgroundColor.ToSD());
private static readonly StringFormat PageNumberLabelFormat = new()
{ Alignment = StringAlignment.Center, Trimming = StringTrimming.EllipsisCharacter };

Expand Down Expand Up @@ -141,7 +141,7 @@ private void CustomRenderItem(object? sender, DrawListViewItemEventArgs e)
e.Graphics.DrawImage(image, new Rectangle(x, y, width, height));

// Draw the text below the image
var drawBrush = Brushes.Black;
var drawBrush = new SolidBrush(_behavior.ColorScheme.ForegroundColor.ToSD());
float x1 = x + width / 2f;
float y1 = y + height + tp;
RectangleF labelRect = new(x1, y1, 0, textSize.Height);
Expand Down
3 changes: 1 addition & 2 deletions NAPS2.Lib.WinForms/Modules/WinFormsModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ protected override void Load(ContainerBuilder builder)

builder.RegisterType<WindowsApplicationLifecycle>().As<ApplicationLifecycle>();
builder.RegisterType<PrintDocumentPrinter>().As<IScannedImagePrinter>();
// TODO: Change this when implementing dark mode on Windows
builder.RegisterType<StubDarkModeProvider>().As<IDarkModeProvider>().SingleInstance();
builder.RegisterType<WinFormsDarkModeProvider>().As<IDarkModeProvider>().SingleInstance();
builder.RegisterType<WindowsServiceManager>().As<IOsServiceManager>().SingleInstance();

builder.RegisterType<WinFormsDesktopForm>().As<DesktopForm>();
Expand Down
8 changes: 8 additions & 0 deletions NAPS2.Lib/EtoForms/ColorScheme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ public class ColorScheme
private static readonly Color MidGray = Color.FromRgb(0x606060);
private static readonly Color LightGray = Color.FromRgb(0xdddddd);
private static readonly Color HighlightBlue = Color.FromRgb(0x007bff);
private static readonly Color MidBlue = Color.FromRgb(0x60a0e8);
private static readonly Color PaleBlue = Color.FromRgb(0xcce8ff);
private static readonly Color DarkGrayBlue = Color.FromRgb(0x28445b);
private static readonly Color DarkOutlineBlue = Color.FromRgb(0x0078d4);

private readonly IDarkModeProvider _darkModeProvider;

Expand All @@ -29,6 +33,10 @@ public ColorScheme(IDarkModeProvider darkModeProvider)

public Color CropColor => DarkMode ? HighlightBlue : Colors.Black;

public Color HighlightBorderColor => DarkMode ? DarkOutlineBlue : MidBlue;

public Color HighlightBackgroundColor => DarkMode ? DarkGrayBlue : PaleBlue;

public Color NotificationBackgroundColor => DarkMode ? Color.FromRgb(0x323232) : Color.FromRgb(0xf2f2f2);

public Color NotificationBorderColor => DarkMode ? Color.FromRgb(0x606060) : Color.FromRgb(0xb2b2b2);
Expand Down
3 changes: 2 additions & 1 deletion NAPS2.Lib/EtoForms/EtoPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public virtual void InitForm(Window window)
{
}

public virtual void ConfigureZoomButton(Button button, string icon)
public virtual void ConfigureZoomButton(Button button, string icon, ColorScheme colorScheme)
{
}

Expand Down Expand Up @@ -131,6 +131,7 @@ public virtual void ShowIcon(Dialog dialog)

public virtual void ConfigureEllipsis(Label label)
{
// TODO: Maybe implement our own ellipsis logic that uses text-measuring to strip trailing characters and add "..."?
}

public virtual Bitmap? ExtractAssociatedIcon(string exePath) => throw new NotSupportedException();
Expand Down
6 changes: 3 additions & 3 deletions NAPS2.Lib/EtoForms/Ui/DesktopForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -446,16 +446,16 @@ protected virtual LayoutElement GetControlButtons()
protected LayoutElement GetSidebarButton()
{
var toggleSidebar = C.ImageButton(Commands.ToggleSidebar);
EtoPlatform.Current.ConfigureZoomButton(toggleSidebar, "application_side_list_small");
EtoPlatform.Current.ConfigureZoomButton(toggleSidebar, "application_side_list_small", _colorScheme);
return toggleSidebar.AlignTrailing();
}

protected LayoutElement GetZoomButtons()
{
var zoomIn = C.ImageButton(Commands.ZoomIn);
EtoPlatform.Current.ConfigureZoomButton(zoomIn, "zoom_in_small");
EtoPlatform.Current.ConfigureZoomButton(zoomIn, "zoom_in_small", _colorScheme);
var zoomOut = C.ImageButton(Commands.ZoomOut);
EtoPlatform.Current.ConfigureZoomButton(zoomOut, "zoom_out_small");
EtoPlatform.Current.ConfigureZoomButton(zoomOut, "zoom_out_small", _colorScheme);
return L.Row(zoomOut.AlignTrailing(), zoomIn.AlignTrailing()).Spacing(-1);
}

Expand Down

0 comments on commit 67e17ee

Please sign in to comment.