mirror of
https://github.com/cyanfish/naps2.git
synced 2024-10-03 19:07:17 +03:00
High-dpi fixes
This commit is contained in:
parent
6e33494e33
commit
233c9005ce
@ -49,12 +49,18 @@ public class MacEtoPlatform : EtoPlatform
|
||||
|
||||
public override void ConfigureImageButton(Button button, ButtonFlags flags)
|
||||
{
|
||||
var nsButton = (NSButton) button.ToNative();
|
||||
if (button.ImagePosition == ButtonImagePosition.Above)
|
||||
{
|
||||
var nsButton = (NSButton) button.ToNative();
|
||||
nsButton.ImageHugsTitle = true;
|
||||
nsButton.Title = Environment.NewLine + nsButton.Title;
|
||||
}
|
||||
var image = nsButton.Image;
|
||||
if (image.Representations() is [NSBitmapImageRep rep, ..])
|
||||
{
|
||||
image.Size = new CGSize(rep.PixelsWide / 2f, rep.PixelsHigh / 2f);
|
||||
nsButton.Image = image;
|
||||
}
|
||||
}
|
||||
|
||||
public override Bitmap ToBitmap(IMemoryImage image)
|
||||
|
@ -109,7 +109,8 @@ public abstract class EtoPlatform
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void AttachDpiDependency(Control control, Action<float> callback) => callback(1f);
|
||||
public virtual void AttachDpiDependency(Control control, Action<float> callback) =>
|
||||
callback(GetScaleFactor(control.ParentWindow));
|
||||
|
||||
public virtual SizeF GetWrappedSize(Control control, int defaultWidth)
|
||||
{
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System.Windows.Input;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
using NAPS2.Scan;
|
||||
|
||||
namespace NAPS2.EtoForms.Layout;
|
||||
|
||||
@ -93,7 +92,8 @@ public static class C
|
||||
return Button(command, command.IconName, imagePosition, flags);
|
||||
}
|
||||
|
||||
public static Button Button(ActionCommand command, string? iconName, ButtonImagePosition imagePosition = default, ButtonFlags flags = default)
|
||||
public static Button Button(ActionCommand command, string? iconName, ButtonImagePosition imagePosition = default,
|
||||
ButtonFlags flags = default)
|
||||
{
|
||||
var button = Button(command);
|
||||
if (command.Image != null)
|
||||
@ -114,8 +114,10 @@ public static class C
|
||||
button.ImagePosition = imagePosition;
|
||||
if (flags.HasFlag(ButtonFlags.LargeText))
|
||||
{
|
||||
var baseFontSize = button.Font.Size;
|
||||
EtoPlatform.Current.AttachDpiDependency(button,
|
||||
scale => button.Font = new Font(button.Font.Family, 12 * scale));
|
||||
_ => button.Font = new Font(button.Font.Family,
|
||||
baseFontSize * 4 / 3 * EtoPlatform.Current.GetLayoutScaleFactor(button.ParentWindow)));
|
||||
}
|
||||
EtoPlatform.Current.ConfigureImageButton(button, flags);
|
||||
return button;
|
||||
|
@ -35,6 +35,7 @@ public class ChooseDeviceForm : EtoDialogBase
|
||||
|
||||
private CancellationTokenSource? _getDevicesCts;
|
||||
private Driver? _activeQuery;
|
||||
private string? _statusIconName;
|
||||
|
||||
public ChooseDeviceForm(Naps2Config config, IIconProvider iconProvider,
|
||||
DeviceListViewBehavior deviceListViewBehavior, ScanningContext scanningContext,
|
||||
@ -47,8 +48,10 @@ public class ChooseDeviceForm : EtoDialogBase
|
||||
_selectDevice = C.OkButton(this, SelectDevice, UiStrings.Select);
|
||||
_deviceIconList = EtoPlatform.Current.CreateListView(deviceListViewBehavior);
|
||||
_deviceIconList.ImageSize = new Size(48, 32);
|
||||
deviceListViewBehavior.SetImage(AlwaysAskMarker, iconProvider.GetIcon("ask")!);
|
||||
deviceListViewBehavior.SetImage(ManualIpMarker, iconProvider.GetIcon("network_ip")!);
|
||||
deviceListViewBehavior.SetIconName(AlwaysAskMarker, "ask");
|
||||
deviceListViewBehavior.SetIconName(ManualIpMarker, "network_ip");
|
||||
|
||||
EtoPlatform.Current.AttachDpiDependency(this, _ => UpdateStatusIcon());
|
||||
|
||||
_deviceTextList.Activated += (_, _) => _selectDevice.PerformClick();
|
||||
_deviceIconList.ItemClicked += (_, _) => _selectDevice.PerformClick();
|
||||
@ -62,6 +65,15 @@ public class ChooseDeviceForm : EtoDialogBase
|
||||
_textListVis.IsVisible = config.Get(c => c.DeviceListAsTextOnly);
|
||||
}
|
||||
|
||||
private void UpdateStatusIcon()
|
||||
{
|
||||
if (_statusIconName != null)
|
||||
{
|
||||
_statusIcon.Image = _iconProvider.GetIcon(_statusIconName, EtoPlatform.Current.GetScaleFactor(this));
|
||||
_statusIcon.Size = Size.Round(new SizeF(16, 16) * EtoPlatform.Current.GetLayoutScaleFactor(this));
|
||||
}
|
||||
}
|
||||
|
||||
private void Driver_MouseUp(object? sender, EventArgs e)
|
||||
{
|
||||
QueryForDevices();
|
||||
@ -274,10 +286,8 @@ public class ChooseDeviceForm : EtoDialogBase
|
||||
if (!cts.IsCancellationRequested)
|
||||
{
|
||||
_spinnerVis.IsVisible = false;
|
||||
_statusIcon.Image =
|
||||
DeviceList.Count > 0
|
||||
? _iconProvider.GetIcon("accept_small")
|
||||
: _iconProvider.GetIcon("exclamation_small");
|
||||
_statusIconName = DeviceList.Count > 0 ? "accept_small" : "exclamation_small";
|
||||
UpdateStatusIcon();
|
||||
_statusLabel.Text = DeviceList.Count switch
|
||||
{
|
||||
> 1 => string.Format(UiStrings.DevicesFound, DeviceList.Count),
|
||||
@ -294,7 +304,8 @@ public class ChooseDeviceForm : EtoDialogBase
|
||||
if (!cts.IsCancellationRequested)
|
||||
{
|
||||
_spinnerVis.IsVisible = false;
|
||||
_statusIcon.Image = _iconProvider.GetIcon("exclamation_small");
|
||||
_statusIconName = "exclamation_small";
|
||||
UpdateStatusIcon();
|
||||
_statusLabel.Text = ex.Message;
|
||||
}
|
||||
});
|
||||
|
@ -68,7 +68,8 @@ public class DesktopCommands
|
||||
};
|
||||
SaveAll = new ActionCommand(imageListActions.SaveAllAsPdfOrImages)
|
||||
{
|
||||
Text = UiStrings.SaveAll
|
||||
Text = UiStrings.SaveAll,
|
||||
IconName = "diskette"
|
||||
};
|
||||
SaveSelected = new ActionCommand(imageListActions.SaveSelectedAsPdfOrImages)
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ namespace NAPS2.EtoForms.Widgets;
|
||||
public class DeviceListViewBehavior : ListViewBehavior<ScanDevice>
|
||||
{
|
||||
private readonly Dictionary<ScanDevice, Image> _imageMap = new();
|
||||
private readonly Dictionary<ScanDevice, string> _iconNameMap = new();
|
||||
|
||||
public DeviceListViewBehavior(ColorScheme colorScheme) : base(colorScheme)
|
||||
{
|
||||
@ -16,10 +17,19 @@ public class DeviceListViewBehavior : ListViewBehavior<ScanDevice>
|
||||
|
||||
public void SetImage(ScanDevice item, Image image) => _imageMap[item] = image;
|
||||
|
||||
public void SetIconName(ScanDevice item, string iconName) => _iconNameMap[item] = iconName;
|
||||
|
||||
public override string GetLabel(ScanDevice item) => item.Name;
|
||||
|
||||
public override Image GetImage(IListView<ScanDevice> listView, ScanDevice item)
|
||||
{
|
||||
return (_imageMap.Get(item)?.Clone() ?? Icons.device.ToEtoImage()).PadTo(listView.ImageSize);
|
||||
float scale = EtoPlatform.Current.GetScaleFactor(listView.Control.ParentWindow);
|
||||
if (_imageMap.Get(item) is { } image)
|
||||
{
|
||||
int scaledSize = (int) Math.Round(48 * scale);
|
||||
return image.Clone().ResizeTo(scaledSize).PadTo(listView.ImageSize);
|
||||
}
|
||||
string iconName = _iconNameMap.Get(item) ?? "device";
|
||||
return EtoPlatform.Current.IconProvider.GetIcon(iconName, scale)!.PadTo(listView.ImageSize);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System.Threading;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
using NAPS2.EtoForms.Layout;
|
||||
using NAPS2.Scan;
|
||||
@ -19,6 +20,8 @@ public class DeviceSelectorWidget
|
||||
private readonly Button _chooseDevice = new() { Text = UiStrings.ChooseDevice };
|
||||
|
||||
private DeviceChoice _choice = DeviceChoice.None;
|
||||
private Image? _deviceIconImage;
|
||||
private string _deviceIconName = "device";
|
||||
private CancellationTokenSource? _loadIconCts;
|
||||
|
||||
public DeviceSelectorWidget(IScanPerformer scanPerformer, DeviceCapsCache deviceCapsCache,
|
||||
@ -29,6 +32,7 @@ public class DeviceSelectorWidget
|
||||
_iconProvider = iconProvider;
|
||||
_parentWindow = parentWindow;
|
||||
_chooseDevice.Click += ChooseDevice;
|
||||
EtoPlatform.Current.AttachDpiDependency(_deviceIcon, _ => UpdateDeviceIconImage());
|
||||
}
|
||||
|
||||
public required Func<ScanProfile> ProfileFunc { get; init; }
|
||||
@ -76,7 +80,6 @@ public class DeviceSelectorWidget
|
||||
|
||||
private async void ChooseDevice(object? sender, EventArgs args)
|
||||
{
|
||||
;
|
||||
var choice = await _scanPerformer.PromptForDevice(ProfileFunc(), AllowAlwaysAsk, _parentWindow.NativeHandle);
|
||||
if (choice.Device != null || choice.AlwaysAsk)
|
||||
{
|
||||
@ -90,15 +93,15 @@ public class DeviceSelectorWidget
|
||||
|
||||
public void SetDeviceIcon(string? iconUri)
|
||||
{
|
||||
var cachedIcon = _deviceCapsCache.GetCachedIcon(iconUri);
|
||||
EtoPlatform.Current.AttachDpiDependency(_deviceIcon, scale =>
|
||||
_deviceIcon.Image =
|
||||
cachedIcon ?? (_choice.AlwaysAsk ? _iconProvider.GetIcon("ask", scale) : _iconProvider.GetIcon("device", scale)));
|
||||
_deviceIconImage = _deviceCapsCache.GetCachedIcon(iconUri);
|
||||
_deviceIconName = _choice.AlwaysAsk ? "ask" : "device";
|
||||
UpdateDeviceIconImage();
|
||||
|
||||
if (((Window) _parentWindow).Loaded)
|
||||
{
|
||||
_parentWindow.LayoutController.Invalidate();
|
||||
}
|
||||
if (cachedIcon == null && iconUri != null)
|
||||
if (_deviceIconImage == null && iconUri != null)
|
||||
{
|
||||
ReloadDeviceIcon(iconUri);
|
||||
}
|
||||
@ -118,7 +121,8 @@ public class DeviceSelectorWidget
|
||||
{
|
||||
if (!cts.IsCancellationRequested)
|
||||
{
|
||||
_deviceIcon.Image = icon;
|
||||
_deviceIconImage = icon;
|
||||
UpdateDeviceIconImage();
|
||||
_parentWindow.LayoutController.Invalidate();
|
||||
}
|
||||
});
|
||||
@ -126,6 +130,14 @@ public class DeviceSelectorWidget
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateDeviceIconImage()
|
||||
{
|
||||
float scale = EtoPlatform.Current.GetScaleFactor(_deviceIcon.ParentWindow);
|
||||
_deviceIcon.Image = _deviceIconImage ?? _iconProvider.GetIcon(_deviceIconName, scale);
|
||||
var size = _deviceIconImage != null ? new SizeF(48, 48) : new SizeF(32, 32);
|
||||
_deviceIcon.Size = Size.Round(size * EtoPlatform.Current.GetLayoutScaleFactor(_deviceIcon.ParentWindow));
|
||||
}
|
||||
|
||||
public static implicit operator LayoutElement(DeviceSelectorWidget control)
|
||||
{
|
||||
return control.AsControl();
|
||||
@ -142,11 +154,8 @@ public class DeviceSelectorWidget
|
||||
_deviceDriver,
|
||||
C.Filler()
|
||||
).Spacing(5).Visible(_deviceVis).Scale(),
|
||||
// TODO: We should probably have a compact choose-device button for the sidebar.
|
||||
// It should also change the name of the profile if it matches the device name.
|
||||
// i.e. for users that are naming their own profiles, its their responsibility to keep the devices
|
||||
// matched up. For a "basic" user that might only create one profile, its name should keep matched
|
||||
// with the device.
|
||||
// TODO: We can consider a compact choose-device button for the sidebar, but maybe simpler to force
|
||||
// creation of separate profiles
|
||||
ShowChooseDevice ? _chooseDevice.AlignCenter() : C.None()
|
||||
)
|
||||
);
|
||||
|
@ -6,8 +6,6 @@ namespace NAPS2.Scan;
|
||||
|
||||
public class DeviceCapsCache
|
||||
{
|
||||
private const int ICON_SIZE = 48;
|
||||
|
||||
private readonly Dictionary<DeviceKey, ScanCaps> _capsCache = new();
|
||||
private readonly Dictionary<string, Image> _iconCache = new();
|
||||
|
||||
@ -120,7 +118,7 @@ public class DeviceCapsCache
|
||||
var imageBytes = await client.GetByteArrayAsync(iconUri);
|
||||
image = _imageContext.Load(imageBytes);
|
||||
}
|
||||
return image.PerformTransform(new ThumbnailTransform(ICON_SIZE)).ToEtoImage();
|
||||
return image.ToEtoImage();
|
||||
}
|
||||
|
||||
private DeviceKey GetDeviceKey(ScanProfile profile)
|
||||
|
Loading…
Reference in New Issue
Block a user