Compare commits

..

23 Commits

Author SHA1 Message Date
ema
a491ed9970 Add 'Copy as path' option to More menu
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
2025-09-08 03:53:16 +08:00
ema
c748f6d7e4 Update NuGet package versions in project files
This commit updates various NuGet package references to newer versions across multiple QuickLook plugin and main project .csproj files. These updates include dependencies such as WixToolset.Dtf.WindowsInstaller, UTF.Unknown, FreeTypeSharp, Microsoft.Web.WebView2, Magick.NET-Q8-AnyCPU, Google.Protobuf, MsgReader, HelixToolkit, bblanchon.PDFiumV8.Win32, Melanchall.DryWetMidi, WPF-UI.Violeta, and Lib.Harmony, ensuring the projects use the latest compatible releases.
2025-09-08 02:42:09 +08:00
ema
e0a2204e56 Add diff file syntax highlighting 2025-09-08 02:16:55 +08:00
ema
d6274ac331 Prepare new feature for MoreMenu 2025-09-08 01:49:36 +08:00
ema
07debda5e4 feat: improve UI/UX of font loading 2025-09-08 01:14:01 +08:00
ema
cddf767c6c refactor: simplify tray menu ctor calling 2025-09-07 23:55:24 +08:00
ema
21a3dd3d4b Fix the same previous issue in other plugins
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
2025-08-15 02:17:50 +08:00
ema
ebb48366a0 Fix font file unicode name is not supported 2025-08-15 02:09:38 +08:00
ema
e12bb2201b Fix issue where font file stays locked #77 2025-08-15 02:01:59 +08:00
ema
14a5bea926 Code Cleanup
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
2025-08-09 00:38:43 +08:00
ema
3dbc9fc763 Remove unimportant UnobservedTaskException #1691
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
2025-08-06 00:19:47 +08:00
ema
139cb873f2 Revert SVG default background to transparent
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
2025-08-05 01:19:42 +08:00
ema
fd1004e6d3 Set default background color for SVG panel 2025-08-05 01:11:37 +08:00
ema
b0dceffa94 Add Exporter class for MediaInfo integration 2025-08-05 00:58:48 +08:00
ema
2246c5a361 Fix style changed from MediaInfoViewer 2025-08-05 00:53:21 +08:00
ema
5a5cce93b4 Add built-in plugin MediaInfoViewer
1. Merged from forked repo https://github.com/emako/QuickLook/tree/master/QuickLook.Plugin/QuickLook.Plugin.MediaInfoViewer
2. Use TextBox instead of AvalonEdit and prepare for new feature
2025-08-05 00:43:47 +08:00
ema
8d7df24798 Remove configuration ModernMessageBox
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
2025-08-04 21:17:25 +08:00
ema
3ae4eeb26d Improve CLI performance
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
2025-08-04 00:17:07 +08:00
ema
da0033b52a Improve CLI performance #1706 #1731 2025-08-03 22:20:35 +08:00
ema
2e941f468e Make exe-installer no forked relaunching
Some checks failed
MSBuild / build (push) Has been cancelled
MSBuild / publish (push) Has been cancelled
Since MicaSetup v2.4.0
2025-08-03 02:39:19 +08:00
ema
fbfd2484df Refactor thumbnail handlers into provider classes 2025-08-02 23:58:55 +08:00
ema
e342cd0851 Refactor AnimationProvider to use primary constructor 2025-08-02 23:58:23 +08:00
ema
d90993817d Refactor DependencyProperty registration 2025-08-02 21:58:08 +08:00
68 changed files with 1483 additions and 400 deletions

View File

@@ -36,6 +36,7 @@
"IsRefreshExplorer": true, "IsRefreshExplorer": true,
"IsInstallCertificate": false, "IsInstallCertificate": false,
"IsEnableUninstallDelayUntilReboot": true, "IsEnableUninstallDelayUntilReboot": true,
"IsUseTempPathFork": false,
"IsEnvironmentVariable": false, "IsEnvironmentVariable": false,
"OverlayInstallRemoveExt": "exe,dll,pdb,config,winmd,txt,bat,ax,manifest,xshd", "OverlayInstallRemoveExt": "exe,dll,pdb,config,winmd,txt,bat,ax,manifest,xshd",
"UnpackingPassword": null, "UnpackingPassword": null,

View File

@@ -61,8 +61,8 @@ public class AppImageReader
public AppImageReader(string path) public AppImageReader(string path)
{ {
using FileStream fs = File.OpenRead(path); using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
Open(fs); Open(fileStream);
} }
private void Open(Stream stream) private void Open(Stream stream)

View File

@@ -29,7 +29,7 @@ internal static class WgtParser
{ {
public static WgtInfo Parse(string path) public static WgtInfo Parse(string path)
{ {
using var fileStream = File.OpenRead(path); using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
using var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read); using var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read);
var manifestEntry = zipArchive.GetEntry("manifest.json"); var manifestEntry = zipArchive.GetEntry("manifest.json");

View File

@@ -72,7 +72,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="6.0.1" /> <PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="6.0.2" />
<PackageReference Include="SharpZipLib" Version="1.4.2" /> <PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="PureSharpCompress" Version="0.40.0" /> <PackageReference Include="PureSharpCompress" Version="0.40.0" />

View File

@@ -45,7 +45,7 @@ public class ArchiveFileEntry : IComparable<ArchiveFileEntry>
public DateTime ModifiedDate { get; set; } public DateTime ModifiedDate { get; set; }
/// <summary> /// <summary>
/// Returns the maximum depth of all siblings /// Returns the maximum depth of all siblings
/// </summary> /// </summary>
public int Level public int Level
{ {
@@ -75,7 +75,7 @@ public class ArchiveFileEntry : IComparable<ArchiveFileEntry>
} }
/// <summary> /// <summary>
/// Returns the number of nodes in the longest path to a leaf /// Returns the number of nodes in the longest path to a leaf
/// </summary> /// </summary>
private int GetDepth() private int GetDepth()
{ {

View File

@@ -134,14 +134,14 @@ public partial class ArchiveInfoPanel : UserControl, IDisposable, INotifyPropert
private void LoadItemsFromArchive(string path) private void LoadItemsFromArchive(string path)
{ {
using var stream = File.OpenRead(path); using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
// ReaderFactory is slow... so limit its usage // ReaderFactory is slow... so limit its usage
string[] useReader = [".tar.gz", ".tgz", ".tar.bz2", ".tar.lz", ".tar.xz"]; string[] useReader = [".tar.gz", ".tgz", ".tar.bz2", ".tar.lz", ".tar.xz"];
if (useReader.Any(path.ToLower().EndsWith)) if (useReader.Any(path.ToLower().EndsWith))
{ {
var reader = ReaderFactory.Open(stream, new ChardetReaderOptions()); var reader = ReaderFactory.Open(fileStream, new ChardetReaderOptions());
_type = reader.ArchiveType.ToString(); _type = reader.ArchiveType.ToString();
@@ -149,13 +149,13 @@ public partial class ArchiveInfoPanel : UserControl, IDisposable, INotifyPropert
{ {
if (_disposed) if (_disposed)
return; return;
LoadPercent = 100d * stream.Position / stream.Length; LoadPercent = 100d * fileStream.Position / fileStream.Length;
ProcessByLevel(reader.Entry); ProcessByLevel(reader.Entry);
} }
} }
else else
{ {
var archive = ArchiveFactory.Open(stream, new ChardetReaderOptions()); var archive = ArchiveFactory.Open(fileStream, new ChardetReaderOptions());
_type = archive.Type.ToString(); _type = archive.Type.ToString();
@@ -163,7 +163,7 @@ public partial class ArchiveInfoPanel : UserControl, IDisposable, INotifyPropert
{ {
if (_disposed) if (_disposed)
return; return;
LoadPercent = 100d * stream.Position / stream.Length; LoadPercent = 100d * fileStream.Position / fileStream.Length;
ProcessByLevel(entry); ProcessByLevel(entry);
} }
} }

View File

@@ -28,9 +28,9 @@ using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ArchiveViewer; namespace QuickLook.Plugin.ArchiveViewer;
/// <summary> /// <summary>
/// Internals are mostly from here: /// Internals are mostly from here:
/// http://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using /// http://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using
/// Caches all results. /// Caches all results.
/// </summary> /// </summary>
public static class IconManager public static class IconManager
{ {
@@ -48,7 +48,7 @@ public static class IconManager
} }
/// <summary> /// <summary>
/// Get the icon of a directory /// Get the icon of a directory
/// </summary> /// </summary>
/// <param name="large">16x16 or 32x32 icon</param> /// <param name="large">16x16 or 32x32 icon</param>
/// <returns>an icon</returns> /// <returns>an icon</returns>
@@ -68,7 +68,7 @@ public static class IconManager
} }
/// <summary> /// <summary>
/// Get an icon for a given filename /// Get an icon for a given filename
/// </summary> /// </summary>
/// <param name="fileName">any filename</param> /// <param name="fileName">any filename</param>
/// <param name="large">16x16 or 32x32 icon</param> /// <param name="large">16x16 or 32x32 icon</param>
@@ -89,7 +89,7 @@ public static class IconManager
} }
/// <summary> /// <summary>
/// http://stackoverflow.com/a/6580799/1943849 /// http://stackoverflow.com/a/6580799/1943849
/// </summary> /// </summary>
private static ImageSource ToImageSource(this Icon icon) private static ImageSource ToImageSource(this Icon icon)
{ {
@@ -101,31 +101,31 @@ public static class IconManager
} }
/// <summary> /// <summary>
/// Provides static methods to read system icons for both folders and files. /// Provides static methods to read system icons for both folders and files.
/// </summary> /// </summary>
/// <example> /// <example>
/// <code>IconReader.GetFileIcon("c:\\general.xls");</code> /// <code>IconReader.GetFileIcon("c:\\general.xls");</code>
/// </example> /// </example>
private static class IconReader private static class IconReader
{ {
/// <summary> /// <summary>
/// Options to specify the size of icons to return. /// Options to specify the size of icons to return.
/// </summary> /// </summary>
public enum IconSize public enum IconSize
{ {
/// <summary> /// <summary>
/// Specify large icon - 32 pixels by 32 pixels. /// Specify large icon - 32 pixels by 32 pixels.
/// </summary> /// </summary>
Large = 0, Large = 0,
/// <summary> /// <summary>
/// Specify small icon - 16 pixels by 16 pixels. /// Specify small icon - 16 pixels by 16 pixels.
/// </summary> /// </summary>
Small = 1 Small = 1
} }
/// <summary> /// <summary>
/// Returns the icon of a folder. /// Returns the icon of a folder.
/// </summary> /// </summary>
/// <param name="size">Large or small</param> /// <param name="size">Large or small</param>
/// <param name="linkOverlay">Whether to include the link icon</param> /// <param name="linkOverlay">Whether to include the link icon</param>
@@ -152,7 +152,7 @@ public static class IconManager
} }
/// <summary> /// <summary>
/// Returns an icon for a given file - indicated by the name parameter. /// Returns an icon for a given file - indicated by the name parameter.
/// </summary> /// </summary>
/// <param name="name">Pathname for file.</param> /// <param name="name">Pathname for file.</param>
/// <param name="size">Large or small</param> /// <param name="size">Large or small</param>
@@ -181,8 +181,8 @@ public static class IconManager
} }
/// <summary> /// <summary>
/// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code /// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
/// courtesy of MSDN Cold Rooster Consulting case study. /// courtesy of MSDN Cold Rooster Consulting case study.
/// </summary> /// </summary>
private static class Shell32 private static class Shell32
{ {
@@ -221,13 +221,13 @@ public static class IconManager
} }
/// <summary> /// <summary>
/// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example. /// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example.
/// </summary> /// </summary>
private static class User32 private static class User32
{ {
/// <summary> /// <summary>
/// Provides access to function required to delete handle. This method is used internally /// Provides access to function required to delete handle. This method is used internally
/// and is not required to be called separately. /// and is not required to be called separately.
/// </summary> /// </summary>
/// <param name="hIcon">Pointer to icon handle.</param> /// <param name="hIcon">Pointer to icon handle.</param>
/// <returns>N/A</returns> /// <returns>N/A</returns>

View File

@@ -53,7 +53,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="PureSharpCompress" Version="0.40.0" /> <PackageReference Include="PureSharpCompress" Version="0.40.0" />
<PackageReference Include="UTF.Unknown" Version="2.5.1" /> <PackageReference Include="UTF.Unknown" Version="2.6.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -53,7 +53,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CsvHelper" Version="33.1.0" /> <PackageReference Include="CsvHelper" Version="33.1.0" />
<PackageReference Include="UTF.Unknown" Version="2.5.1" /> <PackageReference Include="UTF.Unknown" Version="2.6.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -40,12 +40,19 @@ internal unsafe static class FreeTypeApi
error = FT_New_Face(lib, (byte*)Marshal.StringToHGlobalAnsi(path), IntPtr.Zero, &face); error = FT_New_Face(lib, (byte*)Marshal.StringToHGlobalAnsi(path), IntPtr.Zero, &face);
if (error == FT_Error.FT_Err_Ok) try
{ {
var familyName = Marshal.PtrToStringAnsi((nint)face->family_name); if (error == FT_Error.FT_Err_Ok)
return familyName; {
var familyName = Marshal.PtrToStringAnsi((nint)face->family_name);
return familyName;
}
}
finally
{
FT_Done_Face(face);
FT_Done_FreeType(lib);
} }
return null; return null;
} }
} }

