mirror of
https://github.com/cyanfish/naps2.git
synced 2024-10-03 19:07:17 +03:00
Compare commits
8 Commits
0e5a442b86
...
1d69f4852d
Author | SHA1 | Date | |
---|---|---|---|
|
1d69f4852d | ||
|
774efbbd54 | ||
|
5b3d5607e8 | ||
|
67e17ee2cb | ||
|
11f3dad8b3 | ||
|
abff5c5cb8 | ||
|
c5b0703e15 | ||
|
b78bae06d3 |
@ -19,6 +19,7 @@ public class GtkEtoPlatform : EtoPlatform
|
||||
public override bool IsGtk => true;
|
||||
|
||||
public override IIconProvider IconProvider { get; } = new DefaultIconProvider();
|
||||
public override IDarkModeProvider DarkModeProvider { get; } = new GtkDarkModeProvider();
|
||||
|
||||
public override Application CreateApplication()
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ public static class GtkEtoExtensions
|
||||
// physical size, which will look too big and blurry. To get an actual crisp image rendered at 32x32 logical
|
||||
// pixels and 64x64 physical pixels, we first create a surface with a 2x scale factor and then create the
|
||||
// Gtk.Image from that.
|
||||
var surface = Gdk.CairoHelper.SurfaceCreateFromPixbuf(pixbuf, scaleFactor, null);
|
||||
using var surface = Gdk.CairoHelper.SurfaceCreateFromPixbuf(pixbuf, scaleFactor, null);
|
||||
return new Image(surface);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ public class MacEtoPlatform : EtoPlatform
|
||||
public override bool IsMac => true;
|
||||
|
||||
public override IIconProvider IconProvider { get; } = new MacIconProvider(new DefaultIconProvider());
|
||||
public override IDarkModeProvider DarkModeProvider { get; } = new MacDarkModeProvider();
|
||||
|
||||
public override void InitializePlatform()
|
||||
{
|
||||
@ -102,6 +103,8 @@ public class MacEtoPlatform : EtoPlatform
|
||||
control.ToNative().RemoveFromSuperview();
|
||||
}
|
||||
|
||||
public override float GetScaleFactor(Window window) => 2f;
|
||||
|
||||
public override Control AccessibleImageButton(Image image, String text, Action onClick,
|
||||
int xOffset = 0, int yOffset = 0)
|
||||
{
|
||||
|
@ -35,8 +35,6 @@ public class MacDesktopForm : DesktopForm
|
||||
thumbnailController, thumbnailProvider, desktopController, desktopScanController, imageListActions,
|
||||
imageListViewBehavior, desktopFormProvider, desktopSubFormController, commands, sidebar, iconProvider)
|
||||
{
|
||||
// For retina screens
|
||||
_thumbnailController.Oversample = 2.0;
|
||||
}
|
||||
|
||||
protected override void UpdateTitle(ScanProfile? defaultProfile)
|
||||
|
@ -51,6 +51,21 @@ public class WinFormsDesktopForm : DesktopForm
|
||||
|
||||
// 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)
|
||||
|
@ -3,16 +3,13 @@ using Microsoft.Win32;
|
||||
|
||||
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();
|
||||
@ -33,15 +30,17 @@ public class WinFormsDarkModeProvider : IDarkModeProvider, IMessageFilter
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -24,12 +24,17 @@ public class WinFormsEtoPlatform : EtoPlatform
|
||||
public override bool IsWinForms => true;
|
||||
|
||||
public override IIconProvider IconProvider { get; } = new DefaultIconProvider();
|
||||
public override IDarkModeProvider DarkModeProvider { get; } = new WinFormsDarkModeProvider();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -265,6 +270,8 @@ public class WinFormsEtoPlatform : EtoPlatform
|
||||
|
||||
public override float GetScaleFactor(Window window) => window.ToNative().DeviceDpi / 96f;
|
||||
|
||||
public override bool ScaleLayout => true;
|
||||
|
||||
public override void SetImageSize(ButtonMenuItem menuItem, int size)
|
||||
{
|
||||
var handler = (ButtonMenuItemHandler) menuItem.Handler;
|
||||
@ -287,7 +294,7 @@ public class WinFormsEtoPlatform : EtoPlatform
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 };
|
||||
|
||||
@ -141,12 +141,13 @@ public class WinFormsListView<T> : IListView<T> where T : notnull
|
||||
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);
|
||||
float maxLabelWidth = Math.Min(textSize.Width, e.Bounds.Width - 2 * tp);
|
||||
labelRect.Inflate(maxLabelWidth / 2, 0);
|
||||
labelRect.Width += 2;
|
||||
e.Graphics.DrawString(label, _view.Font, drawBrush, labelRect, PageNumberLabelFormat);
|
||||
|
||||
// Draw unselected border
|
||||
|
@ -15,8 +15,7 @@ public class WinFormsModule : GuiModule
|
||||
|
||||
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>();
|
||||
|
@ -11,15 +11,21 @@ public class ToolStripDoubleButton : ToolStripButton
|
||||
public event EventHandler? FirstClick;
|
||||
public event EventHandler? SecondClick;
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public Image? FirstImage { get; set; }
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public Image? SecondImage { get; set; }
|
||||
|
||||
[Localizable(true)]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public required string FirstText { get; init; }
|
||||
|
||||
[Localizable(true)]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public required string SecondText { get; init; }
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public int MaxTextWidth { get; init; }
|
||||
|
||||
public override Size GetPreferredSize(Size constrainingSize)
|
||||
|
@ -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;
|
||||
|
||||
@ -29,9 +33,15 @@ public class ColorScheme
|
||||
|
||||
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);
|
||||
|
||||
public Color LinkColor => DarkMode ? Color.FromRgb(0x60cdff) : Color.FromRgb(0x0000ff);
|
||||
|
||||
public event EventHandler? ColorSchemeChanged;
|
||||
}
|
@ -15,11 +15,18 @@ public abstract class EtoPlatform
|
||||
set => _current = value ?? throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
protected EtoPlatform()
|
||||
{
|
||||
ColorScheme = new ColorScheme(DarkModeProvider);
|
||||
}
|
||||
|
||||
public virtual bool IsGtk => false;
|
||||
public virtual bool IsMac => false;
|
||||
public virtual bool IsWinForms => false;
|
||||
|
||||
public abstract IIconProvider IconProvider { get; }
|
||||
public abstract IDarkModeProvider DarkModeProvider { get; }
|
||||
public ColorScheme ColorScheme { get; }
|
||||
|
||||
public abstract Application CreateApplication();
|
||||
public abstract IListView<T> CreateListView<T>(ListViewBehavior<T> behavior) where T : notnull;
|
||||
@ -131,6 +138,7 @@ public abstract class EtoPlatform
|
||||
|
||||
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();
|
||||
@ -152,6 +160,8 @@ public abstract class EtoPlatform
|
||||
|
||||
public virtual float GetScaleFactor(Window window) => 1;
|
||||
|
||||
public virtual bool ScaleLayout => false;
|
||||
|
||||
public virtual void SetImageSize(ButtonMenuItem menuItem, int size)
|
||||
{
|
||||
}
|
||||
|
@ -15,22 +15,6 @@ public static class C
|
||||
public static Label NoWrap(string text) =>
|
||||
new Label { Text = text, Wrap = WrapMode.None };
|
||||
|
||||
/// <summary>
|
||||
/// Creates a link button with the given URL as both text and click action.
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="label"></param>
|
||||
/// <returns></returns>
|
||||
public static LinkButton UrlLink(string url, string? label = null)
|
||||
{
|
||||
void OnClick() => ProcessHelper.OpenUrl(url);
|
||||
return new LinkButton
|
||||
{
|
||||
Text = label ?? url,
|
||||
Command = new ActionCommand(OnClick)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a link button with the specified text.
|
||||
/// </summary>
|
||||
@ -38,7 +22,13 @@ public static class C
|
||||
/// <returns></returns>
|
||||
public static LinkButton Link(string text)
|
||||
{
|
||||
return new LinkButton { Text = text };
|
||||
var link = new LinkButton { Text = text };
|
||||
if (EtoPlatform.Current.IsWinForms)
|
||||
{
|
||||
// TODO: Remove this when https://github.com/dotnet/winforms/issues/11935 is fixed
|
||||
link.TextColor = EtoPlatform.Current.ColorScheme.LinkColor;
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -49,11 +39,21 @@ public static class C
|
||||
/// <returns></returns>
|
||||
public static LinkButton Link(string text, Action onClick)
|
||||
{
|
||||
return new LinkButton
|
||||
{
|
||||
Text = text,
|
||||
Command = new ActionCommand(onClick)
|
||||
};
|
||||
var link = Link(text);
|
||||
link.Command = new ActionCommand(onClick);
|
||||
return link;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a link button with the given URL as both text and click action.
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="label"></param>
|
||||
/// <returns></returns>
|
||||
public static LinkButton UrlLink(string url, string? label = null)
|
||||
{
|
||||
void OnClick() => ProcessHelper.OpenUrl(url);
|
||||
return Link(label ?? url, OnClick);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -132,7 +132,7 @@ public class LayoutController
|
||||
DefaultSpacing = DefaultSpacing,
|
||||
DefaultLabelSpacing = DefaultLabelSpacing,
|
||||
Invalidate = Invalidate,
|
||||
Scale = EtoPlatform.Current.GetScaleFactor(_window!)
|
||||
Scale = EtoPlatform.Current.ScaleLayout ? EtoPlatform.Current.GetScaleFactor(_window!) : 1f
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,8 @@ public class LinkNotificationView : NotificationView
|
||||
private readonly string? _folderTarget;
|
||||
|
||||
private readonly Label _label = new();
|
||||
private readonly LinkButton _link = new();
|
||||
private readonly ContextMenu _contextMenu = new();
|
||||
private readonly LinkButton _link;
|
||||
|
||||
protected LinkNotificationView(
|
||||
NotificationModel model, string title, string linkLabel, string? linkTarget, string? folderTarget)
|
||||
@ -19,7 +19,7 @@ public class LinkNotificationView : NotificationView
|
||||
{
|
||||
_label.Text = title;
|
||||
_label.Font = new Font(_label.Font.Family, _label.Font.Size, FontStyle.Bold);
|
||||
_link.Text = linkLabel;
|
||||
_link = C.Link(linkLabel);
|
||||
_linkTarget = linkTarget;
|
||||
_folderTarget = folderTarget;
|
||||
|
||||
|
@ -136,15 +136,6 @@ public abstract class DesktopForm : EtoFormBase
|
||||
).Padding(8)
|
||||
).Scale()
|
||||
);
|
||||
|
||||
UpdateColors();
|
||||
// TODO: Memory leak?
|
||||
_colorScheme.ColorSchemeChanged += (_, _) => UpdateColors();
|
||||
}
|
||||
|
||||
protected virtual void UpdateColors()
|
||||
{
|
||||
// TODO: Do something here or in inheritors?
|
||||
}
|
||||
|
||||
private void OpeningContextMenu(object? sender, EventArgs e)
|
||||
|
@ -27,7 +27,7 @@ public class EditProfileForm : EtoDialogBase
|
||||
private readonly EnumDropDownWidget<ScanHorizontalAlign> _horAlign = new();
|
||||
private readonly EnumDropDownWidget<ScanScale> _scale = new();
|
||||
private readonly CheckBox _enableAutoSave = new() { Text = UiStrings.EnableAutoSave };
|
||||
private readonly LinkButton _autoSaveSettings = new() { Text = UiStrings.AutoSaveSettings };
|
||||
private readonly LinkButton _autoSaveSettings = C.Link(UiStrings.AutoSaveSettings);
|
||||
private readonly Button _advanced = new() { Text = UiStrings.Advanced };
|
||||
private readonly SliderWithTextBox _brightnessSlider = new();
|
||||
private readonly SliderWithTextBox _contrastSlider = new();
|
||||
|
@ -139,7 +139,7 @@ public class ProfilesForm : EtoDialogBase
|
||||
|
||||
LayoutController.Content = L.Column(
|
||||
L.Row(
|
||||
_listView.Control.Scale(),
|
||||
_listView.Control.NaturalSize(150, 100).Scale(),
|
||||
C.Button(_scanCommand, "control_play_blue", ButtonImagePosition.Above, ButtonFlags.LargeIcon)
|
||||
.Height(80)
|
||||
).Aligned().Scale(),
|
||||
|
Loading…
Reference in New Issue
Block a user