mirror of
https://github.com/QL-Win/QuickLook.git
synced 2026-05-08 03:06:29 +08:00
Merged QuickLook.Common from submodule
https://github.com/QL-Win/QuickLook.Common/commit/529d07b56577b88329481cdac8f2a6a175b6c21a
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace QuickLook.Common.Commands;
|
||||
|
||||
public class AsyncRelayCommand(Func<Task> execute, Func<bool> canExecute = null) : ICommand
|
||||
{
|
||||
private readonly Func<Task> _execute = execute ?? throw new ArgumentNullException(nameof(execute));
|
||||
private readonly Func<bool> _canExecute = canExecute ?? (() => true);
|
||||
private bool _isExecuting;
|
||||
|
||||
public bool CanExecute(object parameter)
|
||||
{
|
||||
return !_isExecuting && _canExecute();
|
||||
}
|
||||
|
||||
public async void Execute(object parameter)
|
||||
{
|
||||
if (!CanExecute(parameter))
|
||||
return;
|
||||
|
||||
_isExecuting = true;
|
||||
RaiseCanExecuteChanged();
|
||||
try
|
||||
{
|
||||
await _execute();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isExecuting = false;
|
||||
RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
public void RaiseCanExecuteChanged()
|
||||
{
|
||||
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace QuickLook.Common.Commands;
|
||||
|
||||
public class RelayCommand(Action execute, Func<bool> canExecute = null) : ICommand
|
||||
{
|
||||
private readonly Action _execute = execute;
|
||||
private readonly Func<bool> _canExecute = canExecute;
|
||||
|
||||
public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
|
||||
|
||||
public void Execute(object parameter) => _execute();
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
public void RaiseCanExecuteChanged() =>
|
||||
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,143 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using PixelFormat = System.Windows.Media.PixelFormat;
|
||||
|
||||
namespace QuickLook.Common.ExtensionMethods;
|
||||
|
||||
public static class BitmapExtensions
|
||||
{
|
||||
public static BitmapSource ToBitmapSource(this Bitmap source)
|
||||
{
|
||||
var orgSource = source;
|
||||
BitmapSource bs = null;
|
||||
try
|
||||
{
|
||||
var data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
|
||||
ImageLockMode.ReadOnly, source.PixelFormat);
|
||||
|
||||
// BitmapSource.Create throws an exception when the image is scanned backward.
|
||||
// The Clone() will make it back scanning forward.
|
||||
if (data.Stride < 0)
|
||||
{
|
||||
source.UnlockBits(data);
|
||||
source = (Bitmap)source.Clone();
|
||||
data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
|
||||
ImageLockMode.ReadOnly, source.PixelFormat);
|
||||
}
|
||||
|
||||
bs = BitmapSource.Create(source.Width, source.Height, Math.Floor(source.HorizontalResolution),
|
||||
Math.Floor(source.VerticalResolution), ConvertPixelFormat(source.PixelFormat), null,
|
||||
data.Scan0, data.Stride * source.Height, data.Stride);
|
||||
|
||||
source.UnlockBits(data);
|
||||
|
||||
bs.Freeze();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (orgSource != source)
|
||||
source.Dispose();
|
||||
}
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static Bitmap ToBitmap(this BitmapSource source)
|
||||
{
|
||||
using var outStream = new MemoryStream();
|
||||
BitmapEncoder enc = new BmpBitmapEncoder();
|
||||
enc.Frames.Add(BitmapFrame.Create(source));
|
||||
enc.Save(outStream);
|
||||
using var bitmap = new Bitmap(outStream);
|
||||
|
||||
return new Bitmap(bitmap);
|
||||
}
|
||||
|
||||
private static PixelFormat ConvertPixelFormat(
|
||||
System.Drawing.Imaging.PixelFormat sourceFormat)
|
||||
{
|
||||
return sourceFormat switch
|
||||
{
|
||||
System.Drawing.Imaging.PixelFormat.Format24bppRgb => PixelFormats.Bgr24,
|
||||
System.Drawing.Imaging.PixelFormat.Format32bppArgb => PixelFormats.Bgra32,
|
||||
System.Drawing.Imaging.PixelFormat.Format32bppRgb => PixelFormats.Bgr32,
|
||||
_ => new PixelFormat(),
|
||||
};
|
||||
}
|
||||
|
||||
public static bool IsDarkImage(this Bitmap image)
|
||||
{
|
||||
// convert to 24-bit RGB image
|
||||
image = image.Clone(new Rectangle(0, 0, image.Width, image.Height),
|
||||
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
|
||||
|
||||
var sampleCount = (int)(0.2 * 400 * 400);
|
||||
const int pixelSize = 24 / 8;
|
||||
var data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
|
||||
ImageLockMode.ReadWrite, image.PixelFormat);
|
||||
|
||||
var darks = 0;
|
||||
unsafe
|
||||
{
|
||||
var pFirst = (byte*)data.Scan0;
|
||||
|
||||
Parallel.For(0, sampleCount, n =>
|
||||
{
|
||||
var rand = new Random(n);
|
||||
var row = rand.Next(0, data.Height);
|
||||
var col = rand.Next(0, data.Width);
|
||||
var pos = pFirst + row * data.Stride + col * pixelSize;
|
||||
|
||||
var b = pos[0];
|
||||
var g = pos[1];
|
||||
var r = pos[2];
|
||||
|
||||
var y = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
||||
|
||||
if (y < 0.5)
|
||||
darks++;
|
||||
});
|
||||
}
|
||||
|
||||
image.UnlockBits(data);
|
||||
image.Dispose();
|
||||
|
||||
return darks > 0.65 * sampleCount;
|
||||
}
|
||||
|
||||
public static BitmapImage LoadBitmapImage(this Uri source)
|
||||
{
|
||||
var bitmap = new BitmapImage();
|
||||
bitmap.BeginInit();
|
||||
bitmap.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmap.UriSource = source;
|
||||
bitmap.EndInit();
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace QuickLook.Common.ExtensionMethods;
|
||||
|
||||
public static class DispatcherExtensions
|
||||
{
|
||||
public static void Delay(this Dispatcher disp, int delayMs,
|
||||
Action<object> action, object parm = null)
|
||||
{
|
||||
_ = Task.Delay(delayMs).ContinueWith(t => { _ = disp.Invoke(action, parm); });
|
||||
}
|
||||
|
||||
public static void DelayWithPriority(this Dispatcher disp, int delayMs,
|
||||
Action<object> action, object parm = null,
|
||||
DispatcherPriority priority = DispatcherPriority.ApplicationIdle)
|
||||
{
|
||||
_ = Task.Delay(delayMs).ContinueWith(t => { _ = disp.BeginInvoke(action, priority, parm); });
|
||||
}
|
||||
|
||||
public static async Task DelayAsync(this Dispatcher disp, int delayMs,
|
||||
Action<object> action, object parm = null,
|
||||
DispatcherPriority priority = DispatcherPriority.ApplicationIdle)
|
||||
{
|
||||
await Task.Delay(delayMs);
|
||||
await disp.BeginInvoke(action, priority, parm);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuickLook.Common.ExtensionMethods;
|
||||
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
|
||||
{
|
||||
foreach (var item in enumeration)
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace QuickLook.Common.ExtensionMethods;
|
||||
|
||||
public static class FileExtensions
|
||||
{
|
||||
public static string ToPrettySize(this long value, int decimalPlaces = 0)
|
||||
{
|
||||
const long OneKb = 1024L;
|
||||
const long OneMb = OneKb * 1024L;
|
||||
const long OneGb = OneMb * 1024L;
|
||||
const long OneTb = OneGb * 1024L;
|
||||
|
||||
var asTb = Math.Round((double)value / OneTb, decimalPlaces);
|
||||
var asGb = Math.Round((double)value / OneGb, decimalPlaces);
|
||||
var asMb = Math.Round((double)value / OneMb, decimalPlaces);
|
||||
var asKb = Math.Round((double)value / OneKb, decimalPlaces);
|
||||
var chosenValue = asTb > 1
|
||||
? $"{asTb} TB"
|
||||
: asGb > 1
|
||||
? $"{asGb} GB"
|
||||
: asMb > 1
|
||||
? $"{asMb} MB"
|
||||
: asKb > 1
|
||||
? $"{asKb} KB"
|
||||
: $"{Math.Round((double)value, decimalPlaces)} bytes";
|
||||
|
||||
return chosenValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace QuickLook.Common.ExtensionMethods;
|
||||
|
||||
public static class TypeExtensions
|
||||
{
|
||||
public static T CreateInstance<T>(this Type t, params object[] paramArray)
|
||||
{
|
||||
return (T)Activator.CreateInstance(t, paramArray);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using static QuickLook.Common.NativeMethods.MsCms;
|
||||
using static QuickLook.Common.NativeMethods.User32;
|
||||
|
||||
namespace QuickLook.Common.Helpers;
|
||||
|
||||
public static class DisplayDeviceHelper
|
||||
{
|
||||
public const int DefaultDpi = 96;
|
||||
|
||||
public static ScaleFactor GetScaleFactorFromWindow(Window window)
|
||||
{
|
||||
return GetScaleFactorFromWindow(new WindowInteropHelper(window).EnsureHandle());
|
||||
}
|
||||
|
||||
public static ScaleFactor GetCurrentScaleFactor()
|
||||
{
|
||||
return GetScaleFactorFromWindow(GetForegroundWindow());
|
||||
}
|
||||
|
||||
public static ScaleFactor GetScaleFactorFromWindow(nint hwnd)
|
||||
{
|
||||
var dpiX = DefaultDpi;
|
||||
var dpiY = DefaultDpi;
|
||||
|
||||
try
|
||||
{
|
||||
if (Environment.OSVersion.Version > new Version(6, 2)) // Windows 8.1 = 6.3.9200
|
||||
{
|
||||
var hMonitor = MonitorFromWindow(hwnd, MonitorDefaults.TOPRIMARY);
|
||||
GetDpiForMonitor(hMonitor, MonitorDpiType.EFFECTIVE_DPI, out dpiX, out dpiY);
|
||||
}
|
||||
else
|
||||
{
|
||||
using var g = Graphics.FromHwnd(IntPtr.Zero);
|
||||
var desktop = g.GetHdc();
|
||||
try
|
||||
{
|
||||
dpiX = GetDeviceCaps(desktop, DeviceCap.LOGPIXELSX);
|
||||
dpiY = GetDeviceCaps(desktop, DeviceCap.LOGPIXELSY);
|
||||
}
|
||||
finally
|
||||
{
|
||||
g.ReleaseHdc(desktop);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ProcessHelper.WriteLog(e.ToString());
|
||||
}
|
||||
|
||||
return new ScaleFactor { Horizontal = (float)dpiX / DefaultDpi, Vertical = (float)dpiY / DefaultDpi };
|
||||
}
|
||||
|
||||
public static string GetMonitorColorProfileFromWindow(Window window)
|
||||
{
|
||||
try
|
||||
{
|
||||
var hMonitor = MonitorFromWindow(new WindowInteropHelper(window).EnsureHandle(), MonitorDefaults.TONEAREST);
|
||||
return GetMonitorColorProfile(hMonitor);
|
||||
}
|
||||
catch (COMException ex) when (ex.HResult == unchecked((int)0x80263001))
|
||||
{
|
||||
// Desktop composition is disabled (e.g., during eGPU reconnection)
|
||||
ProcessHelper.WriteLog("Failed to get color profile: Desktop composition is disabled. This is expected during display reconfiguration.");
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ProcessHelper.WriteLog($"Failed to get monitor color profile: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetMonitorColorProfile(nint hMonitor)
|
||||
{
|
||||
var profileDir = new StringBuilder(255);
|
||||
var pDirSize = (uint)profileDir.Capacity;
|
||||
GetColorDirectory(null, profileDir, ref pDirSize);
|
||||
|
||||
var mInfo = new MONITORINFOEX();
|
||||
mInfo.cbSize = (uint)Marshal.SizeOf(mInfo);
|
||||
if (!GetMonitorInfo(hMonitor, ref mInfo))
|
||||
return null;
|
||||
|
||||
var dd = new DISPLAYDEVICE();
|
||||
dd.cb = (uint)Marshal.SizeOf(dd);
|
||||
if (!EnumDisplayDevices(mInfo.szDevice, 0, ref dd, 0))
|
||||
return null;
|
||||
|
||||
WcsGetUsePerUserProfiles(dd.DeviceKey, CLASS_MONITOR, out bool usePerUserProfiles);
|
||||
var scope = usePerUserProfiles ? WcsProfileManagementScope.CURRENT_USER : WcsProfileManagementScope.SYSTEM_WIDE;
|
||||
|
||||
if (!WcsGetDefaultColorProfileSize(scope, dd.DeviceKey, ColorProfileType.ICC, ColorProfileSubtype.NONE, 0, out uint size))
|
||||
return null;
|
||||
|
||||
var profileName = new StringBuilder((int)size);
|
||||
if (!WcsGetDefaultColorProfile(scope, dd.DeviceKey, ColorProfileType.ICC, ColorProfileSubtype.NONE, 0, size, profileName))
|
||||
return null;
|
||||
return System.IO.Path.Combine(profileDir.ToString(), profileName.ToString());
|
||||
}
|
||||
|
||||
[DllImport("shcore.dll")]
|
||||
private static extern uint
|
||||
GetDpiForMonitor(nint hMonitor, MonitorDpiType dpiType, out int dpiX, out int dpiY);
|
||||
|
||||
private enum MonitorDpiType
|
||||
{
|
||||
EFFECTIVE_DPI = 0,
|
||||
ANGULAR_DPI = 1,
|
||||
RAW_DPI = 2,
|
||||
}
|
||||
|
||||
public struct ScaleFactor
|
||||
{
|
||||
public float Horizontal;
|
||||
public float Vertical;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace QuickLook.Common.Helpers;
|
||||
|
||||
public static class FileHelper
|
||||
{
|
||||
public static bool IsExecutable(string path, out string appFriendlyName)
|
||||
{
|
||||
appFriendlyName = string.Empty;
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
var isExe = new[] { ".cmd", ".bat", ".pif", ".scf", ".exe", ".com", ".scr" }.Contains(ext.ToLower());
|
||||
|
||||
if (!isExe)
|
||||
return false;
|
||||
|
||||
appFriendlyName = FileVersionInfo.GetVersionInfo(path).FileDescription;
|
||||
if (string.IsNullOrEmpty(appFriendlyName))
|
||||
appFriendlyName = Path.GetFileName(path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string CreateTempFile(string folder, string filename = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filename))
|
||||
filename = Guid.NewGuid() + ".tmp";
|
||||
var fullPath = Path.Combine(folder, filename);
|
||||
|
||||
var handle = new SafeFileHandle(IntPtr.Zero, true);
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
|
||||
handle = NativeMethods.Kernel32.CreateFile(fullPath, FileAccess.ReadWrite,
|
||||
FileShare.None,
|
||||
IntPtr.Zero, FileMode.Create, FileAttributes.Temporary, IntPtr.Zero);
|
||||
|
||||
if (handle.IsInvalid)
|
||||
throw new UnauthorizedAccessException($"{folder} is not writable.");
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!handle.IsInvalid && !handle.IsClosed)
|
||||
handle.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetAssocApplication(string path, out string appFriendlyName)
|
||||
{
|
||||
appFriendlyName = string.Empty;
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
|
||||
// no assoc. app. found
|
||||
if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.Command)))
|
||||
if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.AppId))) // UWP
|
||||
return false;
|
||||
|
||||
appFriendlyName = GetAssocApplicationNative(ext, AssocStr.FriendlyAppName);
|
||||
if (string.IsNullOrEmpty(appFriendlyName))
|
||||
appFriendlyName = Path.GetFileName(path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra,
|
||||
[Out] StringBuilder sOut, [In][Out] ref uint nOut);
|
||||
|
||||
private static string GetAssocApplicationNative(string fileExtensionIncludingDot, AssocStr str)
|
||||
{
|
||||
uint cOut = 0;
|
||||
if (AssocQueryString(AssocF.Verify | AssocF.RemapRunDll | AssocF.InitIgnoreUnknown, str,
|
||||
fileExtensionIncludingDot, null, null,
|
||||
ref cOut) != 1)
|
||||
return null;
|
||||
|
||||
var pOut = new StringBuilder((int)cOut);
|
||||
if (AssocQueryString(AssocF.Verify | AssocF.RemapRunDll | AssocF.InitIgnoreUnknown, str,
|
||||
fileExtensionIncludingDot, null, pOut,
|
||||
ref cOut) != 0)
|
||||
return null;
|
||||
|
||||
return pOut.ToString();
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum AssocF
|
||||
{
|
||||
InitNoRemapCLSID = 0x1,
|
||||
InitByExeName = 0x2,
|
||||
OpenByExeName = 0x2,
|
||||
InitDefaultToStar = 0x4,
|
||||
InitDefaultToFolder = 0x8,
|
||||
NoUserSettings = 0x10,
|
||||
NoTruncate = 0x20,
|
||||
Verify = 0x40,
|
||||
RemapRunDll = 0x80,
|
||||
NoFixUps = 0x100,
|
||||
IgnoreBaseClass = 0x200,
|
||||
InitIgnoreUnknown = 0x400,
|
||||
InitFixedProgid = 0x800,
|
||||
IsProtocol = 0x1000,
|
||||
InitForFile = 0x2000,
|
||||
}
|
||||
|
||||
private enum AssocStr
|
||||
{
|
||||
Command = 1,
|
||||
Executable,
|
||||
FriendlyDocName,
|
||||
FriendlyAppName,
|
||||
NoOpen,
|
||||
ShellNewValue,
|
||||
DdeCommand,
|
||||
DdeIfExec,
|
||||
DdeApplication,
|
||||
DdeTopic,
|
||||
InfoTip,
|
||||
QuickTip,
|
||||
TileInfo,
|
||||
ContentType,
|
||||
DefaultIcon,
|
||||
ShellExtension,
|
||||
DropTarget,
|
||||
DelegateExecute,
|
||||
SupportedUriProtocols,
|
||||
ProgId,
|
||||
AppId,
|
||||
AppPublisher,
|
||||
AppIconReference,
|
||||
Max,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace QuickLook.Common.Helpers;
|
||||
|
||||
public static class OSThemeHelper
|
||||
{
|
||||
public static bool AppsUseDarkTheme()
|
||||
{
|
||||
var value = Registry.GetValue(
|
||||
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
|
||||
"AppsUseLightTheme", 1);
|
||||
|
||||
return value != null && (int)value == 0;
|
||||
}
|
||||
|
||||
public static bool SystemUsesDarkTheme()
|
||||
{
|
||||
var value = Registry.GetValue(
|
||||
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
|
||||
"SystemUsesLightTheme", 0);
|
||||
|
||||
return value == null || (int)value == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace QuickLook.Common.Helpers;
|
||||
|
||||
public static class PluginHelper
|
||||
{
|
||||
public static void RunAndClosePreview()
|
||||
{
|
||||
GetInstance()?.RunAndClosePreview();
|
||||
}
|
||||
|
||||
public static void InvokePreview(string path = null)
|
||||
{
|
||||
GetInstance()?.InvokePreview(path);
|
||||
}
|
||||
|
||||
public static void InvokePreviewWithOption(string path = null, string options = null)
|
||||
{
|
||||
GetInstance()?.InvokePreviewWithOption(path, options);
|
||||
}
|
||||
|
||||
public static void InvokePluginPreview(string plugin, string path = null)
|
||||
{
|
||||
GetInstance()?.InvokePluginPreview(plugin, path);
|
||||
}
|
||||
|
||||
private static dynamic GetInstance()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Obtain the instance from QuickLook::ViewWindowManager.GetInstance()
|
||||
Type type = AppDomain.CurrentDomain
|
||||
.GetAssemblies()
|
||||
.Select(a => a.GetType("QuickLook.ViewWindowManager", throwOnError: false))
|
||||
.FirstOrDefault(t => t != null);
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
MethodInfo method = type.GetMethod("GetInstance",
|
||||
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return method.Invoke(null, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using QuickLook.Common.NativeMethods;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace QuickLook.Common.Helpers;
|
||||
|
||||
public static class ProcessHelper
|
||||
{
|
||||
private const int ErrorInsufficientBuffer = 0x7A;
|
||||
|
||||
public static void PerformAggressiveGC()
|
||||
{
|
||||
// delay some time to make sure that all windows are closed
|
||||
Task.Delay(2000).ContinueWith(t => GC.Collect(GC.MaxGeneration));
|
||||
}
|
||||
|
||||
public static bool IsRunningAsUWP()
|
||||
{
|
||||
if (Environment.OSVersion.Version < new Version(6, 2)) // Windows 8
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
uint len = 0;
|
||||
var r = Kernel32.GetCurrentPackageFullName(ref len, null);
|
||||
|
||||
return r == ErrorInsufficientBuffer;
|
||||
}
|
||||
catch (EntryPointNotFoundException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsOnWindows10S()
|
||||
{
|
||||
const uint PRODUCT_CLOUD = 0x000000B2; // Windows 10 S
|
||||
const uint PRODUCT_CLOUDN = 0x000000B3; // Windows 10 S N
|
||||
|
||||
Kernel32.GetProductInfo(Environment.OSVersion.Version.Major,
|
||||
Environment.OSVersion.Version.Minor, 0, 0, out var osType);
|
||||
|
||||
return osType == PRODUCT_CLOUD || osType == PRODUCT_CLOUDN;
|
||||
}
|
||||
|
||||
public static bool IsShuttingDown()
|
||||
{
|
||||
var isShuttingDownProperty =
|
||||
typeof(Application).GetProperty("IsShuttingDown", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
if (isShuttingDownProperty == null)
|
||||
throw new Exception("Unable to detect Application.IsShuttingDown.");
|
||||
return (bool)isShuttingDownProperty.GetValue(Application.Current);
|
||||
}
|
||||
|
||||
public static void WriteLog(string msg)
|
||||
{
|
||||
Debug.WriteLine(msg);
|
||||
|
||||
var logFilePath = Path.Combine(SettingHelper.LocalDataPath, @"QuickLook.Exception.log");
|
||||
|
||||
using var writer = new StreamWriter(new FileStream(logFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read));
|
||||
writer.BaseStream.Seek(0, SeekOrigin.End);
|
||||
|
||||
writer.WriteLine($"========{DateTime.Now}========");
|
||||
writer.WriteLine(msg);
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Xml;
|
||||
|
||||
namespace QuickLook.Common.Helpers;
|
||||
|
||||
public static class SettingHelper
|
||||
{
|
||||
public static readonly string LocalDataPath =
|
||||
IsPortableVersion()
|
||||
? Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty,
|
||||
@"UserData\")
|
||||
: Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
@"pooi.moe\QuickLook\");
|
||||
|
||||
private static readonly Dictionary<string, XmlDocument> FileCache = [];
|
||||
|
||||
public static T Get<T>(string id, T failsafe = default, string domain = "QuickLook")
|
||||
{
|
||||
if (!typeof(T).IsSerializable && !typeof(ISerializable).IsAssignableFrom(typeof(T)))
|
||||
throw new InvalidOperationException("A serializable Type is required");
|
||||
|
||||
var file = Path.Combine(LocalDataPath, domain + ".config");
|
||||
|
||||
var doc = GetConfigFile(file);
|
||||
|
||||
// try to get setting
|
||||
var s = GetSettingFromXml(doc, id, failsafe);
|
||||
|
||||
return s != null ? s : failsafe;
|
||||
}
|
||||
|
||||
public static void Set(string id, object value, string domain = "QuickLook")
|
||||
{
|
||||
if (!value.GetType().IsSerializable)
|
||||
throw new NotSupportedException("New value if not serializable.");
|
||||
|
||||
var file = Path.Combine(LocalDataPath, domain + ".config");
|
||||
|
||||
WriteSettingToXml(GetConfigFile(file), id, value);
|
||||
}
|
||||
|
||||
public static bool IsPortableVersion()
|
||||
{
|
||||
var lck = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty,
|
||||
"portable.lock");
|
||||
|
||||
return File.Exists(lck);
|
||||
}
|
||||
|
||||
private static T GetSettingFromXml<T>(XmlDocument doc, string id, T failsafe)
|
||||
{
|
||||
var v = doc.SelectSingleNode($@"/Settings/{id}");
|
||||
|
||||
try
|
||||
{
|
||||
var result = v == null ? failsafe : (T)Convert.ChangeType(v.InnerText, typeof(T));
|
||||
return result;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return failsafe;
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteSettingToXml(XmlDocument doc, string id, object value)
|
||||
{
|
||||
var v = doc.SelectSingleNode($@"/Settings/{id}");
|
||||
|
||||
if (v != null)
|
||||
{
|
||||
v.InnerText = value.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
var node = doc.CreateNode(XmlNodeType.Element, id, doc.NamespaceURI);
|
||||
node.InnerText = value.ToString();
|
||||
doc.SelectSingleNode(@"/Settings")?.AppendChild(node);
|
||||
}
|
||||
|
||||
doc.Save(new Uri(doc.BaseURI).LocalPath);
|
||||
}
|
||||
|
||||
private static XmlDocument GetConfigFile(string file)
|
||||
{
|
||||
if (FileCache.ContainsKey(file))
|
||||
return FileCache[file];
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(file));
|
||||
if (!File.Exists(file))
|
||||
CreateNewConfig(file);
|
||||
|
||||
var doc = new XmlDocument();
|
||||
try
|
||||
{
|
||||
doc.Load(file);
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
CreateNewConfig(file);
|
||||
doc.Load(file);
|
||||
}
|
||||
|
||||
if (doc.SelectSingleNode(@"/Settings") == null)
|
||||
{
|
||||
CreateNewConfig(file);
|
||||
doc.Load(file);
|
||||
}
|
||||
|
||||
FileCache.Add(file, doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
private static void CreateNewConfig(string file)
|
||||
{
|
||||
using (var writer = XmlWriter.Create(file))
|
||||
{
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("Settings");
|
||||
writer.WriteEndElement();
|
||||
writer.WriteEndDocument();
|
||||
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml.XPath;
|
||||
|
||||
namespace QuickLook.Common.Helpers;
|
||||
|
||||
public static class TranslationHelper
|
||||
{
|
||||
private static readonly CultureInfo CurrentCultureInfo = CultureInfo.CurrentUICulture;
|
||||
|
||||
private static readonly Dictionary<string, XPathNavigator> FileCache = [];
|
||||
|
||||
public static string Get(string id, string file = null, CultureInfo locale = null, string failsafe = null,
|
||||
string domain = "QuickLook")
|
||||
{
|
||||
if (file == null)
|
||||
{
|
||||
var subDir = domain == "QuickLook" ? string.Empty : $"QuickLook.Plugin\\{domain}";
|
||||
file = Path.Combine(
|
||||
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), // path of QuickLook.Common.dll
|
||||
subDir, "Translations.config");
|
||||
}
|
||||
|
||||
if (!File.Exists(file))
|
||||
return failsafe ?? id;
|
||||
|
||||
if (locale == null)
|
||||
locale = CurrentCultureInfo;
|
||||
|
||||
var nav = GetLangFile(file);
|
||||
|
||||
// try to get string
|
||||
var s = GetStringFromXml(nav, id, locale);
|
||||
if (s != null)
|
||||
return s;
|
||||
|
||||
// try again for parent language
|
||||
if (locale.Parent.Name != string.Empty)
|
||||
s = GetStringFromXml(nav, id, locale.Parent);
|
||||
if (s != null)
|
||||
return s;
|
||||
|
||||
// use fallback language
|
||||
s = GetStringFromXml(nav, id, CultureInfo.GetCultureInfo("en"));
|
||||
if (s != null)
|
||||
return s;
|
||||
|
||||
return failsafe ?? id;
|
||||
}
|
||||
|
||||
private static string GetStringFromXml(XPathNavigator nav, string id, CultureInfo locale)
|
||||
{
|
||||
var result = nav.SelectSingleNode($@"/Translations/{locale.Name}/{id}");
|
||||
|
||||
return result?.Value;
|
||||
}
|
||||
|
||||
private static XPathNavigator GetLangFile(string file)
|
||||
{
|
||||
if (FileCache.ContainsKey(file))
|
||||
return FileCache[file];
|
||||
|
||||
var res = new XPathDocument(file).CreateNavigator();
|
||||
FileCache.Add(file, res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using QuickLook.Common.NativeMethods;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace QuickLook.Common.Helpers;
|
||||
|
||||
public static class WindowHelper
|
||||
{
|
||||
public enum WindowCompositionAttribute
|
||||
{
|
||||
WcaAccentPolicy = 19,
|
||||
}
|
||||
|
||||
public static Size GetCurrentDesktopSize()
|
||||
{
|
||||
var scale = DisplayDeviceHelper.GetCurrentScaleFactor();
|
||||
var rect = GetCurrentDesktopRectInPixel();
|
||||
|
||||
return new Size(rect.Width / scale.Horizontal, rect.Height / scale.Vertical);
|
||||
}
|
||||
|
||||
public static Rect GetCurrentDesktopRectInPixel()
|
||||
{
|
||||
return GetDesktopRectFromWindowInPixel(User32.GetForegroundWindow());
|
||||
}
|
||||
|
||||
public static Rect GetDesktopRectFromWindowInPixel(Window window)
|
||||
{
|
||||
return GetDesktopRectFromWindowInPixel(new WindowInteropHelper(window).Handle);
|
||||
}
|
||||
|
||||
public static Rect GetDesktopRectFromWindowInPixel(nint hwnd)
|
||||
{
|
||||
var screen = Screen.FromHandle(hwnd).WorkingArea;
|
||||
|
||||
var area = new Rect(new Point(screen.X, screen.Y),
|
||||
new Size(screen.Width, screen.Height));
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
public static void BringToFront(this Window window, bool keep)
|
||||
{
|
||||
var handle = new WindowInteropHelper(window).Handle;
|
||||
keep |= window.Topmost;
|
||||
|
||||
User32.SetWindowPos(handle, User32.HWND_TOPMOST, 0, 0, 0, 0,
|
||||
User32.SWP_NOMOVE | User32.SWP_NOSIZE | User32.SWP_NOACTIVATE);
|
||||
|
||||
if (!keep)
|
||||
User32.SetWindowPos(handle, User32.HWND_NOTOPMOST, 0, 0, 0, 0,
|
||||
User32.SWP_NOMOVE | User32.SWP_NOSIZE | User32.SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
public static void MoveWindow(this Window window,
|
||||
double pxLeft,
|
||||
double pxTop,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
var handle = new WindowInteropHelper(window).EnsureHandle();
|
||||
|
||||
// scale the size to the primary display
|
||||
TransformToPixels(window, width, height,
|
||||
out var pxWidth, out var pxHeight);
|
||||
|
||||
// Use absolute location and relative size. WPF will scale the size to the target display
|
||||
User32.MoveWindow(handle, (int)Math.Round(pxLeft), (int)Math.Round(pxTop), pxWidth, pxHeight, true);
|
||||
}
|
||||
|
||||
public static Rect GetWindowRectInPixel(this Window window)
|
||||
{
|
||||
var handle = new WindowInteropHelper(window).EnsureHandle();
|
||||
|
||||
User32.GetWindowRect(handle, out User32.RECT nRect);
|
||||
|
||||
return new Rect(new Point(nRect.Left, nRect.Top), new Point(nRect.Right, nRect.Bottom));
|
||||
}
|
||||
|
||||
private static void TransformToPixels(this Visual visual,
|
||||
double unitX,
|
||||
double unitY,
|
||||
out int pixelX,
|
||||
out int pixelY)
|
||||
{
|
||||
Matrix matrix;
|
||||
var source = PresentationSource.FromVisual(visual);
|
||||
if (source != null)
|
||||
matrix = source.CompositionTarget.TransformToDevice;
|
||||
else
|
||||
using (var src = new HwndSource(new HwndSourceParameters()))
|
||||
{
|
||||
matrix = src.CompositionTarget.TransformToDevice;
|
||||
}
|
||||
|
||||
pixelX = (int)Math.Round(matrix.M11 * unitX);
|
||||
pixelY = (int)Math.Round(matrix.M22 * unitY);
|
||||
}
|
||||
|
||||
public static bool IsForegroundWindowBelongToSelf()
|
||||
{
|
||||
var hwnd = User32.GetForegroundWindow();
|
||||
if (hwnd == IntPtr.Zero)
|
||||
return false;
|
||||
|
||||
User32.GetWindowThreadProcessId(hwnd, out var procId);
|
||||
return procId == Process.GetCurrentProcess().Id;
|
||||
}
|
||||
|
||||
public static void SetNoactivate(this Window window)
|
||||
{
|
||||
var hwnd = new WindowInteropHelper(window).Handle;
|
||||
User32.SetWindowLong(hwnd, User32.GWL_EXSTYLE,
|
||||
User32.GetWindowLong(hwnd, User32.GWL_EXSTYLE) |
|
||||
User32.WS_EX_NOACTIVATE);
|
||||
}
|
||||
|
||||
public static void RemoveWindowControls(this Window window)
|
||||
{
|
||||
var hwnd = new WindowInteropHelper(window).Handle;
|
||||
User32.SetWindowLong(hwnd, User32.GWL_STYLE,
|
||||
User32.GetWindowLong(hwnd, User32.GWL_STYLE) &
|
||||
~User32.WS_SYSMENU);
|
||||
}
|
||||
|
||||
public static void EnableBlur(Window window)
|
||||
{
|
||||
var accent = new AccentPolicy();
|
||||
var accentStructSize = Marshal.SizeOf(accent);
|
||||
accent.AccentState = AccentState.AccentEnableBlurbehind;
|
||||
accent.AccentFlags = 2;
|
||||
accent.GradientColor = 0x99FFFFFF;
|
||||
|
||||
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
|
||||
Marshal.StructureToPtr(accent, accentPtr, false);
|
||||
|
||||
var data = new WindowCompositionAttributeData
|
||||
{
|
||||
Attribute = WindowCompositionAttribute.WcaAccentPolicy,
|
||||
SizeOfData = accentStructSize,
|
||||
Data = accentPtr
|
||||
};
|
||||
|
||||
User32.SetWindowCompositionAttribute(new WindowInteropHelper(window).Handle, ref data);
|
||||
|
||||
Marshal.FreeHGlobal(accentPtr);
|
||||
}
|
||||
|
||||
public static void DisableBlur(Window window)
|
||||
{
|
||||
var accent = new AccentPolicy();
|
||||
var accentStructSize = Marshal.SizeOf(accent);
|
||||
accent.AccentState = AccentState.AccentDisabled;
|
||||
|
||||
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
|
||||
Marshal.StructureToPtr(accent, accentPtr, false);
|
||||
|
||||
var data = new WindowCompositionAttributeData
|
||||
{
|
||||
Attribute = WindowCompositionAttribute.WcaAccentPolicy,
|
||||
SizeOfData = accentStructSize,
|
||||
Data = accentPtr
|
||||
};
|
||||
|
||||
var hwnd = new WindowInteropHelper(window).EnsureHandle();
|
||||
User32.SetWindowCompositionAttribute(hwnd, ref data);
|
||||
|
||||
Marshal.FreeHGlobal(accentPtr);
|
||||
|
||||
var margins = new Dwmapi.Margins(0, 0, 0, 0);
|
||||
Dwmapi.DwmExtendFrameIntoClientArea(hwnd, ref margins);
|
||||
|
||||
if (Environment.OSVersion.Version >= new Version(10, 0, 22523))
|
||||
{
|
||||
var backdropType = (int)Dwmapi.SystembackdropType.None;
|
||||
Dwmapi.DwmSetWindowAttribute(hwnd, (uint)Dwmapi.WindowAttribute.SystembackdropType, ref backdropType, Marshal.SizeOf(typeof(int)));
|
||||
}
|
||||
else if (Environment.OSVersion.Version >= new Version(10, 0, 21996))
|
||||
{
|
||||
var micaEnabled = 0;
|
||||
Dwmapi.DwmSetWindowAttribute(hwnd, (uint)Dwmapi.WindowAttribute.MicaEffect, ref micaEnabled, Marshal.SizeOf(typeof(int)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnableDwmBlur(Window window, bool isDarkTheme, uint dwAttribute, int pvAttribute)
|
||||
{
|
||||
// Mica will handle the color
|
||||
window.Background = Brushes.Transparent;
|
||||
|
||||
var hwnd = new WindowInteropHelper(window).Handle;
|
||||
|
||||
var isDarkThemeInt = isDarkTheme ? 1 : 0;
|
||||
Dwmapi.DwmSetWindowAttribute(hwnd, (uint)Dwmapi.WindowAttribute.UseImmersiveDarkMode, ref isDarkThemeInt, Marshal.SizeOf(typeof(bool)));
|
||||
|
||||
var margins = new Dwmapi.Margins(-1, -1, -1, -1);
|
||||
Dwmapi.DwmExtendFrameIntoClientArea(hwnd, ref margins);
|
||||
|
||||
var val = pvAttribute;
|
||||
Dwmapi.DwmSetWindowAttribute(hwnd, dwAttribute, ref val, Marshal.SizeOf(typeof(int)));
|
||||
}
|
||||
|
||||
public static void EnableMicaBlur(Window window, bool isDarkTheme)
|
||||
{
|
||||
EnableDwmBlur(window, isDarkTheme, (uint)Dwmapi.WindowAttribute.MicaEffect, 1);
|
||||
}
|
||||
|
||||
public static void EnableBackdropMicaBlur(Window window, bool isDarkTheme)
|
||||
{
|
||||
EnableDwmBlur(window, isDarkTheme, (uint)Dwmapi.WindowAttribute.SystembackdropType, (int)Dwmapi.SystembackdropType.MainWindow);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WindowCompositionAttributeData
|
||||
{
|
||||
public WindowCompositionAttribute Attribute;
|
||||
public nint Data;
|
||||
public int SizeOfData;
|
||||
}
|
||||
|
||||
private enum AccentState
|
||||
{
|
||||
AccentDisabled = 0,
|
||||
AccentEnableGradient = 1,
|
||||
AccentEnableTransparentgradient = 2,
|
||||
AccentEnableBlurbehind = 3,
|
||||
AccentInvalidState = 4,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct AccentPolicy
|
||||
{
|
||||
public AccentState AccentState;
|
||||
public int AccentFlags;
|
||||
public uint GradientColor;
|
||||
public readonly int AnimationId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace QuickLook.Common.NativeMethods;
|
||||
|
||||
public static class Dwmapi
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Margins(int cxLeftWidth, int cxRightWidth, int cyTopHeight, int cyBottomHeight)
|
||||
{
|
||||
public int cxLeftWidth = cxLeftWidth;
|
||||
public int cxRightWidth = cxRightWidth;
|
||||
public int cyTopHeight = cyTopHeight;
|
||||
public int cyBottomHeight = cyBottomHeight;
|
||||
}
|
||||
|
||||
public enum WindowAttribute
|
||||
{
|
||||
UseImmersiveDarkMode = 20,
|
||||
SystembackdropType = 38,
|
||||
MicaEffect = 1029,
|
||||
}
|
||||
|
||||
public enum SystembackdropType
|
||||
{
|
||||
Auto = 0,
|
||||
None = 1,
|
||||
MainWindow = 2,
|
||||
TransientWindow = 3,
|
||||
TabbedWindow = 4,
|
||||
}
|
||||
|
||||
[DllImport("DwmApi.dll")]
|
||||
public static extern int DwmExtendFrameIntoClientArea(nint hwnd, ref Margins pMarInset);
|
||||
|
||||
[DllImport("dwmapi.dll")]
|
||||
public static extern int DwmSetWindowAttribute(nint hwnd, uint dwAttribute, ref int pvAttribute, int cbAttribute);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace QuickLook.Common.NativeMethods;
|
||||
|
||||
public static class Kernel32
|
||||
{
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern nint LoadLibrary(string lpFileName);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern int GetCurrentPackageFullName(ref uint packageFullNameLength,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder packageFullName);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern nint GetCurrentThreadId();
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool GetProductInfo(int dwOSMajorVersion, int dwOSMinorVersion, int dwSpMajorVersion,
|
||||
int dwSpMinorVersion, out uint pdwReturnedProductType);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern SafeFileHandle CreateFile(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string filename,
|
||||
[MarshalAs(UnmanagedType.U4)] FileAccess access,
|
||||
[MarshalAs(UnmanagedType.U4)] FileShare share,
|
||||
nint securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
|
||||
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
|
||||
[MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
|
||||
nint templateFile);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace QuickLook.Common.NativeMethods;
|
||||
|
||||
public static class MsCms
|
||||
{
|
||||
[DllImport("mscms.dll", CharSet = CharSet.Auto)]
|
||||
public static extern bool GetColorDirectory(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string pMachineName,
|
||||
StringBuilder pBuffer,
|
||||
ref uint pdwSize);
|
||||
|
||||
[DllImport("mscms.dll", CharSet = CharSet.Auto)]
|
||||
public static extern bool WcsGetUsePerUserProfiles(
|
||||
[MarshalAs(UnmanagedType.LPTStr)] string deviceName,
|
||||
uint deviceClass,
|
||||
out bool usePerUserProfiles);
|
||||
|
||||
[DllImport("mscms.dll", CharSet = CharSet.Auto)]
|
||||
public static extern bool WcsGetDefaultColorProfileSize(
|
||||
WcsProfileManagementScope scope,
|
||||
[MarshalAs(UnmanagedType.LPTStr)] string deviceName,
|
||||
ColorProfileType colorProfileType,
|
||||
ColorProfileSubtype colorProfileSubType,
|
||||
uint dwProfileID,
|
||||
out uint cbProfileName);
|
||||
|
||||
[DllImport("mscms.dll", CharSet = CharSet.Auto)]
|
||||
public static extern bool WcsGetDefaultColorProfile(
|
||||
WcsProfileManagementScope scope,
|
||||
[MarshalAs(UnmanagedType.LPTStr)] string deviceName,
|
||||
ColorProfileType colorProfileType,
|
||||
ColorProfileSubtype colorProfileSubType,
|
||||
uint dwProfileID,
|
||||
uint cbProfileName,
|
||||
StringBuilder pProfileName);
|
||||
|
||||
public enum WcsProfileManagementScope
|
||||
{
|
||||
SYSTEM_WIDE,
|
||||
CURRENT_USER,
|
||||
}
|
||||
|
||||
public enum ColorProfileType
|
||||
{
|
||||
ICC,
|
||||
DMP,
|
||||
CAMP,
|
||||
GMMP,
|
||||
};
|
||||
|
||||
public enum ColorProfileSubtype
|
||||
{
|
||||
PERCEPTUAL,
|
||||
RELATIVE_COLORIMETRIC,
|
||||
SATURATION,
|
||||
ABSOLUTE_COLORIMETRIC,
|
||||
NONE,
|
||||
RGB_WORKING_SPACE,
|
||||
CUSTOM_WORKING_SPACE,
|
||||
STANDARD_DISPLAY_COLOR_MODE,
|
||||
EXTENDED_DISPLAY_COLOR_MODE,
|
||||
};
|
||||
|
||||
public const uint CLASS_MONITOR = 0x6d6e7472; // 'mntr'
|
||||
public const uint CLASS_PRINTER = 0x70727472; // 'prtr'
|
||||
public const uint CLASS_SCANNER = 0x73636e72; // 'scnr'
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using QuickLook.Common.Helpers;
|
||||
|
||||
namespace QuickLook.Common.NativeMethods;
|
||||
|
||||
public static class User32
|
||||
{
|
||||
public delegate int KeyboardHookProc(int code, int wParam, ref KeyboardHookStruct lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int MoveWindow(nint hWnd, int x, int y, int nWidth, int nHeight,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool bRepaint);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy,
|
||||
uint uFlags);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint SetWindowsHookEx(int idHook, KeyboardHookProc callback, nint hInstance,
|
||||
uint threadId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool UnhookWindowsHookEx(nint hInstance);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int CallNextHookEx(nint idHook, int nCode, int wParam, ref KeyboardHookStruct lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint SetWindowLong(nint hWnd, int nIndex, int dwNewLong);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int GetWindowLong(nint hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint GetAncestor(nint hwnd, uint gaFlags);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint GetDesktopWindow();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool GetWindowRect(nint hwnd, out RECT lpRect);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint GetWindowThreadProcessId(nint hWnd, nint processId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint GetWindowThreadProcessId(nint hWnd, out uint processId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint AttachThreadInput(nint idAttach, nint idAttachTo, bool fAttach);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint GetFocus();
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern int GetClassName(nint hWnd, StringBuilder lpClassName, int nMaxCount);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint GetParent(nint hWnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int SetWindowCompositionAttribute(nint hwnd,
|
||||
ref WindowHelper.WindowCompositionAttributeData data);
|
||||
|
||||
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
|
||||
public static extern int GetDeviceCaps(nint hDC, DeviceCap nIndex);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern nint MonitorFromWindow(nint hWnd, MonitorDefaults dwFlags);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public extern static bool GetMonitorInfo(nint hMonitor, ref MONITORINFOEX lpmi);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAYDEVICE lpDisplayDevice, uint dwFlags);
|
||||
|
||||
public enum MonitorDefaults
|
||||
{
|
||||
TONULL = 0,
|
||||
TOPRIMARY = 1,
|
||||
TONEAREST = 2
|
||||
}
|
||||
|
||||
public enum DeviceCap
|
||||
{
|
||||
/// <summary>
|
||||
/// Logical pixels inch in X
|
||||
/// </summary>
|
||||
LOGPIXELSX = 88,
|
||||
|
||||
/// <summary>
|
||||
/// Logical pixels inch in Y
|
||||
/// </summary>
|
||||
LOGPIXELSY = 90
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public struct KeyboardHookStruct
|
||||
{
|
||||
public int vkCode;
|
||||
public int scanCode;
|
||||
public int flags;
|
||||
public int time;
|
||||
public int dwExtraInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MONITORINFOEX
|
||||
{
|
||||
public uint cbSize;
|
||||
public RECT rcMonitor;
|
||||
public RECT rcWork;
|
||||
public uint dwFlags;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||
public string szDevice;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct DISPLAYDEVICE
|
||||
{
|
||||
public uint cb;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||
public string DeviceName;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||
public string DeviceString;
|
||||
|
||||
public uint StateFlags;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||
public string DeviceID;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||
public string DeviceKey;
|
||||
}
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
public static readonly nint HWND_TOPMOST = -1;
|
||||
|
||||
public static readonly nint HWND_NOTOPMOST = -2;
|
||||
public static readonly nint HWND_TOP = 0;
|
||||
public static readonly nint HWND_BOTTOM = 1;
|
||||
|
||||
public const uint SWP_NOSIZE = 0x0001;
|
||||
public const uint SWP_NOMOVE = 0x0002;
|
||||
public const uint SWP_NOZORDER = 0x0004;
|
||||
public const uint SWP_NOREDRAW = 0x0008;
|
||||
public const uint SWP_NOACTIVATE = 0x0010;
|
||||
public const uint SWP_DRAWFRAME = 0x0020;
|
||||
public const uint SWP_FRAMECHANGED = 0x0020;
|
||||
public const uint SWP_SHOWWINDOW = 0x0040;
|
||||
public const uint SWP_HIDEWINDOW = 0x0080;
|
||||
public const uint SWP_NOCOPYBITS = 0x0100;
|
||||
public const uint SWP_NOOWNERZORDER = 0x0200;
|
||||
public const uint SWP_NOREPOSITION = 0x0200;
|
||||
public const uint SWP_NOSENDCHANGING = 0x0400;
|
||||
public const uint SWP_DEFERERASE = 0x2000;
|
||||
public const uint SWP_ASYNCWINDOWPOS = 0x4000;
|
||||
|
||||
public const int WH_KEYBOARD_LL = 13;
|
||||
public const int WM_KEYDOWN = 0x100;
|
||||
public const int WM_KEYUP = 0x101;
|
||||
public const int WM_SYSKEYDOWN = 0x104;
|
||||
public const int WM_SYSKEYUP = 0x105;
|
||||
public const int GWL_STYLE = -16;
|
||||
public const int GWL_EXSTYLE = -20;
|
||||
public const int WS_SYSMENU = 0x00080000;
|
||||
public const int WS_MINIMIZEBOX = 0x00020000;
|
||||
public const int WS_MAXIMIZEBOX = 0x00010000;
|
||||
public const int WS_EX_NOACTIVATE = 0x08000000;
|
||||
|
||||
public const uint GA_PARENT = 1;
|
||||
public const uint GA_ROOT = 2;
|
||||
public const uint GA_ROOTOWNER = 3;
|
||||
// ReSharper restore InconsistentNaming
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using QuickLook.Common.Annotations;
|
||||
using QuickLook.Common.Helpers;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
|
||||
namespace QuickLook.Common.Plugin;
|
||||
|
||||
/// <summary>
|
||||
/// A runtime object which allows interaction between this plugin and QuickLook.
|
||||
/// </summary>
|
||||
public class ContextObject : INotifyPropertyChanged
|
||||
{
|
||||
private bool _canResize = true;
|
||||
private bool _fullWindowDragging;
|
||||
private bool _isBusy;
|
||||
private string _title = string.Empty;
|
||||
private bool _titlebarAutoHide;
|
||||
private bool _titlebarBlurVisibility;
|
||||
private bool _titlebarColourVisibility = true;
|
||||
private bool _titlebarOverlap;
|
||||
private Themes _theme = Themes.None;
|
||||
private object _viewerContent;
|
||||
private string _colorProfileName = null;
|
||||
private bool _isBlocked;
|
||||
|
||||
/// <summary>
|
||||
/// Get the instance of Viewer window.
|
||||
/// </summary>
|
||||
public object Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the title of Viewer window.
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get => _title;
|
||||
set
|
||||
{
|
||||
_title = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the viewer content control.
|
||||
/// </summary>
|
||||
public object ViewerContent
|
||||
{
|
||||
get => _viewerContent;
|
||||
set
|
||||
{
|
||||
_viewerContent = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show or hide the busy indicator icon.
|
||||
/// </summary>
|
||||
public bool IsBusy
|
||||
{
|
||||
get => _isBusy;
|
||||
set
|
||||
{
|
||||
_isBusy = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the exact size you want.
|
||||
/// </summary>
|
||||
public Size PreferredSize { get; set; } = new Size { Width = 800, Height = 600 };
|
||||
|
||||
/// <summary>
|
||||
/// Set whether user are allowed to resize the viewer window.
|
||||
/// </summary>
|
||||
public bool CanResize
|
||||
{
|
||||
get => _canResize;
|
||||
set
|
||||
{
|
||||
_canResize = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set whether the full viewer window can be used for mouse dragging.
|
||||
/// </summary>
|
||||
public bool FullWindowDragging
|
||||
{
|
||||
get => _fullWindowDragging;
|
||||
set
|
||||
{
|
||||
_fullWindowDragging = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set whether the viewer content is overlapped by the title bar
|
||||
/// </summary>
|
||||
public bool TitlebarOverlap
|
||||
{
|
||||
get => _titlebarOverlap;
|
||||
set
|
||||
{
|
||||
_titlebarOverlap = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set whether the title bar shows a blurred background
|
||||
/// </summary>
|
||||
public bool TitlebarBlurVisibility
|
||||
{
|
||||
get => _titlebarBlurVisibility;
|
||||
set
|
||||
{
|
||||
if (value == _titlebarBlurVisibility) return;
|
||||
_titlebarBlurVisibility = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set whether the title bar shows a colour overlay
|
||||
/// </summary>
|
||||
public bool TitlebarColourVisibility
|
||||
{
|
||||
get => _titlebarColourVisibility;
|
||||
set
|
||||
{
|
||||
if (value == _titlebarColourVisibility) return;
|
||||
_titlebarColourVisibility = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should the titlebar hides itself after a short period of inactivity?
|
||||
/// </summary>
|
||||
public bool TitlebarAutoHide
|
||||
{
|
||||
get => _titlebarAutoHide;
|
||||
set
|
||||
{
|
||||
if (value == _titlebarAutoHide) return;
|
||||
_titlebarAutoHide = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Switch to dark theme?
|
||||
/// </summary>
|
||||
public Themes Theme
|
||||
{
|
||||
get => _theme;
|
||||
set
|
||||
{
|
||||
_theme = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The color profile of the monitor that will host the preview window
|
||||
/// </summary>
|
||||
public string ColorProfileName
|
||||
{
|
||||
get => _colorProfileName;
|
||||
set
|
||||
{
|
||||
_colorProfileName = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set whether to block showing the preview window.
|
||||
/// </summary>
|
||||
public bool IsBlocked
|
||||
{
|
||||
get => _isBlocked;
|
||||
set
|
||||
{
|
||||
_isBlocked = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Set the size of viewer window, scale or shrink to fit (to screen resolution).
|
||||
/// The window can take maximum (maxRatio*resolution) space.
|
||||
/// </summary>
|
||||
/// <param name="size">The desired size.</param>
|
||||
/// <param name="maxRatio">The maximum percent (over screen resolution) it can take.</param>
|
||||
public double SetPreferredSizeFit(Size size, double maxRatio)
|
||||
{
|
||||
if (maxRatio > 1)
|
||||
maxRatio = 1;
|
||||
|
||||
var max = WindowHelper.GetCurrentDesktopSize();
|
||||
|
||||
var widthRatio = max.Width * maxRatio / size.Width;
|
||||
var heightRatio = max.Height * maxRatio / size.Height;
|
||||
|
||||
var ratio = Math.Min(widthRatio, heightRatio);
|
||||
if (ratio > 1) ratio = 1;
|
||||
|
||||
PreferredSize = new Size { Width = size.Width * ratio, Height = size.Height * ratio };
|
||||
|
||||
return ratio;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Title = string.Empty;
|
||||
// set to False to prevent showing loading icon
|
||||
IsBusy = false;
|
||||
PreferredSize = new Size();
|
||||
CanResize = true;
|
||||
FullWindowDragging = false;
|
||||
|
||||
Theme = Themes.None;
|
||||
TitlebarOverlap = false;
|
||||
TitlebarAutoHide = false;
|
||||
TitlebarBlurVisibility = false;
|
||||
TitlebarColourVisibility = true;
|
||||
|
||||
ViewerContent = null;
|
||||
|
||||
ColorProfileName = null;
|
||||
IsBlocked = false;
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace QuickLook.Common.Plugin;
|
||||
|
||||
/// <summary>
|
||||
/// Interface implemented by every QuickLook.Plugin
|
||||
/// </summary>
|
||||
public interface IViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Set the priority of this plugin. A plugin with a higher priority may override one with lower priority.
|
||||
/// Set this to int.MaxValue for a maximum priority, int.MinValue for minimum.
|
||||
/// </summary>
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Do ont-time job when application starts. You may extract nessessary resource here.
|
||||
/// </summary>
|
||||
public void Init();
|
||||
|
||||
/// <summary>
|
||||
/// Determine whether this plugin can open this file. Please also check the file header, if applicable.
|
||||
/// </summary>
|
||||
/// <param name="path">The full path of the target file.</param>
|
||||
public bool CanHandle(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Do some preparation stuff before the window is showing. Please not do any work that costs a lot of time.
|
||||
/// </summary>
|
||||
/// <param name="path">The full path of the target file.</param>
|
||||
/// <param name="context">A runtime object which allows interaction between this plugin and QuickLook.</param>
|
||||
public void Prepare(string path, ContextObject context);
|
||||
|
||||
/// <summary>
|
||||
/// Start the loading process. During the process a busy indicator will be shown. Finish by setting context.IsBusy to
|
||||
/// false.
|
||||
/// </summary>
|
||||
/// <param name="path">The full path of the target file.</param>
|
||||
/// <param name="context">A runtime object which allows interaction between this plugin and QuickLook.</param>
|
||||
public void View(string path, ContextObject context);
|
||||
|
||||
/// <summary>
|
||||
/// Release any unmanaged resource here.
|
||||
/// </summary>
|
||||
public void Cleanup();
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace QuickLook.Common.Plugin.MoreMenu;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a menu item that can be added to the QuickLook viewer's context menu.
|
||||
/// </summary>
|
||||
public interface IMenuItem : INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the icon for the menu item. Can be a string (for Unicode symbols)
|
||||
/// String, <seealso cref="Wpf.Ui.Controls.FontSymbols"/> check from https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font
|
||||
/// ImageSource, or null for no icon.
|
||||
/// </summary>
|
||||
public object Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display text for the menu item.
|
||||
/// </summary>
|
||||
public object Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of menu items.
|
||||
/// </summary>
|
||||
public IEnumerable<IMenuItem> MenuItems { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the menu item is visible.
|
||||
/// This allows dynamic show/hide based on file context.
|
||||
/// </summary>
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the menu item is enabled.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the command to execute when the menu item is clicked.
|
||||
/// </summary>
|
||||
public ICommand Command { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the command parameter for the Command.
|
||||
/// </summary>
|
||||
public object CommandParameter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tooltip text for the menu item.
|
||||
/// </summary>
|
||||
public string ToolTip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this menu item represents a separator.
|
||||
/// When true, other properties are ignored and a separator line is shown.
|
||||
/// </summary>
|
||||
public bool IsSeparator { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuickLook.Common.Plugin.MoreMenu;
|
||||
|
||||
/// <summary>
|
||||
/// Interface implemented by QuickLook plugins that want to provide custom context menu items.
|
||||
/// Plugins implementing this interface can add menu items to the viewer's title bar context menu.
|
||||
/// </summary>
|
||||
public interface IMoreMenu
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the collection of menu items that this plugin provides.
|
||||
/// This property will be queried after the Prepare method is called.
|
||||
/// </summary>
|
||||
public IEnumerable<IMenuItem> MenuItems { get; }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace QuickLook.Common.Plugin.MoreMenu;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the extended version of IMoreMenu means that
|
||||
/// the insertion operation will be performed regardless of whether it is a matching plugin or not.
|
||||
/// </summary>
|
||||
public interface IMoreMenuExtended : IMoreMenu;
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using QuickLook.Common.Annotations;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace QuickLook.Common.Plugin.MoreMenu;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for QuickLook menu items that provides common functionality
|
||||
/// and implements INotifyPropertyChanged for dynamic property updates.
|
||||
/// </summary>
|
||||
public class MoreMenuItem : IMenuItem
|
||||
{
|
||||
private object _icon;
|
||||
private object _header;
|
||||
private IEnumerable<IMenuItem> _menuItems;
|
||||
private bool _isVisible = true;
|
||||
private bool _isEnabled = true;
|
||||
private ICommand _command;
|
||||
private object _commandParameter;
|
||||
private string _toolTip;
|
||||
private bool _isSeparator;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual object Icon
|
||||
{
|
||||
get => _icon;
|
||||
set => SetProperty(ref _icon, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual object Header
|
||||
{
|
||||
get => _header;
|
||||
set => SetProperty(ref _header, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<IMenuItem> MenuItems
|
||||
{
|
||||
get => _menuItems;
|
||||
set => SetProperty(ref _menuItems, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual bool IsVisible
|
||||
{
|
||||
get => _isVisible;
|
||||
set => SetProperty(ref _isVisible, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set => SetProperty(ref _isEnabled, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual ICommand Command
|
||||
{
|
||||
get => _command;
|
||||
set => SetProperty(ref _command, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual object CommandParameter
|
||||
{
|
||||
get => _commandParameter;
|
||||
set => SetProperty(ref _commandParameter, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual string ToolTip
|
||||
{
|
||||
get => _toolTip;
|
||||
set => SetProperty(ref _toolTip, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual bool IsSeparator
|
||||
{
|
||||
get => _isSeparator;
|
||||
set => SetProperty(ref _isSeparator, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the PropertyChanged event for the specified property.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">The name of the property that changed.</param>
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the property value and raises PropertyChanged if the value has changed.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the property.</typeparam>
|
||||
/// <param name="field">The backing field for the property.</param>
|
||||
/// <param name="value">The new value.</param>
|
||||
/// <param name="propertyName">The name of the property.</param>
|
||||
/// <returns>True if the property value was changed; otherwise, false.</returns>
|
||||
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
|
||||
{
|
||||
if (Equals(field, value))
|
||||
return false;
|
||||
|
||||
field = value;
|
||||
OnPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright © 2017-2026 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace QuickLook.Common.Plugin;
|
||||
|
||||
public enum Themes
|
||||
{
|
||||
None,
|
||||
Dark,
|
||||
Light,
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("QuickLook.Common")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("QuickLook.Common")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017-2026 QL-Win Contributors")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("85fdd6ba-871d-46c8-bd64-f6bb0cb5ea95")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
@@ -0,0 +1,59 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net462</TargetFramework>
|
||||
<RootNamespace>QuickLook.Common</RootNamespace>
|
||||
<AssemblyName>QuickLook.Common</AssemblyName>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<ProjectGuid>{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Build\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Build\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\Build\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\Build\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>powershell -ExecutionPolicy Bypass -file "$(SolutionDir)Scripts\update-version.ps1"</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="MainWindowBackground" Color="#CC292929" />
|
||||
<SolidColorBrush x:Key="MainWindowBackgroundNoTransparent" Color="#FF292929" />
|
||||
<SolidColorBrush x:Key="WindowTextForeground" Color="#FFEFEFEF" />
|
||||
<SolidColorBrush x:Key="WindowTextForegroundAlternative" Color="#FFD4D4D4" />
|
||||
<SolidColorBrush x:Key="CaptionTextHoverBorder" Color="#DDB9B9B9" />
|
||||
<SolidColorBrush x:Key="CaptionButtonIconForeground" Color="#E5EFEFEF" />
|
||||
<SolidColorBrush x:Key="CaptionButtonHoverBackground" Color="#22FFFFFF" />
|
||||
<SolidColorBrush x:Key="CaptionButtonPressBackground" Color="#44FFFFFF" />
|
||||
<SolidColorBrush x:Key="CaptionCloseButtonHoverForeground" Color="#E5EFEFEF" />
|
||||
<SolidColorBrush x:Key="CaptionCloseButtonHoverBackground" Color="#FFE81123" />
|
||||
<SolidColorBrush x:Key="CaptionCloseButtonPressBackground" Color="#FFB5394B" />
|
||||
<SolidColorBrush x:Key="CaptionBackground" Color="#CC0E0E0E" />
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,102 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
<Thickness x:Key="MainWindowShadowMarginThickness">1</Thickness>
|
||||
<Thickness x:Key="MainWindowResizeThickness">6</Thickness>
|
||||
<system:Double x:Key="MainWindowCaptionHeight">32</system:Double>
|
||||
<SolidColorBrush x:Key="MainWindowBackground" Color="#BBFAFAFA" />
|
||||
<SolidColorBrush x:Key="MainWindowBackgroundNoTransparent" Color="#FFFAFAFA" />
|
||||
<SolidColorBrush x:Key="WindowTextForeground" Color="#FF0E0E0E" />
|
||||
<SolidColorBrush x:Key="WindowTextForegroundAlternative" Color="#FF626262" />
|
||||
<SolidColorBrush x:Key="CaptionTextHoverBorder" Color="#FF3D3D3D" />
|
||||
<SolidColorBrush x:Key="CaptionButtonIconForeground" Color="#E50E0E0E" />
|
||||
<SolidColorBrush x:Key="CaptionButtonHoverBackground" Color="#44FFFFFF" />
|
||||
<SolidColorBrush x:Key="CaptionButtonPressBackground" Color="#88FFFFFF" />
|
||||
<SolidColorBrush x:Key="CaptionCloseButtonHoverForeground" Color="#E5EFEFEF" />
|
||||
<SolidColorBrush x:Key="CaptionCloseButtonHoverBackground" Color="#FFE81123" />
|
||||
<SolidColorBrush x:Key="CaptionCloseButtonPressBackground" Color="#FFB5394B" />
|
||||
<SolidColorBrush x:Key="CaptionBackground" Color="#BBDADADA" />
|
||||
|
||||
<Style x:Key="CaptionButtonBaseStyle" TargetType="Button">
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource WindowTextForeground}" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CaptionTextButtonStyle"
|
||||
BasedOn="{StaticResource CaptionButtonBaseStyle}"
|
||||
TargetType="Button">
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="Padding" Value="6,2,6,2" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<ContentPresenter />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource CaptionTextHoverBorder}" />
|
||||
<Setter Property="Background" Value="{DynamicResource CaptionButtonHoverBackground}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource CaptionButtonPressBackground}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CaptionButtonStyle"
|
||||
BasedOn="{StaticResource CaptionButtonBaseStyle}"
|
||||
TargetType="Button">
|
||||
<Setter Property="Width" Value="45" />
|
||||
<Setter Property="Height" Value="32" />
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource CaptionButtonIconForeground}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderThickness="0">
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
TextBlock.FontFamily="{StaticResource SegoeFluent}" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource CaptionButtonHoverBackground}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource CaptionButtonPressBackground}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CaptionCloseButtonStyle"
|
||||
BasedOn="{StaticResource CaptionButtonStyle}"
|
||||
TargetType="Button">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource CaptionCloseButtonHoverForeground}" />
|
||||
<Setter Property="Background" Value="{DynamicResource CaptionCloseButtonHoverBackground}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource CaptionCloseButtonPressBackground}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,171 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<SolidColorBrush x:Key="StandardBorderBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="StandardBackgroundBrush" Color="#FFF" />
|
||||
<SolidColorBrush x:Key="HoverBorderBrush" Color="#DDD" />
|
||||
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="Gray" />
|
||||
<SolidColorBrush x:Key="SelectedForegroundBrush" Color="White" />
|
||||
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="NormalBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="NormalBorderBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="HorizontalNormalBrush" Color="#888" />
|
||||
<SolidColorBrush x:Key="HorizontalNormalBorderBrush" Color="#888" />
|
||||
<LinearGradientBrush x:Key="StandardBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Offset="0.0" Color="#FFF" />
|
||||
<GradientStop Offset="1.0" Color="#CCC" />
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
|
||||
<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Offset="0.0" Color="#BBB" />
|
||||
<GradientStop Offset="0.1" Color="#EEE" />
|
||||
<GradientStop Offset="0.9" Color="#EEE" />
|
||||
<GradientStop Offset="1.0" Color="#FFF" />
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<!-- SrollViewer ScrollBar Repeat Buttons (at each end) -->
|
||||
<Style x:Key="ScrollBarLineButton" TargetType="{x:Type RepeatButton}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||
<Setter Property="Focusable" Value="false" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type RepeatButton}">
|
||||
<Border x:Name="Border"
|
||||
Margin="1"
|
||||
Background="{StaticResource NormalBrush}"
|
||||
BorderBrush="{StaticResource NormalBorderBrush}"
|
||||
BorderThickness="0.25"
|
||||
CornerRadius="2">
|
||||
<Path HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Fill="{StaticResource GlyphBrush}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsPressed" Value="true">
|
||||
<Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<!--
|
||||
SrollViewer ScrollBar Repeat Buttons (The part in the middle,
|
||||
not the thumb the long area between the buttons )
|
||||
-->
|
||||
<Style x:Key="ScrollBarPageButton" TargetType="{x:Type RepeatButton}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||
<Setter Property="IsTabStop" Value="false" />
|
||||
<Setter Property="Focusable" Value="false" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type RepeatButton}">
|
||||
<Border Background="Transparent" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<!--
|
||||
ScrollViewer ScrollBar Thumb, that part that can be dragged
|
||||
up/down or left/right Buttons
|
||||
-->
|
||||
<Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||
<Setter Property="IsTabStop" Value="false" />
|
||||
<Setter Property="Focusable" Value="false" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="0.25"
|
||||
CornerRadius="2" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<!-- VerticalScrollBar Template using the previously created Templates -->
|
||||
<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||
<Grid Width="13">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.RowSpan="3"
|
||||
Background="Transparent"
|
||||
CornerRadius="2" />
|
||||
<Track x:Name="PART_Track"
|
||||
Grid.Row="0"
|
||||
IsDirectionReversed="true">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton Command="ScrollBar.PageUpCommand" Style="{StaticResource ScrollBarPageButton}" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb Margin="1,0"
|
||||
Background="{StaticResource HorizontalNormalBrush}"
|
||||
BorderBrush="{StaticResource HorizontalNormalBorderBrush}"
|
||||
Style="{StaticResource ScrollBarThumb}" />
|
||||
</Track.Thumb>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton Command="ScrollBar.PageDownCommand" Style="{StaticResource ScrollBarPageButton}" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
</Track>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
<!-- HorizontalScrollBar Template using the previously created Templates -->
|
||||
<ControlTemplate x:Key="HorizontalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.ColumnSpan="3"
|
||||
Background="Transparent"
|
||||
CornerRadius="2" />
|
||||
<Track x:Name="PART_Track"
|
||||
Grid.Column="0"
|
||||
IsDirectionReversed="False">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton Command="ScrollBar.PageLeftCommand" Style="{StaticResource ScrollBarPageButton}" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb Margin="0,2"
|
||||
Background="{StaticResource NormalBrush}"
|
||||
BorderBrush="{StaticResource NormalBorderBrush}"
|
||||
Style="{StaticResource ScrollBarThumb}" />
|
||||
</Track.Thumb>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton Command="ScrollBar.PageRightCommand" Style="{StaticResource ScrollBarPageButton}" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
</Track>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
<!-- Style for overall ScrollBar -->
|
||||
<Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Orientation" Value="Horizontal">
|
||||
<Setter Property="Width" Value="Auto" />
|
||||
<Setter Property="Height" Value="15" />
|
||||
<Setter Property="Template" Value="{StaticResource HorizontalScrollBar}" />
|
||||
</Trigger>
|
||||
<Trigger Property="Orientation" Value="Vertical">
|
||||
<Setter Property="Width" Value="13" />
|
||||
<Setter Property="Height" Value="Auto" />
|
||||
<Setter Property="Template" Value="{StaticResource VerticalScrollBar}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
Reference in New Issue
Block a user