View File

@@ -0,0 +1,26 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace QuickLook.Plugin.FontViewer;
public class ObservableFileStream(string path, FileMode mode, FileAccess access, FileShare share) : FileStream(path, mode, access, share)
{
public bool IsEndOfStream { get; protected set; } = false;
public override int Read(byte[] array, int offset, int count)
{
int result = base.Read(array, offset, count);
if (result == 0)
IsEndOfStream = true;
return result;
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
int result = await base.ReadAsync(buffer, offset, count, cancellationToken);
if (result == 0)
IsEndOfStream = true;
return result;
}
}

View File

@@ -19,6 +19,7 @@ using QuickLook.Common.Plugin;
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
namespace QuickLook.Plugin.FontViewer; namespace QuickLook.Plugin.FontViewer;
@@ -52,7 +53,12 @@ public class Plugin : IViewer
context.ViewerContent = _panel; context.ViewerContent = _panel;
context.Title = Path.GetFileName(path); context.Title = Path.GetFileName(path);
context.IsBusy = false;
_ = Task.Run(() =>
{
_ = _panel.WaitForFontSent();
context.IsBusy = false;
});
} }
public void Cleanup() public void Cleanup()

View File

@@ -71,9 +71,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FreeTypeSharp" Version="3.0.0" /> <PackageReference Include="FreeTypeSharp" Version="3.0.1" />
<PackageReference Include="QuickLook.Typography.OpenFont" Version="1.0.1" /> <PackageReference Include="QuickLook.Typography.OpenFont" Version="1.0.1" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3351.48"> <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3405.78">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>

View File

@@ -26,6 +26,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading;
namespace QuickLook.Plugin.FontViewer; namespace QuickLook.Plugin.FontViewer;
@@ -34,6 +35,7 @@ public class WebfontPanel : WebpagePanel
protected const string _resourcePrefix = "QuickLook.Plugin.FontViewer.Resources."; protected const string _resourcePrefix = "QuickLook.Plugin.FontViewer.Resources.";
protected internal static readonly Dictionary<string, byte[]> _resources = []; protected internal static readonly Dictionary<string, byte[]> _resources = [];
protected byte[] _homePage; protected byte[] _homePage;
protected ObservableFileStream _fontStream = null;
static WebfontPanel() static WebfontPanel()
{ {
@@ -149,14 +151,15 @@ public class WebfontPanel : WebpagePanel
} }
else else
{ {
var localPath = _fallbackPath + requestedUri.AbsolutePath.Replace('/', '\\'); var localPath = _fallbackPath + Uri.UnescapeDataString(requestedUri.AbsolutePath).Replace('/', '\\');
if (File.Exists(localPath)) if (File.Exists(localPath))
{ {
var fileStream = File.OpenRead(localPath); var fileStream = new ObservableFileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse( var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse(
fileStream, 200, "OK", MimeTypes.GetContentType()); fileStream, 200, "OK", MimeTypes.GetContentType());
args.Response = response; args.Response = response;
_fontStream = fileStream; // Only the font request will set this
} }
} }
} }
@@ -168,6 +171,19 @@ public class WebfontPanel : WebpagePanel
} }
} }
public bool WaitForFontSent()
{
bool timeout = SpinWait.SpinUntil(
() => _fontStream is not null && _fontStream.IsEndOfStream,
TimeSpan.FromSeconds(1.5d) // The prediction is MAX 100MB
);
// Only when the `IsEndOfStream` is true
// Delay 15ms per MB for webview2 to render the font
if (timeout) Thread.Sleep(15 * (int)(_fontStream.Position / 1_048_576));
return timeout;
}
public static bool ContainsKey(string key) public static bool ContainsKey(string key)
{ {
return _resources.ContainsKey(key); return _resources.ContainsKey(key);

View File

@@ -52,8 +52,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="HelixToolkit" Version="2.27.0" /> <PackageReference Include="HelixToolkit" Version="2.27.3" />
<PackageReference Include="HelixToolkit.Wpf" Version="2.27.0" /> <PackageReference Include="HelixToolkit.Wpf" Version="2.27.3" />
<PackageReference Include="AssimpNet" Version="5.0.0-beta1" /> <PackageReference Include="AssimpNet" Version="5.0.0-beta1" />
<PackageReference Include="PcdSharp" Version="1.0.1" /> <PackageReference Include="PcdSharp" Version="1.0.1" />
</ItemGroup> </ItemGroup>

View File

@@ -61,7 +61,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3351.48"> <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3405.78">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>

View File

@@ -210,7 +210,7 @@ public class WebpagePanel : UserControl
if (File.Exists(fallbackFilePath)) if (File.Exists(fallbackFilePath))
{ {
// Serve the file from the fallback directory // Serve the file from the fallback directory
var fileStream = File.OpenRead(fallbackFilePath); var fileStream = new FileStream(fallbackFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse( var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse(
fileStream, 200, "OK", "Content-Type: application/octet-stream"); fileStream, 200, "OK", "Content-Type: application/octet-stream");
args.Response = response; args.Response = response;

View File

@@ -59,21 +59,19 @@ public class AnimatedImage : Image, IDisposable
return provider; return provider;
} }
#region DependencyProperty
public static readonly DependencyProperty AnimationFrameIndexProperty = public static readonly DependencyProperty AnimationFrameIndexProperty =
DependencyProperty.Register("AnimationFrameIndex", typeof(int), typeof(AnimatedImage), DependencyProperty.Register(nameof(AnimationFrameIndex), typeof(int), typeof(AnimatedImage),
new UIPropertyMetadata(-1, AnimationFrameIndexChanged)); new UIPropertyMetadata(-1, AnimationFrameIndexChanged));
public static readonly DependencyProperty AnimationUriProperty = public static readonly DependencyProperty AnimationUriProperty =
DependencyProperty.Register("AnimationUri", typeof(Uri), typeof(AnimatedImage), DependencyProperty.Register(nameof(AnimationUri), typeof(Uri), typeof(AnimatedImage),
new UIPropertyMetadata(null, AnimationUriChanged)); new UIPropertyMetadata(null, AnimationUriChanged));
public static readonly DependencyProperty MetaProperty = public static readonly DependencyProperty MetaProperty =
DependencyProperty.Register("Meta", typeof(MetaProvider), typeof(AnimatedImage)); DependencyProperty.Register(nameof(Meta), typeof(MetaProvider), typeof(AnimatedImage));
public static readonly DependencyProperty ContextObjectProperty = public static readonly DependencyProperty ContextObjectProperty =
DependencyProperty.Register("ContextObject", typeof(ContextObject), typeof(AnimatedImage)); DependencyProperty.Register(nameof(ContextObject), typeof(ContextObject), typeof(AnimatedImage));
public int AnimationFrameIndex public int AnimationFrameIndex
{ {
@@ -104,9 +102,6 @@ public class AnimatedImage : Image, IDisposable
if (obj is not AnimatedImage instance) if (obj is not AnimatedImage instance)
return; return;
//var thumbnail = instance.Meta?.GetThumbnail(true);
//instance.Source = thumbnail;
instance._animation = InitAnimationProvider((Uri)ev.NewValue, instance.Meta, instance.ContextObject); instance._animation = InitAnimationProvider((Uri)ev.NewValue, instance.Meta, instance.ContextObject);
ShowThumbnailAndStartAnimation(instance); ShowThumbnailAndStartAnimation(instance);
} }
@@ -161,6 +156,4 @@ public class AnimatedImage : Image, IDisposable
})); }));
task.Start(); task.Start();
} }
#endregion DependencyProperty
} }

View File

