mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-10 09:19:06 +00:00
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e0a2204e56 | ||
![]() |
d6274ac331 | ||
![]() |
07debda5e4 | ||
![]() |
cddf767c6c | ||
![]() |
21a3dd3d4b | ||
![]() |
ebb48366a0 | ||
![]() |
e12bb2201b | ||
![]() |
14a5bea926 | ||
![]() |
3dbc9fc763 | ||
![]() |
139cb873f2 | ||
![]() |
fd1004e6d3 | ||
![]() |
b0dceffa94 | ||
![]() |
2246c5a361 | ||
![]() |
5a5cce93b4 | ||
![]() |
8d7df24798 | ||
![]() |
3ae4eeb26d | ||
![]() |
da0033b52a | ||
![]() |
2e941f468e | ||
![]() |
fbfd2484df | ||
![]() |
e342cd0851 | ||
![]() |
d90993817d | ||
![]() |
5cedcff912 | ||
![]() |
9fe37520d3 | ||
![]() |
67b5dbf310 | ||
![]() |
efe47ff43b | ||
![]() |
417876edd2 | ||
![]() |
03b1ca557f | ||
![]() |
f39b53a5c6 | ||
![]() |
68cb555bad | ||
![]() |
d88c8ab8de | ||
![]() |
a38b7a450a | ||
![]() |
8ad5f39eab | ||
![]() |
83cfd2a3d8 | ||
![]() |
4840a87858 | ||
![]() |
a4d118e11f | ||
![]() |
79b002c0b3 | ||
![]() |
b26575581a | ||
![]() |
8c95a42a64 |
@@ -36,6 +36,7 @@
|
||||
"IsRefreshExplorer": true,
|
||||
"IsInstallCertificate": false,
|
||||
"IsEnableUninstallDelayUntilReboot": true,
|
||||
"IsUseTempPathFork": false,
|
||||
"IsEnvironmentVariable": false,
|
||||
"OverlayInstallRemoveExt": "exe,dll,pdb,config,winmd,txt,bat,ax,manifest,xshd",
|
||||
"UnpackingPassword": null,
|
||||
|
97
CHANGELOG.md
97
CHANGELOG.md
@@ -1,3 +1,18 @@
|
||||
## 4.1.1
|
||||
|
||||
- Add built-in ThumbnailViewer plugin [#1662](https://github.com/QL-Win/QuickLook/issues/1662)
|
||||
- Add built-in HelixViewer for 3d models [#1662](https://github.com/QL-Win/QuickLook/issues/1662)
|
||||
- Add FBX model support using AssimpNet [#1479](https://github.com/QL-Win/QuickLook/issues/1479)
|
||||
- Add `SVGA` and `Lottie Files` animation preview support
|
||||
- Add MathJax inline math support to Markdown [#1640](https://github.com/QL-Win/QuickLook/issues/1640)
|
||||
- Add `SubRip Subtitle (.srt) files`, `Protobuf`, `NSIS`, `.gitmodules`, `.dotsettings`, `.gitignore`, `.gitattributes`, `Markdown`, `reStructuredText`, `simple QML syntax`, `.env`, `Configuration (.conf;.config;.cfg)` highlighting [#1002](https://github.com/QL-Win/QuickLook/issues/1002)
|
||||
- Add dark mode highlighting for `PowerShell`, `Registry`, `C`, `C++`, `Java`, `Rust`, `SQL`, `Ruby`, `R`, `PHP`, `Pascal`, `Objective-C`, `Lisp`, `Kotlin`, `Erlang`, `Dart`, `Swift`, `VisualSolution`, `CMake`
|
||||
- Add `MakefileDetector`, `CMakeListsDetector for CMakeLists.txt`, `DockerfileDetector`, `HostsDetector for hosts` for text viewer
|
||||
- Improve QuickLook initialization speed
|
||||
- Optimize JSONDetector with Span
|
||||
- Set RichTextBox background to transparent
|
||||
- Revert Add Sandbox detection from 4.1.0 which will call crash
|
||||
|
||||
## 4.1.0
|
||||
|
||||
- Add built-in AppViewer plugin for `.msi`, `.appx`, `.msix`, `.wgt`, `.wgtu`, `.apk`, `.ipa`, `.hap`, `.deb`, `.dmg`, `.appimage`, `.rpm`, `.aab`
|
||||
@@ -34,15 +49,11 @@
|
||||
|
||||
## 4.0.2
|
||||
|
||||
[Major Change]
|
||||
|
||||
- Support .pcx image [#1638](https://github.com/QL-Win/QuickLook/issues/1638)
|
||||
- Improve PE parsing with extended buffer size
|
||||
- Fix flickering [#1628](https://github.com/QL-Win/QuickLook/issues/1628)
|
||||
- Fix DpiAwareness for PerMonitor [#1626](https://github.com/QL-Win/QuickLook/issues/1626)
|
||||
|
||||
[Small Change]
|
||||
|
||||
- Hide PEViewer Title just like InfoPanel
|
||||
- Avoid audio cover null exception in xaml
|
||||
|
||||
@@ -59,8 +70,8 @@
|
||||
|
||||
## 4.0.0
|
||||
|
||||
[Common]
|
||||
|
||||
- Add built-in PE viewer plugin
|
||||
- Add built-in font viewer plugin
|
||||
- Update translations
|
||||
- Update dependent packages
|
||||
- Add support for Multi Commander
|
||||
@@ -75,53 +86,27 @@
|
||||
- Fix plugin installer description length limit
|
||||
- Prevent crash when WMI fails [#1379](https://github.com/QL-Win/QuickLook/issues/1379)
|
||||
- Show toast when "Prevent Closing" cannot be cancelled [#1368](https://github.com/QL-Win/QuickLook/issues/1368)
|
||||
|
||||
[ImageViewer]
|
||||
|
||||
- Add support for multi-layer GIMP .xcf files [#1224](https://github.com/QL-Win/QuickLook/issues/1224)
|
||||
- Fix .xcf file extension check [#1229](https://github.com/QL-Win/QuickLook/issues/1229)
|
||||
- Fix HEIC preview rendering [#1470](https://github.com/QL-Win/QuickLook/issues/1470)
|
||||
- Add support for .qoi, .icns, .dds, .svgz, .psb, .cur, and .ani formats
|
||||
- Improve animated WebP support (x64 only) [#1024](https://github.com/QL-Win/QuickLook/issues/1024) [#1324](https://github.com/QL-Win/QuickLook/issues/1324)
|
||||
- Improve GIF decoding performance [#993](https://github.com/QL-Win/QuickLook/issues/993)
|
||||
- Add copy button to image viewer [#1399](https://github.com/QL-Win/QuickLook/issues/1399)
|
||||
- Fix SVG rendering error [#1430](https://github.com/QL-Win/QuickLook/issues/1430)
|
||||
|
||||
[TextViewer]
|
||||
|
||||
- Add double-encoding detection [#471](https://github.com/QL-Win/QuickLook/issues/471) [#600](https://github.com/QL-Win/QuickLook/issues/600) ...
|
||||
- Improve dark mode rendering
|
||||
- Catch exceptions from XSHD loader
|
||||
- Add syntax highlighting for shell scripts [#668](https://github.com/QL-Win/QuickLook/issues/668)
|
||||
- Add dark mode support for C# syntax highlighting
|
||||
|
||||
[ArchiveViewer]
|
||||
|
||||
- Improve support for comic archive formats [#1276](https://github.com/QL-Win/QuickLook/issues/1276)
|
||||
- Redesign file list with Fluent UI
|
||||
|
||||
[CsvViewer]
|
||||
|
||||
- Change default background color to blue
|
||||
- Fix issue with non-UTF8 CSV encoding
|
||||
|
||||
[MarkdownViewer]
|
||||
|
||||
- Improve rendering and stability
|
||||
|
||||
[PDFViewer]
|
||||
|
||||
- Add support for password-protected PDFs [#155](https://github.com/QL-Win/QuickLook/issues/155)
|
||||
- Enable auto-resizing of the viewer window
|
||||
|
||||
[VideoViewer]
|
||||
|
||||
- Fix audio cover parsing error for multiple embedded images
|
||||
- Add lyric (.lrc) support for audio files [#1506](https://github.com/QL-Win/QuickLook/issues/1506)
|
||||
- Add support for .mid audio format [#931](https://github.com/QL-Win/QuickLook/issues/931)
|
||||
- Fix time label overflow in long videos
|
||||
|
||||
[PEViewer & FontViewer]
|
||||
|
||||
- Add built-in PE viewer plugin
|
||||
- Add built-in font viewer plugin
|
||||
- Add support for multi-layer GIMP .xcf files [#1224](https://github.com/QL-Win/QuickLook/issues/1224) for ImageViewer
|
||||
- Fix .xcf file extension check [#1229](https://github.com/QL-Win/QuickLook/issues/1229) for ImageViewer
|
||||
- Fix HEIC preview rendering [#1470](https://github.com/QL-Win/QuickLook/issues/1470) for ImageViewer
|
||||
- Add support for .qoi, .icns, .dds, .svgz, .psb, .cur, and .ani formats for ImageViewer
|
||||
- Improve animated WebP support (x64 only) [#1024](https://github.com/QL-Win/QuickLook/issues/1024) [#1324](https://github.com/QL-Win/QuickLook/issues/1324) for ImageViewer
|
||||
- Improve GIF decoding performance [#993](https://github.com/QL-Win/QuickLook/issues/993) for ImageViewer
|
||||
- Add copy button to image viewer [#1399](https://github.com/QL-Win/QuickLook/issues/1399) for ImageViewer
|
||||
- Fix SVG rendering error [#1430](https://github.com/QL-Win/QuickLook/issues/1430) for ImageViewer
|
||||
- Add double-encoding detection [#471](https://github.com/QL-Win/QuickLook/issues/471) [#600](https://github.com/QL-Win/QuickLook/issues/600) for TextViewer
|
||||
- Improve dark mode rendering for TextViewer
|
||||
- Catch exceptions from XSHD loader for TextViewer
|
||||
- Add syntax highlighting for shell scripts [#668](https://github.com/QL-Win/QuickLook/issues/668) for TextViewer
|
||||
- Add dark mode support for C# syntax highlighting for TextViewer
|
||||
- Improve support for comic archive formats [#1276](https://github.com/QL-Win/QuickLook/issues/1276) for ArchiveViewer
|
||||
- Redesign file list with Fluent UI for ArchiveViewer
|
||||
- Change default background color to blue for CsvViewer
|
||||
- Fix issue with non-UTF8 CSV encoding for CsvViewer
|
||||
- Improve rendering and stability for MarkdownViewer
|
||||
- Add support for password-protected PDFs [#155](https://github.com/QL-Win/QuickLook/issues/155) for PDFViewer
|
||||
- Enable auto-resizing of the viewer window for PDFViewer
|
||||
- Fix audio cover parsing error for multiple embedded images for VideoViewer
|
||||
- Add lyric (.lrc) support for audio files [#1506](https://github.com/QL-Win/QuickLook/issues/1506) for VideoViewer
|
||||
- Add support for .mid audio format [#931](https://github.com/QL-Win/QuickLook/issues/931) for VideoViewer
|
||||
- Fix time label overflow in long videos for VideoViewer
|
||||
|
Submodule QuickLook.Common updated: 8978dce92c...eb72b2eabb
@@ -61,8 +61,8 @@ public class AppImageReader
|
||||
|
||||
public AppImageReader(string path)
|
||||
{
|
||||
using FileStream fs = File.OpenRead(path);
|
||||
Open(fs);
|
||||
using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
|
||||
Open(fileStream);
|
||||
}
|
||||
|
||||
private void Open(Stream stream)
|
||||
|
@@ -29,7 +29,7 @@ internal static class WgtParser
|
||||
{
|
||||
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);
|
||||
var manifestEntry = zipArchive.GetEntry("manifest.json");
|
||||
|
||||
|
@@ -34,6 +34,39 @@
|
||||
<TERMINAL>Terminal</TERMINAL>
|
||||
<VENDOR>Vendor</VENDOR>
|
||||
</en>
|
||||
<ko>
|
||||
<PRODUCT_VERSION>제품 버전</PRODUCT_VERSION>
|
||||
<PRODUCT_NAME>제품 이름</PRODUCT_NAME>
|
||||
<MANUFACTURER>제조업체</MANUFACTURER>
|
||||
<TOTAL_SIZE>전체 크기</TOTAL_SIZE>
|
||||
<LAST_MODIFIED>최종 수정됨</LAST_MODIFIED>
|
||||
<PUBLISHER>발행자</PUBLISHER>
|
||||
<CAPABILITIES>성능</CAPABILITIES>
|
||||
<ABI>ABIs</ABI>
|
||||
<APP_NAME>응용 프로그램</APP_NAME>
|
||||
<APP_VERSION>버전</APP_VERSION>
|
||||
<APP_VERSION_NAME>버전 이름</APP_VERSION_NAME>
|
||||
<APP_VERSION_CODE>버전 코드</APP_VERSION_CODE>
|
||||
<PERMISSIONS>권한</PERMISSIONS>
|
||||
<PACKAGE_NAME>패키지 이름</PACKAGE_NAME>
|
||||
<APP_MIN_SDK_VERSION>최소 SDK 버전</APP_MIN_SDK_VERSION>
|
||||
<APP_TARGET_SDK_VERSION>대상 SDK 버전</APP_TARGET_SDK_VERSION>
|
||||
<APP_MIN_OS_VERSION>최소 OS 버전</APP_MIN_OS_VERSION>
|
||||
<APP_TARGET_OS_VERSION>대상 OS 버전</APP_TARGET_OS_VERSION>
|
||||
<DEVICE_FAMILY>장치 제품군</DEVICE_FAMILY>
|
||||
<BUNDLE_NAME>번들 이름</BUNDLE_NAME>
|
||||
<DEVICE_TYPES>장치 유형</DEVICE_TYPES>
|
||||
<APP_MIN_API_VERSION>최소 API 버전</APP_MIN_API_VERSION>
|
||||
<APP_TARGET_API_VERSION>대상 API 버전</APP_TARGET_API_VERSION>
|
||||
<COMPILE_SDK_VERSION>SDK 버전 컴파일</COMPILE_SDK_VERSION>
|
||||
<ARCHITECTURE>아키텍쳐</ARCHITECTURE>
|
||||
<MAINTAINER>유지 관리자</MAINTAINER>
|
||||
<DESCRIPTION>설명</DESCRIPTION>
|
||||
<ENVIRONMENT>환경</ENVIRONMENT>
|
||||
<TYPE>유형</TYPE>
|
||||
<TERMINAL>터미널</TERMINAL>
|
||||
<VENDOR>공급업체</VENDOR>
|
||||
</ko>
|
||||
<pt-BR>
|
||||
<PRODUCT_VERSION>Versão do produto</PRODUCT_VERSION>
|
||||
<PRODUCT_NAME>Nome do produto</PRODUCT_NAME>
|
||||
|
@@ -45,7 +45,7 @@ public class ArchiveFileEntry : IComparable<ArchiveFileEntry>
|
||||
public DateTime ModifiedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the maximum depth of all siblings
|
||||
/// Returns the maximum depth of all siblings
|
||||
/// </summary>
|
||||
public int Level
|
||||
{
|
||||
@@ -75,7 +75,7 @@ public class ArchiveFileEntry : IComparable<ArchiveFileEntry>
|
||||
}
|
||||
|
||||
/// <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>
|
||||
private int GetDepth()
|
||||
{
|
||||
|
@@ -134,14 +134,14 @@ public partial class ArchiveInfoPanel : UserControl, IDisposable, INotifyPropert
|
||||
|
||||
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
|
||||
string[] useReader = [".tar.gz", ".tgz", ".tar.bz2", ".tar.lz", ".tar.xz"];
|
||||
|
||||
if (useReader.Any(path.ToLower().EndsWith))
|
||||
{
|
||||
var reader = ReaderFactory.Open(stream, new ChardetReaderOptions());
|
||||
var reader = ReaderFactory.Open(fileStream, new ChardetReaderOptions());
|
||||
|
||||
_type = reader.ArchiveType.ToString();
|
||||
|
||||
@@ -149,13 +149,13 @@ public partial class ArchiveInfoPanel : UserControl, IDisposable, INotifyPropert
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
LoadPercent = 100d * stream.Position / stream.Length;
|
||||
LoadPercent = 100d * fileStream.Position / fileStream.Length;
|
||||
ProcessByLevel(reader.Entry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var archive = ArchiveFactory.Open(stream, new ChardetReaderOptions());
|
||||
var archive = ArchiveFactory.Open(fileStream, new ChardetReaderOptions());
|
||||
|
||||
_type = archive.Type.ToString();
|
||||
|
||||
@@ -163,7 +163,7 @@ public partial class ArchiveInfoPanel : UserControl, IDisposable, INotifyPropert
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
LoadPercent = 100d * stream.Position / stream.Length;
|
||||
LoadPercent = 100d * fileStream.Position / fileStream.Length;
|
||||
ProcessByLevel(entry);
|
||||
}
|
||||
}
|
||||
|
@@ -28,9 +28,9 @@ using System.Windows.Media.Imaging;
|
||||
namespace QuickLook.Plugin.ArchiveViewer;
|
||||
|
||||
/// <summary>
|
||||
/// Internals are mostly from here:
|
||||
/// http://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using
|
||||
/// Caches all results.
|
||||
/// Internals are mostly from here:
|
||||
/// http://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using
|
||||
/// Caches all results.
|
||||
/// </summary>
|
||||
public static class IconManager
|
||||
{
|
||||
@@ -48,7 +48,7 @@ public static class IconManager
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the icon of a directory
|
||||
/// Get the icon of a directory
|
||||
/// </summary>
|
||||
/// <param name="large">16x16 or 32x32 icon</param>
|
||||
/// <returns>an icon</returns>
|
||||
@@ -68,7 +68,7 @@ public static class IconManager
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an icon for a given filename
|
||||
/// Get an icon for a given filename
|
||||
/// </summary>
|
||||
/// <param name="fileName">any filename</param>
|
||||
/// <param name="large">16x16 or 32x32 icon</param>
|
||||
@@ -89,7 +89,7 @@ public static class IconManager
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// http://stackoverflow.com/a/6580799/1943849
|
||||
/// http://stackoverflow.com/a/6580799/1943849
|
||||
/// </summary>
|
||||
private static ImageSource ToImageSource(this Icon icon)
|
||||
{
|
||||
@@ -101,31 +101,31 @@ public static class IconManager
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <example>
|
||||
/// <code>IconReader.GetFileIcon("c:\\general.xls");</code>
|
||||
/// <code>IconReader.GetFileIcon("c:\\general.xls");</code>
|
||||
/// </example>
|
||||
private static class IconReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Options to specify the size of icons to return.
|
||||
/// Options to specify the size of icons to return.
|
||||
/// </summary>
|
||||
public enum IconSize
|
||||
{
|
||||
/// <summary>
|
||||
/// Specify large icon - 32 pixels by 32 pixels.
|
||||
/// Specify large icon - 32 pixels by 32 pixels.
|
||||
/// </summary>
|
||||
Large = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Specify small icon - 16 pixels by 16 pixels.
|
||||
/// Specify small icon - 16 pixels by 16 pixels.
|
||||
/// </summary>
|
||||
Small = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the icon of a folder.
|
||||
/// Returns the icon of a folder.
|
||||
/// </summary>
|
||||
/// <param name="size">Large or small</param>
|
||||
/// <param name="linkOverlay">Whether to include the link icon</param>
|
||||
@@ -152,7 +152,7 @@ public static class IconManager
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <param name="name">Pathname for file.</param>
|
||||
/// <param name="size">Large or small</param>
|
||||
@@ -181,8 +181,8 @@ public static class IconManager
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
|
||||
/// courtesy of MSDN Cold Rooster Consulting case study.
|
||||
/// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
|
||||
/// courtesy of MSDN Cold Rooster Consulting case study.
|
||||
/// </summary>
|
||||
private static class Shell32
|
||||
{
|
||||
@@ -221,13 +221,13 @@ public static class IconManager
|
||||
}
|
||||
|
||||
/// <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>
|
||||
private static class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to function required to delete handle. This method is used internally
|
||||
/// and is not required to be called separately.
|
||||
/// Provides access to function required to delete handle. This method is used internally
|
||||
/// and is not required to be called separately.
|
||||
/// </summary>
|
||||
/// <param name="hIcon">Pointer to icon handle.</param>
|
||||
/// <returns>N/A</returns>
|
||||
|
@@ -7,6 +7,12 @@
|
||||
<ConfirmDeleteText>Are you sure you want to permanently delete these {0} item(s)?</ConfirmDeleteText>
|
||||
<RecycleBinSizeText>Total size {0}, {1} items</RecycleBinSizeText>
|
||||
</en>
|
||||
<ko>
|
||||
<RecycleBinEmptyText>휴지통이 비어 있습니다</RecycleBinEmptyText>
|
||||
<RecycleBinButton>휴지통 비우기</RecycleBinButton>
|
||||
<ConfirmDeleteText>{0}개 항목을 영구적으로 삭제하시겠습니까?</ConfirmDeleteText>
|
||||
<RecycleBinSizeText>전체 크기 {0}, {1}개 항목</RecycleBinSizeText>
|
||||
</ko>
|
||||
<zh-CN>
|
||||
<RecycleBinEmptyText>回收站是空的</RecycleBinEmptyText>
|
||||
<RecycleBinButton>清空回收站</RecycleBinButton>
|
||||
@@ -25,12 +31,6 @@
|
||||
<ConfirmDeleteText>これらの {0} 項目を完全に削除してもよろしいですか?</ConfirmDeleteText>
|
||||
<RecycleBinSizeText>合計サイズ {0}、{1} 項目</RecycleBinSizeText>
|
||||
</ja>
|
||||
<ko>
|
||||
<RecycleBinEmptyText>휴지통이 비어 있습니다</RecycleBinEmptyText>
|
||||
<RecycleBinButton>휴지통 비우기</RecycleBinButton>
|
||||
<ConfirmDeleteText>{0}개의 항목을 영구적으로 삭제하시겠습니까?</ConfirmDeleteText>
|
||||
<RecycleBinSizeText>총 크기 {0}, 총 {1}개 항목</RecycleBinSizeText>
|
||||
</ko>
|
||||
<fr>
|
||||
<RecycleBinEmptyText>La corbeille est vide</RecycleBinEmptyText>
|
||||
<RecycleBinButton>Vider la corbeille</RecycleBinButton>
|
||||
|
@@ -7,6 +7,12 @@
|
||||
<FORMAT_PROFILE>Format Profile</FORMAT_PROFILE>
|
||||
<NAME>Name</NAME>
|
||||
</en>
|
||||
<ko>
|
||||
<TOTAL_SIZE>전체 크기</TOTAL_SIZE>
|
||||
<FORMAT>형식</FORMAT>
|
||||
<FORMAT_PROFILE>형식 프로필</FORMAT_PROFILE>
|
||||
<NAME>이름</NAME>
|
||||
</ko>
|
||||
<pt-BR>
|
||||
<TOTAL_SIZE>Tamanho total</TOTAL_SIZE>
|
||||
<FORMAT>Formato</FORMAT>
|
||||
|
@@ -40,12 +40,19 @@ internal unsafe static class FreeTypeApi
|
||||
|
||||
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);
|
||||
return familyName;
|
||||
if (error == FT_Error.FT_Err_Ok)
|
||||
{
|
||||
var familyName = Marshal.PtrToStringAnsi((nint)face->family_name);
|
||||
return familyName;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(lib);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -19,6 +19,7 @@ using QuickLook.Common.Plugin;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace QuickLook.Plugin.FontViewer;
|
||||
@@ -52,7 +53,12 @@ public class Plugin : IViewer
|
||||
|
||||
context.ViewerContent = _panel;
|
||||
context.Title = Path.GetFileName(path);
|
||||
context.IsBusy = false;
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
_ = _panel.WaitForFontSent();
|
||||
context.IsBusy = false;
|
||||
});
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
|
@@ -4,6 +4,9 @@
|
||||
<en>
|
||||
<SAMPLE_TEXT>The quick brown fox jumped over the lazy dog. 1234567890</SAMPLE_TEXT>
|
||||
</en>
|
||||
<ko>
|
||||
<SAMPLE_TEXT>지금 이 순간, 나의 아름다움은 가장 빛난다 - 비너스걸. 1234567890</SAMPLE_TEXT>
|
||||
</ko>
|
||||
<zh-CN>
|
||||
<SAMPLE_TEXT>Innovation in China 中国智造,惠及全球 0123456789</SAMPLE_TEXT>
|
||||
</zh-CN>
|
||||
|
@@ -26,6 +26,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace QuickLook.Plugin.FontViewer;
|
||||
|
||||
@@ -34,6 +35,7 @@ public class WebfontPanel : WebpagePanel
|
||||
protected const string _resourcePrefix = "QuickLook.Plugin.FontViewer.Resources.";
|
||||
protected internal static readonly Dictionary<string, byte[]> _resources = [];
|
||||
protected byte[] _homePage;
|
||||
protected ObservableFileStream _fontStream = null;
|
||||
|
||||
static WebfontPanel()
|
||||
{
|
||||
@@ -149,14 +151,15 @@ public class WebfontPanel : WebpagePanel
|
||||
}
|
||||
else
|
||||
{
|
||||
var localPath = _fallbackPath + requestedUri.AbsolutePath.Replace('/', '\\');
|
||||
var localPath = _fallbackPath + Uri.UnescapeDataString(requestedUri.AbsolutePath).Replace('/', '\\');
|
||||
|
||||
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(
|
||||
fileStream, 200, "OK", MimeTypes.GetContentType());
|
||||
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)
|
||||
{
|
||||
return _resources.ContainsKey(key);
|
||||
|
@@ -17,6 +17,8 @@
|
||||
|
||||
using Assimp;
|
||||
using HelixToolkit.Wpf;
|
||||
using PcdSharp.IO;
|
||||
using PcdSharp.Struct;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -54,6 +56,86 @@ public partial class HelixPanel
|
||||
modelVisual.Content = model;
|
||||
}
|
||||
}
|
||||
if (importerType == ImporterType.Extended_PCD)
|
||||
{
|
||||
// Only support PCD files with PointXYZ format
|
||||
// Not supported for Color or Intensity formats
|
||||
var xyzCloud = PCDReader.Read<PointXYZ>(_path);
|
||||
|
||||
// Create a single geometry for all points to improve performance
|
||||
var pointCloudGeometry = new MeshGeometry3D();
|
||||
var positions = new Point3DCollection();
|
||||
var triangleIndices = new Int32Collection();
|
||||
|
||||
// Create material for points
|
||||
var pointMaterial = new DiffuseMaterial(new SolidColorBrush(Color.FromRgb(0x60, 0x80, 0xFF)));
|
||||
|
||||
// Adaptive point size based on total number of points
|
||||
var totalPoints = xyzCloud.Points.Count;
|
||||
var pointSize = totalPoints > 10000 ? 0.05d : totalPoints > 1000 ? 0.1d : 0.2d;
|
||||
|
||||
// Limit points for performance (show every Nth point if too many)
|
||||
var step = Math.Max(1, totalPoints / 50000); // Limit to ~50k points max
|
||||
|
||||
var vertexIndex = 0;
|
||||
for (int i = 0; i < xyzCloud.Points.Count; i += step)
|
||||
{
|
||||
var point = xyzCloud.Points[i];
|
||||
|
||||
// Create a small cube for each point
|
||||
var halfSize = pointSize / 2;
|
||||
|
||||
// Add 8 vertices for the cube
|
||||
var baseIndex = vertexIndex;
|
||||
|
||||
// Front face vertices
|
||||
positions.Add(new Point3D(point.X - halfSize, point.Y - halfSize, point.Z + halfSize));
|
||||
positions.Add(new Point3D(point.X + halfSize, point.Y - halfSize, point.Z + halfSize));
|
||||
positions.Add(new Point3D(point.X + halfSize, point.Y + halfSize, point.Z + halfSize));
|
||||
positions.Add(new Point3D(point.X - halfSize, point.Y + halfSize, point.Z + halfSize));
|
||||
|
||||
// Back face vertices
|
||||
positions.Add(new Point3D(point.X - halfSize, point.Y - halfSize, point.Z - halfSize));
|
||||
positions.Add(new Point3D(point.X + halfSize, point.Y - halfSize, point.Z - halfSize));
|
||||
positions.Add(new Point3D(point.X + halfSize, point.Y + halfSize, point.Z - halfSize));
|
||||
positions.Add(new Point3D(point.X - halfSize, point.Y + halfSize, point.Z - halfSize));
|
||||
|
||||
// Add triangle indices for the cube (12 triangles, 36 indices)
|
||||
// Front face
|
||||
triangleIndices.Add(baseIndex + 0); triangleIndices.Add(baseIndex + 1); triangleIndices.Add(baseIndex + 2);
|
||||
triangleIndices.Add(baseIndex + 0); triangleIndices.Add(baseIndex + 2); triangleIndices.Add(baseIndex + 3);
|
||||
// Back face
|
||||
triangleIndices.Add(baseIndex + 4); triangleIndices.Add(baseIndex + 6); triangleIndices.Add(baseIndex + 5);
|
||||
triangleIndices.Add(baseIndex + 4); triangleIndices.Add(baseIndex + 7); triangleIndices.Add(baseIndex + 6);
|
||||
// Left face
|
||||
triangleIndices.Add(baseIndex + 4); triangleIndices.Add(baseIndex + 0); triangleIndices.Add(baseIndex + 3);
|
||||
triangleIndices.Add(baseIndex + 4); triangleIndices.Add(baseIndex + 3); triangleIndices.Add(baseIndex + 7);
|
||||
// Right face
|
||||
triangleIndices.Add(baseIndex + 1); triangleIndices.Add(baseIndex + 5); triangleIndices.Add(baseIndex + 6);
|
||||
triangleIndices.Add(baseIndex + 1); triangleIndices.Add(baseIndex + 6); triangleIndices.Add(baseIndex + 2);
|
||||
// Top face
|
||||
triangleIndices.Add(baseIndex + 3); triangleIndices.Add(baseIndex + 2); triangleIndices.Add(baseIndex + 6);
|
||||
triangleIndices.Add(baseIndex + 3); triangleIndices.Add(baseIndex + 6); triangleIndices.Add(baseIndex + 7);
|
||||
// Bottom face
|
||||
triangleIndices.Add(baseIndex + 4); triangleIndices.Add(baseIndex + 5); triangleIndices.Add(baseIndex + 1);
|
||||
triangleIndices.Add(baseIndex + 4); triangleIndices.Add(baseIndex + 1); triangleIndices.Add(baseIndex + 0);
|
||||
|
||||
vertexIndex += 8;
|
||||
}
|
||||
|
||||
pointCloudGeometry.Positions = positions;
|
||||
pointCloudGeometry.TriangleIndices = triangleIndices;
|
||||
|
||||
// Create the model
|
||||
var pointCloudModel = new GeometryModel3D
|
||||
{
|
||||
Geometry = pointCloudGeometry,
|
||||
Material = pointMaterial,
|
||||
BackMaterial = pointMaterial
|
||||
};
|
||||
|
||||
modelVisual.Content = pointCloudModel;
|
||||
}
|
||||
else
|
||||
{
|
||||
var modelImporter = new ModelImporter();
|
||||
@@ -90,6 +172,7 @@ file static class Importer
|
||||
".stl" or ".obj" or ".3ds" or ".lwo" or ".ply" => ImporterType.Default,
|
||||
".fbx" or ".3mf" or ".glb" or ".gltf" or ".dae" or ".dxf" => ImporterType.Extended,
|
||||
".pmx" => ImporterType.Extended_MMD,
|
||||
".pcd" => ImporterType.Extended_PCD,
|
||||
_ => ImporterType.Unknown,
|
||||
};
|
||||
}
|
||||
@@ -97,8 +180,28 @@ file static class Importer
|
||||
|
||||
file enum ImporterType
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved or unspecified import type
|
||||
/// </summary>
|
||||
Unknown,
|
||||
|
||||
/// <summary>
|
||||
/// Default importer supported by HelixToolkit
|
||||
/// </summary>
|
||||
Default,
|
||||
|
||||
/// <summary>
|
||||
/// Extended importer supported by Assimp
|
||||
/// </summary>
|
||||
Extended,
|
||||
|
||||
/// <summary>
|
||||
/// Extended MMD (MikuMikuDance) importer
|
||||
/// </summary>
|
||||
Extended_MMD,
|
||||
|
||||
/// <summary>
|
||||
/// Extended PCD (Point Cloud Data) importer for 3D spatial data
|
||||
/// </summary>
|
||||
Extended_PCD,
|
||||
}
|
||||
|
@@ -31,17 +31,20 @@ public class Plugin : IViewer
|
||||
/// </summary>
|
||||
private static readonly HashSet<string> WellKnownExtensions = new(
|
||||
[
|
||||
// Default
|
||||
// Default supported by HelixToolkit
|
||||
".stl", ".obj", ".3ds", ".lwo", ".ply",
|
||||
|
||||
// Extended
|
||||
// Extended supported by Assimp
|
||||
".fbx", ".3mf", ".blend", ".glb", ".gltf", ".dae",
|
||||
#if S_DXF
|
||||
".dxf",
|
||||
#endif
|
||||
|
||||
// Extended_MMD
|
||||
".pmx",
|
||||
// TBD: MMD (MikuMikuDance)
|
||||
//".pmx",
|
||||
|
||||
// PCD (Point Cloud Data)
|
||||
".pcd",
|
||||
]);
|
||||
|
||||
private HelixPanel _hp;
|
||||
|
@@ -55,6 +55,7 @@
|
||||
<PackageReference Include="HelixToolkit" Version="2.27.0" />
|
||||
<PackageReference Include="HelixToolkit.Wpf" Version="2.27.0" />
|
||||
<PackageReference Include="AssimpNet" Version="5.0.0-beta1" />
|
||||
<PackageReference Include="PcdSharp" Version="1.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -4,6 +4,9 @@
|
||||
<en>
|
||||
<WEBVIEW2_NOT_AVAILABLE>Viewing this file requires Microsoft Edge WebView2 to be installed. Click here to download it.</WEBVIEW2_NOT_AVAILABLE>
|
||||
</en>
|
||||
<ko>
|
||||
<WEBVIEW2_NOT_AVAILABLE>이 파일을 보려면 Microsoft Edge WebView2를 설치해야 합니다. 여기를 클릭하여 다운로드하세요.</WEBVIEW2_NOT_AVAILABLE>
|
||||
</ko>
|
||||
<de>
|
||||
<WEBVIEW2_NOT_AVAILABLE>Für das Anzeigen dieses Dateityps wird MS Edge WebView2 benötigt. Hier klicken zum Downloaden.</WEBVIEW2_NOT_AVAILABLE>
|
||||
</de>
|
||||
@@ -13,9 +16,6 @@
|
||||
<ja>
|
||||
<WEBVIEW2_NOT_AVAILABLE>このファイルを閲覧するには、Microsoft Edge WebView2 がインストールされている必要があります。 ここをクリックしてダウンロードを開始する。</WEBVIEW2_NOT_AVAILABLE>
|
||||
</ja>
|
||||
<ko-KR>
|
||||
<WEBVIEW2_NOT_AVAILABLE>이 파일을 표시하려면 Microsoft Edge WebView2가 필요합니다. 여기를 클릭해서 다운로드 하세요.</WEBVIEW2_NOT_AVAILABLE>
|
||||
</ko-KR>
|
||||
<zh-CN>
|
||||
<WEBVIEW2_NOT_AVAILABLE>查看此文件需要安装 Microsoft Edge WebView2。 点击这里开始下载。</WEBVIEW2_NOT_AVAILABLE>
|
||||
</zh-CN>
|
||||
|
@@ -210,7 +210,7 @@ public class WebpagePanel : UserControl
|
||||
if (File.Exists(fallbackFilePath))
|
||||
{
|
||||
// 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(
|
||||
fileStream, 200, "OK", "Content-Type: application/octet-stream");
|
||||
args.Response = response;
|
||||
|
@@ -59,21 +59,19 @@ public class AnimatedImage : Image, IDisposable
|
||||
return provider;
|
||||
}
|
||||
|
||||
#region DependencyProperty
|
||||
|
||||
public static readonly DependencyProperty AnimationFrameIndexProperty =
|
||||
DependencyProperty.Register("AnimationFrameIndex", typeof(int), typeof(AnimatedImage),
|
||||
DependencyProperty.Register(nameof(AnimationFrameIndex), typeof(int), typeof(AnimatedImage),
|
||||
new UIPropertyMetadata(-1, AnimationFrameIndexChanged));
|
||||
|
||||
public static readonly DependencyProperty AnimationUriProperty =
|
||||
DependencyProperty.Register("AnimationUri", typeof(Uri), typeof(AnimatedImage),
|
||||
DependencyProperty.Register(nameof(AnimationUri), typeof(Uri), typeof(AnimatedImage),
|
||||
new UIPropertyMetadata(null, AnimationUriChanged));
|
||||
|
||||
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 =
|
||||
DependencyProperty.Register("ContextObject", typeof(ContextObject), typeof(AnimatedImage));
|
||||
DependencyProperty.Register(nameof(ContextObject), typeof(ContextObject), typeof(AnimatedImage));
|
||||
|
||||
public int AnimationFrameIndex
|
||||
{
|
||||
@@ -104,9 +102,6 @@ public class AnimatedImage : Image, IDisposable
|
||||
if (obj is not AnimatedImage instance)
|
||||
return;
|
||||
|
||||
//var thumbnail = instance.Meta?.GetThumbnail(true);
|
||||
//instance.Source = thumbnail;
|
||||
|
||||
instance._animation = InitAnimationProvider((Uri)ev.NewValue, instance.Meta, instance.ContextObject);
|
||||
ShowThumbnailAndStartAnimation(instance);
|
||||
}
|
||||
@@ -161,6 +156,4 @@ public class AnimatedImage : Image, IDisposable
|
||||
}));
|
||||
task.Start();
|
||||
}
|
||||
|
||||
#endregion DependencyProperty
|
||||
}
|
||||
|
@@ -24,20 +24,13 @@ using System.Windows.Media.Imaging;
|
||||
|
||||
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)
|
||||
{
|
||||
Path = path;
|
||||
Meta = meta;
|
||||
ContextObject = contextObject;
|
||||
}
|
||||
public Uri Path { get; } = path;
|
||||
|
||||
public Uri Path { get; }
|
||||
public MetaProvider Meta { get; } = meta;
|
||||
|
||||
public MetaProvider Meta { get; }
|
||||
|
||||
public ContextObject ContextObject { get; }
|
||||
public ContextObject ContextObject { get; } = contextObject;
|
||||
|
||||
public Int32AnimationUsingKeyFrames Animator { get; protected set; }
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
|
||||
using LibAPNG;
|
||||
using QuickLook.Common.ExtensionMethods;
|
||||
using QuickLook.Common.Helpers;
|
||||
using QuickLook.Common.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -30,20 +31,28 @@ using System.Windows.Media.Imaging;
|
||||
|
||||
namespace QuickLook.Plugin.ImageViewer.AnimatedImage.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// This provider is only for Animated PNG.
|
||||
/// The others will fall back to another provider.
|
||||
/// </summary>
|
||||
internal class APngProvider : AnimationProvider
|
||||
{
|
||||
private readonly Frame _baseFrame;
|
||||
private readonly List<FrameInfo> _frames;
|
||||
private readonly List<BitmapSource> _renderedFrames;
|
||||
private int _lastEffectivePreviousPreviousFrameIndex;
|
||||
private NativeProvider _nativeImageProvider;
|
||||
private AnimationProvider _fallbackImageProvider;
|
||||
|
||||
public APngProvider(Uri path, MetaProvider meta, ContextObject contextObject) : base(path, meta, contextObject)
|
||||
{
|
||||
if (!IsAnimatedPng(path.LocalPath))
|
||||
{
|
||||
_nativeImageProvider = new NativeProvider(path, meta, contextObject);
|
||||
Animator = _nativeImageProvider.Animator;
|
||||
var useNativeProvider = SettingHelper.Get("UseNativeProvider", true, "QuickLook.Plugin.ImageViewer");
|
||||
|
||||
_fallbackImageProvider = useNativeProvider ?
|
||||
new NativeProvider(path, meta, contextObject) :
|
||||
new ImageMagickProvider(path, meta, contextObject);
|
||||
Animator = _fallbackImageProvider.Animator;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,8 +80,8 @@ internal class APngProvider : AnimationProvider
|
||||
|
||||
public override Task<BitmapSource> GetThumbnail(Size renderSize)
|
||||
{
|
||||
if (_nativeImageProvider != null)
|
||||
return _nativeImageProvider.GetThumbnail(renderSize);
|
||||
if (_fallbackImageProvider != null)
|
||||
return _fallbackImageProvider.GetThumbnail(renderSize);
|
||||
|
||||
return new Task<BitmapSource>(() =>
|
||||
{
|
||||
@@ -85,8 +94,8 @@ internal class APngProvider : AnimationProvider
|
||||
|
||||
public override Task<BitmapSource> GetRenderedFrame(int index)
|
||||
{
|
||||
if (_nativeImageProvider != null)
|
||||
return _nativeImageProvider.GetRenderedFrame(index);
|
||||
if (_fallbackImageProvider != null)
|
||||
return _fallbackImageProvider.GetRenderedFrame(index);
|
||||
|
||||
if (_renderedFrames[index] != null)
|
||||
return new Task<BitmapSource>(() => _renderedFrames[index]);
|
||||
@@ -102,10 +111,10 @@ internal class APngProvider : AnimationProvider
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (_nativeImageProvider != null)
|
||||
if (_fallbackImageProvider != null)
|
||||
{
|
||||
_nativeImageProvider.Dispose();
|
||||
_nativeImageProvider = null;
|
||||
_fallbackImageProvider.Dispose();
|
||||
_fallbackImageProvider = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -214,7 +223,7 @@ internal class APngProvider : AnimationProvider
|
||||
return false;
|
||||
}
|
||||
|
||||
uint ToUInt32BE(byte[] data)
|
||||
static uint ToUInt32BE(byte[] data)
|
||||
{
|
||||
Array.Reverse(data);
|
||||
return BitConverter.ToUInt32(data, 0);
|
||||
|
@@ -40,11 +40,6 @@ internal class NativeProvider : AnimationProvider
|
||||
public override Task<BitmapSource> GetThumbnail(Size renderSize)
|
||||
{
|
||||
var fullSize = Meta.GetSize();
|
||||
|
||||
//var decodeWidth = (int) Math.Round(fullSize.Width *
|
||||
// Math.Min(renderSize.Width / 2 / fullSize.Width,
|
||||
// renderSize.Height / 2 / fullSize.Height));
|
||||
//var decodeHeight = (int) Math.Round(fullSize.Height / fullSize.Width * decodeWidth);
|
||||
var decodeWidth =
|
||||
(int)Math.Round(Math.Min(Meta.GetSize().Width, Math.Max(1d, Math.Floor(renderSize.Width))));
|
||||
var decodeHeight =
|
||||
|
@@ -103,9 +103,7 @@ public partial class ImagePanel : UserControl, INotifyPropertyChanged, IDisposab
|
||||
ContextObject = context;
|
||||
Meta = meta;
|
||||
|
||||
var s = meta.GetSize();
|
||||
//_minZoomFactor = Math.Min(200d / s.Height, 400d / s.Width);
|
||||
//_maxZoomFactor = Math.Min(9000d / s.Height, 9000d / s.Width);
|
||||
_ = meta.GetSize();
|
||||
|
||||
ShowMeta();
|
||||
Theme = ContextObject.Theme;
|
||||
|
@@ -65,8 +65,16 @@ public class Plugin : IViewer
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Option of UseColorProfile:
|
||||
// Default is False (disable color profile conversion)
|
||||
// Note that enabling this feature will slow down image previewing, especially on large images.
|
||||
var useColorProfile = SettingHelper.Get("UseColorProfile", false, "QuickLook.Plugin.ImageViewer");
|
||||
|
||||
// Option of UseNativeProvider:
|
||||
// Default is True (disable precise colors and choose faster response)
|
||||
// Note that disabling this feature may slightly slow down image previewing but you can get precise colors.
|
||||
var useNativeProvider = SettingHelper.Get("UseNativeProvider", true, "QuickLook.Plugin.ImageViewer");
|
||||
|
||||
AnimatedImage.AnimatedImage.Providers.Add(
|
||||
new KeyValuePair<string[], Type>(
|
||||
useColorProfile ? [".apng"] : [".apng", ".png"],
|
||||
@@ -76,11 +84,10 @@ public class Plugin : IViewer
|
||||
typeof(GifProvider)));
|
||||
AnimatedImage.AnimatedImage.Providers.Add(
|
||||
new KeyValuePair<string[], Type>(
|
||||
useColorProfile ? [] : [".bmp", ".jpg", ".jpeg", ".jfif", ".tif", ".tiff"],
|
||||
useColorProfile ? [] : (useNativeProvider ? [".bmp", ".jpg", ".jpeg", ".jfif", ".tif", ".tiff"] : []),
|
||||
typeof(NativeProvider)));
|
||||
AnimatedImage.AnimatedImage.Providers.Add(
|
||||
new KeyValuePair<string[], Type>(
|
||||
useColorProfile ? [] : [".jxr"],
|
||||
new KeyValuePair<string[], Type>([".jxr"],
|
||||
typeof(WmpProvider)));
|
||||
AnimatedImage.AnimatedImage.Providers.Add(
|
||||
new KeyValuePair<string[], Type>([".icns"],
|
||||
|
@@ -59,7 +59,7 @@
|
||||
<PackageReference Include="QuickLook.ImageGlass.WebP" Version="1.4.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.6.0">
|
||||
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.7.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3351.48">
|
||||
|
@@ -27,7 +27,7 @@ internal static class LottieExtractor
|
||||
{
|
||||
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);
|
||||
|
||||
var manifestEntry = zipArchive.GetEntry("manifest.json");
|
||||
|
@@ -22,6 +22,7 @@ using QuickLook.Plugin.HtmlViewer;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -67,6 +68,7 @@ public class SvgImagePanel : WebpagePanel, IWebImagePanel
|
||||
{
|
||||
UserDataFolder = Path.Combine(SettingHelper.LocalDataPath, @"WebView2_Data\"),
|
||||
},
|
||||
DefaultBackgroundColor = Color.Transparent,
|
||||
};
|
||||
_webView.CoreWebView2InitializationCompleted += WebView_CoreWebView2InitializationCompleted;
|
||||
Content = _webView;
|
||||
@@ -128,11 +130,11 @@ public class SvgImagePanel : WebpagePanel, IWebImagePanel
|
||||
}
|
||||
else
|
||||
{
|
||||
var localPath = _fallbackPath + requestedUri.AbsolutePath.Replace('/', '\\');
|
||||
var localPath = _fallbackPath + Uri.UnescapeDataString(requestedUri.AbsolutePath).Replace('/', '\\');
|
||||
|
||||
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(
|
||||
fileStream, 200, "OK", MimeTypes.GetContentTypeHeader());
|
||||
args.Response = response;
|
||||
@@ -147,7 +149,7 @@ public class SvgImagePanel : WebpagePanel, IWebImagePanel
|
||||
{
|
||||
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(
|
||||
fileStream, 200, "OK",
|
||||
$"""
|
||||
|
@@ -16,10 +16,12 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using QuickLook.Common.Helpers;
|
||||
using QuickLook.Plugin.HtmlViewer;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -78,7 +80,21 @@ public class MarkdownPanel : WebpagePanel
|
||||
var content = encoding.GetString(bytes);
|
||||
|
||||
var template = ReadString("/md2html.html");
|
||||
var html = template.Replace("{{content}}", content);
|
||||
|
||||
// Support automatic RTL for markdown files
|
||||
bool isRtl = false;
|
||||
if (CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft)
|
||||
{
|
||||
string isSupportRTL = TranslationHelper.Get("IsSupportRTL",
|
||||
failsafe: bool.TrueString,
|
||||
domain: Assembly.GetExecutingAssembly().GetName().Name);
|
||||
|
||||
if (bool.TrueString.Equals(isSupportRTL, StringComparison.OrdinalIgnoreCase))
|
||||
isRtl = true;
|
||||
}
|
||||
|
||||
var html = template.Replace("{{content}}", content)
|
||||
.Replace("{{rtl}}", isRtl ? "rtl" : "ltr");
|
||||
|
||||
return html;
|
||||
}
|
||||
@@ -108,11 +124,11 @@ public class MarkdownPanel : WebpagePanel
|
||||
}
|
||||
else
|
||||
{
|
||||
var localPath = _fallbackPath + requestedUri.AbsolutePath.Replace('/', '\\');
|
||||
var localPath = _fallbackPath + Uri.UnescapeDataString(requestedUri.AbsolutePath).Replace('/', '\\');
|
||||
|
||||
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(
|
||||
fileStream, 200, "OK", MimeTypes.GetContentType());
|
||||
args.Response = response;
|
||||
|
2314
QuickLook.Plugin/QuickLook.Plugin.MarkdownViewer/Resources/js/mermaid.min.js
vendored
Normal file
2314
QuickLook.Plugin/QuickLook.Plugin.MarkdownViewer/Resources/js/mermaid.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html dir="{{rtl}}">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<script src="highlight.js/highlight.min.js"></script>
|
||||
|
||||
<script src="js/markdownItAnchor.umd.js"></script>
|
||||
<script src="js/mermaid.min.js"></script>
|
||||
</head>
|
||||
<body class="markdown-body">
|
||||
<link rel="stylesheet" href="css/github-markdown.css" />
|
||||
@@ -144,6 +145,61 @@
|
||||
cursor: ew-resize;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* RTL support */
|
||||
html[dir="rtl"] .container {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
html[dir="rtl"] #toc {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .table-of-contents a {
|
||||
border-right: 2px solid transparent;
|
||||
border-left: none;
|
||||
margin-right: -1em;
|
||||
margin-left: 0;
|
||||
padding-right: calc(1em - 2px);
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .table-of-contents .active {
|
||||
border-right: 2px solid var(--fgColor-accent);
|
||||
border-left: none;
|
||||
margin-right: -1em;
|
||||
margin-left: 0;
|
||||
padding-right: calc(1em - 2px);
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
/* Mermaid diagram styles */
|
||||
.mermaid {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.mermaid-placeholder {
|
||||
border: 2px dashed var(--borderColor-default);
|
||||
background: var(--bgColor-muted);
|
||||
color: var(--fgColor-muted);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.mermaid-placeholder pre {
|
||||
background: var(--bgColor-default);
|
||||
border: 1px solid var(--borderColor-default);
|
||||
color: var(--fgColor-default);
|
||||
}
|
||||
</style>
|
||||
|
||||
<textarea id="text-input" style="display: none">{{content}}</textarea>
|
||||
@@ -160,6 +216,9 @@
|
||||
typographer: false,
|
||||
quotes: "“”‘’",
|
||||
highlight: function (str, lang) {
|
||||
if (lang === 'mermaid') {
|
||||
return '<div class="mermaid">' + str + '</div>';
|
||||
}
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return (
|
||||
@@ -190,6 +249,62 @@
|
||||
document.getElementById("text-input").value
|
||||
);
|
||||
|
||||
// Initialize Mermaid after markdown rendering
|
||||
if (window.mermaid) {
|
||||
// Determine theme based on system preference
|
||||
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: isDarkMode ? 'dark' : 'default',
|
||||
securityLevel: 'loose', // Allow HTML in diagrams for enhanced features
|
||||
fontFamily: 'Segoe UI, Helvetica, Arial, sans-serif',
|
||||
themeVariables: {
|
||||
primaryColor: isDarkMode ? '#58a6ff' : '#0969da',
|
||||
primaryTextColor: isDarkMode ? '#f0f6fc' : '#24292f',
|
||||
primaryBorderColor: isDarkMode ? '#30363d' : '#d0d7de',
|
||||
lineColor: isDarkMode ? '#484f58' : '#656d76',
|
||||
sectionBkgColor: isDarkMode ? '#21262d' : '#f6f8fa',
|
||||
altSectionBkgColor: isDarkMode ? '#161b22' : '#ffffff',
|
||||
gridColor: isDarkMode ? '#21262d' : '#f6f8fa',
|
||||
cScale0: isDarkMode ? '#58a6ff' : '#0969da',
|
||||
cScale1: isDarkMode ? '#a5f3fc' : '#54aeff',
|
||||
cScale2: isDarkMode ? '#ff7b72' : '#d1242f'
|
||||
}
|
||||
});
|
||||
|
||||
// Render Mermaid diagrams with error handling
|
||||
setTimeout(() => {
|
||||
try {
|
||||
mermaid.init(undefined, document.querySelectorAll('.mermaid'));
|
||||
} catch (error) {
|
||||
console.warn('Mermaid rendering error:', error);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
// Listen for theme changes and re-render diagrams
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
||||
if (window.mermaid) {
|
||||
const newTheme = e.matches ? 'dark' : 'default';
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: newTheme,
|
||||
securityLevel: 'loose',
|
||||
fontFamily: 'Segoe UI, Helvetica, Arial, sans-serif'
|
||||
});
|
||||
|
||||
// Re-render all Mermaid diagrams
|
||||
setTimeout(() => {
|
||||
try {
|
||||
mermaid.init(undefined, document.querySelectorAll('.mermaid'));
|
||||
} catch (error) {
|
||||
console.warn('Mermaid re-rendering error:', error);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* codes below are adopted from https://codepen.io/jtojnar/full/Juiop */
|
||||
var ToC = `<nav role='navigation' class='table-of-contents'>
|
||||
<h2>Contents</h2>
|
||||
@@ -337,6 +452,21 @@
|
||||
if (e.code === "Space") {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// Support keyboard shortcuts for RTL and LTR text direction
|
||||
// RTL: Ctrl + RShift
|
||||
// LTR: Ctrl + LShift
|
||||
if ((e.ctrlKey || e.metaKey)) {
|
||||
if (e.shiftKey && e.location === KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
|
||||
// Right Shift + Ctrl: RTL
|
||||
document.documentElement.setAttribute('dir', 'rtl');
|
||||
e.preventDefault();
|
||||
} else if (e.shiftKey && e.location === KeyboardEvent.DOM_KEY_LOCATION_LEFT) {
|
||||
// Left Shift + Ctrl: LTR
|
||||
document.documentElement.setAttribute('dir', 'ltr');
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
109
QuickLook.Plugin/QuickLook.Plugin.MediaInfoViewer/Plugin.cs
Normal file
109
QuickLook.Plugin/QuickLook.Plugin.MediaInfoViewer/Plugin.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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.*")]
|
@@ -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>
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -7,6 +7,12 @@
|
||||
<ConfirmDeleteText>Are you sure you want to permanently delete these {0} item(s)?</ConfirmDeleteText>
|
||||
<RecycleBinSizeText>Total size {0}, {1} items</RecycleBinSizeText>
|
||||
</en>
|
||||
<ko>
|
||||
<RecycleBinEmptyText>휴지통이 비어 있습니다</RecycleBinEmptyText>
|
||||
<RecycleBinButton>휴지통 비우기</RecycleBinButton>
|
||||
<ConfirmDeleteText>{0}개 항목을 영구적으로 삭제하시겠습니까?</ConfirmDeleteText>
|
||||
<RecycleBinSizeText>전체 크기 {0}, {1}개 항목</RecycleBinSizeText>
|
||||
</ko>
|
||||
<zh-CN>
|
||||
<RecycleBinEmptyText>回收站是空的</RecycleBinEmptyText>
|
||||
<RecycleBinButton>清空回收站</RecycleBinButton>
|
||||
|
@@ -8,6 +8,13 @@
|
||||
<BTN_OpenFile>Open File</BTN_OpenFile>
|
||||
<BTN_Cancel>Cancel</BTN_Cancel>
|
||||
</en>
|
||||
<ko>
|
||||
<PW_Title>비밀번호 입력</PW_Title>
|
||||
<Pw_Hint>이 파일은 비밀번호로 보호되어 있습니다. 파일을 열려면 비밀번호를 입력하세요.</Pw_Hint>
|
||||
<PW_Error>비밀번호 확인</PW_Error>
|
||||
<BTN_OpenFile>파일 열기</BTN_OpenFile>
|
||||
<BTN_Cancel>취소</BTN_Cancel>
|
||||
</ko>
|
||||
<ja-JP>
|
||||
<PW_Title>パスワード入力</PW_Title>
|
||||
<Pw_Hint>このファイルではパスワードで保護されています。ファイルを開くにはパスワードを入力してください。</Pw_Hint>
|
||||
|
@@ -6,6 +6,11 @@
|
||||
<FILE_VERSION>File Version</FILE_VERSION>
|
||||
<PRODUCT_VERSION>Product Version</PRODUCT_VERSION>
|
||||
</en>
|
||||
<ko>
|
||||
<TOTAL_SIZE>전체 크기</TOTAL_SIZE>
|
||||
<FILE_VERSION>파일 버전</FILE_VERSION>
|
||||
<PRODUCT_VERSION>제품 버전</PRODUCT_VERSION>
|
||||
</ko>
|
||||
<pt-BR>
|
||||
<TOTAL_SIZE>Tamanho total</TOTAL_SIZE>
|
||||
<FILE_VERSION>Versão do arquivo</FILE_VERSION>
|
||||
|
@@ -69,9 +69,9 @@ public class Plugin : IViewer
|
||||
if (path.EndsWith(".rtf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
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.Selection.Load(fs, DataFormats.Rtf);
|
||||
rtfBox.Selection.Load(fileStream, DataFormats.Rtf);
|
||||
rtfBox.IsReadOnly = true;
|
||||
rtfBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
|
||||
rtfBox.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
|
||||
|
@@ -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; } = [];
|
||||
}
|
@@ -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; } = [];
|
||||
}
|
@@ -187,8 +187,8 @@ public class HighlightingThemeManager
|
||||
{
|
||||
Debug.WriteLine(file);
|
||||
var ext = Path.GetFileNameWithoutExtension(file);
|
||||
using Stream s = File.OpenRead(Path.GetFullPath(file));
|
||||
using var reader = new XmlTextReader(s);
|
||||
using var fileStream = new FileStream(Path.GetFullPath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
|
||||
using var reader = new XmlTextReader(fileStream);
|
||||
var xshd = HighlightingLoader.LoadXshd(reader);
|
||||
var highlightingDefinition = HighlightingLoader.Load(xshd, hlm);
|
||||
if (xshd.Extensions.Count > 0)
|
||||
|
@@ -39,9 +39,11 @@
|
||||
<Editor_Copy>コピー</Editor_Copy>
|
||||
<Editor_SelectAll>すべて選択</Editor_SelectAll>
|
||||
</ja-JP>
|
||||
<ko-KR>
|
||||
<Editor_FontFamily>Consolas,Malgun Gothic,Batang</Editor_FontFamily>
|
||||
</ko-KR>
|
||||
<ko>
|
||||
<Editor_FontFamily>Consolas,Malgun Gothic,Gulim</Editor_FontFamily>
|
||||
<Editor_Copy>복사</Editor_Copy>
|
||||
<Editor_SelectAll>모두 선택</Editor_SelectAll>
|
||||
</ko>
|
||||
<nb-NO>
|
||||
<Editor_FontFamily>Consolas</Editor_FontFamily>
|
||||
</nb-NO>
|
||||
|
@@ -15,16 +15,9 @@
|
||||
// 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 QuickLook.Common.Plugin;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using QuickLook.Plugin.ThumbnailViewer.Providors;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace QuickLook.Plugin.ThumbnailViewer;
|
||||
|
||||
@@ -32,131 +25,33 @@ internal static class Handler
|
||||
{
|
||||
public static void Prepare(string path, ContextObject context)
|
||||
{
|
||||
try
|
||||
(Path.GetExtension(path).ToLower() switch
|
||||
{
|
||||
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 };
|
||||
}
|
||||
".cdr" => new CdrProvider(),
|
||||
".fig" => new FigProvidor(),
|
||||
".kra" => new KraProvidor(),
|
||||
".pdn" => new PdnProvider(),
|
||||
".pip" or ".pix" => new PixProvidor(),
|
||||
".sketch" => new SketchProvidor(),
|
||||
".xd" => new XdProvidor(),
|
||||
".xmind" => new XmindProvidor(),
|
||||
_ => (AbstractProvidor)null,
|
||||
})?.Prepare(path, context);
|
||||
}
|
||||
|
||||
public static Stream ViewImage(string path)
|
||||
{
|
||||
try
|
||||
return (Path.GetExtension(path).ToLower() switch
|
||||
{
|
||||
using ZipArchive archive = ZipArchive.Open(path, new());
|
||||
using IReader reader = archive.ExtractAllEntries();
|
||||
|
||||
if (path.EndsWith(".xd", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
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;
|
||||
".cdr" => new CdrProvider(),
|
||||
".fig" => new FigProvidor(),
|
||||
".kra" => new KraProvidor(),
|
||||
".pdn" => new PdnProvider(),
|
||||
".pip" or ".pix" => new PixProvidor(),
|
||||
".sketch" => new SketchProvidor(),
|
||||
".xd" => new XdProvidor(),
|
||||
".xmind" => new XmindProvidor(),
|
||||
_ => (AbstractProvidor)null,
|
||||
})?.ViewImage(path);
|
||||
}
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@ public class Plugin : IViewer
|
||||
".cdr", // CorelDraw
|
||||
".fig", // Figma
|
||||
".kra", // Krita
|
||||
".pdn", // Paint.NET
|
||||
".pip", ".pix", // Pixso
|
||||
".sketch", // Sketch
|
||||
".xd", // AdobeXD
|
||||
|
@@ -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);
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
// 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 System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
|
||||
|
||||
internal class PdnProvider : AbstractProvidor
|
||||
{
|
||||
public override Stream ViewImage(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
using TextReader reader = new StreamReader(path, Encoding.UTF8);
|
||||
string line = reader.ReadLine();
|
||||
|
||||
if (!line.StartsWith("PDN"))
|
||||
return null;
|
||||
|
||||
int indexOfStart = line.IndexOf("<");
|
||||
int indexOfEnd = line.LastIndexOf(">");
|
||||
|
||||
if (indexOfStart < 0 || indexOfEnd < 0)
|
||||
return null;
|
||||
|
||||
string xml = line.Substring(indexOfStart, indexOfEnd - indexOfStart + 1);
|
||||
|
||||
// <pdnImage>
|
||||
// <custom>
|
||||
// <thumb png="..." />
|
||||
// </custom>
|
||||
// </pdnImage>
|
||||
XDocument doc = XDocument.Parse(xml);
|
||||
var pngBase64 = doc.Root
|
||||
?.Element("custom")
|
||||
?.Element("thumb")
|
||||
?.Attribute("png")
|
||||
?.Value;
|
||||
|
||||
if (pngBase64 != null)
|
||||
{
|
||||
byte[] imageBytes = Convert.FromBase64String(pngBase64);
|
||||
MemoryStream ms = new(imageBytes);
|
||||
return ms;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ProcessHelper.WriteLog(e.ToString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -41,7 +41,7 @@
|
||||
<PackageReference Include="MediaInfo.Wrapper" Version="21.9.3">
|
||||
<Aliases>MediaInfoWrapper</Aliases>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MediaInfoDLL" Version="25.4.0">
|
||||
<PackageReference Include="MediaInfoDLL" Version="25.7.0">
|
||||
<Aliases>MediaInfoDLL</Aliases>
|
||||
</PackageReference>
|
||||
<Reference Include="WindowsBase" />
|
||||
@@ -187,17 +187,17 @@
|
||||
<DestinationFolder>$(OutDir)\LAVFilters-x86\</DestinationFolder>
|
||||
<Link>LAVFilters-x86\swscale-lav-8.dll</Link>
|
||||
</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>
|
||||
<DestinationFolder>$(OutDir)MediaInfo-x64\</DestinationFolder>
|
||||
<Link>MediaInfo-x64\MediaInfo.dll</Link>
|
||||
</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>
|
||||
<DestinationFolder>$(OutDir)MediaInfo-x86\</DestinationFolder>
|
||||
<Link>MediaInfo-x86\MediaInfo.dll</Link>
|
||||
</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>
|
||||
<DestinationFolder>$(OutDir)MediaInfo-ARM64\</DestinationFolder>
|
||||
<Link>MediaInfo-ARM64\MediaInfo.dll</Link>
|
||||
|
@@ -8,16 +8,16 @@ using System.Xml.Serialization;
|
||||
namespace RegFileParser;
|
||||
|
||||
/// <summary>
|
||||
/// The main reg file parsing class.
|
||||
/// 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" />
|
||||
/// The main reg file parsing class.
|
||||
/// 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" />
|
||||
/// </summary>
|
||||
public class RegFileObject
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dictionary containing all entries
|
||||
/// Gets the dictionary containing all entries
|
||||
/// </summary>
|
||||
public Dictionary<string, Dictionary<string, RegValueObject>> RegValues => regvalues;
|
||||
|
||||
@@ -26,12 +26,12 @@ public class RegFileObject
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Raw content of the reg file
|
||||
/// Raw content of the reg file
|
||||
/// </summary>
|
||||
private string content;
|
||||
|
||||
/// <summary>
|
||||
/// the dictionary containing parsed registry values
|
||||
/// the dictionary containing parsed registry values
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, Dictionary<string, RegValueObject>> regvalues;
|
||||
|
||||
@@ -61,7 +61,7 @@ public class RegFileObject
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Imports the reg file
|
||||
/// Imports the reg file
|
||||
/// </summary>
|
||||
public void Read(string path)
|
||||
{
|
||||
@@ -70,7 +70,7 @@ public class RegFileObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports the reg file
|
||||
/// Imports the reg file
|
||||
/// </summary>
|
||||
public void Read(byte[] bytes)
|
||||
{
|
||||
@@ -109,7 +109,7 @@ public class RegFileObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the reg file for reg keys and reg values
|
||||
/// Parses the reg file for reg keys and reg values
|
||||
/// </summary>
|
||||
/// <returns>A Dictionary with reg keys as Dictionary keys and a Dictionary of (valuename, valuedata)</returns>
|
||||
private Dictionary<string, Dictionary<string, string>> ParseFile()
|
||||
@@ -141,7 +141,7 @@ public class RegFileObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a flat Dictionary using given searcn pattern
|
||||
/// Creates a flat Dictionary using given searcn pattern
|
||||
/// </summary>
|
||||
/// <param name="content">The content string to be parsed</param>
|
||||
/// <returns>A Dictionary with retrieved keys and remaining content</returns>
|
||||
@@ -202,7 +202,7 @@ public class RegFileObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a flat Dictionary using given searcn pattern
|
||||
/// Creates a flat Dictionary using given searcn pattern
|
||||
/// </summary>
|
||||
/// <param name="content">The content string to be parsed</param>
|
||||
/// <returns>A Dictionary with retrieved keys and remaining content</returns>
|
||||
@@ -254,7 +254,7 @@ public class RegFileObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the leading and ending characters from the given string
|
||||
/// Removes the leading and ending characters from the given string
|
||||
/// </summary>
|
||||
/// <param name="sLine">given string</param>
|
||||
/// <returns>edited string</returns>
|
||||
@@ -268,7 +268,7 @@ public class RegFileObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the leading and ending parenthesis from the given string
|
||||
/// Removes the leading and ending parenthesis from the given string
|
||||
/// </summary>
|
||||
/// <param name="sLine">given string</param>
|
||||
/// <returns>edited string</returns>
|
||||
@@ -294,7 +294,7 @@ public class RegValueObject
|
||||
private string value;
|
||||
|
||||
/// <summary>
|
||||
/// Parameterless constructor
|
||||
/// Parameterless constructor
|
||||
/// </summary>
|
||||
public RegValueObject()
|
||||
{
|
||||
@@ -307,7 +307,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overloaded constructor
|
||||
/// Overloaded constructor
|
||||
/// </summary>
|
||||
/// <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)
|
||||
@@ -326,7 +326,7 @@ public class RegValueObject
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Overriden Method
|
||||
/// Overriden Method
|
||||
/// </summary>
|
||||
/// <returns>An entry for the [Registry] section of the *.sig signature file</returns>
|
||||
public override string ToString()
|
||||
@@ -339,7 +339,7 @@ public class RegValueObject
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Regsitry value name
|
||||
/// Regsitry value name
|
||||
/// </summary>
|
||||
[XmlElement("entry", typeof(string))]
|
||||
public string Entry
|
||||
@@ -349,7 +349,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registry value parent key
|
||||
/// Registry value parent key
|
||||
/// </summary>
|
||||
[XmlElement("key", typeof(string))]
|
||||
public string ParentKey
|
||||
@@ -364,7 +364,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registry value root hive
|
||||
/// Registry value root hive
|
||||
/// </summary>
|
||||
[XmlElement("root", typeof(string))]
|
||||
public string Root
|
||||
@@ -374,7 +374,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registry value type
|
||||
/// Registry value type
|
||||
/// </summary>
|
||||
[XmlElement("type", typeof(string))]
|
||||
public string Type
|
||||
@@ -384,7 +384,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registry value data
|
||||
/// Registry value data
|
||||
/// </summary>
|
||||
[XmlElement("value", typeof(string))]
|
||||
public string Value
|
||||
@@ -447,7 +447,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the reg value type, parsing the prefix of the value
|
||||
/// Retrieves the reg value type, parsing the prefix of the value
|
||||
/// </summary>
|
||||
/// <param name="sTextLine">Registry value row string</param>
|
||||
/// <returns>Value</returns>
|
||||
@@ -546,7 +546,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the leading and ending characters from the given string
|
||||
/// Removes the leading and ending characters from the given string
|
||||
/// </summary>
|
||||
/// <param name="sline">given string</param>
|
||||
/// <returns>edited string</returns>
|
||||
@@ -560,7 +560,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the leading and ending parenthesis from the given string
|
||||
/// Removes the leading and ending parenthesis from the given string
|
||||
/// </summary>
|
||||
/// <param name="sline">given string</param>
|
||||
/// <returns>edited string</returns>
|
||||
@@ -573,7 +573,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the ending backslashes from the given string
|
||||
/// Removes the ending backslashes from the given string
|
||||
/// </summary>
|
||||
/// <param name="sline">given string</param>
|
||||
/// <returns>edited string</returns>
|
||||
@@ -585,7 +585,7 @@ public class RegValueObject
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the byte arrays (saved as array of string) into string
|
||||
/// Converts the byte arrays (saved as array of string) into string
|
||||
/// </summary>
|
||||
/// <param name="stringArray">Array of string</param>
|
||||
/// <returns>String value</returns>
|
||||
|
@@ -56,6 +56,7 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "QuickLook.Installer", "Quic
|
||||
{63C00175-0FF3-42C7-8621-2F1959F26064} = {63C00175-0FF3-42C7-8621-2F1959F26064}
|
||||
{B4F7C88D-C79D-49E7-A1FB-FB69CF72585F} = {B4F7C88D-C79D-49E7-A1FB-FB69CF72585F}
|
||||
{311E6E78-3A5B-4E51-802A-5755BD5F9F97} = {311E6E78-3A5B-4E51-802A-5755BD5F9F97}
|
||||
{B0054A16-472E-44AC-BA40-349303E524FF} = {B0054A16-472E-44AC-BA40-349303E524FF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
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
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.HelixViewer", "QuickLook.Plugin\QuickLook.Plugin.HelixViewer\QuickLook.Plugin.HelixViewer.csproj", "{311E6E78-3A5B-4E51-802A-5755BD5F9F97}"
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|x64.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -303,6 +314,7 @@ Global
|
||||
{63C00175-0FF3-42C7-8621-2F1959F26064} = {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}
|
||||
{B0054A16-472E-44AC-BA40-349303E524FF} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D3761C32-8C5F-498A-892B-3B0882994B62}
|
||||
|
@@ -117,22 +117,8 @@ public partial class App : Application
|
||||
// Exception handling events which are not caught in the Task thread
|
||||
TaskScheduler.UnobservedTaskException += (_, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
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();
|
||||
}
|
||||
ProcessHelper.WriteLog(e.Exception.ToString());
|
||||
e.SetObserved();
|
||||
};
|
||||
|
||||
// Exception handling events which are not caught in UI thread
|
||||
@@ -210,12 +196,9 @@ public partial class App : Application
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize MessageBox patching
|
||||
bool modernMessageBox = SettingHelper.Get("ModernMessageBox", true, "QuickLook");
|
||||
if (modernMessageBox) MessageBoxPatcher.Initialize();
|
||||
// Initialize TrayIcon patching
|
||||
bool modernTrayIcon = SettingHelper.Get("ModernTrayIcon", true, "QuickLook");
|
||||
if (modernTrayIcon) TrayIconPatcher.Initialize();
|
||||
// We should improve the performance of the CLI application
|
||||
// Therefore, the time-consuming initialization code can't be placed before `OnStartup`
|
||||
base.OnStartup(e);
|
||||
|
||||
// Set initial theme based on system settings
|
||||
ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light);
|
||||
@@ -223,14 +206,15 @@ public partial class App : Application
|
||||
ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light);
|
||||
UxTheme.ApplyPreferredAppMode();
|
||||
|
||||
base.OnStartup(e);
|
||||
// Initialize MessageBox patching
|
||||
MessageBoxPatcher.Initialize();
|
||||
}
|
||||
|
||||
private void Application_Startup(object sender, StartupEventArgs e)
|
||||
{
|
||||
if (!EnsureOSVersion()
|
||||
|| !EnsureFirstInstance(e.Args)
|
||||
|| !EnsureFolderWritable(SettingHelper.LocalDataPath))
|
||||
|| !EnsureFirstInstance(e.Args)
|
||||
|| !EnsureFolderWritable(SettingHelper.LocalDataPath))
|
||||
{
|
||||
_cleanExit = false;
|
||||
Shutdown();
|
||||
@@ -240,7 +224,7 @@ public partial class App : Application
|
||||
CheckUpdate();
|
||||
RunListener(e);
|
||||
|
||||
// first instance: run and preview this file
|
||||
// First instance: run and preview this file
|
||||
if (e.Args.Any() && (Directory.Exists(e.Args.First()) || File.Exists(e.Args.First())))
|
||||
PipeServerManager.SendMessage(PipeMessages.Toggle, e.Args.First());
|
||||
}
|
||||
@@ -318,15 +302,17 @@ public partial class App : Application
|
||||
if (isFirst)
|
||||
return true;
|
||||
|
||||
// second instance: preview this file
|
||||
// Second instance: preview this file
|
||||
if (args.Any() && (Directory.Exists(args.First()) || File.Exists(args.First())))
|
||||
{
|
||||
PipeServerManager.SendMessage(PipeMessages.Toggle, args.First(), [.. args.Skip(1)]);
|
||||
}
|
||||
// second instance: duplicate
|
||||
// Second instance: duplicate
|
||||
else
|
||||
{
|
||||
MessageBox.Show(TranslationHelper.Get("APP_SECOND_TEXT"), TranslationHelper.Get("APP_SECOND"),
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -81,8 +81,7 @@ public class BackgroundVisualHost : FrameworkElement
|
||||
private readonly CreateContentFunction _createContent;
|
||||
private readonly Action _invalidateMeasure;
|
||||
|
||||
private readonly AutoResetEvent _sync =
|
||||
new AutoResetEvent(false);
|
||||
private readonly AutoResetEvent _sync = new(false);
|
||||
|
||||
public ThreadedVisualHelper(
|
||||
CreateContentFunction createContent,
|
||||
@@ -125,17 +124,11 @@ public class BackgroundVisualHost : FrameworkElement
|
||||
}
|
||||
}
|
||||
|
||||
#region Private Fields
|
||||
|
||||
public ThreadedVisualHelper ThreadedHelper;
|
||||
private HostVisual _hostVisual;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region IsContentShowingProperty
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the IsContentShowing dependency property.
|
||||
/// Identifies the IsContentShowing dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsContentShowingProperty = DependencyProperty.Register(
|
||||
"IsContentShowing",
|
||||
@@ -144,7 +137,7 @@ public class BackgroundVisualHost : FrameworkElement
|
||||
new FrameworkPropertyMetadata(false, OnIsContentShowingChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the content is being displayed.
|
||||
/// Gets or sets if the content is being displayed.
|
||||
/// </summary>
|
||||
public bool IsContentShowing
|
||||
{
|
||||
@@ -163,12 +156,8 @@ public class BackgroundVisualHost : FrameworkElement
|
||||
bvh.HideContentHelper();
|
||||
}
|
||||
|
||||
#endregion IsContentShowingProperty
|
||||
|
||||
#region CreateContent Property
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the CreateContent dependency property.
|
||||
/// Identifies the CreateContent dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CreateContentProperty = DependencyProperty.Register(
|
||||
"CreateContent",
|
||||
@@ -177,7 +166,7 @@ public class BackgroundVisualHost : FrameworkElement
|
||||
new FrameworkPropertyMetadata(OnCreateContentChanged));
|
||||
|
||||
/// <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>
|
||||
public CreateContentFunction CreateContent
|
||||
{
|
||||
@@ -196,6 +185,4 @@ public class BackgroundVisualHost : FrameworkElement
|
||||
bvh.CreateContentHelper();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion CreateContent Property
|
||||
}
|
||||
|
@@ -135,7 +135,7 @@ public class BusyDecorator : Decorator, IDisposable
|
||||
#region IsBusyIndicatorShowing Property
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the IsBusyIndicatorShowing dependency property.
|
||||
/// Identifies the IsBusyIndicatorShowing dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsBusyIndicatorShowingProperty = DependencyProperty.Register(
|
||||
"IsBusyIndicatorShowing",
|
||||
@@ -146,7 +146,7 @@ public class BusyDecorator : Decorator, IDisposable
|
||||
OnIsBusyIndicatorShowingChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the BusyIndicator is being shown.
|
||||
/// Gets or sets if the BusyIndicator is being shown.
|
||||
/// </summary>
|
||||
public bool IsBusyIndicatorShowing
|
||||
{
|
||||
@@ -178,7 +178,7 @@ public class BusyDecorator : Decorator, IDisposable
|
||||
#region BusyStyle
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="BusyStyle" /> property.
|
||||
/// Identifies the <see cref="BusyStyle" /> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty BusyStyleProperty =
|
||||
DependencyProperty.Register(
|
||||
@@ -188,7 +188,7 @@ public class BusyDecorator : Decorator, IDisposable
|
||||
new FrameworkPropertyMetadata(OnBusyStyleChanged));
|
||||
|
||||
/// <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>
|
||||
public Style BusyStyle
|
||||
{
|
||||
@@ -208,7 +208,7 @@ public class BusyDecorator : Decorator, IDisposable
|
||||
#region BusyHorizontalAlignment
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="BusyHorizontalAlignment" /> property.
|
||||
/// Identifies the <see cref="BusyHorizontalAlignment" /> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty BusyHorizontalAlignmentProperty = DependencyProperty.Register(
|
||||
"BusyHorizontalAlignment",
|
||||
@@ -217,7 +217,7 @@ public class BusyDecorator : Decorator, IDisposable
|
||||
new FrameworkPropertyMetadata(HorizontalAlignment.Center));
|
||||
|
||||
/// <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>
|
||||
public HorizontalAlignment BusyHorizontalAlignment
|
||||
{
|
||||
@@ -230,7 +230,7 @@ public class BusyDecorator : Decorator, IDisposable
|
||||
#region BusyVerticalAlignment
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="BusyVerticalAlignment" /> property.
|
||||
/// Identifies the <see cref="BusyVerticalAlignment" /> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty BusyVerticalAlignmentProperty = DependencyProperty.Register(
|
||||
"BusyVerticalAlignment",
|
||||
@@ -239,7 +239,7 @@ public class BusyDecorator : Decorator, IDisposable
|
||||
new FrameworkPropertyMetadata(VerticalAlignment.Center));
|
||||
|
||||
/// <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>
|
||||
public VerticalAlignment BusyVerticalAlignment
|
||||
{
|
||||
|
@@ -24,17 +24,17 @@ using System.Windows.Media.Animation;
|
||||
namespace QuickLook.Controls.BusyDecorator;
|
||||
|
||||
/// <summary>
|
||||
/// Control extensions
|
||||
/// Control extensions
|
||||
/// </summary>
|
||||
internal static class ControlExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// The key used for storing the spinner Storyboard.
|
||||
/// The key used for storing the spinner Storyboard.
|
||||
/// </summary>
|
||||
private static readonly string SpinnerStoryBoardName = $"{typeof(FrameworkElement).Name}Spinner";
|
||||
|
||||
/// <summary>
|
||||
/// Start the spinning animation
|
||||
/// Start the spinning animation
|
||||
/// </summary>
|
||||
/// <typeparam name="T">FrameworkElement and ISpinable</typeparam>
|
||||
/// <param name="control">Control to apply the rotation </param>
|
||||
@@ -78,7 +78,7 @@ internal static class ControlExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the spinning animation
|
||||
/// Stop the spinning animation
|
||||
/// </summary>
|
||||
/// <typeparam name="T">FrameworkElement and ISpinable</typeparam>
|
||||
/// <param name="control">Control to stop the rotation.</param>
|
||||
|
@@ -18,17 +18,17 @@
|
||||
namespace QuickLook.Controls.BusyDecorator;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a spinable control
|
||||
/// Represents a spinable control
|
||||
/// </summary>
|
||||
internal interface ISpinable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the current spin (angle) animation of the icon.
|
||||
/// Gets or sets the current spin (angle) animation of the icon.
|
||||
/// </summary>
|
||||
public bool Spin { get; set; }
|
||||
|
||||
/// <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>
|
||||
public double SpinDuration { get; set; }
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ internal class SpinIcon : TextBlock, ISpinable
|
||||
#region public bool Spin
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the Spin dependency property.
|
||||
/// Identifies the Spin dependency property.
|
||||
/// </summary>
|
||||
public static DependencyProperty SpinProperty =
|
||||
DependencyProperty.Register("Spin", typeof(bool), typeof(SpinIcon),
|
||||
@@ -44,7 +44,7 @@ internal class SpinIcon : TextBlock, ISpinable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current spin (angle) animation of the icon.
|
||||
/// Gets or sets the current spin (angle) animation of the icon.
|
||||
/// </summary>
|
||||
public bool Spin
|
||||
{
|
||||
@@ -58,7 +58,7 @@ internal class SpinIcon : TextBlock, ISpinable
|
||||
#region public double SpinDuration
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the SpinDuration dependency property.
|
||||
/// Identifies the SpinDuration dependency property.
|
||||
/// </summary>
|
||||
public static DependencyProperty SpinDurationProperty =
|
||||
DependencyProperty.Register("SpinDuration", typeof(double), typeof(SpinIcon),
|
||||
@@ -76,7 +76,7 @@ internal class SpinIcon : TextBlock, ISpinable
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public double SpinDuration
|
||||
{
|
||||
|
@@ -43,7 +43,7 @@ public partial class GlassLayer : UserControl
|
||||
#region public Visual BlurredElement
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the BlurredElement dependency property.
|
||||
/// Identifies the BlurredElement dependency property.
|
||||
/// </summary>
|
||||
public static DependencyProperty BlurredElementProperty =
|
||||
DependencyProperty.Register("BlurredElement", typeof(Visual), typeof(GlassLayer), null);
|
||||
@@ -62,7 +62,7 @@ public partial class GlassLayer : UserControl
|
||||
#region public SolidColorBrush OverlayColor
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the OverlayColor dependency property.
|
||||
/// Identifies the OverlayColor dependency property.
|
||||
/// </summary>
|
||||
public static DependencyProperty OverlayColorProperty =
|
||||
DependencyProperty.Register("OverlayColor", typeof(SolidColorBrush), typeof(GlassLayer),
|
||||
@@ -82,7 +82,7 @@ public partial class GlassLayer : UserControl
|
||||
#region public Visibility ColorOverlayVisibility
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the ColorOverlayVisibilityProperty dependency property.
|
||||
/// Identifies the ColorOverlayVisibilityProperty dependency property.
|
||||
/// </summary>
|
||||
public static DependencyProperty ColorOverlayVisibilityProperty =
|
||||
DependencyProperty.Register("ColorOverlayVisibility", typeof(Visibility), typeof(GlassLayer),
|
||||
@@ -100,7 +100,7 @@ public partial class GlassLayer : UserControl
|
||||
#region public Visibility NoiseVisibility
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the NoiseVisibility dependency property.
|
||||
/// Identifies the NoiseVisibility dependency property.
|
||||
/// </summary>
|
||||
public static DependencyProperty NoiseVisibilityProperty =
|
||||
DependencyProperty.Register("NoiseVisibility", typeof(Visibility), typeof(GlassLayer),
|
||||
@@ -120,7 +120,7 @@ public partial class GlassLayer : UserControl
|
||||
#region public Visibility GlassVisibility
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the GlassVisibility dependency property.
|
||||
/// Identifies the GlassVisibility dependency property.
|
||||
/// </summary>
|
||||
public static DependencyProperty GlassVisibilityProperty =
|
||||
DependencyProperty.Register("GlassVisibility", typeof(Visibility), typeof(GlassLayer),
|
||||
|
@@ -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
1
QuickLook/GlobalUsing.cs
Normal file
@@ -0,0 +1 @@
|
||||
global using MessageBox = Wpf.Ui.Violeta.Controls.MessageBox;
|
@@ -1,298 +0,0 @@
|
||||
// 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 HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace QuickLook.Helpers;
|
||||
|
||||
public static class TrayIconPatcher
|
||||
{
|
||||
private static readonly Harmony Harmony = new("com.quicklook.trayicon.patch");
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
var targetMethod = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (targetMethod != null)
|
||||
{
|
||||
_ = Harmony.Patch(targetMethod, transpiler: new HarmonyMethod(typeof(TrayIconPatcher).GetMethod(nameof(ShowContextMenuTranspiler))));
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowContextMenu(this NotifyIcon icon)
|
||||
{
|
||||
var targetMethod = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
targetMethod?.Invoke(icon, []);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We need to change the NotifyIcon.ShowContextMenu to use TPM_RIGHTBUTTON instead of TPM_VERTICAL.
|
||||
/// private void ShowContextMenu()
|
||||
/// {
|
||||
/// if (contextMenu != null || contextMenuStrip != null)
|
||||
/// {
|
||||
/// NativeMethods.POINT pOINT = new NativeMethods.POINT();
|
||||
/// UnsafeNativeMethods.GetCursorPos(pOINT);
|
||||
/// UnsafeNativeMethods.SetForegroundWindow(new HandleRef(window, window.Handle));
|
||||
/// if (contextMenu != null)
|
||||
/// {
|
||||
/// contextMenu.OnPopup(EventArgs.Empty);
|
||||
/// SafeNativeMethods.TrackPopupMenuEx(new HandleRef(contextMenu, contextMenu.Handle), 72, pOINT.x, pOINT.y, new HandleRef(window, window.Handle), null);
|
||||
/// UnsafeNativeMethods.PostMessage(new HandleRef(window, window.Handle), 0, IntPtr.Zero, IntPtr.Zero);
|
||||
/// }
|
||||
/// else if (contextMenuStrip != null)
|
||||
/// {
|
||||
/// contextMenuStrip.ShowInTaskbar(pOINT.x, pOINT.y);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ---
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
|
||||
/// Opcode: brtrue.s, Operand: System.Reflection.Emit.Label
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenuStrip contextMenuStrip
|
||||
/// Opcode: brfalse, Operand: System.Reflection.Emit.Label
|
||||
/// Opcode: newobj, Operand: Void.ctor()
|
||||
/// Opcode: stloc.0, Operand:
|
||||
/// Opcode: ldloc.0, Operand:
|
||||
/// Opcode: call, Operand: Boolean GetCursorPos(POINT)
|
||||
/// Opcode: pop, Operand:
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
|
||||
/// Opcode: callvirt, Operand: IntPtr get_Handle()
|
||||
/// Opcode: newobj, Operand: Void.ctor(System.Object, IntPtr)
|
||||
/// Opcode: call, Operand: Boolean SetForegroundWindow(System.Runtime.InteropServices.HandleRef)
|
||||
/// Opcode: pop, Operand:
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
|
||||
/// Opcode: brfalse.s, Operand: System.Reflection.Emit.Label
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
|
||||
/// Opcode: ldsfld, Operand: System.EventArgs Empty
|
||||
/// Opcode: callvirt, Operand: Void OnPopup(System.EventArgs)
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenu contextMenu
|
||||
/// Opcode: callvirt, Operand: IntPtr get_Handle()
|
||||
/// Opcode: newobj, Operand: Void.ctor(System.Object, IntPtr)
|
||||
/// Opcode: ldc.i4.s, Operand: 72
|
||||
/// Opcode: ldloc.0, Operand:
|
||||
/// Opcode: ldfld, Operand: Int32 x
|
||||
/// Opcode: ldloc.0, Operand:
|
||||
/// Opcode: ldfld, Operand: Int32 y
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
|
||||
/// Opcode: callvirt, Operand: IntPtr get_Handle()
|
||||
/// Opcode: newobj, Operand: Void.ctor(System.Object, IntPtr)
|
||||
/// Opcode: ldnull, Operand:
|
||||
/// Opcode: call, Operand: Boolean TrackPopupMenuEx(System.Runtime.InteropServices.HandleRef, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, TPMPARAMS)
|
||||
/// Opcode: pop, Operand:
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: NotifyIconNativeWindow window
|
||||
/// Opcode: callvirt, Operand: IntPtr get_Handle()
|
||||
/// Opcode: newobj, Operand: Void.ctor(System.Object, IntPtr)
|
||||
/// Opcode: ldc.i4.0, Operand:
|
||||
/// Opcode: ldsfld, Operand: IntPtr Zero
|
||||
/// Opcode: ldsfld, Operand: IntPtr Zero
|
||||
/// Opcode: call, Operand: Boolean PostMessage(System.Runtime.InteropServices.HandleRef, Int32, IntPtr, IntPtr)
|
||||
/// Opcode: pop, Operand:
|
||||
/// Opcode: ret, Operand:
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenuStrip contextMenuStrip
|
||||
/// Opcode: brfalse.s, Operand: System.Reflection.Emit.Label
|
||||
/// Opcode: ldarg.0, Operand:
|
||||
/// Opcode: ldfld, Operand: System.Windows.Forms.ContextMenuStrip contextMenuStrip
|
||||
/// Opcode: ldloc.0, Operand:
|
||||
/// Opcode: ldfld, Operand: Int32 x
|
||||
/// Opcode: ldloc.0, Operand:
|
||||
/// Opcode: ldfld, Operand: Int32 y
|
||||
/// Opcode: callvirt, Operand: Void ShowInTaskbar(Int32, Int32)
|
||||
/// Opcode: ret, Operand:
|
||||
/// </summary>
|
||||
/// <param name="instructions"></param>
|
||||
/// <returns></returns>
|
||||
[HarmonyTranspiler]
|
||||
public static IEnumerable<CodeInstruction> ShowContextMenuTranspiler(IEnumerable<CodeInstruction> instructions)
|
||||
{
|
||||
try
|
||||
{
|
||||
var codes = instructions.ToArray();
|
||||
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
// Test code to print the IL codes
|
||||
foreach (var code in codes)
|
||||
{
|
||||
Debug.WriteLine($"Opcode: {code.opcode}, Operand: {code.operand}");
|
||||
}
|
||||
}
|
||||
|
||||
// How to change source code for proxy:
|
||||
// from SafeNativeMethods.TrackPopupMenuEx(new HandleRef(contextMenu, contextMenu.Handle), 72, pOINT.x, pOINT.y, new HandleRef(window, window.Handle), null);
|
||||
// to SafeNativeMethods.TrackPopupMenuEx(new HandleRef(contextMenu, contextMenu.Handle), 66, pOINT.x, pOINT.y, new HandleRef(window, window.Handle), null);
|
||||
// [TrackPopupMenuEx] uFlags: A set of flags that determine how the menu behaves.
|
||||
// The number 72 in binary is 0100 1000. Breaking it down:
|
||||
// * TPM_VERTICAL(0x0040)
|
||||
// * TPM_RIGHTALIGN(0x0008)
|
||||
// The number 64 in binary is 0100 0000. Breaking it down:
|
||||
// * TPM_VERTICAL(0x0040)
|
||||
// * TPM_LEFTALIGN(0x0000)
|
||||
const sbyte sourceFlag = (sbyte)(TrackPopupMenuFlags.TPM_VERTICAL | TrackPopupMenuFlags.TPM_RIGHTALIGN);
|
||||
const sbyte targetFlag = (sbyte)(TrackPopupMenuFlags.TPM_VERTICAL | TrackPopupMenuFlags.TPM_LEFTALIGN);
|
||||
|
||||
for (int i = 0; i < codes.Length; i++)
|
||||
{
|
||||
if (codes[i].opcode == OpCodes.Ldc_I4_S && (sbyte)codes[i].operand == sourceFlag)
|
||||
{
|
||||
codes[i].operand = targetFlag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return codes;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No fallback needed in this case
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-trackpopupmenuex
|
||||
/// </summary>
|
||||
[Flags]
|
||||
private enum TrackPopupMenuFlags : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// The user can select menu items with only the left mouse button.
|
||||
/// </summary>
|
||||
TPM_LEFTBUTTON = 0x0000,
|
||||
|
||||
/// <summary>
|
||||
/// The user can select menu items with both the left and right mouse buttons.
|
||||
/// </summary>
|
||||
TPM_RIGHTBUTTON = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// Positions the shortcut menu so that its left side is aligned with the coordinate specified by the x parameter.
|
||||
/// </summary>
|
||||
TPM_LEFTALIGN = 0x0000,
|
||||
|
||||
/// <summary>
|
||||
/// Centers the shortcut menu horizontally relative to the coordinate specified by the x parameter.
|
||||
/// </summary>
|
||||
TPM_CENTERALIGN = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// Positions the shortcut menu so that its right side is aligned with the coordinate specified by the x parameter.
|
||||
/// </summary>
|
||||
TPM_RIGHTALIGN = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// Positions the shortcut menu so that its top side is aligned with the coordinate specified by the y parameter.
|
||||
/// </summary>
|
||||
TPM_TOPALIGN = 0x0000,
|
||||
|
||||
/// <summary>
|
||||
/// Centers the shortcut menu vertically relative to the coordinate specified by the y parameter.
|
||||
/// </summary>
|
||||
TPM_VCENTERALIGN = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// Positions the shortcut menu so that its bottom side is aligned with the coordinate specified by the y parameter.
|
||||
/// </summary>
|
||||
TPM_BOTTOMALIGN = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// TPM_HORIZONTAL
|
||||
/// </summary>
|
||||
TPM_HORIZONTAL = 0x0000,
|
||||
|
||||
/// <summary>
|
||||
/// TPM_VERTICAL
|
||||
/// </summary>
|
||||
TPM_VERTICAL = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// The function does not send notification messages when the user clicks a menu item.
|
||||
/// </summary>
|
||||
TPM_NONOTIFY = 0x0080,
|
||||
|
||||
/// <summary>
|
||||
/// The function returns the menu item identifier of the user's selection in the return value.
|
||||
/// </summary>
|
||||
TPM_RETURNCMD = 0x0100,
|
||||
|
||||
/// <summary>
|
||||
/// TPM_RECURSE
|
||||
/// </summary>
|
||||
TPM_RECURSE = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// Animates the menu from left to right.
|
||||
/// </summary>
|
||||
TPM_HORPOSANIMATION = 0x0400,
|
||||
|
||||
/// <summary>
|
||||
/// Animates the menu from right to left.
|
||||
/// </summary>
|
||||
TPM_HORNEGANIMATION = 0x0800,
|
||||
|
||||
/// <summary>
|
||||
/// Animates the menu from top to bottom.
|
||||
/// </summary>
|
||||
TPM_VERPOSANIMATION = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// Animates the menu from bottom to top.
|
||||
/// </summary>
|
||||
TPM_VERNEGANIMATION = 0x2000,
|
||||
|
||||
/// <summary>
|
||||
/// Displays menu without animation.
|
||||
/// </summary>
|
||||
TPM_NOANIMATION = 0x4000,
|
||||
|
||||
/// <summary>
|
||||
/// TPM_LAYOUTRTL
|
||||
/// </summary>
|
||||
TPM_LAYOUTRTL = 0x8000,
|
||||
|
||||
/// <summary>
|
||||
/// TPM_WORKAREA
|
||||
/// </summary>
|
||||
TPM_WORKAREA = 0x10000,
|
||||
}
|
||||
}
|
@@ -33,8 +33,8 @@ internal enum SLGP_FLAGS
|
||||
SLGP_UNCPRIORITY = 0x2,
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the raw path name. A raw path is something that might not exist and may include environment
|
||||
/// variables that need to be expanded
|
||||
/// Retrieves the raw path name. A raw path is something that might not exist and may include environment
|
||||
/// variables that need to be expanded
|
||||
/// </summary>
|
||||
SLGP_RAWPATH = 0x4
|
||||
}
|
||||
@@ -62,13 +62,13 @@ internal struct WIN32_FIND_DATAW
|
||||
internal enum SLR_FLAGS
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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
|
||||
/// duration, in milliseconds.
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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
|
||||
/// duration, in milliseconds.
|
||||
/// </summary>
|
||||
SLR_NO_UI = 0x1,
|
||||
|
||||
@@ -76,9 +76,9 @@ internal enum SLR_FLAGS
|
||||
SLR_ANY_MATCH = 0x2,
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// whether or not the link object has changed.
|
||||
/// 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
|
||||
/// whether or not the link object has changed.
|
||||
/// </summary>
|
||||
SLR_UPDATE = 0x4,
|
||||
|
||||
@@ -92,10 +92,10 @@ internal enum SLR_FLAGS
|
||||
SLR_NOTRACK = 0x20,
|
||||
|
||||
/// <summary>
|
||||
/// Disable distributed link tracking. By default, distributed link tracking tracks
|
||||
/// 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
|
||||
/// has changed. Setting SLR_NOLINKINFO disables both types of tracking.
|
||||
/// Disable distributed link tracking. By default, distributed link tracking tracks
|
||||
/// 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
|
||||
/// has changed. Setting SLR_NOLINKINFO disables both types of tracking.
|
||||
/// </summary>
|
||||
SLR_NOLINKINFO = 0x40,
|
||||
|
||||
|
@@ -102,7 +102,7 @@
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="WPF-UI.Violeta" Version="4.0.3">
|
||||
<PackageReference Include="WPF-UI.Violeta" Version="4.0.3.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Lib.Harmony" Version="2.3.6">
|
||||
|
@@ -109,15 +109,20 @@
|
||||
<InfoPanel_Files>{0} berkas</InfoPanel_Files>
|
||||
<InfoPanel_FolderAndFile>({0} dan {1})</InfoPanel_FolderAndFile>
|
||||
</id-ID>
|
||||
<ko-KR>
|
||||
<ko>
|
||||
<UI_FontFamily>Segoe UI</UI_FontFamily>
|
||||
<APP_START>QuickLook이 백그라운드에서 실행 중입니다.</APP_START>
|
||||
<APP_SECOND>QuickLook이 이미 실행 중입니다</APP_SECOND>
|
||||
<APP_SECOND_TEXT>QuickLook은 지원되는 파일 형식에 한해 파일 선택 후 스페이스바를 사용하여 미리보기를 할 수 있습니다.</APP_SECOND_TEXT>
|
||||
<APP_SECOND_TEXT>QuickLook은 강조 표시된 상태에서 스페이스바를 눌러 특정 유형의 파일을 빠르게 미리 볼 수 있게 해줍니다.</APP_SECOND_TEXT>
|
||||
<APP_PATH_NOT_WRITABLE>데이터 경로 "{0}"에 쓸 수 없습니다. 충분한 권한이 있는지 확인하세요.</APP_PATH_NOT_WRITABLE>
|
||||
<MW_StayTop>맨 위에 유지</MW_StayTop>
|
||||
<MW_BrowseFolder>{0} 열기</MW_BrowseFolder>
|
||||
<MW_PreventClosing>닫힘 방지</MW_PreventClosing>
|
||||
<MW_BrowseFolder>브라우저 {0}</MW_BrowseFolder>
|
||||
<MW_Open>{0} 열기</MW_Open>
|
||||
<MW_OpenWith>다음으로 열기 : {0}</MW_OpenWith>
|
||||
<MW_OpenWith>{0}(으)로 열기</MW_OpenWith>
|
||||
<MW_Run>{0} 실행</MW_Run>
|
||||
<MW_Share>공유</MW_Share>
|
||||
<Icon_RunAtStartup>시작 시 실행(&S)</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>업데이트 확인(&U)</Icon_CheckUpdate>
|
||||
@@ -125,17 +130,18 @@
|
||||
<Icon_OpenDataFolder>데이터 폴더 열기</Icon_OpenDataFolder>
|
||||
<Icon_Restart>다시 시작(&R)</Icon_Restart>
|
||||
<Icon_Quit>종료(&Q)</Icon_Quit>
|
||||
<Update_NoUpdate>최신 버전을 사용 중입니다.</Update_NoUpdate>
|
||||
<Update_Found>QuickLook {0} 버전이 출시되었습니다. 다운로드 페이지로 가려면 이곳을 클릭하십시오.</Update_Found>
|
||||
<Update_Error>업데이트 확인 중 오류가 발생하였습니다: {0}</Update_Error>
|
||||
<InfoPanel_LastModified>수정한 날짜: {0}</InfoPanel_LastModified>
|
||||
<InfoPanel_DriveSize>용량: {0}, 사용 가능한 공간: {1}</InfoPanel_DriveSize>
|
||||
<InfoPanel_Folder>폴더 {0}개</InfoPanel_Folder>
|
||||
<InfoPanel_Folders>폴더 {0}개</InfoPanel_Folders>
|
||||
<InfoPanel_File>파일 {0}개</InfoPanel_File>
|
||||
<InfoPanel_Files>파일 {0}개</InfoPanel_Files>
|
||||
<InfoPanel_FolderAndFile>({0}, {1})</InfoPanel_FolderAndFile>
|
||||
</ko-KR>
|
||||
<Update_NoUpdate>현재 최신 버전을 사용하고 있습니다.</Update_NoUpdate>
|
||||
<Update_Found>QuickLook {0}이 출시되었습니다. 여기를 클릭하여 다운로드 페이지를 여세요.</Update_Found>
|
||||
<Update_Error>업데이트를 확인하는 중 오류가 발생했습니다: {0}</Update_Error>
|
||||
<InfoPanel_LastModified>{0}에 마지막으로 수정됨</InfoPanel_LastModified>
|
||||
<InfoPanel_DriveSize>사용 가능한 용량 {0}, {1}</InfoPanel_DriveSize>
|
||||
<InfoPanel_Folder>{0}개 폴더</InfoPanel_Folder>
|
||||
<InfoPanel_Folders>{0}개 폴더</InfoPanel_Folders>
|
||||
<InfoPanel_File>{0}개 파일</InfoPanel_File>
|
||||
<InfoPanel_Files>{0}개 파일</InfoPanel_Files>
|
||||
<InfoPanel_FolderAndFile>({0} 및 {1})</InfoPanel_FolderAndFile>
|
||||
<InfoPanel_CantPreventClosing>"닫힘 방지" 취소는 지원되지 않습니다</InfoPanel_CantPreventClosing>
|
||||
</ko>
|
||||
<ca>
|
||||
<UI_FontFamily>Segoe UI</UI_FontFamily>
|
||||
<APP_START>El QuickLook s'està executant en segon pla.</APP_START>
|
||||
@@ -176,6 +182,7 @@
|
||||
<MW_Run>{0} ausführen</MW_Run>
|
||||
<MW_Share>Freigeben</MW_Share>
|
||||
<MW_Reload>Neu laden</MW_Reload>
|
||||
<MW_More>Mehr</MW_More>
|
||||
<Icon_RunAtStartup>Beim Systemstart &ausführen</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>Nach &Updates suchen</Icon_CheckUpdate>
|
||||
@@ -210,6 +217,7 @@
|
||||
<MW_Run>Run {0}</MW_Run>
|
||||
<MW_Share>Share</MW_Share>
|
||||
<MW_Reload>Reload</MW_Reload>
|
||||
<MW_More>More</MW_More>
|
||||
<Icon_RunAtStartup>Run at &Startup</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>Check for &Updates...</Icon_CheckUpdate>
|
||||
@@ -244,6 +252,7 @@
|
||||
<MW_Run>Iniciar {0}</MW_Run>
|
||||
<MW_Share>Compartir</MW_Share>
|
||||
<MW_Reload>Recargar</MW_Reload>
|
||||
<MW_More>Más</MW_More>
|
||||
<Icon_RunAtStartup>Iniciar con el &sistema</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>Buscar &Actualizaciones...</Icon_CheckUpdate>
|
||||
@@ -273,6 +282,7 @@
|
||||
<MW_OpenWith>Ouvrir avec {0}</MW_OpenWith>
|
||||
<MW_Run>Exécuter {0}</MW_Run>
|
||||
<MW_Reload>Recharger</MW_Reload>
|
||||
<MW_More>Plus</MW_More>
|
||||
<Icon_RunAtStartup>Exécuter au &démarrage</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>Vérifier s'il existe des &mises à jour...</Icon_CheckUpdate>
|
||||
@@ -302,6 +312,7 @@
|
||||
<MW_OpenWith>Apri con {0}</MW_OpenWith>
|
||||
<MW_Run>Esegui {0}</MW_Run>
|
||||
<MW_Reload>Ricarica</MW_Reload>
|
||||
<MW_More>Altro</MW_More>
|
||||
<Icon_RunAtStartup>Esegui all'&Avvio</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>Verifica &Aggiornamenti...</Icon_CheckUpdate>
|
||||
@@ -334,6 +345,7 @@
|
||||
<MW_Run>{0} を起動</MW_Run>
|
||||
<MW_Share>シェア</MW_Share>
|
||||
<MW_Reload>再読み込み</MW_Reload>
|
||||
<MW_More>その他</MW_More>
|
||||
<Icon_RunAtStartup>スタートアップ時に起動</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>更新を確認する... (&U)</Icon_CheckUpdate>
|
||||
@@ -412,12 +424,13 @@
|
||||
<MW_BrowseFolder>Przeglądaj {0}</MW_BrowseFolder>
|
||||
<MW_StayTop>Przypnij do ekranu</MW_StayTop>
|
||||
<MW_PreventClosing>Zablokuj zamykanie</MW_PreventClosing>
|
||||
<MW_BrowseFolder>Przeglądaj {0}</MW_BrowseFolder>
|
||||
<MW_Open>Otwórz {0}</MW_Open>
|
||||
<MW_OpenWith>Otwórz w {0}</MW_OpenWith>
|
||||
<MW_OpenWithMenu>Otwórz za pomocą...</MW_OpenWithMenu>
|
||||
<MW_Run>Uruchom {0}</MW_Run>
|
||||
<MW_Share>Udostępnij</MW_Share>
|
||||
<MW_Reload>Przeładuj</MW_Reload>
|
||||
<MW_More>Więcej</MW_More>
|
||||
<Icon_RunAtStartup>Uruchamiaj automatycznie z systemem</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>Sprawdź &aktualizacje...</Icon_CheckUpdate>
|
||||
@@ -435,6 +448,7 @@
|
||||
<InfoPanel_File>{0} plik</InfoPanel_File>
|
||||
<InfoPanel_Files>{0} plików</InfoPanel_Files>
|
||||
<InfoPanel_FolderAndFile>({0} i {1})</InfoPanel_FolderAndFile>
|
||||
<InfoPanel_CantPreventClosing>Anulowanie dla funkcji blokady zamykania okna nie jest wspierane</InfoPanel_CantPreventClosing>
|
||||
</pl>
|
||||
<pt-BR>
|
||||
<UI_FontFamily>Segoe UI</UI_FontFamily>
|
||||
@@ -451,6 +465,7 @@
|
||||
<MW_Run>Executar {0}</MW_Run>
|
||||
<MW_Share>Compartilhar</MW_Share>
|
||||
<MW_Reload>Recarregar</MW_Reload>
|
||||
<MW_More>Mais</MW_More>
|
||||
<Icon_RunAtStartup>Executar na &Inicialização</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>Procurar por &Atualizações...</Icon_CheckUpdate>
|
||||
@@ -508,6 +523,7 @@
|
||||
<MW_PreventClosing>Закрепить</MW_PreventClosing>
|
||||
<MW_Share>Поделиться</MW_Share>
|
||||
<MW_Reload>Перезагрузить</MW_Reload>
|
||||
<MW_More>Еще</MW_More>
|
||||
<Icon_RunAtStartup>Автозапуск</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>Проверить &обновления…</Icon_CheckUpdate>
|
||||
@@ -568,6 +584,7 @@
|
||||
<MW_Run>Запустити {0}</MW_Run>
|
||||
<MW_Share>Поширити</MW_Share>
|
||||
<MW_Reload>Перезавантажити</MW_Reload>
|
||||
<MW_More>Більше</MW_More>
|
||||
<Icon_RunAtStartup>Запускати під час &старту</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>Перевірити наявність &оновлення…</Icon_CheckUpdate>
|
||||
@@ -627,6 +644,7 @@
|
||||
<MW_Run>运行 {0}</MW_Run>
|
||||
<MW_Share>分享</MW_Share>
|
||||
<MW_Reload>重新加载</MW_Reload>
|
||||
<MW_More>更多</MW_More>
|
||||
<Icon_RunAtStartup>启动时自动运行 (&S)</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>检查更新... (&U)</Icon_CheckUpdate>
|
||||
@@ -661,6 +679,7 @@
|
||||
<MW_Run>執行 {0}</MW_Run>
|
||||
<MW_Share>分享</MW_Share>
|
||||
<MW_Reload>重新載入</MW_Reload>
|
||||
<MW_More>更多</MW_More>
|
||||
<Icon_RunAtStartup>系統啟動時自動執行 (&S)</Icon_RunAtStartup>
|
||||
<Icon_ToolTip>QuickLook v{0}</Icon_ToolTip>
|
||||
<Icon_CheckUpdate>檢查更新... (&U)</Icon_CheckUpdate>
|
||||
|
@@ -15,79 +15,93 @@
|
||||
// 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.Commands;
|
||||
using QuickLook.Common.Helpers;
|
||||
using QuickLook.Helpers;
|
||||
using QuickLook.Properties;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Wpf.Ui.Violeta.Win32;
|
||||
using ToolTipIcon = Wpf.Ui.Violeta.Win32.ToolTipIcon;
|
||||
|
||||
namespace QuickLook;
|
||||
|
||||
internal class TrayIconManager : IDisposable
|
||||
internal partial class TrayIconManager : IDisposable
|
||||
{
|
||||
private static TrayIconManager _instance;
|
||||
|
||||
private readonly NotifyIcon _icon;
|
||||
private readonly TrayIconHost _icon;
|
||||
|
||||
private readonly MenuItem _itemAutorun =
|
||||
new(TranslationHelper.Get("Icon_RunAtStartup"),
|
||||
(sender, e) =>
|
||||
{
|
||||
if (AutoStartupHelper.IsAutorun())
|
||||
AutoStartupHelper.RemoveAutorunShortcut();
|
||||
else
|
||||
AutoStartupHelper.CreateAutorunShortcut();
|
||||
})
|
||||
{ Enabled = !App.IsUWP };
|
||||
private readonly TrayMenuItem _itemAutorun = null!;
|
||||
|
||||
private TrayIconManager()
|
||||
{
|
||||
_icon = new NotifyIcon
|
||||
_icon = new TrayIconHost
|
||||
{
|
||||
Text = string.Format(TranslationHelper.Get("Icon_ToolTip"),
|
||||
ToolTipText = string.Format(TranslationHelper.Get("Icon_ToolTip"),
|
||||
Application.ProductVersion),
|
||||
Icon = GetTrayIconByDPI(),
|
||||
ContextMenu = new ContextMenu(
|
||||
Menu =
|
||||
[
|
||||
new MenuItem($"v{Application.ProductVersion}{(App.IsUWP ? " (UWP)" : string.Empty)}") {Enabled = false},
|
||||
new MenuItem("-"),
|
||||
new MenuItem(TranslationHelper.Get("Icon_CheckUpdate"), (_, _) => Updater.CheckForUpdates()),
|
||||
new MenuItem(TranslationHelper.Get("Icon_GetPlugin"),
|
||||
(_, _) => Process.Start("https://github.com/QL-Win/QuickLook/wiki/Available-Plugins")),
|
||||
new MenuItem(TranslationHelper.Get("Icon_OpenDataFolder"), (_, _) => Process.Start("explorer.exe", SettingHelper.LocalDataPath)),
|
||||
_itemAutorun,
|
||||
new MenuItem(TranslationHelper.Get("Icon_Restart"), (_, _) => Restart(forced: true)),
|
||||
new MenuItem(TranslationHelper.Get("Icon_Quit"),
|
||||
(_, _) => System.Windows.Application.Current.Shutdown())
|
||||
]),
|
||||
Visible = SettingHelper.Get("ShowTrayIcon", true)
|
||||
new TrayMenuItem()
|
||||
{
|
||||
Header = $"v{Application.ProductVersion}{(App.IsUWP ? " (UWP)" : string.Empty)}",
|
||||
IsEnabled = false,
|
||||
},
|
||||
new TraySeparator(),
|
||||
new TrayMenuItem()
|
||||
{
|
||||
Header = TranslationHelper.Get("Icon_CheckUpdate"),
|
||||
Command = new RelayCommand(() => Updater.CheckForUpdates()),
|
||||
},
|
||||
new TrayMenuItem()
|
||||
{
|
||||
Header = TranslationHelper.Get("Icon_GetPlugin"),
|
||||
Command = new RelayCommand(() => Process.Start("https://github.com/QL-Win/QuickLook/wiki/Available-Plugins")),
|
||||
},
|
||||
new TrayMenuItem()
|
||||
{
|
||||
Header = TranslationHelper.Get("Icon_OpenDataFolder"),
|
||||
Command = new RelayCommand(() => Process.Start("explorer.exe", SettingHelper.LocalDataPath)),
|
||||
},
|
||||
_itemAutorun = new TrayMenuItem()
|
||||
{
|
||||
Header = TranslationHelper.Get("Icon_RunAtStartup"),
|
||||
Command = new RelayCommand(() =>
|
||||
{
|
||||
if (AutoStartupHelper.IsAutorun())
|
||||
AutoStartupHelper.RemoveAutorunShortcut();
|
||||
else
|
||||
AutoStartupHelper.CreateAutorunShortcut();
|
||||
}),
|
||||
IsEnabled = !App.IsUWP,
|
||||
},
|
||||
new TrayMenuItem()
|
||||
{
|
||||
Header = TranslationHelper.Get("Icon_Restart"),
|
||||
Command = new RelayCommand(() => Restart(forced: true)),
|
||||
},
|
||||
new TrayMenuItem()
|
||||
{
|
||||
Header = TranslationHelper.Get("Icon_Quit"),
|
||||
Command = new RelayCommand(System.Windows.Application.Current.Shutdown),
|
||||
}
|
||||
],
|
||||
IsVisible = SettingHelper.Get("ShowTrayIcon", true)
|
||||
};
|
||||
|
||||
_icon.ContextMenu.Popup += (sender, e) => { _itemAutorun.Checked = AutoStartupHelper.IsAutorun(); };
|
||||
|
||||
// Readjust the display position of ContextMenu
|
||||
if (SettingHelper.Get("ModernTrayIcon", true, "QuickLook"))
|
||||
_icon.RightDown += (_, _) =>
|
||||
{
|
||||
_icon.MouseDown += (_, e) =>
|
||||
{
|
||||
if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
// Call ShowContextMenu here will be later than the native call,
|
||||
// so here can readjust the ContextMenu position.
|
||||
// You can check the source code to determine the behavior.
|
||||
_icon.ShowContextMenu();
|
||||
}
|
||||
};
|
||||
}
|
||||
_itemAutorun.IsChecked = AutoStartupHelper.IsAutorun();
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_icon.Visible = false;
|
||||
_icon.IsVisible = false;
|
||||
}
|
||||
|
||||
public void Restart(string fileName = null, string dir = null, string args = null, int? exitCode = null, bool forced = false)
|
||||
@@ -118,16 +132,16 @@ internal class TrayIconManager : IDisposable
|
||||
Environment.Exit(exitCode ?? 'r' + 'e' + 's' + 't' + 'a' + 'r' + 't');
|
||||
}
|
||||
|
||||
private Icon GetTrayIconByDPI()
|
||||
private nint GetTrayIconByDPI()
|
||||
{
|
||||
var scale = DisplayDeviceHelper.GetCurrentScaleFactor().Vertical;
|
||||
|
||||
if (!App.IsWin10)
|
||||
return scale > 1 ? Resources.app : Resources.app_16;
|
||||
return scale > 1 ? Resources.app.Handle : Resources.app_16.Handle;
|
||||
|
||||
return OSThemeHelper.SystemUsesDarkTheme()
|
||||
? (scale > 1 ? Resources.app_white : Resources.app_white_16)
|
||||
: (scale > 1 ? Resources.app_black : Resources.app_black_16);
|
||||
? (scale > 1 ? Resources.app_white.Handle : Resources.app_white_16.Handle)
|
||||
: (scale > 1 ? Resources.app_black.Handle : Resources.app_black_16.Handle);
|
||||
}
|
||||
|
||||
public static void ShowNotification(string title, string content, bool isError = false, int timeout = 5000,
|
||||
|
@@ -22,12 +22,13 @@ using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace QuickLook;
|
||||
|
||||
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")
|
||||
};
|
||||
@@ -50,6 +51,8 @@ public partial class ViewerWindow : INotifyPropertyChanged
|
||||
public ContextObject ContextObject { get; private set; }
|
||||
public Themes CurrentTheme { get; private set; }
|
||||
|
||||
public ICommand CloseCommand { get; private set; }
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
|
@@ -6,7 +6,10 @@
|
||||
xmlns:converters="clr-namespace:QuickLook.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
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:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:vio="http://schemas.lepo.co/wpfui/2022/xaml/violeta"
|
||||
x:Name="mainWindow"
|
||||
Title="QuickLook"
|
||||
MinWidth="400"
|
||||
@@ -122,15 +125,24 @@
|
||||
DockPanel.Dock="Right"
|
||||
Style="{StaticResource CaptionButtonStyle}"
|
||||
ToolTip="Reload" />
|
||||
<!--<Button x:Name="buttonOpen" DockPanel.Dock="Right"
|
||||
Style="{StaticResource CaptionTextButtonStyle}"
|
||||
Visibility="{Binding ActualWidth, ElementName=windowCaptionContainer, Converter={StaticResource WidthToVisibilityCollapsedConverter}}">
|
||||
<Button.Content>
|
||||
<TextBlock x:Name="buttonOpenText" VerticalAlignment="Center">
|
||||
Open with <Bold>AppName</Bold>
|
||||
</TextBlock>
|
||||
</Button.Content>
|
||||
</Button>-->
|
||||
<Button x:Name="buttonMore"
|
||||
Content=""
|
||||
DockPanel.Dock="Right"
|
||||
Style="{StaticResource CaptionButtonStyle}"
|
||||
ToolTip="More">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu FontSize="12">
|
||||
<MenuItem Command="{Binding OpenSettingsFileFolderCommand}" Header="SettingsFile">
|
||||
<MenuItem.Icon>
|
||||
<ui:FontIcon FontFamily="{DynamicResource SymbolThemeFontFamily}" Glyph="{x:Static ui:FontSymbols.OpenLocal}" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
<i:Interaction.Behaviors>
|
||||
<controls:LeftContextMenuBehavior />
|
||||
</i:Interaction.Behaviors>
|
||||
</Button>
|
||||
<Button x:Name="buttonTop"
|
||||
DockPanel.Dock="Left"
|
||||
Tag="Auto"
|
||||
|
@@ -116,6 +116,7 @@ public partial class ViewerWindow : Window
|
||||
buttonOpenWith.ToolTip = TranslationHelper.Get("MW_OpenWithMenu");
|
||||
buttonShare.ToolTip = TranslationHelper.Get("MW_Share");
|
||||
buttonReload.ToolTip = TranslationHelper.Get("MW_Reload", failsafe: "Reload");
|
||||
buttonMore.ToolTip = TranslationHelper.Get("MW_More", failsafe: "More");
|
||||
}
|
||||
|
||||
public new void Close()
|
||||
|
Reference in New Issue
Block a user