diff --git a/OPTIONS.md b/OPTIONS.md
index e7e68b138..ee2c747d2 100644
--- a/OPTIONS.md
+++ b/OPTIONS.md
@@ -74,6 +74,13 @@ Example:
- Example:
- `True`
+### ``
+- Default: `False`
+- Type: `Boolean`
+- Description: Automatically hide the preview window's toolbar when the pointer leaves it. The toolbar reappears when the pointer moves to the top edge of the window. Can also be toggled from the tray menu.
+- Example:
+ - `True`
+
### ``
- Default: `True`
- Type: `Boolean`
diff --git a/QuickLook.Common/Styles/MainWindowStyles.Dark.xaml b/QuickLook.Common/Styles/MainWindowStyles.Dark.xaml
index ccc6054ed..813573f5b 100644
--- a/QuickLook.Common/Styles/MainWindowStyles.Dark.xaml
+++ b/QuickLook.Common/Styles/MainWindowStyles.Dark.xaml
@@ -1,6 +1,7 @@
+
diff --git a/QuickLook.Common/Styles/MainWindowStyles.xaml b/QuickLook.Common/Styles/MainWindowStyles.xaml
index deee5d596..f41acd0a6 100644
--- a/QuickLook.Common/Styles/MainWindowStyles.xaml
+++ b/QuickLook.Common/Styles/MainWindowStyles.xaml
@@ -6,6 +6,7 @@
32
+
diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml
index e177a8509..a0f550962 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml
+++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml
@@ -102,6 +102,7 @@
Margin="0,0,8,0"
Content=""
Style="{StaticResource CaptionButtonStyle}"
+ ToolTip="{Binding CopyTooltip, ElementName=imagePanel}"
Visibility="{Binding ElementName=imagePanel, Path=CopyIconVisibility}" />
+ ToolTipService.InitialShowDelay="0"
+ Visibility="{Binding ElementName=imagePanel, Path=MetaIconVisibility}">
+
+
+
+
+
+
-
-
- Camera maker
- :
- SONY
-
-
-
-
-
\ No newline at end of file
diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml.cs
index 5c9654925..75ce8e48e 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml.cs
@@ -28,6 +28,7 @@
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
+using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@@ -66,6 +67,9 @@ public partial class ImagePanel : UserControl, INotifyPropertyChanged, IDisposab
private Visibility _reverseColorVisibility = Visibility.Collapsed;
private Visibility _metaIconVisibility = Visibility.Visible;
+ public string CopyTooltip { get; } = GetTranslation("IV_Copy");
+ public string BackgroundTooltip { get; } = GetTranslation("IV_Background");
+
public ImagePanel()
{
InitializeComponent();
@@ -78,11 +82,6 @@ public ImagePanel()
buttonReverseColor.Click += OnReverseColorOnClick;
- buttonMeta.Click += (sender, e) =>
- textMeta.Visibility = textMeta.Visibility == Visibility.Collapsed
- ? Visibility.Visible
- : Visibility.Collapsed;
-
buttonBackgroundColour.Click += OnBackgroundColourOnClick;
SizeChanged += ImagePanel_SizeChanged;
@@ -111,6 +110,15 @@ public ImagePanel()
viewPanel.ManipulationDelta += ViewPanel_ManipulationDelta;
}
+ private static string GetTranslation(string key)
+ {
+ var translationFile = Path.Combine(
+ Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
+ "Translations.config");
+
+ return TranslationHelper.Get(key, translationFile);
+ }
+
internal ImagePanel(ContextObject context, MetaProvider meta) : this()
{
ContextObject = context;
@@ -401,19 +409,27 @@ private void OnBackgroundColourOnClick(object sender, RoutedEventArgs e)
private void ShowMeta()
{
- textMeta.Inlines.Clear();
- Meta.GetExif().Values.ForEach(m =>
+ textMetaContent.Inlines.Clear();
+ Meta.GetExif()
+ .OrderBy(item => item.Key switch
+ {
+ "_.Size.Width" => 0,
+ "_.Size.Height" => 1,
+ _ => 2,
+ })
+ .Select(item => item.Value)
+ .ForEach(m =>
{
if (string.IsNullOrWhiteSpace(m.Item1) || string.IsNullOrWhiteSpace(m.Item2))
return;
- textMeta.Inlines.Add(new Run(m.Item1) { FontWeight = FontWeights.SemiBold });
- textMeta.Inlines.Add(": ");
- textMeta.Inlines.Add(m.Item2);
- textMeta.Inlines.Add("\r\n");
+ textMetaContent.Inlines.Add(new Run(m.Item1) { FontWeight = FontWeights.SemiBold });
+ textMetaContent.Inlines.Add(": ");
+ textMetaContent.Inlines.Add(m.Item2);
+ textMetaContent.Inlines.Add("\r\n");
});
- textMeta.Inlines.Remove(textMeta.Inlines.LastInline);
- if (!textMeta.Inlines.Any())
+ textMetaContent.Inlines.Remove(textMetaContent.Inlines.LastInline);
+ if (!textMetaContent.Inlines.Any())
MetaIconVisibility = Visibility.Collapsed;
}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Translations.config b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Translations.config
index 1a96fa15a..9adf5c3da 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Translations.config
+++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Translations.config
@@ -3,6 +3,9 @@
Torna a obrir com a codi font
+ Copiar la imatge
+ Mostrar les metadades
+ Canvia el fons
Servei PlantUML en línia
La previsualització d'aquest fitxer requereix enviar el seu contingut a un servidor PlantUML remot (plantuml.com) per al renderitzat.
@@ -11,6 +14,9 @@ Voleu permetre l'accés a la xarxa?
פתח מחדש כקוד מקור
+ העתק תמונה
+ הצג מטא-נתונים
+ החלף רקע
שירות PlantUML מקוון
תצוגה מקדימה של קובץ זה מחייבת שליחת תוכנו לשרת PlantUML מרוחק (plantuml.com) לעיבוד.
@@ -19,6 +25,9 @@ Voleu permetre l'accés a la xarxa?
सोर्स कोड के रूप में पुनः खोलें
+ छवि कॉपी करें
+ मेटाडेटा दिखाएँ
+ पृष्ठभूमि बदलें
PlantUML ऑनलाइन सेवा
इस फ़ाइल का पूर्वावलोकन करने के लिए इसकी सामग्री को रेंडरिंग के लिए एक दूरस्थ PlantUML सर्वर (plantuml.com) पर भेजना आवश्यक है।
@@ -27,6 +36,9 @@ Voleu permetre l'accés a la xarxa?
Újranyitás forráskódként
+ Kép másolása
+ Metaadatok megjelenítése
+ Háttér váltása
PlantUML online szolgáltatás
Ennek a fájlnak az előnézete megköveteli a tartalmának elküldését egy távoli PlantUML kiszolgálóra (plantuml.com) renderelés céljából.
@@ -35,6 +47,9 @@ Engedélyezi a hálózati hozzáférést?
Buka ulang sebagai kode sumber
+ Salin gambar
+ Tampilkan metadata
+ Beralih latar belakang
Layanan PlantUML Online
Pratinjau file ini memerlukan pengiriman kontennya ke server PlantUML jarak jauh (plantuml.com) untuk dirender.
@@ -43,6 +58,9 @@ Izinkan akses jaringan?
स्रोत कोड म्हणून पुन्हा उघडा
+ प्रतिमा कॉपी करा
+ मेटाडेटा दाखवा
+ पार्श्वभूमी बदला
PlantUML ऑनलाइन सेवा
या फाइलचे पूर्वावलोकन करण्यासाठी तिची सामग्री रेंडरिंगसाठी दूरस्थ PlantUML सर्व्हरवर (plantuml.com) पाठवणे आवश्यक आहे.
@@ -51,6 +69,9 @@ Izinkan akses jaringan?
Åpne på nytt som kildekode
+ Kopier bilde
+ Vis metadata
+ Bytt bakgrunn
PlantUML nettjeneste
Forhåndsvisning av denne filen krever at innholdet sendes til en ekstern PlantUML-server (plantuml.com) for gjengivelse.
@@ -59,6 +80,9 @@ Tillate nettverkstilgang?
Opnieuw openen als broncode
+ Afbeelding kopiëren
+ Metagegevens tonen
+ Achtergrond wisselen
PlantUML online service
Voor het bekijken van dit bestand moet de inhoud worden verzonden naar een externe PlantUML-server (plantuml.com) voor weergave.
@@ -67,6 +91,9 @@ Netwerktogang toestaan?
Reabrir como código-fonte
+ Copiar imagem
+ Mostrar metadados
+ Alternar plano de fundo
Serviço PlantUML Online
A visualização deste arquivo requer o envio do seu conteúdo para um servidor PlantUML remoto (plantuml.com) para renderização.
@@ -75,6 +102,9 @@ Permitir acesso à rede?
Reabrir como código-fonte
+ Copiar imagem
+ Mostrar metadados
+ Alternar fundo
Serviço PlantUML Online
A pré-visualização deste ficheiro requer o envio do seu conteúdo para um servidor PlantUML remoto (plantuml.com) para renderização.
@@ -83,6 +113,9 @@ Permitir acesso à rede?
Открыть заново как исходный код
+ Копировать изображение
+ Показать метаданные
+ Изменить фон
Онлайн-сервис PlantUML
Предварительный просмотр этого файла требует отправки его содержимого на удалённый сервер PlantUML (plantuml.com) для рендеринга.
@@ -91,6 +124,9 @@ Permitir acesso à rede?
Znovu otvoriť ako zdrojový kód
+ Kopírovať obrázok
+ Zobraziť metadáta
+ Prepnúť pozadie
Online služba PlantUML
Náhľad tohto súboru vyžaduje odoslanie jeho obsahu na vzdialený server PlantUML (plantuml.com) na vykresľovanie.
@@ -99,6 +135,9 @@ Povoliť prístup k sieti?
Kaynak kod olarak yeniden aç
+ Görüntüyü kopyala
+ Üst verileri göster
+ Arka planı değiştir
PlantUML Çevrimiçi Hizmeti
Bu dosyanın önizlemesi, içeriğinin işlenmek üzere uzak bir PlantUML sunucusuna (plantuml.com) gönderilmesini gerektirir.
@@ -107,6 +146,9 @@ Ağ erişimine izin verilsin mi?
Mở lại dưới dạng mã nguồn
+ Sao chép hình ảnh
+ Hiện siêu dữ liệu
+ Chuyển đổi nền
Dịch vụ PlantUML trực tuyến
Xem trước tệp này yêu cầu gửi nội dung của nó đến máy chủ PlantUML từ xa (plantuml.com) để kết xuất.
@@ -115,6 +157,9 @@ Cho phép truy cập mạng?
Reopen as source code
+ Copy image
+ Show metadata
+ Toggle background
PlantUML Online Service
Previewing this file requires sending its content to a remote PlantUML server (plantuml.com) for rendering.
@@ -123,6 +168,9 @@ Allow network access?
소스 코드로 다시 열기
+ 이미지 복사
+ 메타데이터 표시
+ 배경 전환
PlantUML 온라인 서비스
이 파일을 미리 보려면 내용을 원격 PlantUML 서버 (plantuml.com)로 보내 렌더링해야 합니다.
@@ -131,6 +179,9 @@ Allow network access?
Als Quellcode erneut öffnen
+ Bild kopieren
+ Metadaten anzeigen
+ Hintergrund wechseln
PlantUML Online-Dienst
Für die Vorschau dieser Datei muss ihr Inhalt zur Darstellung an einen entfernten PlantUML-Server (plantuml.com) gesendet werden.
@@ -139,6 +190,9 @@ Netzwerkzugriff erlauben?
Rouvrir en tant que code source
+ Copier l’image
+ Afficher les métadonnées
+ Changer l’arrière-plan
Service PlantUML en ligne
L'aperçu de ce fichier nécessite l'envoi de son contenu à un serveur PlantUML distant (plantuml.com) pour le rendu.
@@ -147,6 +201,9 @@ Autoriser l'accès au réseau ?
ソースコードとして再度開く
+ 画像をコピー
+ メタデータを表示
+ 背景を切り替え
PlantUML オンラインサービス
このファイルをプレビューするには、内容をリモートの PlantUML サーバー (plantuml.com) に送信してレンダリングする必要があります。
@@ -155,6 +212,9 @@ Autoriser l'accès au réseau ?
以源代码方式重新打开
+ 复制图像
+ 显示元数据
+ 切换背景
PlantUML 在线服务
预览此文件需要将内容发送到远程 PlantUML 服务器 (plantuml.com) 进行渲染。
@@ -163,6 +223,9 @@ Autoriser l'accès au réseau ?
以原始碼方式重新開啟
+ 複製影像
+ 顯示中繼資料
+ 切換背景
PlantUML 線上服務
預覽此檔案需要將內容傳送至遠端 PlantUML 伺服器 (plantuml.com) 進行渲染。
@@ -171,6 +234,9 @@ Autoriser l'accès au réseau ?
Reabrir como código fuente
+ Copiar imagen
+ Mostrar metadatos
+ Cambiar fondo
Servicio PlantUML en línea
La vista previa de este archivo requiere enviar su contenido a un servidor PlantUML remoto (plantuml.com) para su procesamiento.
@@ -179,6 +245,9 @@ Autoriser l'accès au réseau ?
Riapri come codice sorgente
+ Copia immagine
+ Mostra metadati
+ Cambia sfondo
Servizio PlantUML online
L'anteprima di questo file richiede l'invio del suo contenuto a un server PlantUML remoto (plantuml.com) per il rendering.
@@ -187,6 +256,9 @@ Consentire l'accesso alla rete?
إعادة الفتح كرمز مصدر
+ نسخ الصورة
+ إظهار البيانات الوصفية
+ تبديل الخلفية
خدمة PlantUML عبر الإنترنت
يتطلب معاينة هذا الملف إرسال محتواه إلى خادم PlantUML البعيد (plantuml.com) للعرض.
@@ -195,6 +267,9 @@ Consentire l'accesso alla rete?
Otwórz ponownie jako kod źródłowy
+ Kopiuj obraz
+ Pokaż metadane
+ Przełącz tło
Usługa PlantUML online
Podgląd tego pliku wymaga wysłania jego zawartości do zdalnego serwera PlantUML (plantuml.com) w celu renderowania.
@@ -203,6 +278,9 @@ Czy zezwolić na dostęp do sieci?
Επαναάνοιγμα ως πηγαίος κώδικας
+ Αντιγραφή εικόνας
+ Εμφάνιση μεταδεδομένων
+ Εναλλαγή φόντου
Διαδικτυακή υπηρεσία PlantUML
Η προεπισκόπηση αυτού του αρχείου απαιτεί την αποστολή του περιεχομένου του σε έναν απομακρυσμένο διακομιστή PlantUML (plantuml.com) για απόδοση.
@@ -211,6 +289,9 @@ Czy zezwolić na dostęp do sieci?
Відкрити знову як вихідний код
+ Копіювати зображення
+ Показати метадані
+ Змінити тло
Онлайн-сервіс PlantUML
Попередній перегляд цього файлу вимагає надсилання його вмісту на віддалений сервер PlantUML (plantuml.com) для рендерингу.
@@ -219,6 +300,9 @@ Czy zezwolić na dostęp do sieci?
Öppna igen som källkod
+ Kopiera bild
+ Visa metadata
+ Byt bakgrund
PlantUML onlinetjänst
Förhandsgranskning av den här filen kräver att dess innehåll skickas till en fjärr-PlantUML-server (plantuml.com) för renderering.
@@ -227,6 +311,9 @@ Tillåt nätverksåtkomst?
Redeschideți ca cod sursă
+ Copiază imaginea
+ Arată metadatele
+ Comută fundalul
Serviciul online PlantUML
Previzualizarea acestui fișier necesită trimiterea conținutului său la un server PlantUML la distanță (plantuml.com) pentru randare.
diff --git a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/AsyncPageToThumbnailConverter.cs b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/AsyncPageToThumbnailConverter.cs
index dec92f40f..b0da285aa 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/AsyncPageToThumbnailConverter.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/AsyncPageToThumbnailConverter.cs
@@ -18,7 +18,6 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
-using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media.Imaging;
@@ -31,7 +30,7 @@ internal class AsyncPageToThumbnailConverter : IMultiValueConverter
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
- if (values.Length < 3)
+ if (values.Length < 2)
throw new Exception("PageIdToImageConverter");
if (values[0] is not PdfDocumentWrapper handle) return null;
@@ -39,17 +38,11 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur
var pageId = (int)values[1];
if (pageId < 0) return null;
- if (values[2] is not UserControl thisPdfViewer) return null;
-
var task = Task.Run(() =>
{
try
{
- if (handle is null || thisPdfViewer is null) return Loading;
- return thisPdfViewer.Dispatcher.Invoke(() =>
- {
- return handle.RenderThumbnail(pageId);
- });
+ return handle.RenderThumbnail(pageId);
}
catch (Exception)
{
diff --git a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfDocumentWrapper.cs b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfDocumentWrapper.cs
index e1883d734..037f9da0a 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfDocumentWrapper.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfDocumentWrapper.cs
@@ -16,42 +16,85 @@
// along with this program. If not, see .
using System;
+using System.Drawing;
using System.IO;
+using System.Linq;
using PdfiumViewer;
namespace QuickLook.Plugin.PDFViewer;
public class PdfDocumentWrapper : IDisposable
{
+ private readonly string _path;
+ private readonly string _password;
+ private SizeF[] _pageSizes;
+ private bool _disposed;
+
+ public PdfDocumentWrapper(string path, string password = null)
+ {
+ _path = path;
+ _password = password;
+ PdfDocument = PdfDocument.Load(path, password);
+ _pageSizes = PdfDocument.PageSizes.ToArray();
+ PageCount = PdfDocument.PageCount;
+ }
+
public PdfDocumentWrapper(Stream stream, string password = null)
{
+ _password = password;
PdfStream = new MemoryStream((int)stream.Length);
stream.CopyTo(PdfStream);
+ PdfStream.Position = 0;
PdfDocument = PdfDocument.Load(PdfStream, password);
+ _pageSizes = PdfDocument.PageSizes.ToArray();
+ PageCount = PdfDocument.PageCount;
}
public PdfDocument PdfDocument { get; private set; }
public MemoryStream PdfStream { get; private set; }
+ public int PageCount { get; private set; }
+
+ public SizeF GetPageSize(int page) => _pageSizes[page];
+
public void Dispose()
{
- PdfDocument.Dispose();
- PdfDocument = null;
- PdfStream.Dispose();
- PdfStream = null;
+ lock (PdfPageExtension.RenderLock)
+ {
+ if (_disposed)
+ return;
+
+ _disposed = true;
+ PdfDocument?.Dispose();
+ PdfDocument = null;
+ PdfStream?.Dispose();
+ PdfStream = null;
+ }
}
public void Refresh()
{
- var oldD = PdfDocument;
+ lock (PdfPageExtension.RenderLock)
+ {
+ if (_disposed)
+ return;
- PdfStream.Position = 0;
- var newObj = new PdfDocumentWrapper(PdfStream);
- PdfDocument = newObj.PdfDocument;
- PdfStream = newObj.PdfStream;
+ if (PdfStream != null)
+ PdfStream.Position = 0;
+
+ var newDocument = _path != null
+ ? PdfDocument.Load(_path, _password)
+ : PdfDocument.Load(PdfStream, _password);
+ var newPageSizes = newDocument.PageSizes.ToArray();
+ var oldDocument = PdfDocument;
+
+ PdfDocument = newDocument;
+ PageCount = newDocument.PageCount;
+ _pageSizes = newPageSizes;
- oldD.Dispose();
+ oldDocument.Dispose();
+ }
}
}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfPageExtension.cs b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfPageExtension.cs
index 35ea04663..4db38de62 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfPageExtension.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfPageExtension.cs
@@ -27,11 +27,11 @@ namespace QuickLook.Plugin.PDFViewer;
internal static class PdfPageExtension
{
private static int _renderCount;
- private static readonly object LockObj = new();
+ internal static readonly object RenderLock = new();
public static BitmapSource RenderThumbnail(this PdfDocumentWrapper doc, int page)
{
- lock (LockObj)
+ lock (RenderLock)
{
if (_renderCount++ == 50)
{
@@ -40,7 +40,7 @@ public static BitmapSource RenderThumbnail(this PdfDocumentWrapper doc, int page
}
}
- var size = doc.PdfDocument.PageSizes[page];
+ var size = doc.GetPageSize(page);
var factorX = 60d / size.Width;
var factorY = 120d / size.Height;
@@ -55,9 +55,9 @@ public static BitmapSource Render(this PdfDocumentWrapper doc, int page, double
Bitmap bitmap;
- lock (LockObj)
+ lock (RenderLock)
{
- var size = doc.PdfDocument.PageSizes[page];
+ var size = doc.GetPageSize(page);
var realWidth = (int)Math.Round(size.Width * scale.Horizontal * factor);
var realHeight = (int)Math.Round(size.Height * scale.Vertical * factor);
diff --git a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml
index 59b41481f..aa55ec539 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml
+++ b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml
@@ -62,7 +62,6 @@
-
@@ -88,4 +87,4 @@
ZoomWithControlKey="True" />
-
\ No newline at end of file
+
diff --git a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml.cs b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml.cs
index f684547a9..0d4552773 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml.cs
@@ -15,8 +15,6 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-using PdfiumViewer;
-using QuickLook.Common.ExtensionMethods;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
@@ -24,8 +22,10 @@
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.PDFViewer;
@@ -33,6 +33,7 @@ public partial class PdfViewerControl : UserControl, INotifyPropertyChanged, IDi
{
private int _changePageDeltaSum;
private bool _initPage = true;
+ private int _renderRequestId;
private double _maxZoomFactor = double.NaN;
private double _minZoomFactor = double.NaN;
@@ -52,9 +53,9 @@ public PdfViewerControl()
pagePanel.ImageScrolled += NavigatePage;
}
- public ObservableCollection PageThumbnails { get; set; } = [];
+ public ObservableCollection PageThumbnails { get; private set; } = [];
- public int TotalPages => PdfDocumentWrapper.PdfDocument.PageCount;
+ public int TotalPages => PdfDocumentWrapper.PageCount;
public int CurrentPage
{
@@ -81,6 +82,7 @@ public void Dispose()
pagePanel.ImageScrolled -= NavigatePage;
}
+ _renderRequestId++;
_pdfLoaded = false;
PdfDocumentWrapper?.Dispose();
PdfDocumentWrapper = null;
@@ -142,33 +144,37 @@ private void PrevPage()
}
}
- private void ReRenderCurrentPage()
+ private async void ReRenderCurrentPage()
{
if (!_pdfLoaded)
return;
- if (CurrentPage < 0 || CurrentPage >= TotalPages)
+ var page = CurrentPage;
+ var document = PdfDocumentWrapper;
+ if (document == null || page < 0 || page >= TotalPages)
return;
- Debug.WriteLine($"Re-rendering page {CurrentPage}");
+ Debug.WriteLine($"Re-rendering page {page}");
var pos = pagePanel.GetScrollPosition();
+ var requestId = ++_renderRequestId;
double factor;
+ var pageSize = document.GetPageSize(page);
// First time showing. Set thresholds here.
if (double.IsNaN(_minZoomFactor) || double.IsNaN(_maxZoomFactor))
{
- factor = Math.Min(pagePanel.ActualHeight / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Height,
- pagePanel.ActualWidth / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Width);
+ factor = Math.Min(pagePanel.ActualHeight / pageSize.Height,
+ pagePanel.ActualWidth / pageSize.Width);
_viewRenderFactor = factor;
_minZoomFactor = 0.1 * factor;
_maxZoomFactor = 5 * factor;
}
else if (pagePanel.ZoomToFit)
{
- factor = Math.Min(pagePanel.ActualHeight / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Height,
- pagePanel.ActualWidth / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Width);
+ factor = Math.Min(pagePanel.ActualHeight / pageSize.Height,
+ pagePanel.ActualWidth / pageSize.Width);
}
else
{
@@ -179,7 +185,19 @@ private void ReRenderCurrentPage()
pagePanel.MaxZoomFactor = _maxZoomFactor / factor;
}
- var image = PdfDocumentWrapper.Render(CurrentPage, factor);
+ BitmapSource image;
+ try
+ {
+ image = await Task.Run(() => document.Render(page, factor));
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Failed to render PDF page {page}: {ex}");
+ return;
+ }
+
+ if (!_pdfLoaded || requestId != _renderRequestId || !ReferenceEquals(document, PdfDocumentWrapper))
+ return;
pagePanel.Source = image;
pagePanel.ResetZoom();
@@ -187,8 +205,6 @@ private void ReRenderCurrentPage()
_viewRenderFactor = factor;
pagePanel.SetScrollPosition(pos);
-
- Dispatcher.Delay(500, t => GC.Collect());
}
private void UpdatePageViewWhenSelectionChanged(object sender, SelectionChangedEventArgs e)
@@ -210,56 +226,64 @@ private void UpdatePageViewWhenSelectionChanged(object sender, SelectionChangedE
}
}
- public static Size GetDesiredControlSizeByFirstPage(string path, string password = null)
+ public static Size GetDesiredControlSizeByFirstPage(PdfDocumentWrapper document)
{
- Size size;
-
- using (var s = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ var size = new Size(0, 0);
+ for (var page = 0; page < Math.Min(5, document.PageCount); page++)
{
- using (var tempHandle = PdfDocument.Load(s, password))
- {
- size = new Size(0, 0);
- tempHandle.PageSizes.Take(5).ForEach(p =>
- {
- size.Width = Math.Max(size.Width, p.Width);
- size.Height = Math.Max(size.Height, p.Height);
- });
-
- if (tempHandle.PageCount > 1)
- size.Width += /*listThumbnails.ActualWidth*/ 150;
- }
+ var pageSize = document.GetPageSize(page);
+ size.Width = Math.Max(size.Width, pageSize.Width);
+ size.Height = Math.Max(size.Height, pageSize.Height);
}
+ if (document.PageCount > 1)
+ size.Width += 150;
+
return new Size(size.Width * 3, size.Height * 3);
}
public void LoadPdf(string path, string password = null)
{
- var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- PdfDocumentWrapper = new PdfDocumentWrapper(stream, password);
+ LoadPdf(new PdfDocumentWrapper(path, password));
+ }
+
+ public void LoadPdf(PdfDocumentWrapper document)
+ {
+ var previousDocument = PdfDocumentWrapper;
+ _pdfLoaded = false;
+ _renderRequestId++;
+ listThumbnails.SelectedIndex = -1;
+ if (previousDocument != null && !ReferenceEquals(previousDocument, document))
+ previousDocument.Dispose();
+
+ PdfDocumentWrapper = document;
_pdfLoaded = true;
+ _initPage = true;
+ _minZoomFactor = double.NaN;
+ _maxZoomFactor = double.NaN;
+ _viewRenderFactor = double.NaN;
- if (PdfDocumentWrapper.PdfDocument.PageCount < 2)
+ if (PdfDocumentWrapper.PageCount < 2)
listThumbnails.Visibility = Visibility.Collapsed;
+ else
+ listThumbnails.Visibility = Visibility.Visible;
BeginLoadThumbnails();
+
+ if (PdfDocumentWrapper.PageCount > 0)
+ listThumbnails.SelectedIndex = 0;
}
public void LoadPdf(MemoryStream stream)
{
stream.Position = 0;
- PdfDocumentWrapper = new PdfDocumentWrapper(stream);
- _pdfLoaded = true;
-
- if (PdfDocumentWrapper.PdfDocument.PageCount < 2)
- listThumbnails.Visibility = Visibility.Collapsed;
-
- BeginLoadThumbnails();
+ LoadPdf(new PdfDocumentWrapper(stream));
}
private void BeginLoadThumbnails()
{
- Enumerable.Range(0, PdfDocumentWrapper.PdfDocument.PageCount).ForEach(PageThumbnails.Add);
+ PageThumbnails = new ObservableCollection(Enumerable.Range(0, PdfDocumentWrapper.PageCount));
+ OnPropertyChanged(nameof(PageThumbnails));
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
diff --git a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/Plugin.cs
index 54733c2d7..bd30f26af 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/Plugin.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.PDFViewer/Plugin.cs
@@ -33,6 +33,7 @@ public sealed class Plugin : IViewer
private string _path;
private PdfViewerControl _pdfControl;
private PasswordControl _passwordControl;
+ private PdfDocumentWrapper _preparedDocument;
public int Priority => -1;
@@ -59,16 +60,22 @@ public bool CanHandle(string path)
public void Prepare(string path, ContextObject context)
{
+ _preparedDocument?.Dispose();
+ _preparedDocument = null;
_context = context;
_path = path;
try
{
- var desiredSize = PdfViewerControl.GetDesiredControlSizeByFirstPage(path);
+ _preparedDocument = new PdfDocumentWrapper(path);
+ var desiredSize = PdfViewerControl.GetDesiredControlSizeByFirstPage(_preparedDocument);
context.SetPreferredSizeFit(desiredSize, 0.9);
}
catch (PdfException ex) when (ex.Message == "Password required or incorrect password")
{
+ _preparedDocument?.Dispose();
+ _preparedDocument = null;
+
// Fallback to a size to request the password
context.PreferredSize = new Size { Width = 800, Height = 600 };
}
@@ -85,7 +92,9 @@ public void View(string path, ContextObject context)
{
try
{
- _pdfControl.LoadPdf(path);
+ var document = _preparedDocument;
+ _preparedDocument = null;
+ _pdfControl.LoadPdf(document ?? new PdfDocumentWrapper(path));
context.Title = $"1 / {_pdfControl.TotalPages}: {Path.GetFileName(path)}";
@@ -100,7 +109,8 @@ public void View(string path, ContextObject context)
{
try
{
- var desiredSize = PdfViewerControl.GetDesiredControlSizeByFirstPage(path, password);
+ var document = new PdfDocumentWrapper(path, password);
+ var desiredSize = PdfViewerControl.GetDesiredControlSizeByFirstPage(document);
context.SetPreferredSizeFit(desiredSize, 0.9); // Actually it is no longer effective here
context.ViewerContent = _pdfControl;
@@ -120,7 +130,7 @@ public void View(string path, ContextObject context)
}
context.IsBusy = true;
- _pdfControl.LoadPdf(path, password);
+ _pdfControl.LoadPdf(document);
context.Title = $"1 / {_pdfControl.TotalPages}: {Path.GetFileName(path)}";
@@ -158,6 +168,9 @@ public void Cleanup()
_pdfControl?.Dispose();
_pdfControl = null;
+ _preparedDocument?.Dispose();
+ _preparedDocument = null;
+
_context = null;
}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.VideoViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.VideoViewer/Plugin.cs
index 02014b085..82f7894a2 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.VideoViewer/Plugin.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.VideoViewer/Plugin.cs
@@ -32,7 +32,8 @@ public sealed class Plugin : IViewer
private ViewerPanel _vp;
- public int Priority => -3;
+ // Let cheap text, archive, and model-format checks run before probing files with MediaInfo.
+ public int Priority => -9;
static Plugin()
{
@@ -53,7 +54,10 @@ public void Init()
public bool CanHandle(string path)
{
- if (!Directory.Exists(path))
+ if (Directory.Exists(path))
+ return false;
+
+ if (File.Exists(path))
{
try
{
diff --git a/QuickLook/QuickLook.csproj b/QuickLook/QuickLook.csproj
index 93b877ed2..06af9976d 100644
--- a/QuickLook/QuickLook.csproj
+++ b/QuickLook/QuickLook.csproj
@@ -140,6 +140,9 @@
all
+
+ all
+
diff --git a/QuickLook/Translations.config b/QuickLook/Translations.config
index 684efd329..942736fdd 100644
--- a/QuickLook/Translations.config
+++ b/QuickLook/Translations.config
@@ -19,6 +19,7 @@
افتح مجلد البيانات
إعادة تشغيل
Close on Lost Focus
+ إخفاء شريط الأدوات
أغلق البرنامج
أنت تمتلك النسخة الأحدث من البرنامج
كويك لووك {0} تم إصداره. إنقر هنا لفتح صفحة التحميل
@@ -50,6 +51,7 @@
Adatmappa Megnyitása
&Újraindítás
Close on Lost Focus
+ Eszköztár elrejtése
&Kilépés
A legújabb verziót használja.
QuickLook {0} megjelent. Kattintson ide a letöltési oldal megnyitásához.
@@ -80,6 +82,7 @@
Otvoriť Priečinok S Údajmi
&Reštart
Close on Lost Focus
+ Skryť panel s nástrojmi
&Ukončiť
Máte nainštalovanú najnovšiu verziu
QuickLook {0} nie je v aktuálnej verzii. Kliknite sem na otvorenie stránky pre stiahnutie.
@@ -111,6 +114,7 @@
Buka Folder Data
&Mulai Ulang
Close on Lost Focus
+ Sembunyikan bilah alat
&Keluar
Anda saat ini menggunakan versi terbaru.
QuickLook v. {0} dirilis. Klik disini untuk membuka halaman unduhan.
@@ -147,6 +151,7 @@
데이터 폴더 열기
다시 시작(&R)
Close on Lost Focus
+ 도구 모음 숨기기
종료(&Q)
현재 최신 버전을 사용하고 있습니다.
QuickLook {0}이 출시되었습니다. 여기를 클릭하여 다운로드 페이지를 여세요.
@@ -177,6 +182,7 @@
Obre La Carpeta De Dades
&Reinicia
Close on Lost Focus
+ Amaga la barra d'eines
&Surt
Ja teniu l'última versió.
S'ha alliberat el QuickLook {0}. Feu clic aquí per a obrir la pàgina de baixada.
@@ -215,6 +221,7 @@
Datenordner öffnen
&Neustart
Close on Lost Focus
+ Symbolleiste ausblenden
&Beenden
Sie haben die neueste Version.
QuickLook v{0} wurde veröffentlicht. Hier klicken um die Downloadseite zu öffnen.
@@ -254,6 +261,7 @@
Open Data Folder
&Restart
Close on Lost Focus
+ Hide toolbar
&Quit
You are now on the latest version.
QuickLook {0} has been released. Click here to open the download page.
@@ -293,6 +301,7 @@
Abrir Carpeta De Datos
&Reiniciar
Close on Lost Focus
+ Ocultar barra de herramientas
&Salir
Está usando la última versión.
QuickLook {0} está disponible. Haga clic aquí para abrir la página de descarga.
@@ -327,6 +336,7 @@
Ouvrir Le Dossier De Données
&Redémarrer
Close on Lost Focus
+ Masquer la barre d'outils
&Quitter
Vous êtes maintenant sur la dernière version.
QuickLook {0} est disponible. Cliquez ici pour ouvrir la page de téléchargement.
@@ -361,6 +371,7 @@
Apri Cartella Dati
&Riavvia
Close on Lost Focus
+ Nascondi barra degli strumenti
&Esci
Stai usando l'ultima versione.
QuickLook {0} è disponibile. Fai click qui per aprire la pagina di download.
@@ -399,6 +410,7 @@
データフォルダーを開く
再起動(&R)
フォーカスが外れたら閉じる
+ ツールバーを隠す
終了(&Q)
最新版です
QuickLook {0} がリリースされました。ここをクリックするとダウンロードページを開きます。
@@ -429,6 +441,7 @@
Åpne Datamappen
&Start på nytt
Close on Lost Focus
+ Skjul verktøylinje
&Avslutt
Du bruker nå siste versjon.
QuickLook {0} er kommet ut. Klikk her for å åpne nedlastingssiden.
@@ -458,6 +471,7 @@
Open Gegevensmap
&Opnieuw starten
Close on Lost Focus
+ Werkbalk verbergen
&Sluiten
U heeft de meest recente versie.
QuickLook {0} is gereleased. Klik hier om de downloadpagina te openen.
@@ -496,6 +510,7 @@
Otwórz Folder Danych
&Uruchom ponownie
Close on Lost Focus
+ Ukryj pasek narzędzi
&Zakończ
Używasz już najnowszej wersji.
QuickLook {0} jest dostępny. Kliknij tutaj, aby otworzyć stronę z aktualizacją do pobrania.
@@ -535,6 +550,7 @@
Abrir Pasta de Dados
&Reiniciar
Close on Lost Focus
+ Ocultar barra de ferramentas
&Fechar
Executando a versão mais recente.
Nova versão disponível. QuickLook {0}. Clique aqui para abrir a página de download.
@@ -565,6 +581,7 @@
Abrir Pasta De Dados
&Reiniciar
Close on Lost Focus
+ Ocultar barra de ferramentas
&Fechar
Está a executar a versão mais recente.
Está disponível o QuickLook {0}. Clique aqui para abrir a página de download.
@@ -601,6 +618,7 @@
Открыть Папку Данных
&Перезапуск
Close on Lost Focus
+ Скрыть панель инструментов
&Выход
Вы используете последнюю версию.
Выпущен QuickLook {0}. Нажмите здесь для перехода на страницу загрузки.
@@ -632,6 +650,7 @@
Veri Klasörünü Aç
Yeniden &Başlat
Close on Lost Focus
+ Araç çubuğunu gizle
Çı&kış
Son sürümü kullanıyorsunuz.
QuickLook {0} sürümü yayınladı. İndirme sayfasını açmak için buraya tıklayın.
@@ -670,6 +689,7 @@
Відкрити Папку Даних
&Перезавантажити
Close on Lost Focus
+ Сховати панель інструментів
&Вийти
Ви зараз на самій свіжій версії.
Випущено QuickLook {0}. Натисніть тут, щоб відкрити сторінку завантаження.
@@ -700,6 +720,7 @@
Mở Thư Mục Dữ Liệu
&Khởi động lại
Close on Lost Focus
+ Ẩn thanh công cụ
&Thoát
Bạn hiện đang sử dụng phiên bản mới nhất.
Đã có phiên bản QuickLook {0}. Nhấp vào đây để mở trang tải xuống.
@@ -738,6 +759,7 @@
打开数据文件夹
重启 (&R)
失去焦点时关闭
+ 隐藏工具栏
退出 (&Q)
当前已是最新版本
发现新版本:QuickLook {0} 点击这里打开下载页面
@@ -777,6 +799,7 @@
開啟資料夾
重啟 (&R)
失去焦點時關閉
+ 隱藏工具列
結束 Quicklook (&Q)
您正在使用最新版本。
QuickLook {0} 新版本已發布。請按一下此處開啟下載頁面。
@@ -809,6 +832,7 @@
डेटा फोल्डर उघडा
&पुनः आरंभ
Close on Lost Focus
+ टूलबार लपवा
&बंद करा
आपण आता नवीनतम आवृत्ती वापरत आहात.
QuickLook ची नवीन आवृत्ती {0} उपलब्ध आहे. डाउनलोड पृष्ठ उघडण्यासाठी येथे क्लिक करा.
@@ -838,6 +862,7 @@
डेटा फ़ोल्डर खोलें
&पुनः प्रारंभ करें
Close on Lost Focus
+ टूलबार छिपाएँ
&बंद किजीए
अब आप नवीनतम संस्करण पर हैं।
QuickLook का नया संस्करण उपलब्ध है। डाउनलोड पेज खोलने के लिए यहां क्लिक करें।
@@ -869,6 +894,7 @@
פתח את תיקיית הנתונים
&אתחול מחדש
Close on Lost Focus
+ הסתר סרגל כלים
&צא
אתה כעת על הגרסא האחרונה
'תצוגה מהירה' {0} שוחררה. לחץ כאן על מנת להוריד את העדכון
@@ -899,6 +925,7 @@
Άνοιγμα Φακέλου Δεδομένων
&Επανεκκίνηση
Close on Lost Focus
+ Απόκρυψη γραμμής εργαλείων
&Κλείσιμο
Έχετε την πιο πρόσφατη έκδοση.
Διαθέσιμη ενημέρωση {0} βρέθηκε. Κάντε κλικ εδώ για να ανοίξετε τη σελίδα λήψης.
@@ -934,6 +961,7 @@
Öppna datamappen
&Starta om
Close on Lost Focus
+ Dölj verktygsfältet
&Avsluta
Du har den senaste versionen.
QuickLook {0} har lanserats. Klicka här för att öppna nedladdningssidan.
@@ -971,6 +999,7 @@
Deschideți folderul Date
&Repornire
Close on Lost Focus
+ Ascunde bara de instrumente
&Ieșire
Acum utilizați cea mai recentă versiune.
A fost lansat QuickLook {0}. Faceți clic aici pentru a deschide pagina de descărcare.
diff --git a/QuickLook/TrayIconManager.cs b/QuickLook/TrayIconManager.cs
index e07ee3b70..0cd3b44e5 100644
--- a/QuickLook/TrayIconManager.cs
+++ b/QuickLook/TrayIconManager.cs
@@ -38,6 +38,7 @@ internal partial class TrayIconManager : IDisposable
private readonly TrayMenuItem _itemAutorun = null!;
private readonly TrayMenuItem _itemCloseOnLostFocus = null!;
+ private readonly TrayMenuItem _itemHideToolbar = null!;
private TrayIconManager()
{
@@ -95,6 +96,15 @@ private TrayIconManager()
SettingHelper.Set("CloseOnLostFocus", !current);
}),
},
+ _itemHideToolbar = new TrayMenuItem()
+ {
+ Header = TranslationHelper.Get("Icon_HideToolbar"),
+ Command = new RelayCommand(() =>
+ {
+ var current = SettingHelper.Get("HideToolbar", false);
+ SettingHelper.Set("HideToolbar", !current);
+ }),
+ },
new TrayMenuItem()
{
Header = TranslationHelper.Get("Icon_Restart"),
@@ -113,6 +123,7 @@ private TrayIconManager()
{
_itemAutorun.IsChecked = AutoStartupHelper.IsAutorun();
_itemCloseOnLostFocus.IsChecked = SettingHelper.Get("CloseOnLostFocus", false);
+ _itemHideToolbar.IsChecked = SettingHelper.Get("HideToolbar", false);
};
}
diff --git a/QuickLook/ViewWindowManager.cs b/QuickLook/ViewWindowManager.cs
index e18fc7004..69d6faabb 100644
--- a/QuickLook/ViewWindowManager.cs
+++ b/QuickLook/ViewWindowManager.cs
@@ -22,6 +22,9 @@
using System.Diagnostics;
using System.IO;
using System.Runtime.ExceptionServices;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Threading;
namespace QuickLook;
@@ -31,6 +34,8 @@ public class ViewWindowManager : IDisposable
private string _invokedPath = string.Empty;
private ViewerWindow _viewerWindow;
+ private readonly SemaphoreSlim _pluginMatchLock = new(1, 1);
+ private int _previewRequestId;
internal ViewWindowManager()
{
@@ -66,6 +71,8 @@ public void RunAndClosePreview()
public void ClosePreview()
{
+ _previewRequestId++;
+
if (!_viewerWindow.IsVisible)
return;
@@ -163,10 +170,7 @@ public void InvokePreview(string path = null)
_invokedPath = path;
RunFocusMonitor();
-
- var matchedPlugin = PluginManager.GetInstance().FindMatch(path);
-
- BeginShowNewWindow(path, matchedPlugin);
+ BeginPreviewRequest(path);
}
public void InvokePluginPreview(string plugin, string path = null)
@@ -194,6 +198,7 @@ public void InvokePluginPreview(string plugin, string path = null)
if (matchedPlugin != null)
{
+ _previewRequestId++;
BeginShowNewWindow(path, matchedPlugin);
}
}
@@ -203,9 +208,7 @@ public void ReloadPreview()
if (!_viewerWindow.IsVisible || string.IsNullOrEmpty(_invokedPath))
return;
- var matchedPlugin = PluginManager.GetInstance().FindMatch(_invokedPath);
-
- BeginShowNewWindow(_invokedPath, matchedPlugin);
+ BeginPreviewRequest(_invokedPath);
}
public void ToggleFullscreen()
@@ -223,6 +226,49 @@ private void BeginShowNewWindow(string path, IViewer matchedPlugin)
_viewerWindow.BeginShow(matchedPlugin, path, CurrentPluginFailed);
}
+ private void BeginPreviewRequest(string path)
+ {
+ var requestId = ++_previewRequestId;
+
+ _viewerWindow.UnloadPlugin();
+ _viewerWindow.BeginLoading(path);
+
+ _ = FindPluginAndShowAsync(path, requestId);
+ }
+
+ private async Task FindPluginAndShowAsync(string path, int requestId)
+ {
+ await _pluginMatchLock.WaitAsync();
+
+ try
+ {
+ if (requestId != _previewRequestId)
+ return;
+
+ var matchedPlugin = await Task.Run(() => PluginManager.GetInstance().FindMatch(path));
+
+ if (requestId != _previewRequestId || !_viewerWindow.IsVisible)
+ return;
+
+ // Let WPF draw the loading window before a plugin runs its preparation step.
+ await _viewerWindow.Dispatcher.InvokeAsync(() => { }, DispatcherPriority.ApplicationIdle);
+
+ if (requestId != _previewRequestId || !_viewerWindow.IsVisible)
+ return;
+
+ BeginShowNewWindow(path, matchedPlugin);
+ }
+ catch (Exception e)
+ {
+ if (requestId == _previewRequestId && _viewerWindow.IsVisible)
+ CurrentPluginFailed(path, ExceptionDispatchInfo.Capture(e));
+ }
+ finally
+ {
+ _pluginMatchLock.Release();
+ }
+ }
+
private void CurrentPluginFailed(string path, ExceptionDispatchInfo e)
{
var plugin = _viewerWindow.Plugin?.GetType();
diff --git a/QuickLook/ViewerWindow.Actions.cs b/QuickLook/ViewerWindow.Actions.cs
index c5fb50506..d07090491 100644
--- a/QuickLook/ViewerWindow.Actions.cs
+++ b/QuickLook/ViewerWindow.Actions.cs
@@ -294,6 +294,8 @@ internal void BeginShow(IViewer matchedPlugin, string path,
return;
}
+ HideToolbar = SettingHelper.Get("HideToolbar", false);
+
if (ContextObject.IsBlocked)
{
ContextObject.ViewerContent = new System.Windows.Controls.TextBlock
@@ -393,6 +395,47 @@ internal void BeginShow(IViewer matchedPlugin, string path,
}, DispatcherPriority.Input);
}
+ ///
+ /// Shows the window in a loading state before the plugin for is known,
+ /// so slow plugin matching does not leave the user without feedback.
+ ///
+ internal void BeginLoading(string path)
+ {
+ _path = path;
+ ContextObject.Reset();
+ ContextObject.Title = Path.GetFileName(path);
+ ContextObject.PreferredSize = new Size(800, 600);
+ ContextObject.IsBusy = true;
+
+ HideToolbar = SettingHelper.Get("HideToolbar", false);
+
+ var newHeight = ContextObject.PreferredSize.Height + BorderThickness.Top + BorderThickness.Bottom +
+ (ContextObject.TitlebarOverlap ? 0 : windowCaptionContainer.Height);
+ var newWidth = ContextObject.PreferredSize.Width + BorderThickness.Left + BorderThickness.Right;
+ var newSize = _customWindowSize == Size.Empty
+ ? new Size(newWidth, newHeight)
+ : _customWindowSize;
+
+ if (_customWindowSize == Size.Empty)
+ _ignoreNextWindowSizeChange = true;
+
+ PositionWindow(newSize);
+
+ if (IsVisible)
+ return;
+
+ Dispatcher.BeginInvoke(new Action(() =>
+ {
+ this.BringToFront(Topmost);
+ if (SettingHelper.Get("FocusWindowOnOpen", false))
+ Activate();
+ }), DispatcherPriority.Render);
+ if (!SettingHelper.Get("ShowWindowTransition", true, "QuickLook"))
+ this.ShowWithoutTransition();
+ else
+ Show();
+ }
+
private void ClearMoreMenuUnpin()
{
var toRemove = buttonMore.ContextMenu.Items
diff --git a/QuickLook/ViewerWindow.Properties.cs b/QuickLook/ViewerWindow.Properties.cs
index 5f628e384..6aa7fdf90 100644
--- a/QuickLook/ViewerWindow.Properties.cs
+++ b/QuickLook/ViewerWindow.Properties.cs
@@ -44,6 +44,20 @@ public partial class ViewerWindow : INotifyPropertyChanged
private Rect _preFullscreenBounds;
private double _preFullscreenCaptionHeight;
private Thickness _preFullscreenResizeBorderThickness;
+ private bool _hideToolbar;
+
+ public bool HideToolbar
+ {
+ get => _hideToolbar;
+ private set
+ {
+ if (value == _hideToolbar)
+ return;
+
+ _hideToolbar = value;
+ OnPropertyChanged();
+ }
+ }
public bool Pinned
{
diff --git a/QuickLook/ViewerWindow.xaml b/QuickLook/ViewerWindow.xaml
index 147cf9bc1..f6202c8f6 100644
--- a/QuickLook/ViewerWindow.xaml
+++ b/QuickLook/ViewerWindow.xaml
@@ -61,6 +61,9 @@
+
+
+
@@ -71,12 +74,11 @@
To="1"
Duration="0:0:0.05" />
-
+
-
-
+
@@ -229,7 +231,18 @@
+ Visibility="{Binding ContextObject.TitlebarOverlap, ElementName=mainWindow, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}">
+
+
+
+
_ignoreNextWindowSizeChange = true;
windowFrameContainer.PreviewMouseMove += ShowWindowCaptionContainer;
+ windowCaptionContainer.MouseLeave += HideWindowCaptionContainer;
+ _toolbarCursorTimer.Tick += UpdateToolbarVisibility;
+ _toolbarCursorTimer.Start();
Topmost = SettingHelper.Get("Topmost", false);
buttonTop.Tag = Topmost ? "Top" : "Auto";
@@ -458,25 +464,98 @@ private void SaveWindowSizeOnSizeChanged(object sender, SizeChangedEventArgs e)
private void ShowWindowCaptionContainer(object sender, MouseEventArgs e)
{
- var show = (Storyboard)windowCaptionContainer.FindResource("ShowCaptionContainerStoryboard");
+ if (HideToolbar)
+ return;
- if (windowCaptionContainer.Opacity == 0 || windowCaptionContainer.Opacity == 1)
- show.Begin();
+ ShowToolbar();
}
private void AutoHideCaptionContainer(object sender, EventArgs e)
{
- if (!ContextObject.TitlebarAutoHide)
+ _toolbarAnimationRunning = false;
+
+ if (!ContextObject.TitlebarAutoHide && !HideToolbar)
return;
- if (!ContextObject.TitlebarOverlap)
+ if (!ContextObject.TitlebarOverlap && !HideToolbar)
return;
- if (windowCaptionContainer.IsMouseOver)
+ if (windowCaptionContainer.IsMouseOver || IsPointerInToolbarKeepVisibleZone())
return;
- var hide = (Storyboard)windowCaptionContainer.FindResource("HideCaptionContainerStoryboard");
+ HideToolbarWithAnimation();
+ }
+
+ private void HideWindowCaptionContainer(object sender, MouseEventArgs e)
+ {
+ if (!HideToolbar || IsPointerInToolbarKeepVisibleZone())
+ return;
+
+ HideToolbarWithAnimation();
+ }
+
+ private void UpdateToolbarVisibility(object sender, EventArgs e)
+ {
+ if (!HideToolbar || !IsVisible || PresentationSource.FromVisual(windowFrameContainer) is null)
+ return;
+
+ if (IsPointerInToolbarRevealZone())
+ ShowToolbar();
+ else if (windowCaptionContainer.Opacity >= 0.99 && !IsPointerInToolbarKeepVisibleZone())
+ HideToolbarWithAnimation();
+ }
+
+ private void ShowToolbar()
+ {
+ if (_toolbarAnimationRunning || !HideToolbar && !ContextObject.TitlebarAutoHide || windowCaptionContainer.Opacity > 0.01)
+ return;
+
+ _toolbarAnimationRunning = true;
+ var show = (Storyboard)windowCaptionContainer.FindResource("ShowCaptionContainerStoryboard");
+ show.Begin();
+ }
+
+ private void HideToolbarWithAnimation()
+ {
+ if (_toolbarAnimationRunning)
+ return;
+ _toolbarAnimationRunning = true;
+ var hide = (Storyboard)windowCaptionContainer.FindResource("HideCaptionContainerStoryboard");
hide.Begin();
}
+
+ private void FinishToolbarAnimation(object sender, EventArgs e)
+ {
+ _toolbarAnimationRunning = false;
+ }
+
+ private bool IsPointerInToolbarRevealZone()
+ {
+ return GetPointerY() <= GetToolbarRevealHeight();
+ }
+
+ private bool IsPointerInToolbarKeepVisibleZone()
+ {
+ return GetPointerY() <= GetToolbarKeepVisibleHeight();
+ }
+
+ private double GetPointerY()
+ {
+ if (!IsVisible || PresentationSource.FromVisual(windowFrameContainer) is null)
+ return double.PositiveInfinity;
+
+ var origin = windowFrameContainer.PointToScreen(new Point(0, 0));
+ return Forms.Cursor.Position.Y - origin.Y;
+ }
+
+ private double GetToolbarRevealHeight()
+ {
+ return ActualHeight * 0.35;
+ }
+
+ private double GetToolbarKeepVisibleHeight()
+ {
+ return ActualHeight * 0.45;
+ }
}
diff --git a/Scripts/update-version.ps1 b/Scripts/update-version.ps1
index 58c4c6871..b47b2215e 100644
--- a/Scripts/update-version.ps1
+++ b/Scripts/update-version.ps1
@@ -1,6 +1,10 @@
$tag = git describe --always --tags "--abbrev=0" --exclude latest
$revision = git describe --always --tags --exclude latest
+if ($tag -notmatch '^\d+(\.\d+){0,3}$') {
+ $tag = '0.0.0.0'
+}
+
$text = @"
// This file is generated by update-version.ps1