@@ -24,20 +24,13 @@ using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage; namespace QuickLook.Plugin.ImageViewer.AnimatedImage;
internal abstract class AnimationProvider : IDisposable internal abstract class AnimationProvider(Uri path, MetaProvider meta, ContextObject contextObject) : IDisposable
{ {
protected AnimationProvider(Uri path, MetaProvider meta, ContextObject contextObject) public Uri Path { get; } = path;
{
Path = path;
Meta = meta;
ContextObject = contextObject;
}
public Uri Path { get; } public MetaProvider Meta { get; } = meta;
public MetaProvider Meta { get; } public ContextObject ContextObject { get; } = contextObject;
public ContextObject ContextObject { get; }
public Int32AnimationUsingKeyFrames Animator { get; protected set; } public Int32AnimationUsingKeyFrames Animator { get; protected set; }

View File

@@ -103,9 +103,7 @@ public partial class ImagePanel : UserControl, INotifyPropertyChanged, IDisposab
ContextObject = context; ContextObject = context;
Meta = meta; Meta = meta;
var s = meta.GetSize(); _ = meta.GetSize();
//_minZoomFactor = Math.Min(200d / s.Height, 400d / s.Width);
//_maxZoomFactor = Math.Min(9000d / s.Height, 9000d / s.Width);
ShowMeta(); ShowMeta();
Theme = ContextObject.Theme; Theme = ContextObject.Theme;

View File

@@ -59,13 +59,13 @@
<PackageReference Include="QuickLook.ImageGlass.WebP" Version="1.4.0"> <PackageReference Include="QuickLook.ImageGlass.WebP" Version="1.4.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.7.0"> <PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.8.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3351.48"> <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3405.78">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Google.Protobuf" Version="3.31.1"> <PackageReference Include="Google.Protobuf" Version="3.32.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="System.Memory" Version="4.6.3"> <PackageReference Include="System.Memory" Version="4.6.3">

View File

@@ -27,7 +27,7 @@ internal static class LottieExtractor
{ {
public static string GetJsonContent(string path) public static string GetJsonContent(string path)
{ {
using var fileStream = File.OpenRead(path); using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
using var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read); using var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read);
var manifestEntry = zipArchive.GetEntry("manifest.json"); var manifestEntry = zipArchive.GetEntry("manifest.json");

View File

@@ -22,6 +22,7 @@ using QuickLook.Plugin.HtmlViewer;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@@ -67,6 +68,7 @@ public class SvgImagePanel : WebpagePanel, IWebImagePanel
{ {
UserDataFolder = Path.Combine(SettingHelper.LocalDataPath, @"WebView2_Data\"), UserDataFolder = Path.Combine(SettingHelper.LocalDataPath, @"WebView2_Data\"),
}, },
DefaultBackgroundColor = Color.Transparent,
}; };
_webView.CoreWebView2InitializationCompleted += WebView_CoreWebView2InitializationCompleted; _webView.CoreWebView2InitializationCompleted += WebView_CoreWebView2InitializationCompleted;
Content = _webView; Content = _webView;
@@ -128,11 +130,11 @@ public class SvgImagePanel : WebpagePanel, IWebImagePanel
} }
else else
{ {
var localPath = _fallbackPath + requestedUri.AbsolutePath.Replace('/', '\\'); var localPath = _fallbackPath + Uri.UnescapeDataString(requestedUri.AbsolutePath).Replace('/', '\\');
if (File.Exists(localPath)) if (File.Exists(localPath))
{ {
var fileStream = File.OpenRead(localPath); var fileStream = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse( var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse(
fileStream, 200, "OK", MimeTypes.GetContentTypeHeader()); fileStream, 200, "OK", MimeTypes.GetContentTypeHeader());
args.Response = response; args.Response = response;
@@ -147,7 +149,7 @@ public class SvgImagePanel : WebpagePanel, IWebImagePanel
{ {
if (File.Exists(localPath)) if (File.Exists(localPath))
{ {
var fileStream = File.OpenRead(localPath); var fileStream = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse( var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse(
fileStream, 200, "OK", fileStream, 200, "OK",
$""" $"""

View File

@@ -55,7 +55,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MsgReader" Version="6.0.1" /> <PackageReference Include="MsgReader" Version="6.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -124,11 +124,11 @@ public class MarkdownPanel : WebpagePanel
} }
else else
{ {
var localPath = _fallbackPath + requestedUri.AbsolutePath.Replace('/', '\\'); var localPath = _fallbackPath + Uri.UnescapeDataString(requestedUri.AbsolutePath).Replace('/', '\\');
if (File.Exists(localPath)) if (File.Exists(localPath))
{ {
var fileStream = File.OpenRead(localPath); var fileStream = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse( var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse(
fileStream, 200, "OK", MimeTypes.GetContentType()); fileStream, 200, "OK", MimeTypes.GetContentType());
args.Response = response; args.Response = response;

View File

@@ -59,9 +59,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="UTF.Unknown" Version="2.5.1" /> <PackageReference Include="UTF.Unknown" Version="2.6.0" />
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3351.48"> <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3405.78">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>

View File

@@ -0,0 +1,16 @@
using MediaInfoLib;
using System.ComponentModel.Composition;
namespace QuickLook.Plugin.MediaInfoViewer;
[Export]
public static class Exporter
{
public static MediaInfo Open(string path)
{
MediaInfo lib = new MediaInfo()
.WithOpen(path);
return lib;
}
}

View File

@@ -0,0 +1,109 @@
// Copyright © 2017-2025 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 MediaInfoLib;
using QuickLook.Common.Helpers;
using QuickLook.Common.Plugin;
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media;
namespace QuickLook.Plugin.MediaInfoViewer;
public class Plugin : IViewer
{
private TextViewerPanel _tvp;
public int Priority => 0;
public void Init()
{
}
public bool CanHandle(string path)
{
// We only handle files with specific caller
return false;
}
public void Prepare(string path, ContextObject context)
{
context.PreferredSize = new Size { Width = 800, Height = 600 };
}
public void View(string path, ContextObject context)
{
using MediaInfo lib = new MediaInfo()
.WithOpen(path);
_tvp = new TextViewerPanel(lib.Inform(), context);
AssignHighlightingManager(_tvp, context);
_tvp.Tag = context;
_tvp.Drop += OnDrop;
context.ViewerContent = _tvp;
context.Title = $"{Path.GetFileName(path)}";
context.IsBusy = false;
}
private void OnDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
if (e.Data.GetData(DataFormats.FileDrop) is string[] files
&& files.FirstOrDefault() is string path)
{
if (_tvp!.Tag is ContextObject context)
{
context.Title = $"{Path.GetFileName(path)}";
}
using MediaInfo lib = new MediaInfo()
.WithOpen(path);
_tvp!.Text = lib.Inform();
}
}
}
public void Cleanup()
{
GC.SuppressFinalize(this);
_tvp = null!;
}
private void AssignHighlightingManager(TextViewerPanel tvp, ContextObject context)
{
var isDark = OSThemeHelper.AppsUseDarkTheme();
if (isDark)
{
context.Theme = Themes.Dark;
tvp.Foreground = new BrushConverter().ConvertFromString("#FFEFEFEF") as SolidColorBrush;
tvp.Background = Brushes.Transparent;
}
else
{
context.Theme = Themes.Light;
tvp.Foreground = new BrushConverter().ConvertFromString("#BBFAFAFA") as SolidColorBrush;
tvp.Background = Brushes.Transparent;
}
}
}

View File

@@ -0,0 +1,50 @@
// Copyright © 2017-2025 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.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.Plugin.MediaInfoViewer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("pooi.moe")]
[assembly: AssemblyProduct("QuickLook.Plugin.MediaInfoViewer")]
[assembly: AssemblyCopyright("Copyright © 2017-2025 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("b0054a16-472e-44ac-ba40-349303e524ff")]
// 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.*")]

View File

@@ -0,0 +1,84 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net462</TargetFramework>
<RootNamespace>QuickLook.Plugin.MediaInfoViewer</RootNamespace>
<AssemblyName>QuickLook.Plugin.MediaInfoViewer</AssemblyName>
<FileAlignment>512</FileAlignment>
<SignAssembly>false</SignAssembly>
<UseWPF>true</UseWPF>
<LangVersion>latest</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<ProjectGuid>{B0054A16-472E-44AC-BA40-349303E524FF}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<OutputPath>..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\QuickLook.Common\QuickLook.Common.csproj">
<Project>{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}</Project>
<Name>QuickLook.Common</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\GitVersion.cs">
<Link>Properties\GitVersion.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System.ComponentModel.Composition" />
<PackageReference Include="MediaInfoDLL" Version="25.7.0" />
</ItemGroup>
<Target Name="ReduceReleasePackaging" AfterTargets="Build">
<!-- MediaInfoDLL will copy the MediaInfo.dll file according to the architecture, we do not use this usage so delete it manually -->
<Delete Files="$(OutputPath)\MediaInfo.dll" Condition="Exists('$(OutputPath)\MediaInfo.dll')" />
</Target>
<ItemGroup>
<None Update="Translations.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,100 @@
// Copyright © 2017-2025 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.Helpers;
using QuickLook.Common.Plugin;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace QuickLook.Plugin.MediaInfoViewer;
public class TextViewerPanel : TextBox
{
public TextViewerPanel(string text, ContextObject context)
{
_ = context;
TextWrapping = TextWrapping.Wrap;
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
Margin = new Thickness(8d, 0d, 0d, 0d);
BorderThickness = new Thickness(0d);
FontSize = 14d;
IsReadOnly = true;
IsManipulationEnabled = true;
ContextMenu = new ContextMenu();
ContextMenu.Items.Add(new MenuItem
{
Header = TranslationHelper.Get("Editor_Copy", domain: "QuickLook.Plugin.TextViewer"),
Command = ApplicationCommands.Copy,
});
ContextMenu.Items.Add(new MenuItem
{
Header = TranslationHelper.Get("Editor_SelectAll",
domain: "QuickLook.Plugin.TextViewer"),
Command = ApplicationCommands.SelectAll,
});
ManipulationInertiaStarting += Viewer_ManipulationInertiaStarting;
ManipulationStarting += Viewer_ManipulationStarting;
ManipulationDelta += Viewer_ManipulationDelta;
PreviewMouseWheel += Viewer_MouseWheel;
FontFamily = new FontFamily("Consolas, " + TranslationHelper.Get("Editor_FontFamily",
domain: "QuickLook.Plugin.TextViewer"));
LoadTextAsync(text);
}
private void Viewer_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
{
e.TranslationBehavior = new InertiaTranslationBehavior
{
InitialVelocity = e.InitialVelocities.LinearVelocity,
DesiredDeceleration = 10d * 96d / (1000d * 1000d)
};
}
private void Viewer_MouseWheel(object sender, MouseWheelEventArgs e)
{
e.Handled = true;
ScrollToVerticalOffset(VerticalOffset - e.Delta);
}
private void Viewer_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
e.Handled = true;
var delta = e.DeltaManipulation;
ScrollToVerticalOffset(VerticalOffset - delta.Translation.Y);
}
private void Viewer_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
{
e.Mode = ManipulationModes.Translate;
}
private void LoadTextAsync(string text)
{
Text = text;
}
}

View File

@@ -64,7 +64,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="PdfiumViewer.Updated" Version="2.14.5" /> <PackageReference Include="PdfiumViewer.Updated" Version="2.14.5" />
<PackageReference Include="bblanchon.PDFiumV8.Win32" Version="140.0.7269" /> <PackageReference Include="bblanchon.PDFiumV8.Win32" Version="141.0.7388" />
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
</ItemGroup> </ItemGroup>

View File

@@ -69,9 +69,9 @@ public class Plugin : IViewer
if (path.EndsWith(".rtf", StringComparison.OrdinalIgnoreCase)) if (path.EndsWith(".rtf", StringComparison.OrdinalIgnoreCase))
{ {
var rtfBox = new RichTextBox(); var rtfBox = new RichTextBox();
using FileStream fs = File.OpenRead(path); using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
rtfBox.Background = new SolidColorBrush(Colors.Transparent); rtfBox.Background = new SolidColorBrush(Colors.Transparent);
rtfBox.Selection.Load(fs, DataFormats.Rtf); rtfBox.Selection.Load(fileStream, DataFormats.Rtf);
rtfBox.IsReadOnly = true; rtfBox.IsReadOnly = true;
rtfBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; rtfBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
rtfBox.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto; rtfBox.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;

View File

@@ -60,7 +60,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AvalonEdit" Version="6.3.1.120" /> <PackageReference Include="AvalonEdit" Version="6.3.1.120" />
<PackageReference Include="UTF.Unknown" Version="2.5.1" /> <PackageReference Include="UTF.Unknown" Version="2.6.0" />
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
<Reference Include="System.ComponentModel.Composition" /> <Reference Include="System.ComponentModel.Composition" />
<PackageReference Include="System.Memory" Version="4.6.3" /> <PackageReference Include="System.Memory" Version="4.6.3" />

View File

@@ -0,0 +1,124 @@
// Copyright © 2017-2025 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 ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Rendering;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace QuickLook.Plugin.TextViewer.Themes.HighlightingDefinitions.Dark;
public class DiffHighlightingDefinition : DarkHighlightingDefinition
{
public override string Name => "Diff";
public override string Extension => ".diff";
public override HighlightingRuleSet MainRuleSet => new()
{
Rules =
{
// Diff header (diff --git, index, etc.)
new HighlightingRule
{
Regex = new Regex(@"^(diff --git|index|---|\+\+\+)", RegexOptions.Compiled),
Color = GetNamedColor("Header")
},
// File mode and other metadata
new HighlightingRule
{
Regex = new Regex(@"^(new file mode|deleted file mode|old mode|new mode|similarity index|dissimilarity index|rename from|rename to|copy from|copy to)", RegexOptions.Compiled),
Color = GetNamedColor("Metadata")
},
// Hunk headers (@@ ... @@)
new HighlightingRule
{
Regex = new Regex(@"^@@.*@@$", RegexOptions.Compiled),
Color = GetNamedColor("HunkHeader")
},
// Added lines (+)
new HighlightingRule
{
Regex = new Regex(@"^\+.*$", RegexOptions.Compiled),
Color = GetNamedColor("Added")
},
// Removed lines (-)
new HighlightingRule
{
Regex = new Regex(@"^-.*$", RegexOptions.Compiled),
Color = GetNamedColor("Removed")
},
// Context lines (unchanged)
new HighlightingRule
{
Regex = new Regex(@"^ .*", RegexOptions.Compiled),
Color = GetNamedColor("Context")
}
}
};
public override HighlightingColor GetNamedColor(string name)
{
return name switch
{
"Header" => new HighlightingColor
{
Name = "Header",
Foreground = new SimpleHighlightingBrush("#569CD6".ToColor()), // Blue for headers
},
"Metadata" => new HighlightingColor
{
Name = "Metadata",
Foreground = new SimpleHighlightingBrush("#808080".ToColor()), // Gray for metadata
},
"HunkHeader" => new HighlightingColor
{
Name = "HunkHeader",
Foreground = new SimpleHighlightingBrush("#C586C0".ToColor()), // Purple for hunk headers
},
"Added" => new HighlightingColor
{
Name = "Added",
Foreground = new SimpleHighlightingBrush("#6A9949".ToColor()), // Green for added lines
},
"Removed" => new HighlightingColor
{
Name = "Removed",
Foreground = new SimpleHighlightingBrush("#F44747".ToColor()), // Red for removed lines
},
"Context" => new HighlightingColor
{
Name = "Context",
Foreground = new SimpleHighlightingBrush("#D4D4D4".ToColor()), // Light gray for context
},
_ => null,
};
}
public override IEnumerable<HighlightingColor> NamedHighlightingColors =>
[
GetNamedColor("Header"),
GetNamedColor("Metadata"),
GetNamedColor("HunkHeader"),
GetNamedColor("Added"),
GetNamedColor("Removed"),
GetNamedColor("Context"),
];
public override DocumentColorizingTransformer[] LineTransformers { get; } = [];
}

View File

@@ -0,0 +1,124 @@
// Copyright © 2017-2025 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 ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Rendering;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace QuickLook.Plugin.TextViewer.Themes.HighlightingDefinitions.Light;
public class DiffHighlightingDefinition : LightHighlightingDefinition
{
public override string Name => "Diff";
public override string Extension => ".diff";
public override HighlightingRuleSet MainRuleSet => new()
{
Rules =
{
// Diff header (diff --git, index, etc.)
new HighlightingRule
{
Regex = new Regex(@"^(diff --git|index|---|\+\+\+)", RegexOptions.Compiled),
Color = GetNamedColor("Header")
},
// File mode and other metadata
new HighlightingRule
{
Regex = new Regex(@"^(new file mode|deleted file mode|old mode|new mode|similarity index|dissimilarity index|rename from|rename to|copy from|copy to)", RegexOptions.Compiled),
Color = GetNamedColor("Metadata")
},
// Hunk headers (@@ ... @@)
new HighlightingRule
{
Regex = new Regex(@"^@@.*@@$", RegexOptions.Compiled),
Color = GetNamedColor("HunkHeader")
},
// Added lines (+)
new HighlightingRule
{
Regex = new Regex(@"^\+.*$", RegexOptions.Compiled),
Color = GetNamedColor("Added")
},
// Removed lines (-)
new HighlightingRule
{
Regex = new Regex(@"^-.*$", RegexOptions.Compiled),
Color = GetNamedColor("Removed")
},
// Context lines (unchanged)
new HighlightingRule
{
Regex = new Regex(@"^ .*", RegexOptions.Compiled),
Color = GetNamedColor("Context")
}
}
};
public override HighlightingColor GetNamedColor(string name)
{
return name switch
{
"Header" => new HighlightingColor
{
Name = "Header",
Foreground = new SimpleHighlightingBrush("#2563EB".ToColor()), // Blue for headers
},
"Metadata" => new HighlightingColor
{
Name = "Metadata",
Foreground = new SimpleHighlightingBrush("#6B7280".ToColor()), // Gray for metadata
},
"HunkHeader" => new HighlightingColor
{
Name = "HunkHeader",
Foreground = new SimpleHighlightingBrush("#7C3AED".ToColor()), // Purple for hunk headers
},
"Added" => new HighlightingColor
{
Name = "Added",
Foreground = new SimpleHighlightingBrush("#15803D".ToColor()), // Green for added lines
},
"Removed" => new HighlightingColor
{
Name = "Removed",
Foreground = new SimpleHighlightingBrush("#DC2626".ToColor()), // Red for removed lines
},
"Context" => new HighlightingColor
{
Name = "Context",
Foreground = new SimpleHighlightingBrush("#374151".ToColor()), // Gray for context
},
_ => null,
};
}
public override IEnumerable<HighlightingColor> NamedHighlightingColors =>
[
GetNamedColor("Header"),
GetNamedColor("Metadata"),
GetNamedColor("HunkHeader"),
GetNamedColor("Added"),
GetNamedColor("Removed"),
GetNamedColor("Context"),
];
public override DocumentColorizingTransformer[] LineTransformers { get; } = [];
}

View File

@@ -187,8 +187,8 @@ public class HighlightingThemeManager
{ {
Debug.WriteLine(file); Debug.WriteLine(file);
var ext = Path.GetFileNameWithoutExtension(file); var ext = Path.GetFileNameWithoutExtension(file);
using Stream s = File.OpenRead(Path.GetFullPath(file)); using var fileStream = new FileStream(Path.GetFullPath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
using var reader = new XmlTextReader(s); using var reader = new XmlTextReader(fileStream);
var xshd = HighlightingLoader.LoadXshd(reader); var xshd = HighlightingLoader.LoadXshd(reader);
var highlightingDefinition = HighlightingLoader.Load(xshd, hlm); var highlightingDefinition = HighlightingLoader.Load(xshd, hlm);
if (xshd.Extensions.Count > 0) if (xshd.Extensions.Count > 0)

View File

@@ -15,165 +15,43 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
using PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using QuickLook.Common.Plugin; using QuickLook.Common.Plugin;
using System; using QuickLook.Plugin.ThumbnailViewer.Providors;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ThumbnailViewer; namespace QuickLook.Plugin.ThumbnailViewer;
internal static class Handler internal static class Handler
{ {
// List<Pair<formats, type>>
public static List<KeyValuePair<string[], Type>> Providers = [];
public static void Prepare(string path, ContextObject context) public static void Prepare(string path, ContextObject context)
{ {
// Temporary codes (Path.GetExtension(path).ToLower() switch
if (path.EndsWith(".pdn", StringComparison.OrdinalIgnoreCase))
{ {
new PdnProvider().Prepare(path, context); ".cdr" => new CdrProvider(),
return; ".fig" => new FigProvidor(),
} ".kra" => new KraProvidor(),
".pdn" => new PdnProvider(),
try ".pip" or ".pix" => new PixProvidor(),
{ ".sketch" => new SketchProvidor(),
using Stream imageData = ViewImage(path); ".xd" => new XdProvidor(),
BitmapImage bitmap = imageData.ReadAsBitmapImage(); ".xmind" => new XmindProvidor(),
context.SetPreferredSizeFit(new Size(bitmap.PixelWidth, bitmap.PixelHeight), 0.8d); _ => (AbstractProvidor)null,
} })?.Prepare(path, context);
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
context.PreferredSize = new Size { Width = 800, Height = 600 };
}
} }
public static Stream ViewImage(string path) public static Stream ViewImage(string path)
{ {
// Temporary codes return (Path.GetExtension(path).ToLower() switch
if (path.EndsWith(".pdn", StringComparison.OrdinalIgnoreCase))
{ {
return new PdnProvider().ViewImage(path); ".cdr" => new CdrProvider(),
} ".fig" => new FigProvidor(),
".kra" => new KraProvidor(),
try ".pdn" => new PdnProvider(),
{ ".pip" or ".pix" => new PixProvidor(),
using ZipArchive archive = ZipArchive.Open(path, new()); ".sketch" => new SketchProvidor(),
using IReader reader = archive.ExtractAllEntries(); ".xd" => new XdProvidor(),
".xmind" => new XmindProvidor(),
if (path.EndsWith(".xd", StringComparison.OrdinalIgnoreCase)) _ => (AbstractProvidor)null,
{ })?.ViewImage(path);
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("preview.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
else if (reader.Entry.Key!.Equals("thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".fig", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".pip", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".pix", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.EndsWith(".thumb.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".sketch", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.EndsWith("previews/preview.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".xmind", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("Thumbnails/thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".kra", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Contains("mergedimage"))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".cdr", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("previews/thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
} }
} }

View File

@@ -47,8 +47,6 @@ public class Plugin : IViewer
public void Init() public void Init()
{ {
Handler.Providers.Add(new KeyValuePair<string[], Type>(
[".pdn"], typeof(PdnProvider)));
} }
public bool CanHandle(string path) public bool CanHandle(string path)

View File

@@ -0,0 +1,45 @@
// Copyright © 2017-2025 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.Plugin;
using System;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal abstract class AbstractProvidor
{
public virtual void Prepare(string path, ContextObject context)
{
try
{
using Stream imageData = ViewImage(path);
BitmapImage bitmap = imageData.ReadAsBitmapImage();
context.SetPreferredSizeFit(new Size(bitmap.PixelWidth, bitmap.PixelHeight), 0.8d);
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
context.PreferredSize = new Size { Width = 800, Height = 600 };
}
}
public abstract Stream ViewImage(string path);
}

View File

@@ -0,0 +1,56 @@
// Copyright © 2017-2025 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class CdrProvider : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("previews/thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -0,0 +1,56 @@
// Copyright © 2017-2025 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class FigProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -0,0 +1,56 @@
// Copyright © 2017-2025 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class KraProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Contains("mergedimage"))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -16,36 +16,16 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
using QuickLook.Common.Helpers; using QuickLook.Common.Helpers;
using QuickLook.Common.Plugin;
using QuickLook.Plugin.ImageViewer;
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Xml.Linq; using System.Xml.Linq;
namespace QuickLook.Plugin.ThumbnailViewer; namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class PdnProvider internal class PdnProvider : AbstractProvidor
{ {
public void Prepare(string path, ContextObject context) public override Stream ViewImage(string path)
{
try
{
using Stream imageData = ViewImage(path);
BitmapImage bitmap = imageData.ReadAsBitmapImage();
context.SetPreferredSizeFit(new Size(bitmap.PixelWidth, bitmap.PixelHeight), 0.8d);
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
context.PreferredSize = new Size { Width = 800, Height = 600 };
}
}
public Stream ViewImage(string path)
{ {
try try
{ {

View File

@@ -0,0 +1,56 @@
// Copyright © 2017-2025 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class PixProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.EndsWith(".thumb.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -0,0 +1,56 @@
// Copyright © 2017-2025 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class SketchProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.EndsWith("previews/preview.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -0,0 +1,63 @@
// Copyright © 2017-2025 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class XdProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("preview.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
else if (reader.Entry.Key!.Equals("thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -0,0 +1,56 @@
// Copyright © 2017-2025 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class XmindProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("Thumbnails/thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -41,15 +41,15 @@
<PackageReference Include="MediaInfo.Wrapper" Version="21.9.3"> <PackageReference Include="MediaInfo.Wrapper" Version="21.9.3">
<Aliases>MediaInfoWrapper</Aliases> <Aliases>MediaInfoWrapper</Aliases>
</PackageReference> </PackageReference>
<PackageReference Include="MediaInfoDLL" Version="25.4.0"> <PackageReference Include="MediaInfoDLL" Version="25.7.0">
<Aliases>MediaInfoDLL</Aliases> <Aliases>MediaInfoDLL</Aliases>
</PackageReference> </PackageReference>
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
<Reference Include="DirectShowLib-2005, Version=2.1.0.26626, Culture=neutral, PublicKeyToken=67e7b740cdfc2d3f, processorArchitecture=MSIL"> <Reference Include="DirectShowLib-2005, Version=2.1.0.26626, Culture=neutral, PublicKeyToken=67e7b740cdfc2d3f, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
</Reference> </Reference>
<PackageReference Include="UTF.Unknown" Version="2.5.1" /> <PackageReference Include="UTF.Unknown" Version="2.6.0" />
<PackageReference Include="Melanchall.DryWetMidi" Version="8.0.1" /> <PackageReference Include="Melanchall.DryWetMidi" Version="8.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -187,17 +187,17 @@
<DestinationFolder>$(OutDir)\LAVFilters-x86\</DestinationFolder> <DestinationFolder>$(OutDir)\LAVFilters-x86\</DestinationFolder>
<Link>LAVFilters-x86\swscale-lav-8.dll</Link> <Link>LAVFilters-x86\swscale-lav-8.dll</Link>
</Content> </Content>
<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.4.0\lib\netstandard2.0\x64\MediaInfo.dll"> <Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.7.0\lib\netstandard2.0\x64\MediaInfo.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DestinationFolder>$(OutDir)MediaInfo-x64\</DestinationFolder> <DestinationFolder>$(OutDir)MediaInfo-x64\</DestinationFolder>
<Link>MediaInfo-x64\MediaInfo.dll</Link> <Link>MediaInfo-x64\MediaInfo.dll</Link>
</Content> </Content>
<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.4.0\lib\netstandard2.0\x86\MediaInfo.dll"> <Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.7.0\lib\netstandard2.0\x86\MediaInfo.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DestinationFolder>$(OutDir)MediaInfo-x86\</DestinationFolder> <DestinationFolder>$(OutDir)MediaInfo-x86\</DestinationFolder>
<Link>MediaInfo-x86\MediaInfo.dll</Link> <Link>MediaInfo-x86\MediaInfo.dll</Link>
</Content> </Content>
<!--<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.4.0\lib\netstandard2.0\arm64\MediaInfo.dll"> <!--<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.7.0\lib\netstandard2.0\arm64\MediaInfo.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DestinationFolder>$(OutDir)MediaInfo-ARM64\</DestinationFolder> <DestinationFolder>$(OutDir)MediaInfo-ARM64\</DestinationFolder>
<Link>MediaInfo-ARM64\MediaInfo.dll</Link> <Link>MediaInfo-ARM64\MediaInfo.dll</Link>

View File

@@ -8,16 +8,16 @@ using System.Xml.Serialization;
namespace RegFileParser; namespace RegFileParser;
/// <summary> /// <summary>
/// The main reg file parsing class. /// The main reg file parsing class.
/// Reads the given reg file and stores the content as /// Reads the given reg file and stores the content as
/// a Dictionary of registry keys and values as a Dictionary of registry values <see cref="RegValueObject" /> /// a Dictionary of registry keys and values as a Dictionary of registry values <see cref="RegValueObject" />
/// </summary> /// </summary>
public class RegFileObject public class RegFileObject
{ {
#region Public Properties #region Public Properties
/// <summary> /// <summary>
/// Gets the dictionary containing all entries /// Gets the dictionary containing all entries
/// </summary> /// </summary>
public Dictionary<string, Dictionary<string, RegValueObject>> RegValues => regvalues; public Dictionary<string, Dictionary<string, RegValueObject>> RegValues => regvalues;
@@ -26,12 +26,12 @@ public class RegFileObject
#region Private Fields #region Private Fields
/// <summary> /// <summary>
/// Raw content of the reg file /// Raw content of the reg file
/// </summary> /// </summary>
private string content; private string content;
/// <summary> /// <summary>
/// the dictionary containing parsed registry values /// the dictionary containing parsed registry values
/// </summary> /// </summary>
private readonly Dictionary<string, Dictionary<string, RegValueObject>> regvalues; private readonly Dictionary<string, Dictionary<string, RegValueObject>> regvalues;
@@ -61,7 +61,7 @@ public class RegFileObject
#region Private Methods #region Private Methods
/// <summary> /// <summary>
/// Imports the reg file /// Imports the reg file
/// </summary> /// </summary>
public void Read(string path) public void Read(string path)
{ {
@@ -70,7 +70,7 @@ public class RegFileObject
} }
/// <summary> /// <summary>
/// Imports the reg file /// Imports the reg file
/// </summary> /// </summary>
public void Read(byte[] bytes) public void Read(byte[] bytes)
{ {
@@ -109,7 +109,7 @@ public class RegFileObject
} }
/// <summary> /// <summary>
/// Parses the reg file for reg keys and reg values /// Parses the reg file for reg keys and reg values
/// </summary> /// </summary>
/// <returns>A Dictionary with reg keys as Dictionary keys and a Dictionary of (valuename, valuedata)</returns> /// <returns>A Dictionary with reg keys as Dictionary keys and a Dictionary of (valuename, valuedata)</returns>
private Dictionary<string, Dictionary<string, string>> ParseFile() private Dictionary<string, Dictionary<string, string>> ParseFile()
@@ -141,7 +141,7 @@ public class RegFileObject
} }
/// <summary> /// <summary>
/// Creates a flat Dictionary using given searcn pattern /// Creates a flat Dictionary using given searcn pattern
/// </summary> /// </summary>
/// <param name="content">The content string to be parsed</param> /// <param name="content">The content string to be parsed</param>
/// <returns>A Dictionary with retrieved keys and remaining content</returns> /// <returns>A Dictionary with retrieved keys and remaining content</returns>
@@ -202,7 +202,7 @@ public class RegFileObject
} }
/// <summary> /// <summary>
/// Creates a flat Dictionary using given searcn pattern /// Creates a flat Dictionary using given searcn pattern
/// </summary> /// </summary>
/// <param name="content">The content string to be parsed</param> /// <param name="content">The content string to be parsed</param>
/// <returns>A Dictionary with retrieved keys and remaining content</returns> /// <returns>A Dictionary with retrieved keys and remaining content</returns>
@@ -254,7 +254,7 @@ public class RegFileObject
} }
/// <summary> /// <summary>
/// Removes the leading and ending characters from the given string /// Removes the leading and ending characters from the given string
/// </summary> /// </summary>
/// <param name="sLine">given string</param> /// <param name="sLine">given string</param>
/// <returns>edited string</returns> /// <returns>edited string</returns>
@@ -268,7 +268,7 @@ public class RegFileObject
} }
/// <summary> /// <summary>
/// Removes the leading and ending parenthesis from the given string /// Removes the leading and ending parenthesis from the given string
/// </summary> /// </summary>
/// <param name="sLine">given string</param> /// <param name="sLine">given string</param>
/// <returns>edited string</returns> /// <returns>edited string</returns>
@@ -294,7 +294,7 @@ public class RegValueObject
private string value; private string value;
/// <summary> /// <summary>
/// Parameterless constructor /// Parameterless constructor
/// </summary> /// </summary>
public RegValueObject() public RegValueObject()
{ {
@@ -307,7 +307,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Overloaded constructor /// Overloaded constructor
/// </summary> /// </summary>
/// <param name="propertyString">A line from the [Registry] section of the *.sig signature file</param> /// <param name="propertyString">A line from the [Registry] section of the *.sig signature file</param>
public RegValueObject(string regKeyName, string regValueName, string regValueData, string encoding) public RegValueObject(string regKeyName, string regValueName, string regValueData, string encoding)
@@ -326,7 +326,7 @@ public class RegValueObject
#region Public Methods #region Public Methods
/// <summary> /// <summary>
/// Overriden Method /// Overriden Method
/// </summary> /// </summary>
/// <returns>An entry for the [Registry] section of the *.sig signature file</returns> /// <returns>An entry for the [Registry] section of the *.sig signature file</returns>
public override string ToString() public override string ToString()
@@ -339,7 +339,7 @@ public class RegValueObject
#region Public Properties #region Public Properties
/// <summary> /// <summary>
/// Regsitry value name /// Regsitry value name
/// </summary> /// </summary>
[XmlElement("entry", typeof(string))] [XmlElement("entry", typeof(string))]
public string Entry public string Entry
@@ -349,7 +349,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Registry value parent key /// Registry value parent key
/// </summary> /// </summary>
[XmlElement("key", typeof(string))] [XmlElement("key", typeof(string))]
public string ParentKey public string ParentKey
@@ -364,7 +364,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Registry value root hive /// Registry value root hive
/// </summary> /// </summary>
[XmlElement("root", typeof(string))] [XmlElement("root", typeof(string))]
public string Root public string Root
@@ -374,7 +374,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Registry value type /// Registry value type
/// </summary> /// </summary>
[XmlElement("type", typeof(string))] [XmlElement("type", typeof(string))]
public string Type public string Type
@@ -384,7 +384,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Registry value data /// Registry value data
/// </summary> /// </summary>
[XmlElement("value", typeof(string))] [XmlElement("value", typeof(string))]
public string Value public string Value
@@ -447,7 +447,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Retrieves the reg value type, parsing the prefix of the value /// Retrieves the reg value type, parsing the prefix of the value
/// </summary> /// </summary>
/// <param name="sTextLine">Registry value row string</param> /// <param name="sTextLine">Registry value row string</param>
/// <returns>Value</returns> /// <returns>Value</returns>
@@ -546,7 +546,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Removes the leading and ending characters from the given string /// Removes the leading and ending characters from the given string
/// </summary> /// </summary>
/// <param name="sline">given string</param> /// <param name="sline">given string</param>
/// <returns>edited string</returns> /// <returns>edited string</returns>
@@ -560,7 +560,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Removes the leading and ending parenthesis from the given string /// Removes the leading and ending parenthesis from the given string
/// </summary> /// </summary>
/// <param name="sline">given string</param> /// <param name="sline">given string</param>
/// <returns>edited string</returns> /// <returns>edited string</returns>
@@ -573,7 +573,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Removes the ending backslashes from the given string /// Removes the ending backslashes from the given string
/// </summary> /// </summary>
/// <param name="sline">given string</param> /// <param name="sline">given string</param>
/// <returns>edited string</returns> /// <returns>edited string</returns>
@@ -585,7 +585,7 @@ public class RegValueObject
} }
/// <summary> /// <summary>
/// Converts the byte arrays (saved as array of string) into string /// Converts the byte arrays (saved as array of string) into string
/// </summary> /// </summary>
/// <param name="stringArray">Array of string</param> /// <param name="stringArray">Array of string</param>
/// <returns>String value</returns> /// <returns>String value</returns>

View File

@@ -56,6 +56,7 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "QuickLook.Installer", "Quic
{63C00175-0FF3-42C7-8621-2F1959F26064} = {63C00175-0FF3-42C7-8621-2F1959F26064} {63C00175-0FF3-42C7-8621-2F1959F26064} = {63C00175-0FF3-42C7-8621-2F1959F26064}
{B4F7C88D-C79D-49E7-A1FB-FB69CF72585F} = {B4F7C88D-C79D-49E7-A1FB-FB69CF72585F} {B4F7C88D-C79D-49E7-A1FB-FB69CF72585F} = {B4F7C88D-C79D-49E7-A1FB-FB69CF72585F}
{311E6E78-3A5B-4E51-802A-5755BD5F9F97} = {311E6E78-3A5B-4E51-802A-5755BD5F9F97} {311E6E78-3A5B-4E51-802A-5755BD5F9F97} = {311E6E78-3A5B-4E51-802A-5755BD5F9F97}
{B0054A16-472E-44AC-BA40-349303E524FF} = {B0054A16-472E-44AC-BA40-349303E524FF}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickLook.Native64", "QuickLook.Native\QuickLook.Native64\QuickLook.Native64.vcxproj", "{794E4DCF-F715-4836-9D30-ABD296586D23}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickLook.Native64", "QuickLook.Native\QuickLook.Native64\QuickLook.Native64.vcxproj", "{794E4DCF-F715-4836-9D30-ABD296586D23}"
@@ -86,6 +87,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.ThumbnailV
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.HelixViewer", "QuickLook.Plugin\QuickLook.Plugin.HelixViewer\QuickLook.Plugin.HelixViewer.csproj", "{311E6E78-3A5B-4E51-802A-5755BD5F9F97}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.HelixViewer", "QuickLook.Plugin\QuickLook.Plugin.HelixViewer\QuickLook.Plugin.HelixViewer.csproj", "{311E6E78-3A5B-4E51-802A-5755BD5F9F97}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.MediaInfoViewer", "QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\QuickLook.Plugin.MediaInfoViewer.csproj", "{B0054A16-472E-44AC-BA40-349303E524FF}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -278,6 +281,14 @@ Global
{311E6E78-3A5B-4E51-802A-5755BD5F9F97}.Release|Any CPU.Build.0 = Release|Any CPU {311E6E78-3A5B-4E51-802A-5755BD5F9F97}.Release|Any CPU.Build.0 = Release|Any CPU
{311E6E78-3A5B-4E51-802A-5755BD5F9F97}.Release|x64.ActiveCfg = Release|Any CPU {311E6E78-3A5B-4E51-802A-5755BD5F9F97}.Release|x64.ActiveCfg = Release|Any CPU
{311E6E78-3A5B-4E51-802A-5755BD5F9F97}.Release|x64.Build.0 = Release|Any CPU {311E6E78-3A5B-4E51-802A-5755BD5F9F97}.Release|x64.Build.0 = Release|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Debug|x64.ActiveCfg = Debug|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Debug|x64.Build.0 = Debug|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Release|Any CPU.Build.0 = Release|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Release|x64.ActiveCfg = Release|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -303,6 +314,7 @@ Global
{63C00175-0FF3-42C7-8621-2F1959F26064} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} {63C00175-0FF3-42C7-8621-2F1959F26064} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
{B4F7C88D-C79D-49E7-A1FB-FB69CF72585F} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} {B4F7C88D-C79D-49E7-A1FB-FB69CF72585F} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
{311E6E78-3A5B-4E51-802A-5755BD5F9F97} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} {311E6E78-3A5B-4E51-802A-5755BD5F9F97} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
{B0054A16-472E-44AC-BA40-349303E524FF} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D3761C32-8C5F-498A-892B-3B0882994B62} SolutionGuid = {D3761C32-8C5F-498A-892B-3B0882994B62}

View File

@@ -117,22 +117,8 @@ public partial class App : Application
// Exception handling events which are not caught in the Task thread // Exception handling events which are not caught in the Task thread
TaskScheduler.UnobservedTaskException += (_, e) => TaskScheduler.UnobservedTaskException += (_, e) =>
{ {
try ProcessHelper.WriteLog(e.Exception.ToString());
{ e.SetObserved();
ProcessHelper.WriteLog(e.Exception.ToString());
Current?.Dispatcher?.BeginInvoke(() =>
{
Wpf.Ui.Violeta.Controls.ExceptionReport.Show(e.Exception);
});
}
catch (Exception ex)
{
ProcessHelper.WriteLog(ex.ToString());
}
finally
{
e.SetObserved();
}
}; };
// Exception handling events which are not caught in UI thread // Exception handling events which are not caught in UI thread
@@ -210,9 +196,9 @@ public partial class App : Application
} }
}; };
// Initialize MessageBox patching // We should improve the performance of the CLI application
bool modernMessageBox = SettingHelper.Get("ModernMessageBox", true, "QuickLook"); // Therefore, the time-consuming initialization code can't be placed before `OnStartup`
if (modernMessageBox) MessageBoxPatcher.Initialize(); base.OnStartup(e);
// Set initial theme based on system settings // Set initial theme based on system settings
ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light); ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light);
@@ -220,17 +206,15 @@ public partial class App : Application
ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light); ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light);
UxTheme.ApplyPreferredAppMode(); UxTheme.ApplyPreferredAppMode();
// Initialize TrayIcon // Initialize MessageBox patching
_ = TrayIconManager.GetInstance(); MessageBoxPatcher.Initialize();
base.OnStartup(e);
} }
private void Application_Startup(object sender, StartupEventArgs e) private void Application_Startup(object sender, StartupEventArgs e)
{ {
if (!EnsureOSVersion() if (!EnsureOSVersion()
|| !EnsureFirstInstance(e.Args) || !EnsureFirstInstance(e.Args)
|| !EnsureFolderWritable(SettingHelper.LocalDataPath)) || !EnsureFolderWritable(SettingHelper.LocalDataPath))
{ {
_cleanExit = false; _cleanExit = false;
Shutdown(); Shutdown();
@@ -325,8 +309,10 @@ public partial class App : Application
} }
// Second instance: duplicate // Second instance: duplicate
else else
{
MessageBox.Show(TranslationHelper.Get("APP_SECOND_TEXT"), TranslationHelper.Get("APP_SECOND"), MessageBox.Show(TranslationHelper.Get("APP_SECOND_TEXT"), TranslationHelper.Get("APP_SECOND"),
MessageBoxButton.OK, MessageBoxImage.Information); MessageBoxButton.OK, MessageBoxImage.Information);
}
return false; return false;
} }

View File

@@ -81,8 +81,7 @@ public class BackgroundVisualHost : FrameworkElement
private readonly CreateContentFunction _createContent; private readonly CreateContentFunction _createContent;
private readonly Action _invalidateMeasure; private readonly Action _invalidateMeasure;
private readonly AutoResetEvent _sync = private readonly AutoResetEvent _sync = new(false);
new AutoResetEvent(false);
public ThreadedVisualHelper( public ThreadedVisualHelper(
CreateContentFunction createContent, CreateContentFunction createContent,
@@ -125,17 +124,11 @@ public class BackgroundVisualHost : FrameworkElement
} }
} }
#region Private Fields
public ThreadedVisualHelper ThreadedHelper; public ThreadedVisualHelper ThreadedHelper;
private HostVisual _hostVisual; private HostVisual _hostVisual;
#endregion Private Fields
#region IsContentShowingProperty
/// <summary> /// <summary>
/// Identifies the IsContentShowing dependency property. /// Identifies the IsContentShowing dependency property.
/// </summary> /// </summary>
public static readonly DependencyProperty IsContentShowingProperty = DependencyProperty.Register( public static readonly DependencyProperty IsContentShowingProperty = DependencyProperty.Register(
"IsContentShowing", "IsContentShowing",
@@ -144,7 +137,7 @@ public class BackgroundVisualHost : FrameworkElement
new FrameworkPropertyMetadata(false, OnIsContentShowingChanged)); new FrameworkPropertyMetadata(false, OnIsContentShowingChanged));
/// <summary> /// <summary>
/// Gets or sets if the content is being displayed. /// Gets or sets if the content is being displayed.
/// </summary> /// </summary>
public bool IsContentShowing public bool IsContentShowing
{ {
@@ -163,12 +156,8 @@ public class BackgroundVisualHost : FrameworkElement
bvh.HideContentHelper(); bvh.HideContentHelper();
} }
#endregion IsContentShowingProperty
#region CreateContent Property
/// <summary> /// <summary>
/// Identifies the CreateContent dependency property. /// Identifies the CreateContent dependency property.
/// </summary> /// </summary>
public static readonly DependencyProperty CreateContentProperty = DependencyProperty.Register( public static readonly DependencyProperty CreateContentProperty = DependencyProperty.Register(
"CreateContent", "CreateContent",
@@ -177,7 +166,7 @@ public class BackgroundVisualHost : FrameworkElement
new FrameworkPropertyMetadata(OnCreateContentChanged)); new FrameworkPropertyMetadata(OnCreateContentChanged));
/// <summary> /// <summary>
/// Gets or sets the function used to create the visual to display in a background thread. /// Gets or sets the function used to create the visual to display in a background thread.
/// </summary> /// </summary>
public CreateContentFunction CreateContent public CreateContentFunction CreateContent
{ {
@@ -196,6 +185,4 @@ public class BackgroundVisualHost : FrameworkElement
bvh.CreateContentHelper(); bvh.CreateContentHelper();
} }
} }
#endregion CreateContent Property
} }

View File

@@ -135,7 +135,7 @@ public class BusyDecorator : Decorator, IDisposable
#region IsBusyIndicatorShowing Property #region IsBusyIndicatorShowing Property
/// <summary> /// <summary>
/// Identifies the IsBusyIndicatorShowing dependency property. /// Identifies the IsBusyIndicatorShowing dependency property.
/// </summary> /// </summary>
public static readonly DependencyProperty IsBusyIndicatorShowingProperty = DependencyProperty.Register( public static readonly DependencyProperty IsBusyIndicatorShowingProperty = DependencyProperty.Register(
"IsBusyIndicatorShowing", "IsBusyIndicatorShowing",
@@ -146,7 +146,7 @@ public class BusyDecorator : Decorator, IDisposable
OnIsBusyIndicatorShowingChanged)); OnIsBusyIndicatorShowingChanged));
/// <summary> /// <summary>
/// Gets or sets if the BusyIndicator is being shown. /// Gets or sets if the BusyIndicator is being shown.
/// </summary> /// </summary>
public bool IsBusyIndicatorShowing public bool IsBusyIndicatorShowing
{ {
@@ -178,7 +178,7 @@ public class BusyDecorator : Decorator, IDisposable
#region BusyStyle #region BusyStyle
/// <summary> /// <summary>
/// Identifies the <see cref="BusyStyle" /> property. /// Identifies the <see cref="BusyStyle" /> property.
/// </summary> /// </summary>
public static readonly DependencyProperty BusyStyleProperty = public static readonly DependencyProperty BusyStyleProperty =
DependencyProperty.Register( DependencyProperty.Register(
@@ -188,7 +188,7 @@ public class BusyDecorator : Decorator, IDisposable
new FrameworkPropertyMetadata(OnBusyStyleChanged)); new FrameworkPropertyMetadata(OnBusyStyleChanged));
/// <summary> /// <summary>
/// Gets or sets the Style to apply to the Control that is displayed as the busy indication. /// Gets or sets the Style to apply to the Control that is displayed as the busy indication.
/// </summary> /// </summary>
public Style BusyStyle public Style BusyStyle
{ {
@@ -208,7 +208,7 @@ public class BusyDecorator : Decorator, IDisposable
#region BusyHorizontalAlignment #region BusyHorizontalAlignment
/// <summary> /// <summary>
/// Identifies the <see cref="BusyHorizontalAlignment" /> property. /// Identifies the <see cref="BusyHorizontalAlignment" /> property.
/// </summary> /// </summary>
public static readonly DependencyProperty BusyHorizontalAlignmentProperty = DependencyProperty.Register( public static readonly DependencyProperty BusyHorizontalAlignmentProperty = DependencyProperty.Register(
"BusyHorizontalAlignment", "BusyHorizontalAlignment",
@@ -217,7 +217,7 @@ public class BusyDecorator : Decorator, IDisposable
new FrameworkPropertyMetadata(HorizontalAlignment.Center)); new FrameworkPropertyMetadata(HorizontalAlignment.Center));
/// <summary> /// <summary>
/// Gets or sets the HorizontalAlignment to use to layout the control that contains the busy indicator control. /// Gets or sets the HorizontalAlignment to use to layout the control that contains the busy indicator control.
/// </summary> /// </summary>
public HorizontalAlignment BusyHorizontalAlignment public HorizontalAlignment BusyHorizontalAlignment
{ {
@@ -230,7 +230,7 @@ public class BusyDecorator : Decorator, IDisposable
#region BusyVerticalAlignment #region BusyVerticalAlignment
/// <summary> /// <summary>
/// Identifies the <see cref="BusyVerticalAlignment" /> property. /// Identifies the <see cref="BusyVerticalAlignment" /> property.
/// </summary> /// </summary>
public static readonly DependencyProperty BusyVerticalAlignmentProperty = DependencyProperty.Register( public static readonly DependencyProperty BusyVerticalAlignmentProperty = DependencyProperty.Register(
"BusyVerticalAlignment", "BusyVerticalAlignment",
@@ -239,7 +239,7 @@ public class BusyDecorator : Decorator, IDisposable
new FrameworkPropertyMetadata(VerticalAlignment.Center)); new FrameworkPropertyMetadata(VerticalAlignment.Center));
/// <summary> /// <summary>
/// Gets or sets the the VerticalAlignment to use to layout the control that contains the busy indicator. /// Gets or sets the the VerticalAlignment to use to layout the control that contains the busy indicator.
/// </summary> /// </summary>
public VerticalAlignment BusyVerticalAlignment public VerticalAlignment BusyVerticalAlignment
{ {

View File

@@ -24,17 +24,17 @@ using System.Windows.Media.Animation;
namespace QuickLook.Controls.BusyDecorator; namespace QuickLook.Controls.BusyDecorator;
/// <summary> /// <summary>
/// Control extensions /// Control extensions
/// </summary> /// </summary>
internal static class ControlExtensions internal static class ControlExtensions
{ {
/// <summary> /// <summary>
/// The key used for storing the spinner Storyboard. /// The key used for storing the spinner Storyboard.
/// </summary> /// </summary>
private static readonly string SpinnerStoryBoardName = $"{typeof(FrameworkElement).Name}Spinner"; private static readonly string SpinnerStoryBoardName = $"{typeof(FrameworkElement).Name}Spinner";
/// <summary> /// <summary>
/// Start the spinning animation /// Start the spinning animation
/// </summary> /// </summary>
/// <typeparam name="T">FrameworkElement and ISpinable</typeparam> /// <typeparam name="T">FrameworkElement and ISpinable</typeparam>
/// <param name="control">Control to apply the rotation </param> /// <param name="control">Control to apply the rotation </param>
@@ -78,7 +78,7 @@ internal static class ControlExtensions
} }
/// <summary> /// <summary>
/// Stop the spinning animation /// Stop the spinning animation
/// </summary> /// </summary>
/// <typeparam name="T">FrameworkElement and ISpinable</typeparam> /// <typeparam name="T">FrameworkElement and ISpinable</typeparam>
/// <param name="control">Control to stop the rotation.</param> /// <param name="control">Control to stop the rotation.</param>

View File

@@ -18,17 +18,17 @@
namespace QuickLook.Controls.BusyDecorator; namespace QuickLook.Controls.BusyDecorator;
/// <summary> /// <summary>
/// Represents a spinable control /// Represents a spinable control
/// </summary> /// </summary>
internal interface ISpinable internal interface ISpinable
{ {
/// <summary> /// <summary>
/// Gets or sets the current spin (angle) animation of the icon. /// Gets or sets the current spin (angle) animation of the icon.
/// </summary> /// </summary>
public bool Spin { get; set; } public bool Spin { get; set; }
/// <summary> /// <summary>
/// Gets or sets the duration of the spinning animation (in seconds). This will stop and start the spin animation. /// Gets or sets the duration of the spinning animation (in seconds). This will stop and start the spin animation.
/// </summary> /// </summary>
public double SpinDuration { get; set; } public double SpinDuration { get; set; }
} }

View File

@@ -25,7 +25,7 @@ internal class SpinIcon : TextBlock, ISpinable
#region public bool Spin #region public bool Spin
/// <summary> /// <summary>
/// Identifies the Spin dependency property. /// Identifies the Spin dependency property.
/// </summary> /// </summary>
public static DependencyProperty SpinProperty = public static DependencyProperty SpinProperty =
DependencyProperty.Register("Spin", typeof(bool), typeof(SpinIcon), DependencyProperty.Register("Spin", typeof(bool), typeof(SpinIcon),
@@ -44,7 +44,7 @@ internal class SpinIcon : TextBlock, ISpinable
} }
/// <summary> /// <summary>
/// Gets or sets the current spin (angle) animation of the icon. /// Gets or sets the current spin (angle) animation of the icon.
/// </summary> /// </summary>
public bool Spin public bool Spin
{ {
@@ -58,7 +58,7 @@ internal class SpinIcon : TextBlock, ISpinable
#region public double SpinDuration #region public double SpinDuration
/// <summary> /// <summary>
/// Identifies the SpinDuration dependency property. /// Identifies the SpinDuration dependency property.
/// </summary> /// </summary>
public static DependencyProperty SpinDurationProperty = public static DependencyProperty SpinDurationProperty =
DependencyProperty.Register("SpinDuration", typeof(double), typeof(SpinIcon), DependencyProperty.Register("SpinDuration", typeof(double), typeof(SpinIcon),
@@ -76,7 +76,7 @@ internal class SpinIcon : TextBlock, ISpinable
} }
/// <summary> /// <summary>
/// Gets or sets the duration of the spinning animation (in seconds). This will stop and start the spin animation. /// Gets or sets the duration of the spinning animation (in seconds). This will stop and start the spin animation.
/// </summary> /// </summary>
public double SpinDuration public double SpinDuration
{ {

View File

@@ -43,7 +43,7 @@ public partial class GlassLayer : UserControl
#region public Visual BlurredElement #region public Visual BlurredElement
/// <summary> /// <summary>
/// Identifies the BlurredElement dependency property. /// Identifies the BlurredElement dependency property.
/// </summary> /// </summary>
public static DependencyProperty BlurredElementProperty = public static DependencyProperty BlurredElementProperty =
DependencyProperty.Register("BlurredElement", typeof(Visual), typeof(GlassLayer), null); DependencyProperty.Register("BlurredElement", typeof(Visual), typeof(GlassLayer), null);
@@ -62,7 +62,7 @@ public partial class GlassLayer : UserControl
#region public SolidColorBrush OverlayColor #region public SolidColorBrush OverlayColor
/// <summary> /// <summary>
/// Identifies the OverlayColor dependency property. /// Identifies the OverlayColor dependency property.
/// </summary> /// </summary>
public static DependencyProperty OverlayColorProperty = public static DependencyProperty OverlayColorProperty =
DependencyProperty.Register("OverlayColor", typeof(SolidColorBrush), typeof(GlassLayer), DependencyProperty.Register("OverlayColor", typeof(SolidColorBrush), typeof(GlassLayer),
@@ -82,7 +82,7 @@ public partial class GlassLayer : UserControl
#region public Visibility ColorOverlayVisibility #region public Visibility ColorOverlayVisibility
/// <summary> /// <summary>
/// Identifies the ColorOverlayVisibilityProperty dependency property. /// Identifies the ColorOverlayVisibilityProperty dependency property.
/// </summary> /// </summary>
public static DependencyProperty ColorOverlayVisibilityProperty = public static DependencyProperty ColorOverlayVisibilityProperty =
DependencyProperty.Register("ColorOverlayVisibility", typeof(Visibility), typeof(GlassLayer), DependencyProperty.Register("ColorOverlayVisibility", typeof(Visibility), typeof(GlassLayer),
@@ -100,7 +100,7 @@ public partial class GlassLayer : UserControl
#region public Visibility NoiseVisibility #region public Visibility NoiseVisibility
/// <summary> /// <summary>
/// Identifies the NoiseVisibility dependency property. /// Identifies the NoiseVisibility dependency property.
/// </summary> /// </summary>
public static DependencyProperty NoiseVisibilityProperty = public static DependencyProperty NoiseVisibilityProperty =
DependencyProperty.Register("NoiseVisibility", typeof(Visibility), typeof(GlassLayer), DependencyProperty.Register("NoiseVisibility", typeof(Visibility), typeof(GlassLayer),
@@ -120,7 +120,7 @@ public partial class GlassLayer : UserControl
#region public Visibility GlassVisibility #region public Visibility GlassVisibility
/// <summary> /// <summary>
/// Identifies the GlassVisibility dependency property. /// Identifies the GlassVisibility dependency property.
/// </summary> /// </summary>
public static DependencyProperty GlassVisibilityProperty = public static DependencyProperty GlassVisibilityProperty =
DependencyProperty.Register("GlassVisibility", typeof(Visibility), typeof(GlassLayer), DependencyProperty.Register("GlassVisibility", typeof(Visibility), typeof(GlassLayer),

View File

@@ -0,0 +1,88 @@
// Copyright © 2017-2025 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.Xaml.Behaviors;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace QuickLook.Controls;
public sealed class LeftContextMenuBehavior : Behavior<FrameworkElement>
{
public Point? PlacementOffset { get; set; } = null;
public PlacementMode Placement { get; set; } = PlacementMode.Bottom;
public double? PlacementOffsetX
{
get => PlacementOffset?.X;
set => PlacementOffset = value != null ? new(value ?? 0d, PlacementOffset?.Y ?? 0d) : null;
}
public double? PlacementOffsetY
{
get => PlacementOffset?.Y;
set => PlacementOffset = value != null ? new(PlacementOffset?.X ?? 0d, value ?? 0d) : null;
}
public LeftContextMenuBehavior()
{
}
protected override void OnAttached()
{
base.OnAttached();
Register(AssociatedObject, PlacementOffset, Placement);
}
protected override void OnDetaching()
{
base.OnDetaching();
Unregister(AssociatedObject);
}
public static void Register(FrameworkElement frameworkElement, Point? placementOffset = null, PlacementMode placement = PlacementMode.Bottom)
{
if (frameworkElement?.ContextMenu == null)
{
return;
}
frameworkElement.PreviewMouseRightButtonUp += (_, e) => e.Handled = true;
frameworkElement.MouseRightButtonUp += (_, e) => e.Handled = true;
frameworkElement.PreviewMouseLeftButtonDown += (_, _) =>
{
ContextMenu contextMenu = frameworkElement.ContextMenu;
if (contextMenu != null)
{
if (contextMenu.PlacementTarget != frameworkElement)
{
contextMenu.PlacementTarget = frameworkElement;
contextMenu.PlacementRectangle = new Rect(placementOffset ?? new Point(), new Size(frameworkElement.ActualWidth, frameworkElement.ActualHeight));
contextMenu.Placement = placement;
contextMenu.StaysOpen = false;
}
contextMenu.IsOpen = !contextMenu.IsOpen;
}
};
}
public static void Unregister(FrameworkElement frameworkElement)
{
_ = frameworkElement;
}
}

1
QuickLook/GlobalUsing.cs Normal file
View File

@@ -0,0 +1 @@
global using MessageBox = Wpf.Ui.Violeta.Controls.MessageBox;

View File

@@ -33,8 +33,8 @@ internal enum SLGP_FLAGS
SLGP_UNCPRIORITY = 0x2, SLGP_UNCPRIORITY = 0x2,
/// <summary> /// <summary>
/// Retrieves the raw path name. A raw path is something that might not exist and may include environment /// Retrieves the raw path name. A raw path is something that might not exist and may include environment
/// variables that need to be expanded /// variables that need to be expanded
/// </summary> /// </summary>
SLGP_RAWPATH = 0x4 SLGP_RAWPATH = 0x4
} }
@@ -62,13 +62,13 @@ internal struct WIN32_FIND_DATAW
internal enum SLR_FLAGS internal enum SLR_FLAGS
{ {
/// <summary> /// <summary>
/// Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set, /// Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set,
/// the high-order word of fFlags can be set to a time-out value that specifies the /// the high-order word of fFlags can be set to a time-out value that specifies the
/// maximum amount of time to be spent resolving the link. The function returns if the /// maximum amount of time to be spent resolving the link. The function returns if the
/// link cannot be resolved within the time-out duration. If the high-order word is set /// link cannot be resolved within the time-out duration. If the high-order word is set
/// to zero, the time-out duration will be set to the default value of 3,000 milliseconds /// to zero, the time-out duration will be set to the default value of 3,000 milliseconds
/// (3 seconds). To specify a value, set the high word of fFlags to the desired time-out /// (3 seconds). To specify a value, set the high word of fFlags to the desired time-out
/// duration, in milliseconds. /// duration, in milliseconds.
/// </summary> /// </summary>
SLR_NO_UI = 0x1, SLR_NO_UI = 0x1,
@@ -76,9 +76,9 @@ internal enum SLR_FLAGS
SLR_ANY_MATCH = 0x2, SLR_ANY_MATCH = 0x2,
/// <summary> /// <summary>
/// If the link object has changed, update its path and list of identifiers. /// If the link object has changed, update its path and list of identifiers.
/// If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine /// If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine
/// whether or not the link object has changed. /// whether or not the link object has changed.
/// </summary> /// </summary>
SLR_UPDATE = 0x4, SLR_UPDATE = 0x4,
@@ -92,10 +92,10 @@ internal enum SLR_FLAGS
SLR_NOTRACK = 0x20, SLR_NOTRACK = 0x20,
/// <summary> /// <summary>
/// Disable distributed link tracking. By default, distributed link tracking tracks /// Disable distributed link tracking. By default, distributed link tracking tracks
/// removable media across multiple devices based on the volume name. It also uses the /// removable media across multiple devices based on the volume name. It also uses the
/// Universal Naming Convention (UNC) path to track remote file systems whose drive letter /// Universal Naming Convention (UNC) path to track remote file systems whose drive letter
/// has changed. Setting SLR_NOLINKINFO disables both types of tracking. /// has changed. Setting SLR_NOLINKINFO disables both types of tracking.
/// </summary> /// </summary>
SLR_NOLINKINFO = 0x40, SLR_NOLINKINFO = 0x40,

View File

@@ -102,10 +102,10 @@
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135"> <PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="WPF-UI.Violeta" Version="4.0.3.2"> <PackageReference Include="WPF-UI.Violeta" Version="4.0.3.6">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Lib.Harmony" Version="2.3.6"> <PackageReference Include="Lib.Harmony" Version="2.4.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="UnblockZoneIdentifier" Version="1.0.0"> <PackageReference Include="UnblockZoneIdentifier" Version="1.0.0">

View File

@@ -182,6 +182,7 @@
<MW_Run>{0} ausführen</MW_Run> <MW_Run>{0} ausführen</MW_Run>
<MW_Share>Freigeben</MW_Share> <MW_Share>Freigeben</MW_Share>
<MW_Reload>Neu laden</MW_Reload> <MW_Reload>Neu laden</MW_Reload>
<MW_More>Mehr</MW_More>
<Icon_RunAtStartup>Beim Systemstart &amp;ausführen</Icon_RunAtStartup> <Icon_RunAtStartup>Beim Systemstart &amp;ausführen</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>Nach &amp;Updates suchen</Icon_CheckUpdate> <Icon_CheckUpdate>Nach &amp;Updates suchen</Icon_CheckUpdate>
@@ -216,6 +217,7 @@
<MW_Run>Run {0}</MW_Run> <MW_Run>Run {0}</MW_Run>
<MW_Share>Share</MW_Share> <MW_Share>Share</MW_Share>
<MW_Reload>Reload</MW_Reload> <MW_Reload>Reload</MW_Reload>
<MW_More>More</MW_More>
<Icon_RunAtStartup>Run at &amp;Startup</Icon_RunAtStartup> <Icon_RunAtStartup>Run at &amp;Startup</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>Check for &amp;Updates...</Icon_CheckUpdate> <Icon_CheckUpdate>Check for &amp;Updates...</Icon_CheckUpdate>
@@ -234,6 +236,8 @@
<InfoPanel_Files>{0} files</InfoPanel_Files> <InfoPanel_Files>{0} files</InfoPanel_Files>
<InfoPanel_FolderAndFile>({0} and {1})</InfoPanel_FolderAndFile> <InfoPanel_FolderAndFile>({0} and {1})</InfoPanel_FolderAndFile>
<InfoPanel_CantPreventClosing>Cancellation of "Prevent Closing" is not supported</InfoPanel_CantPreventClosing> <InfoPanel_CantPreventClosing>Cancellation of "Prevent Closing" is not supported</InfoPanel_CantPreventClosing>
<InfoPanelMoreItem_CopyAsPath>Copy as path</InfoPanelMoreItem_CopyAsPath>
<InfoPanelMoreItem_CopySucc>Copy successfully</InfoPanelMoreItem_CopySucc>
</en> </en>
<es> <es>
<UI_FontFamily>Segoe UI</UI_FontFamily> <UI_FontFamily>Segoe UI</UI_FontFamily>
@@ -250,6 +254,7 @@
<MW_Run>Iniciar {0}</MW_Run> <MW_Run>Iniciar {0}</MW_Run>
<MW_Share>Compartir</MW_Share> <MW_Share>Compartir</MW_Share>
<MW_Reload>Recargar</MW_Reload> <MW_Reload>Recargar</MW_Reload>
<MW_More>Más</MW_More>
<Icon_RunAtStartup>Iniciar con el &amp;sistema</Icon_RunAtStartup> <Icon_RunAtStartup>Iniciar con el &amp;sistema</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>Buscar &amp;Actualizaciones...</Icon_CheckUpdate> <Icon_CheckUpdate>Buscar &amp;Actualizaciones...</Icon_CheckUpdate>
@@ -279,6 +284,7 @@
<MW_OpenWith>Ouvrir avec {0}</MW_OpenWith> <MW_OpenWith>Ouvrir avec {0}</MW_OpenWith>
<MW_Run>Exécuter {0}</MW_Run> <MW_Run>Exécuter {0}</MW_Run>
<MW_Reload>Recharger</MW_Reload> <MW_Reload>Recharger</MW_Reload>
<MW_More>Plus</MW_More>
<Icon_RunAtStartup>Exécuter au &amp;démarrage</Icon_RunAtStartup> <Icon_RunAtStartup>Exécuter au &amp;démarrage</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>Vérifier s'il existe des &amp;mises à jour...</Icon_CheckUpdate> <Icon_CheckUpdate>Vérifier s'il existe des &amp;mises à jour...</Icon_CheckUpdate>
@@ -308,6 +314,7 @@
<MW_OpenWith>Apri con {0}</MW_OpenWith> <MW_OpenWith>Apri con {0}</MW_OpenWith>
<MW_Run>Esegui {0}</MW_Run> <MW_Run>Esegui {0}</MW_Run>
<MW_Reload>Ricarica</MW_Reload> <MW_Reload>Ricarica</MW_Reload>
<MW_More>Altro</MW_More>
<Icon_RunAtStartup>Esegui all'&amp;Avvio</Icon_RunAtStartup> <Icon_RunAtStartup>Esegui all'&amp;Avvio</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>Verifica &amp;Aggiornamenti...</Icon_CheckUpdate> <Icon_CheckUpdate>Verifica &amp;Aggiornamenti...</Icon_CheckUpdate>
@@ -340,6 +347,7 @@
<MW_Run>{0} を起動</MW_Run> <MW_Run>{0} を起動</MW_Run>
<MW_Share>シェア</MW_Share> <MW_Share>シェア</MW_Share>
<MW_Reload>再読み込み</MW_Reload> <MW_Reload>再読み込み</MW_Reload>
<MW_More>その他</MW_More>
<Icon_RunAtStartup>スタートアップ時に起動</Icon_RunAtStartup> <Icon_RunAtStartup>スタートアップ時に起動</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>更新を確認する... (&amp;U)</Icon_CheckUpdate> <Icon_CheckUpdate>更新を確認する... (&amp;U)</Icon_CheckUpdate>
@@ -424,6 +432,7 @@
<MW_Run>Uruchom {0}</MW_Run> <MW_Run>Uruchom {0}</MW_Run>
<MW_Share>Udostępnij</MW_Share> <MW_Share>Udostępnij</MW_Share>
<MW_Reload>Przeładuj</MW_Reload> <MW_Reload>Przeładuj</MW_Reload>
<MW_More>Więcej</MW_More>
<Icon_RunAtStartup>Uruchamiaj automatycznie z systemem</Icon_RunAtStartup> <Icon_RunAtStartup>Uruchamiaj automatycznie z systemem</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>Sprawdź &amp;aktualizacje...</Icon_CheckUpdate> <Icon_CheckUpdate>Sprawdź &amp;aktualizacje...</Icon_CheckUpdate>
@@ -458,6 +467,7 @@
<MW_Run>Executar {0}</MW_Run> <MW_Run>Executar {0}</MW_Run>
<MW_Share>Compartilhar</MW_Share> <MW_Share>Compartilhar</MW_Share>
<MW_Reload>Recarregar</MW_Reload> <MW_Reload>Recarregar</MW_Reload>
<MW_More>Mais</MW_More>
<Icon_RunAtStartup>Executar na &amp;Inicialização</Icon_RunAtStartup> <Icon_RunAtStartup>Executar na &amp;Inicialização</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>Procurar por &amp;Atualizações...</Icon_CheckUpdate> <Icon_CheckUpdate>Procurar por &amp;Atualizações...</Icon_CheckUpdate>
@@ -515,6 +525,7 @@
<MW_PreventClosing>Закрепить</MW_PreventClosing> <MW_PreventClosing>Закрепить</MW_PreventClosing>
<MW_Share>Поделиться</MW_Share> <MW_Share>Поделиться</MW_Share>
<MW_Reload>Перезагрузить</MW_Reload> <MW_Reload>Перезагрузить</MW_Reload>
<MW_More>Еще</MW_More>
<Icon_RunAtStartup>Автозапуск</Icon_RunAtStartup> <Icon_RunAtStartup>Автозапуск</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>Проверить &amp;обновления…</Icon_CheckUpdate> <Icon_CheckUpdate>Проверить &amp;обновления…</Icon_CheckUpdate>
@@ -575,6 +586,7 @@
<MW_Run>Запустити {0}</MW_Run> <MW_Run>Запустити {0}</MW_Run>
<MW_Share>Поширити</MW_Share> <MW_Share>Поширити</MW_Share>
<MW_Reload>Перезавантажити</MW_Reload> <MW_Reload>Перезавантажити</MW_Reload>
<MW_More>Більше</MW_More>
<Icon_RunAtStartup>Запускати під час &amp;старту</Icon_RunAtStartup> <Icon_RunAtStartup>Запускати під час &amp;старту</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>Перевірити наявність &amp;оновлення…</Icon_CheckUpdate> <Icon_CheckUpdate>Перевірити наявність &amp;оновлення…</Icon_CheckUpdate>
@@ -634,6 +646,7 @@
<MW_Run>运行 {0}</MW_Run> <MW_Run>运行 {0}</MW_Run>
<MW_Share>分享</MW_Share> <MW_Share>分享</MW_Share>
<MW_Reload>重新加载</MW_Reload> <MW_Reload>重新加载</MW_Reload>
<MW_More>更多</MW_More>
<Icon_RunAtStartup>启动时自动运行 (&amp;S)</Icon_RunAtStartup> <Icon_RunAtStartup>启动时自动运行 (&amp;S)</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>检查更新... (&amp;U)</Icon_CheckUpdate> <Icon_CheckUpdate>检查更新... (&amp;U)</Icon_CheckUpdate>
@@ -668,6 +681,7 @@
<MW_Run>執行 {0}</MW_Run> <MW_Run>執行 {0}</MW_Run>
<MW_Share>分享</MW_Share> <MW_Share>分享</MW_Share>
<MW_Reload>重新載入</MW_Reload> <MW_Reload>重新載入</MW_Reload>
<MW_More>更多</MW_More>
<Icon_RunAtStartup>系統啟動時自動執行 (&amp;S)</Icon_RunAtStartup> <Icon_RunAtStartup>系統啟動時自動執行 (&amp;S)</Icon_RunAtStartup>
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip> <Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
<Icon_CheckUpdate>檢查更新... (&amp;U)</Icon_CheckUpdate> <Icon_CheckUpdate>檢查更新... (&amp;U)</Icon_CheckUpdate>

View File

@@ -35,19 +35,7 @@ internal partial class TrayIconManager : IDisposable
private readonly TrayIconHost _icon; private readonly TrayIconHost _icon;
private readonly TrayMenuItem _itemAutorun = private readonly TrayMenuItem _itemAutorun = null!;
new()
{
Header = TranslationHelper.Get("Icon_RunAtStartup"),
Command = new RelayCommand(() =>
{
if (AutoStartupHelper.IsAutorun())
AutoStartupHelper.RemoveAutorunShortcut();
else
AutoStartupHelper.CreateAutorunShortcut();
}),
IsEnabled = !App.IsUWP,
};
private TrayIconManager() private TrayIconManager()
{ {
@@ -79,7 +67,18 @@ internal partial class TrayIconManager : IDisposable
Header = TranslationHelper.Get("Icon_OpenDataFolder"), Header = TranslationHelper.Get("Icon_OpenDataFolder"),
Command = new RelayCommand(() => Process.Start("explorer.exe", SettingHelper.LocalDataPath)), Command = new RelayCommand(() => Process.Start("explorer.exe", SettingHelper.LocalDataPath)),
}, },
_itemAutorun, _itemAutorun = new TrayMenuItem()
{
Header = TranslationHelper.Get("Icon_RunAtStartup"),
Command = new RelayCommand(() =>
{
if (AutoStartupHelper.IsAutorun())
AutoStartupHelper.RemoveAutorunShortcut();
else
AutoStartupHelper.CreateAutorunShortcut();
}),
IsEnabled = !App.IsUWP,
},
new TrayMenuItem() new TrayMenuItem()
{ {
Header = TranslationHelper.Get("Icon_Restart"), Header = TranslationHelper.Get("Icon_Restart"),
@@ -94,7 +93,10 @@ internal partial class TrayIconManager : IDisposable
IsVisible = SettingHelper.Get("ShowTrayIcon", true) IsVisible = SettingHelper.Get("ShowTrayIcon", true)
}; };
_icon.RightDown += (sender, e) => { _itemAutorun.IsChecked = AutoStartupHelper.IsAutorun(); }; _icon.RightDown += (_, _) =>
{
_itemAutorun.IsChecked = AutoStartupHelper.IsAutorun();
};
} }
public void Dispose() public void Dispose()

View File

@@ -22,12 +22,13 @@ using System;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Windows; using System.Windows;
using System.Windows.Input;
namespace QuickLook; namespace QuickLook;
public partial class ViewerWindow : INotifyPropertyChanged public partial class ViewerWindow : INotifyPropertyChanged
{ {
private readonly ResourceDictionary _darkDict = new ResourceDictionary private readonly ResourceDictionary _darkDict = new()
{ {
Source = new Uri("pack://application:,,,/QuickLook.Common;component/Styles/MainWindowStyles.Dark.xaml") Source = new Uri("pack://application:,,,/QuickLook.Common;component/Styles/MainWindowStyles.Dark.xaml")
}; };
@@ -50,6 +51,8 @@ public partial class ViewerWindow : INotifyPropertyChanged
public ContextObject ContextObject { get; private set; } public ContextObject ContextObject { get; private set; }
public Themes CurrentTheme { get; private set; } public Themes CurrentTheme { get; private set; }
public ICommand CloseCommand { get; private set; }
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] [NotifyPropertyChangedInvocator]

View File

@@ -6,7 +6,10 @@
xmlns:converters="clr-namespace:QuickLook.Converters" xmlns:converters="clr-namespace:QuickLook.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:glassLayer="clr-namespace:QuickLook.Controls.GlassLayer" xmlns:glassLayer="clr-namespace:QuickLook.Controls.GlassLayer"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:vio="http://schemas.lepo.co/wpfui/2022/xaml/violeta"
x:Name="mainWindow" x:Name="mainWindow"
Title="QuickLook" Title="QuickLook"
MinWidth="400" MinWidth="400"
@@ -122,15 +125,32 @@
DockPanel.Dock="Right" DockPanel.Dock="Right"
Style="{StaticResource CaptionButtonStyle}" Style="{StaticResource CaptionButtonStyle}"
ToolTip="Reload" /> ToolTip="Reload" />
<!--<Button x:Name="buttonOpen" DockPanel.Dock="Right" <Button x:Name="buttonMore"
Style="{StaticResource CaptionTextButtonStyle}" Content="&#xE712;"
Visibility="{Binding ActualWidth, ElementName=windowCaptionContainer, Converter={StaticResource WidthToVisibilityCollapsedConverter}}"> DockPanel.Dock="Right"
<Button.Content> Style="{StaticResource CaptionButtonStyle}"
<TextBlock x:Name="buttonOpenText" VerticalAlignment="Center"> ToolTip="More">
Open with <Bold>AppName</Bold> <Button.ContextMenu>
</TextBlock> <ContextMenu FontSize="12">
</Button.Content> <MenuItem x:Name="moreItemCopyAsPath">
</Button>--> <MenuItem.Icon>
<ui:FontIcon FontFamily="{DynamicResource SymbolThemeFontFamily}" Glyph="{x:Static ui:FontSymbols.Copy}" />
</MenuItem.Icon>
</MenuItem>
<Separator Visibility="Collapsed" />
<MenuItem x:Name="moreItemOpenSettings"
Header="Settings"
Visibility="Collapsed">
<MenuItem.Icon>
<ui:FontIcon FontFamily="{DynamicResource SymbolThemeFontFamily}" Glyph="{x:Static ui:FontSymbols.Settings}" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
<i:Interaction.Behaviors>
<controls:LeftContextMenuBehavior />
</i:Interaction.Behaviors>
</Button>
<Button x:Name="buttonTop" <Button x:Name="buttonTop"
DockPanel.Dock="Left" DockPanel.Dock="Left"
Tag="Auto" Tag="Auto"

View File

@@ -20,6 +20,7 @@ using QuickLook.Common.Helpers;
using QuickLook.Common.Plugin; using QuickLook.Common.Plugin;
using QuickLook.Helpers; using QuickLook.Helpers;
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
@@ -110,12 +111,32 @@ public partial class ViewerWindow : Window
buttonReload.Visibility = SettingHelper.Get("ShowReload", false) ? Visibility.Visible : Visibility.Collapsed; buttonReload.Visibility = SettingHelper.Get("ShowReload", false) ? Visibility.Visible : Visibility.Collapsed;
moreItemCopyAsPath.Click += (_, _) =>
{
try
{
Clipboard.SetText(_path);
Toast.Success(TranslationHelper.Get("InfoPanelMoreItem_CopySucc"));
}
catch (Exception e)
{
Debug.WriteLine(e);
}
};
moreItemOpenSettings.Click += (_, _) =>
{
Toast.Warning("Coming soon...");
};
// Set UI translations // Set UI translations
buttonTop.ToolTip = TranslationHelper.Get("MW_StayTop"); buttonTop.ToolTip = TranslationHelper.Get("MW_StayTop");
buttonPin.ToolTip = TranslationHelper.Get("MW_PreventClosing"); buttonPin.ToolTip = TranslationHelper.Get("MW_PreventClosing");
buttonOpenWith.ToolTip = TranslationHelper.Get("MW_OpenWithMenu"); buttonOpenWith.ToolTip = TranslationHelper.Get("MW_OpenWithMenu");
buttonShare.ToolTip = TranslationHelper.Get("MW_Share"); buttonShare.ToolTip = TranslationHelper.Get("MW_Share");
buttonReload.ToolTip = TranslationHelper.Get("MW_Reload", failsafe: "Reload"); buttonReload.ToolTip = TranslationHelper.Get("MW_Reload", failsafe: "Reload");
buttonMore.ToolTip = TranslationHelper.Get("MW_More", failsafe: "More");
moreItemCopyAsPath.Header = TranslationHelper.Get("InfoPanelMoreItem_CopyAsPath");
} }
public new void Close() public new void Close()