mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-11 09:49:07 +00:00
Async busy indicator; Change plugin interface, and more
This commit is contained in:
@@ -45,17 +45,19 @@ namespace QuickLook.Plugin.ArchiveViewer
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Prepare(string path, ViewContentContainer container)
|
public void BoundViewSize(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
container.PreferedSize = new Size {Width = 800, Height = 600};
|
context.PreferredSize = new Size {Width = 800, Height = 600};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void View(string path, ViewContentContainer container)
|
public void View(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
_panel = new ArchiveInfoPanel(path);
|
_panel = new ArchiveInfoPanel(path);
|
||||||
|
|
||||||
container.SetContent(_panel);
|
context.ViewerContent = _panel;
|
||||||
container.Title = $"{Path.GetFileName(path)}";
|
context.Title = $"{Path.GetFileName(path)}";
|
||||||
|
|
||||||
|
context.IsBusy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@@ -33,19 +33,21 @@ namespace QuickLook.Plugin.ImageViewer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Prepare(string path, ViewContentContainer container)
|
public void BoundViewSize(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
_imageSize = ImageFileHelper.GetImageSize(path);
|
_imageSize = ImageFileHelper.GetImageSize(path);
|
||||||
|
|
||||||
container.SetPreferedSizeFit(_imageSize, 0.8);
|
context.SetPreferredSizeFit(_imageSize, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void View(string path, ViewContentContainer container)
|
public void View(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
_ip = new ImagePanel(path);
|
_ip = new ImagePanel(path);
|
||||||
|
|
||||||
container.SetContent(_ip);
|
context.ViewerContent = _ip;
|
||||||
container.Title = $"{Path.GetFileName(path)} ({_imageSize.Width} × {_imageSize.Height})";
|
context.Title = $"{Path.GetFileName(path)} ({_imageSize.Width} × {_imageSize.Height})";
|
||||||
|
|
||||||
|
context.IsBusy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@@ -31,12 +31,12 @@ namespace QuickLook.Plugin.OfficeViewer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Prepare(string path, ViewContentContainer container)
|
public void BoundViewSize(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
container.SetPreferedSizeFit(new Size {Width = 800, Height = 600}, 0.8);
|
context.SetPreferredSizeFit(new Size {Width = 800, Height = 600}, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void View(string path, ViewContentContainer container)
|
public void View(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
using (var officeApp = new OfficeInteropWrapper(path))
|
using (var officeApp = new OfficeInteropWrapper(path))
|
||||||
{
|
{
|
||||||
@@ -59,12 +59,14 @@ namespace QuickLook.Plugin.OfficeViewer
|
|||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.Title = $"{Path.GetFileName(path)} (1 / {_pdfViewer.TotalPages})";
|
context.Title = $"{Path.GetFileName(path)} (1 / {_pdfViewer.TotalPages})";
|
||||||
};
|
};
|
||||||
_pdfViewer.CurrentPageChanged += (sender, e) => container.Title =
|
_pdfViewer.CurrentPageChanged += (sender, e) => context.Title =
|
||||||
$"{Path.GetFileName(path)} ({_pdfViewer.CurrectPage + 1} / {_pdfViewer.TotalPages})";
|
$"{Path.GetFileName(path)} ({_pdfViewer.CurrectPage + 1} / {_pdfViewer.TotalPages})";
|
||||||
|
|
||||||
container.SetContent(_pdfViewer);
|
context.ViewerContent = _pdfViewer;
|
||||||
|
|
||||||
|
context.IsBusy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@@ -7,6 +7,7 @@ namespace QuickLook.Plugin.PDFViewer
|
|||||||
public class Plugin : IViewer
|
public class Plugin : IViewer
|
||||||
{
|
{
|
||||||
private PdfViewerControl _pdfControl;
|
private PdfViewerControl _pdfControl;
|
||||||
|
|
||||||
public int Priority => int.MaxValue;
|
public int Priority => int.MaxValue;
|
||||||
|
|
||||||
public bool CanHandle(string path)
|
public bool CanHandle(string path)
|
||||||
@@ -23,26 +24,28 @@ namespace QuickLook.Plugin.PDFViewer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Prepare(string path, ViewContentContainer container)
|
public void BoundViewSize(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
_pdfControl = new PdfViewerControl();
|
_pdfControl = new PdfViewerControl();
|
||||||
|
|
||||||
var desiredSize = _pdfControl.GetDesiredControlSizeByFirstPage(path);
|
var desiredSize = _pdfControl.GetDesiredControlSizeByFirstPage(path);
|
||||||
|
|
||||||
container.SetPreferedSizeFit(desiredSize, 0.8);
|
context.SetPreferredSizeFit(desiredSize, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void View(string path, ViewContentContainer container)
|
public void View(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
container.SetContent(_pdfControl);
|
context.ViewerContent = _pdfControl;
|
||||||
|
|
||||||
_pdfControl.Loaded += (sender, e) =>
|
_pdfControl.Loaded += (sender, e) =>
|
||||||
{
|
{
|
||||||
_pdfControl.LoadPdf(path);
|
_pdfControl.LoadPdf(path);
|
||||||
|
|
||||||
container.Title = $"{Path.GetFileName(path)} (1 / {_pdfControl.TotalPages})";
|
context.Title = $"{Path.GetFileName(path)} (1 / {_pdfControl.TotalPages})";
|
||||||
_pdfControl.CurrentPageChanged += (sender2, e2) => container.Title =
|
_pdfControl.CurrentPageChanged += (sender2, e2) => context.Title =
|
||||||
$"{Path.GetFileName(path)} ({_pdfControl.CurrectPage + 1} / {_pdfControl.TotalPages})";
|
$"{Path.GetFileName(path)} ({_pdfControl.CurrectPage + 1} / {_pdfControl.TotalPages})";
|
||||||
|
|
||||||
|
context.IsBusy = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -40,17 +40,19 @@ namespace QuickLook.Plugin.TextViewer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Prepare(string path, ViewContentContainer container)
|
public void BoundViewSize(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
container.PreferedSize = new Size {Width = 800, Height = 600};
|
context.PreferredSize = new Size {Width = 800, Height = 600};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void View(string path, ViewContentContainer container)
|
public void View(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
_tvp = new TextViewerPanel(path);
|
_tvp = new TextViewerPanel(path);
|
||||||
|
|
||||||
container.SetContent(_tvp);
|
context.ViewerContent = _tvp;
|
||||||
container.Title = $"{Path.GetFileName(path)}";
|
context.Title = $"{Path.GetFileName(path)}";
|
||||||
|
|
||||||
|
context.IsBusy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="Styles/ScrollBarStyleDictionary.xaml" />
|
<ResourceDictionary Source="Styles/ScrollBarStyleDictionary.xaml" />
|
||||||
|
<ResourceDictionary Source="Styles/BusyDecorator.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
|
184
QuickLook/Controls/BackgroundVisualHost.cs
Normal file
184
QuickLook/Controls/BackgroundVisualHost.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace QuickLook.Controls
|
||||||
|
{
|
||||||
|
public delegate Visual CreateContentFunction();
|
||||||
|
|
||||||
|
public class BackgroundVisualHost : FrameworkElement
|
||||||
|
{
|
||||||
|
protected override int VisualChildrenCount => _hostVisual != null ? 1 : 0;
|
||||||
|
|
||||||
|
protected override IEnumerator LogicalChildren
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_hostVisual != null)
|
||||||
|
yield return _hostVisual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Visual GetVisualChild(int index)
|
||||||
|
{
|
||||||
|
if (_hostVisual != null && index == 0)
|
||||||
|
return _hostVisual;
|
||||||
|
|
||||||
|
throw new IndexOutOfRangeException("index");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateContentHelper()
|
||||||
|
{
|
||||||
|
_threadedHelper = new ThreadedVisualHelper(CreateContent, SafeInvalidateMeasure);
|
||||||
|
_hostVisual = _threadedHelper.HostVisual;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SafeInvalidateMeasure()
|
||||||
|
{
|
||||||
|
Dispatcher.BeginInvoke(new Action(InvalidateMeasure), DispatcherPriority.Loaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HideContentHelper()
|
||||||
|
{
|
||||||
|
if (_threadedHelper != null)
|
||||||
|
{
|
||||||
|
_threadedHelper.Exit();
|
||||||
|
_threadedHelper = null;
|
||||||
|
InvalidateMeasure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
|
{
|
||||||
|
if (_threadedHelper != null)
|
||||||
|
return _threadedHelper.DesiredSize;
|
||||||
|
|
||||||
|
return base.MeasureOverride(availableSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ThreadedVisualHelper
|
||||||
|
{
|
||||||
|
private readonly CreateContentFunction _createContent;
|
||||||
|
private readonly Action _invalidateMeasure;
|
||||||
|
private readonly AutoResetEvent _sync =
|
||||||
|
new AutoResetEvent(false);
|
||||||
|
|
||||||
|
public ThreadedVisualHelper(
|
||||||
|
CreateContentFunction createContent,
|
||||||
|
Action invalidateMeasure)
|
||||||
|
{
|
||||||
|
HostVisual = new HostVisual();
|
||||||
|
_createContent = createContent;
|
||||||
|
_invalidateMeasure = invalidateMeasure;
|
||||||
|
|
||||||
|
var backgroundUi = new Thread(CreateAndShowContent);
|
||||||
|
backgroundUi.SetApartmentState(ApartmentState.STA);
|
||||||
|
backgroundUi.Name = "BackgroundVisualHostThread";
|
||||||
|
backgroundUi.IsBackground = true;
|
||||||
|
backgroundUi.Start();
|
||||||
|
|
||||||
|
_sync.WaitOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HostVisual HostVisual { get; }
|
||||||
|
public Size DesiredSize { get; private set; }
|
||||||
|
private Dispatcher Dispatcher { get; set; }
|
||||||
|
|
||||||
|
public void Exit()
|
||||||
|
{
|
||||||
|
Dispatcher.BeginInvokeShutdown(DispatcherPriority.Send);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateAndShowContent()
|
||||||
|
{
|
||||||
|
Dispatcher = Dispatcher.CurrentDispatcher;
|
||||||
|
var source =
|
||||||
|
new VisualTargetPresentationSource(HostVisual);
|
||||||
|
_sync.Set();
|
||||||
|
source.RootVisual = _createContent();
|
||||||
|
DesiredSize = source.DesiredSize;
|
||||||
|
_invalidateMeasure();
|
||||||
|
|
||||||
|
Dispatcher.Run();
|
||||||
|
source.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Private Fields
|
||||||
|
|
||||||
|
private ThreadedVisualHelper _threadedHelper;
|
||||||
|
private HostVisual _hostVisual;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IsContentShowingProperty
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the IsContentShowing dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty IsContentShowingProperty = DependencyProperty.Register(
|
||||||
|
"IsContentShowing",
|
||||||
|
typeof(bool),
|
||||||
|
typeof(BackgroundVisualHost),
|
||||||
|
new FrameworkPropertyMetadata(false, OnIsContentShowingChanged));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the content is being displayed.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsContentShowing
|
||||||
|
{
|
||||||
|
get => (bool) GetValue(IsContentShowingProperty);
|
||||||
|
set => SetValue(IsContentShowingProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnIsContentShowingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var bvh = (BackgroundVisualHost) d;
|
||||||
|
|
||||||
|
if (bvh.CreateContent != null)
|
||||||
|
if ((bool) e.NewValue)
|
||||||
|
bvh.CreateContentHelper();
|
||||||
|
else
|
||||||
|
bvh.HideContentHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region CreateContent Property
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the CreateContent dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty CreateContentProperty = DependencyProperty.Register(
|
||||||
|
"CreateContent",
|
||||||
|
typeof(CreateContentFunction),
|
||||||
|
typeof(BackgroundVisualHost),
|
||||||
|
new FrameworkPropertyMetadata(OnCreateContentChanged));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the function used to create the visual to display in a background thread.
|
||||||
|
/// </summary>
|
||||||
|
public CreateContentFunction CreateContent
|
||||||
|
{
|
||||||
|
get => (CreateContentFunction) GetValue(CreateContentProperty);
|
||||||
|
set => SetValue(CreateContentProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnCreateContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var bvh = (BackgroundVisualHost) d;
|
||||||
|
|
||||||
|
if (bvh.IsContentShowing)
|
||||||
|
{
|
||||||
|
bvh.HideContentHelper();
|
||||||
|
if (e.NewValue != null)
|
||||||
|
bvh.CreateContentHelper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
197
QuickLook/Controls/BusyDecorator.cs
Normal file
197
QuickLook/Controls/BusyDecorator.cs
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace QuickLook.Controls
|
||||||
|
{
|
||||||
|
[StyleTypedProperty(Property = "BusyStyle", StyleTargetType = typeof(Control))]
|
||||||
|
public class BusyDecorator : Decorator
|
||||||
|
{
|
||||||
|
private readonly BackgroundVisualHost _busyHost = new BackgroundVisualHost();
|
||||||
|
|
||||||
|
static BusyDecorator()
|
||||||
|
{
|
||||||
|
DefaultStyleKeyProperty.OverrideMetadata(
|
||||||
|
typeof(BusyDecorator),
|
||||||
|
new FrameworkPropertyMetadata(typeof(BusyDecorator)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusyDecorator()
|
||||||
|
{
|
||||||
|
AddLogicalChild(_busyHost);
|
||||||
|
AddVisualChild(_busyHost);
|
||||||
|
|
||||||
|
SetBinding(_busyHost, IsBusyIndicatorShowingProperty, BackgroundVisualHost.IsContentShowingProperty);
|
||||||
|
SetBinding(_busyHost, BusyHorizontalAlignmentProperty, HorizontalAlignmentProperty);
|
||||||
|
SetBinding(_busyHost, BusyVerticalAlignmentProperty, VerticalAlignmentProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int VisualChildrenCount => Child != null ? 2 : 1;
|
||||||
|
|
||||||
|
protected override IEnumerator LogicalChildren
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Child != null)
|
||||||
|
yield return Child;
|
||||||
|
|
||||||
|
yield return _busyHost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Visual GetVisualChild(int index)
|
||||||
|
{
|
||||||
|
if (Child != null)
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return Child;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return _busyHost;
|
||||||
|
}
|
||||||
|
else if (index == 0)
|
||||||
|
return _busyHost;
|
||||||
|
|
||||||
|
throw new IndexOutOfRangeException("index");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetBinding(DependencyObject obj, DependencyProperty source, DependencyProperty target)
|
||||||
|
{
|
||||||
|
var b = new Binding();
|
||||||
|
b.Source = this;
|
||||||
|
b.Path = new PropertyPath(source);
|
||||||
|
BindingOperations.SetBinding(obj, target, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(Size constraint)
|
||||||
|
{
|
||||||
|
var ret = new Size(0, 0);
|
||||||
|
if (Child != null)
|
||||||
|
{
|
||||||
|
Child.Measure(constraint);
|
||||||
|
ret = Child.DesiredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
_busyHost.Measure(constraint);
|
||||||
|
|
||||||
|
return new Size(Math.Max(ret.Width, _busyHost.DesiredSize.Width),
|
||||||
|
Math.Max(ret.Height, _busyHost.DesiredSize.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size ArrangeOverride(Size arrangeSize)
|
||||||
|
{
|
||||||
|
var ret = new Size(0, 0);
|
||||||
|
if (Child != null)
|
||||||
|
{
|
||||||
|
Child.Arrange(new Rect(arrangeSize));
|
||||||
|
ret = Child.RenderSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
_busyHost.Arrange(new Rect(arrangeSize));
|
||||||
|
|
||||||
|
return new Size(Math.Max(ret.Width, _busyHost.RenderSize.Width),
|
||||||
|
Math.Max(ret.Height, _busyHost.RenderSize.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IsBusyIndicatorShowing Property
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the IsBusyIndicatorShowing dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty IsBusyIndicatorShowingProperty = DependencyProperty.Register(
|
||||||
|
"IsBusyIndicatorShowing",
|
||||||
|
typeof(bool),
|
||||||
|
typeof(BusyDecorator),
|
||||||
|
new FrameworkPropertyMetadata(false,
|
||||||
|
FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the BusyIndicator is being shown.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsBusyIndicatorShowing
|
||||||
|
{
|
||||||
|
get => (bool) GetValue(IsBusyIndicatorShowingProperty);
|
||||||
|
set => SetValue(IsBusyIndicatorShowingProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region BusyStyle
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="BusyStyle" /> property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty BusyStyleProperty =
|
||||||
|
DependencyProperty.Register(
|
||||||
|
"BusyStyle",
|
||||||
|
typeof(Style),
|
||||||
|
typeof(BusyDecorator),
|
||||||
|
new FrameworkPropertyMetadata(OnBusyStyleChanged));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Style to apply to the Control that is displayed as the busy indication.
|
||||||
|
/// </summary>
|
||||||
|
public Style BusyStyle
|
||||||
|
{
|
||||||
|
get => (Style) GetValue(BusyStyleProperty);
|
||||||
|
set => SetValue(BusyStyleProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnBusyStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var bd = (BusyDecorator) d;
|
||||||
|
var nVal = (Style) e.NewValue;
|
||||||
|
bd._busyHost.CreateContent = () => new Control {Style = nVal};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region BusyHorizontalAlignment
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="BusyHorizontalAlignment" /> property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty BusyHorizontalAlignmentProperty = DependencyProperty.Register(
|
||||||
|
"BusyHorizontalAlignment",
|
||||||
|
typeof(HorizontalAlignment),
|
||||||
|
typeof(BusyDecorator),
|
||||||
|
new FrameworkPropertyMetadata(HorizontalAlignment.Center));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the HorizontalAlignment to use to layout the control that contains the busy indicator control.
|
||||||
|
/// </summary>
|
||||||
|
public HorizontalAlignment BusyHorizontalAlignment
|
||||||
|
{
|
||||||
|
get => (HorizontalAlignment) GetValue(BusyHorizontalAlignmentProperty);
|
||||||
|
set => SetValue(BusyHorizontalAlignmentProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region BusyVerticalAlignment
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="BusyVerticalAlignment" /> property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty BusyVerticalAlignmentProperty = DependencyProperty.Register(
|
||||||
|
"BusyVerticalAlignment",
|
||||||
|
typeof(VerticalAlignment),
|
||||||
|
typeof(BusyDecorator),
|
||||||
|
new FrameworkPropertyMetadata(VerticalAlignment.Center));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the the VerticalAlignment to use to layout the control that contains the busy indicator.
|
||||||
|
/// </summary>
|
||||||
|
public VerticalAlignment BusyVerticalAlignment
|
||||||
|
{
|
||||||
|
get => (VerticalAlignment) GetValue(BusyVerticalAlignmentProperty);
|
||||||
|
set => SetValue(BusyVerticalAlignmentProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
64
QuickLook/Controls/VisualTargetPresentationSource.cs
Normal file
64
QuickLook/Controls/VisualTargetPresentationSource.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace QuickLook.Controls
|
||||||
|
{
|
||||||
|
public class VisualTargetPresentationSource : PresentationSource
|
||||||
|
{
|
||||||
|
private readonly VisualTarget _visualTarget;
|
||||||
|
private bool _isDisposed;
|
||||||
|
|
||||||
|
public VisualTargetPresentationSource(HostVisual hostVisual)
|
||||||
|
{
|
||||||
|
_visualTarget = new VisualTarget(hostVisual);
|
||||||
|
AddSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Size DesiredSize { get; private set; }
|
||||||
|
|
||||||
|
public override Visual RootVisual
|
||||||
|
{
|
||||||
|
get => _visualTarget.RootVisual;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var oldRoot = _visualTarget.RootVisual;
|
||||||
|
|
||||||
|
// Set the root visual of the VisualTarget. This visual will
|
||||||
|
// now be used to visually compose the scene.
|
||||||
|
_visualTarget.RootVisual = value;
|
||||||
|
|
||||||
|
// Tell the PresentationSource that the root visual has
|
||||||
|
// changed. This kicks off a bunch of stuff like the
|
||||||
|
// Loaded event.
|
||||||
|
RootChanged(oldRoot, value);
|
||||||
|
|
||||||
|
// Kickoff layout...
|
||||||
|
var rootElement = value as UIElement;
|
||||||
|
if (rootElement != null)
|
||||||
|
{
|
||||||
|
rootElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||||
|
rootElement.Arrange(new Rect(rootElement.DesiredSize));
|
||||||
|
|
||||||
|
DesiredSize = rootElement.DesiredSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DesiredSize = new Size(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsDisposed => _isDisposed;
|
||||||
|
|
||||||
|
protected override CompositionTarget GetCompositionTargetCore()
|
||||||
|
{
|
||||||
|
return _visualTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Dispose()
|
||||||
|
{
|
||||||
|
RemoveSource();
|
||||||
|
_isDisposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -3,9 +3,9 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
|
|
||||||
namespace QuickLook.Utilities
|
namespace QuickLook.Helpers
|
||||||
{
|
{
|
||||||
internal static class AeroGlass
|
internal static class AeroGlassHelper
|
||||||
{
|
{
|
||||||
internal static void EnableBlur(Window window)
|
internal static void EnableBlur(Window window)
|
||||||
{
|
{
|
46
QuickLook/Helpers/DpiHelpers.cs
Normal file
46
QuickLook/Helpers/DpiHelpers.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace QuickLook.Helpers
|
||||||
|
{
|
||||||
|
internal static class DpiHelper
|
||||||
|
{
|
||||||
|
public const float DEFAULT_DPI = 96;
|
||||||
|
|
||||||
|
public static Dpi GetCurrentDpi()
|
||||||
|
{
|
||||||
|
var g = Graphics.FromHwnd(IntPtr.Zero);
|
||||||
|
var desktop = g.GetHdc();
|
||||||
|
|
||||||
|
var dpi = new Dpi
|
||||||
|
{
|
||||||
|
HorizontalDpi = GetDeviceCaps(desktop, (int) DeviceCap.LOGPIXELSX),
|
||||||
|
VerticalDpi = GetDeviceCaps(desktop, (int) DeviceCap.LOGPIXELSY)
|
||||||
|
};
|
||||||
|
|
||||||
|
return dpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
|
||||||
|
public static extern int GetDeviceCaps(IntPtr hDC, int nIndex);
|
||||||
|
|
||||||
|
private enum DeviceCap
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Logical pixels inch in X
|
||||||
|
/// </summary>
|
||||||
|
LOGPIXELSX = 88,
|
||||||
|
/// <summary>
|
||||||
|
/// Logical pixels inch in Y
|
||||||
|
/// </summary>
|
||||||
|
LOGPIXELSY = 90
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Dpi
|
||||||
|
{
|
||||||
|
public float HorizontalDpi;
|
||||||
|
public float VerticalDpi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -3,7 +3,7 @@ using System.Text;
|
|||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using QuickLook.NativeMethods;
|
using QuickLook.NativeMethods;
|
||||||
|
|
||||||
namespace QuickLook.Utilities
|
namespace QuickLook.Helpers
|
||||||
{
|
{
|
||||||
internal static class WindowHelper
|
internal static class WindowHelper
|
||||||
{
|
{
|
@@ -2,72 +2,84 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
|
||||||
xmlns:local="clr-namespace:QuickLook"
|
xmlns:local="clr-namespace:QuickLook"
|
||||||
|
xmlns:control="clr-namespace:QuickLook.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:plugin="clr-namespace:QuickLook.Plugin"
|
|
||||||
mc:Ignorable="d" x:Class="QuickLook.MainWindow" x:Name="mainWindow"
|
mc:Ignorable="d" x:Class="QuickLook.MainWindow" x:Name="mainWindow"
|
||||||
UseLayoutRounding="True"
|
UseLayoutRounding="True"
|
||||||
Topmost="True" d:DesignWidth="624" d:DesignHeight="700"
|
d:DesignWidth="624" d:DesignHeight="700"
|
||||||
MinWidth="275" MinHeight="150"
|
MinWidth="275" MinHeight="150"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
x:ClassModifier="internal" Focusable="False"
|
x:ClassModifier="internal" Focusable="False"
|
||||||
ShowActivated="False" ShowInTaskbar="False" WindowStyle="None"
|
ShowActivated="False" ShowInTaskbar="False" WindowStyle="None"
|
||||||
ResizeMode="CanResizeWithGrip" AllowsTransparency="True">
|
ResizeMode="CanResizeWithGrip" AllowsTransparency="True">
|
||||||
<Window.Background>
|
<Window.Background>
|
||||||
<SolidColorBrush Color="#DFFFFFFF" />
|
<SolidColorBrush Color="#E5FAFAFA" />
|
||||||
</Window.Background>
|
</Window.Background>
|
||||||
<Border x:Name="windowBorder" BorderThickness="1" BorderBrush="#FF7B7B7B">
|
<Border x:Name="windowBorder" BorderThickness="1" BorderBrush="#FF7B7B7B">
|
||||||
<Grid>
|
<Grid>
|
||||||
<DockPanel Opacity="1">
|
<DockPanel x:Name="windowPanel" Opacity="1">
|
||||||
<DockPanel x:Name="titlebar" Height="28" Dock="Top">
|
<DockPanel.Style>
|
||||||
<DockPanel.Background>
|
|
||||||
<SolidColorBrush Color="#00B8B8B8" />
|
|
||||||
</DockPanel.Background>
|
|
||||||
<!--<DockPanel.Style>
|
|
||||||
<Style TargetType="{x:Type DockPanel}">
|
<Style TargetType="{x:Type DockPanel}">
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<Trigger Property="IsMouseOver" Value="True">
|
<DataTrigger Binding="{Binding ViewerObject.IsBusy, ElementName=mainWindow}" Value="False">
|
||||||
<Trigger.EnterActions>
|
<DataTrigger.EnterActions>
|
||||||
<BeginStoryboard>
|
<BeginStoryboard>
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Opacity"
|
<DoubleAnimation Storyboard.TargetProperty="Opacity"
|
||||||
To="1" />
|
From="0"
|
||||||
|
To="1"
|
||||||
|
BeginTime="0:0:0.1"
|
||||||
|
Duration="0:0:0.2" />
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</BeginStoryboard>
|
</BeginStoryboard>
|
||||||
</Trigger.EnterActions>
|
</DataTrigger.EnterActions>
|
||||||
<Trigger.ExitActions>
|
</DataTrigger>
|
||||||
<BeginStoryboard>
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation Duration="0:0:0.6" Storyboard.TargetProperty="Opacity"
|
|
||||||
To="0" />
|
|
||||||
</Storyboard>
|
|
||||||
</BeginStoryboard>
|
|
||||||
</Trigger.ExitActions>
|
|
||||||
</Trigger>
|
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</DockPanel.Style>-->
|
</DockPanel.Style>
|
||||||
<fa:ImageAwesome DockPanel.Dock="Right" x:Name="buttonCloseWindow" Icon="WindowClose" Height="15"
|
<DockPanel x:Name="titlebar" Height="28" Dock="Top">
|
||||||
Margin="10,0"
|
<fa:ImageAwesome DockPanel.Dock="Right" x:Name="buttonCloseWindow" Icon="TimesCircle"
|
||||||
|
Height="15" Margin="10,0" Foreground="Gray"
|
||||||
Cursor="Hand" />
|
Cursor="Hand" />
|
||||||
<Label x:Name="titlebarTitleArea" Content="{Binding Title, ElementName=viewContentContainer}"
|
<Label x:Name="titlebarTitleArea" Content="{Binding ViewerObject.Title, ElementName=mainWindow}"
|
||||||
FontSize="14" HorizontalContentAlignment="Center"
|
FontSize="14" HorizontalContentAlignment="Center"
|
||||||
VerticalContentAlignment="Center" />
|
VerticalContentAlignment="Center" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<Grid>
|
<Grid>
|
||||||
<plugin:ViewContentContainer x:Name="viewContentContainer" />
|
<local:ViewContentContainer x:Name="viewContentContainer" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<Grid x:Name="loadingIconLayer" Opacity="0.3">
|
<Grid x:Name="busyIndicatorLayer" Visibility="Hidden">
|
||||||
<Grid.Background>
|
<Grid.Style>
|
||||||
<SolidColorBrush Color="#FFFFFFFF" />
|
<Style TargetType="{x:Type Grid}">
|
||||||
</Grid.Background>
|
<Style.Triggers>
|
||||||
<Grid x:Name="loadingIcon" Height="50" Width="50" HorizontalAlignment="Center"
|
<DataTrigger Binding="{Binding ViewerObject.IsBusy, ElementName=mainWindow}" Value="False">
|
||||||
VerticalAlignment="Center">
|
<DataTrigger.EnterActions>
|
||||||
<fa:ImageAwesome Icon="CircleOutlineNotch" Spin="True" SpinDuration="1" />
|
<BeginStoryboard>
|
||||||
</Grid>
|
<Storyboard>
|
||||||
|
<ParallelTimeline>
|
||||||
|
<DoubleAnimation Storyboard.TargetProperty="Opacity"
|
||||||
|
From="1"
|
||||||
|
To="0"
|
||||||
|
BeginTime="0:0:0.1"
|
||||||
|
Duration="0:0:0.2" />
|
||||||
|
<ObjectAnimationUsingKeyFrames
|
||||||
|
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0.4"
|
||||||
|
Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</ParallelTimeline>
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</DataTrigger.EnterActions>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Grid.Style>
|
||||||
|
<control:BusyDecorator IsBusyIndicatorShowing="True" VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
@@ -1,54 +1,74 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using System.Windows.Media.Animation;
|
using QuickLook.Helpers;
|
||||||
using System.Windows.Threading;
|
|
||||||
using QuickLook.Annotations;
|
|
||||||
using QuickLook.ExtensionMethods;
|
|
||||||
using QuickLook.Plugin;
|
using QuickLook.Plugin;
|
||||||
using QuickLook.Utilities;
|
|
||||||
|
|
||||||
namespace QuickLook
|
namespace QuickLook
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for MainWindow.xaml
|
/// Interaction logic for MainWindow.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal partial class MainWindow : Window, INotifyPropertyChanged, IDisposable
|
internal partial class MainWindow : Window, IDisposable
|
||||||
{
|
{
|
||||||
internal MainWindow()
|
internal MainWindow()
|
||||||
{
|
{
|
||||||
|
// this object should be initialized before loading UI components, because many of which are binding to it.
|
||||||
|
ViewerObject = new ViewerObject();
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
DataContext = this;
|
// do not set TopMost property if we are now debugging. it makes debugging painful...
|
||||||
|
if (!Debugger.IsAttached)
|
||||||
|
Topmost = true;
|
||||||
|
|
||||||
ContentRendered += (sender, e) => AeroGlass.EnableBlur(this);
|
// restore changes by Designer
|
||||||
|
windowPanel.Opacity = 0d;
|
||||||
|
busyIndicatorLayer.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
buttonCloseWindow.MouseLeftButtonUp += CloseCurrentWindow;
|
Loaded += (sender, e) => AeroGlassHelper.EnableBlur(this);
|
||||||
titlebarTitleArea.MouseLeftButtonDown += (sender, e) => DragMove();
|
|
||||||
|
buttonCloseWindow.MouseLeftButtonUp += (sender, e) => Close();
|
||||||
|
titlebarTitleArea.MouseLeftButtonDown += DragMoveCurrentWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ViewerObject ViewerObject { get; }
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
|
|
||||||
viewContentContainer?.Dispose();
|
ViewerObject?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
private void DragMoveCurrentWindow(object sender, MouseButtonEventArgs e)
|
||||||
|
|
||||||
internal new void Show()
|
|
||||||
{
|
{
|
||||||
loadingIconLayer.Opacity = 1;
|
if (WindowState == WindowState.Maximized)
|
||||||
|
{
|
||||||
|
var dpi = DpiHelper.GetCurrentDpi();
|
||||||
|
|
||||||
Height = viewContentContainer.PreferedSize.Height + titlebar.Height + windowBorder.BorderThickness.Top +
|
// MouseDevice.GetPosition() returns device-dependent coordinate, however WPF is not like that
|
||||||
|
var point = PointToScreen(e.MouseDevice.GetPosition(this));
|
||||||
|
|
||||||
|
Left = point.X / (dpi.HorizontalDpi / DpiHelper.DEFAULT_DPI) - RestoreBounds.Width * 0.5;
|
||||||
|
Top = point.Y / (dpi.VerticalDpi / DpiHelper.DEFAULT_DPI);
|
||||||
|
|
||||||
|
WindowState = WindowState.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
DragMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private new void Show()
|
||||||
|
{
|
||||||
|
Height = ViewerObject.PreferredSize.Height + titlebar.Height + windowBorder.BorderThickness.Top +
|
||||||
windowBorder.BorderThickness.Bottom;
|
windowBorder.BorderThickness.Bottom;
|
||||||
Width = viewContentContainer.PreferedSize.Width + windowBorder.BorderThickness.Left +
|
Width = ViewerObject.PreferredSize.Width + windowBorder.BorderThickness.Left +
|
||||||
windowBorder.BorderThickness.Right;
|
windowBorder.BorderThickness.Right;
|
||||||
|
|
||||||
ResizeMode = viewContentContainer.CanResize ? ResizeMode.CanResizeWithGrip : ResizeMode.NoResize;
|
ResizeMode = ViewerObject.CanResize ? ResizeMode.CanResizeWithGrip : ResizeMode.NoResize;
|
||||||
|
|
||||||
base.Show();
|
base.Show();
|
||||||
|
|
||||||
@@ -57,54 +77,15 @@ namespace QuickLook
|
|||||||
|
|
||||||
internal void BeginShow(IViewer matchedPlugin, string path)
|
internal void BeginShow(IViewer matchedPlugin, string path)
|
||||||
{
|
{
|
||||||
viewContentContainer.ViewerPlugin = matchedPlugin;
|
ViewerObject.CurrentContentContainer = viewContentContainer;
|
||||||
|
ViewerObject.ViewerPlugin = matchedPlugin;
|
||||||
|
|
||||||
// get window size before showing it
|
// get window size before showing it
|
||||||
matchedPlugin.Prepare(path, viewContentContainer);
|
matchedPlugin.BoundViewSize(path, ViewerObject);
|
||||||
|
|
||||||
Show();
|
Show();
|
||||||
|
|
||||||
matchedPlugin.View(path, viewContentContainer);
|
matchedPlugin.View(path, ViewerObject);
|
||||||
|
|
||||||
ShowFinishLoadingAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowFinishLoadingAnimation()
|
|
||||||
{
|
|
||||||
var speed = 100;
|
|
||||||
|
|
||||||
var sb = new Storyboard();
|
|
||||||
var ptl = new ParallelTimeline();
|
|
||||||
|
|
||||||
var aOpacityR = new DoubleAnimation
|
|
||||||
{
|
|
||||||
From = 1,
|
|
||||||
To = 0,
|
|
||||||
Duration = TimeSpan.FromMilliseconds(speed)
|
|
||||||
};
|
|
||||||
|
|
||||||
Storyboard.SetTarget(aOpacityR, loadingIconLayer);
|
|
||||||
Storyboard.SetTargetProperty(aOpacityR, new PropertyPath(OpacityProperty));
|
|
||||||
|
|
||||||
ptl.Children.Add(aOpacityR);
|
|
||||||
|
|
||||||
sb.Children.Add(ptl);
|
|
||||||
|
|
||||||
sb.Begin();
|
|
||||||
|
|
||||||
Dispatcher.DelayWithPriority(speed, o => loadingIconLayer.Visibility = Visibility.Hidden, null,
|
|
||||||
DispatcherPriority.Render);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CloseCurrentWindow(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
[NotifyPropertyChangedInvocator]
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~MainWindow()
|
~MainWindow()
|
||||||
|
@@ -1,11 +1,40 @@
|
|||||||
namespace QuickLook.Plugin
|
namespace QuickLook.Plugin
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface implemented by every QuickLook.Plugin
|
||||||
|
/// </summary>
|
||||||
public interface IViewer
|
public interface IViewer
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Set the priority of this plugin. A plugin with a higher priority may override one with lower priority.
|
||||||
|
/// Set this to int.MaxValue for a maximum priority, int.MinValue for minimum.
|
||||||
|
/// </summary>
|
||||||
int Priority { get; }
|
int Priority { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determine whether this plugin can open this file. Please also check the file header, if applicable.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the target file.</param>
|
||||||
bool CanHandle(string path);
|
bool CanHandle(string path);
|
||||||
void Prepare(string path, ViewContentContainer container);
|
|
||||||
void View(string path, ViewContentContainer container);
|
/// <summary>
|
||||||
|
/// Tell QuickLook the desired window size. Please not do any work that costs a lot of time.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the target file.</param>
|
||||||
|
/// <param name="context">A runtime object which allows interaction between this plugin and QuickLook.</param>
|
||||||
|
void BoundViewSize(string path, ViewerObject context);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start the loading process. During the process a busy indicator will be shown. Finish by setting context.IsBusy to
|
||||||
|
/// false.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the target file.</param>
|
||||||
|
/// <param name="context">A runtime object which allows interaction between this plugin and QuickLook.</param>
|
||||||
|
void View(string path, ViewerObject context);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Release any unmanaged resource here.
|
||||||
|
/// </summary>
|
||||||
void Dispose();
|
void Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -14,19 +14,21 @@ namespace QuickLook.Plugin.InfoPanel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Prepare(string path, ViewContentContainer container)
|
public void BoundViewSize(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
_ip = new InfoPanel();
|
_ip = new InfoPanel();
|
||||||
|
|
||||||
container.CanResize = false;
|
context.CanResize = false;
|
||||||
container.PreferedSize = new Size {Width = _ip.Width, Height = _ip.Height};
|
context.PreferredSize = new Size {Width = _ip.Width, Height = _ip.Height};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void View(string path, ViewContentContainer container)
|
public void View(string path, ViewerObject context)
|
||||||
{
|
{
|
||||||
_ip.DisplayInfo(path);
|
_ip.DisplayInfo(path);
|
||||||
|
|
||||||
container.SetContent(_ip);
|
context.ViewerContent = _ip;
|
||||||
|
|
||||||
|
context.IsBusy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@@ -1,87 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using QuickLook.Annotations;
|
|
||||||
|
|
||||||
namespace QuickLook.Plugin
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for ViewContentContainer.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class ViewContentContainer : UserControl, INotifyPropertyChanged, IDisposable
|
|
||||||
{
|
|
||||||
private string _title = string.Empty;
|
|
||||||
|
|
||||||
public ViewContentContainer()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Title
|
|
||||||
{
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_title = value;
|
|
||||||
OnPropertyChanged(nameof(Title));
|
|
||||||
}
|
|
||||||
get => _title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IViewer ViewerPlugin { get; set; }
|
|
||||||
|
|
||||||
public Size PreferedSize { get; set; }
|
|
||||||
|
|
||||||
public bool CanResize { get; set; } = true;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
|
|
||||||
ViewerPlugin?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
public void SetContent(object content)
|
|
||||||
{
|
|
||||||
container.Content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double SetPreferedSizeFit(Size size, double maxRatio)
|
|
||||||
{
|
|
||||||
if (maxRatio > 1)
|
|
||||||
maxRatio = 1;
|
|
||||||
|
|
||||||
var max = GetMaximumDisplayBound();
|
|
||||||
|
|
||||||
var widthRatio = max.Width * maxRatio / size.Width;
|
|
||||||
var heightRatio = max.Height * maxRatio / size.Height;
|
|
||||||
|
|
||||||
var ratio = Math.Min(widthRatio, heightRatio);
|
|
||||||
|
|
||||||
if (ratio > 1) ratio = 1;
|
|
||||||
|
|
||||||
PreferedSize = new Size {Width = size.Width * ratio, Height = size.Height * ratio};
|
|
||||||
|
|
||||||
return ratio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Size GetMaximumDisplayBound()
|
|
||||||
{
|
|
||||||
return new Size(SystemParameters.VirtualScreenWidth, SystemParameters.VirtualScreenHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NotifyPropertyChangedInvocator]
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
~ViewContentContainer()
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
119
QuickLook/Plugin/ViewerObject.cs
Normal file
119
QuickLook/Plugin/ViewerObject.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Windows;
|
||||||
|
using QuickLook.Annotations;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A runtime object which allows interaction between this plugin and QuickLook.
|
||||||
|
/// </summary>
|
||||||
|
public class ViewerObject : INotifyPropertyChanged, IDisposable
|
||||||
|
{
|
||||||
|
private bool _isBusy = true;
|
||||||
|
|
||||||
|
private string _title = "";
|
||||||
|
internal ViewContentContainer CurrentContentContainer;
|
||||||
|
internal IViewer ViewerPlugin;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get or set the title of Viewer window.
|
||||||
|
/// </summary>
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get => _title;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_title = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get or set the viewer content control.
|
||||||
|
/// </summary>
|
||||||
|
public object ViewerContent
|
||||||
|
{
|
||||||
|
get => CurrentContentContainer.container.Content;
|
||||||
|
set => CurrentContentContainer.container.Content = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show or hide the busy indicator icon.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsBusy
|
||||||
|
{
|
||||||
|
get => _isBusy;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_isBusy = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the exact size you want.
|
||||||
|
/// </summary>
|
||||||
|
public Size PreferredSize { get; set; } = new Size {Width = 800, Height = 600};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set whether user are allowed to resize the viewer window.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanResize { get; set; } = true;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
|
||||||
|
ViewerPlugin?.Dispose();
|
||||||
|
ViewerPlugin = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the size of viewer window and shrink to fit (to screen resolution).
|
||||||
|
/// The window can take maximum (maxRatio*resolution) space.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size">The desired size.</param>
|
||||||
|
/// <param name="maxRatio">The maximum percent (over screen resolution) it can take.</param>
|
||||||
|
public double SetPreferredSizeFit(Size size, double maxRatio)
|
||||||
|
{
|
||||||
|
if (maxRatio > 1)
|
||||||
|
maxRatio = 1;
|
||||||
|
|
||||||
|
var max = GetMaximumDisplayBound();
|
||||||
|
|
||||||
|
var widthRatio = max.Width * maxRatio / size.Width;
|
||||||
|
var heightRatio = max.Height * maxRatio / size.Height;
|
||||||
|
|
||||||
|
var ratio = Math.Min(widthRatio, heightRatio);
|
||||||
|
|
||||||
|
if (ratio > 1) ratio = 1;
|
||||||
|
|
||||||
|
PreferredSize = new Size {Width = size.Width * ratio, Height = size.Height * ratio};
|
||||||
|
|
||||||
|
return ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the device-independent resolution.
|
||||||
|
/// </summary>
|
||||||
|
public Size GetMaximumDisplayBound()
|
||||||
|
{
|
||||||
|
return new Size(SystemParameters.VirtualScreenWidth, SystemParameters.VirtualScreenHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NotifyPropertyChangedInvocator]
|
||||||
|
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
~ViewerObject()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -75,6 +75,9 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</ApplicationDefinition>
|
</ApplicationDefinition>
|
||||||
|
<Compile Include="Controls\BackgroundVisualHost.cs" />
|
||||||
|
<Compile Include="Controls\BusyDecorator.cs" />
|
||||||
|
<Compile Include="Controls\VisualTargetPresentationSource.cs" />
|
||||||
<Compile Include="ExtensionMethods\TypeExtensions.cs" />
|
<Compile Include="ExtensionMethods\TypeExtensions.cs" />
|
||||||
<Compile Include="PluginManager.cs" />
|
<Compile Include="PluginManager.cs" />
|
||||||
<Compile Include="Plugin\InfoPanel\Extensions.cs" />
|
<Compile Include="Plugin\InfoPanel\Extensions.cs" />
|
||||||
@@ -85,10 +88,12 @@
|
|||||||
<Compile Include="Plugin\InfoPanel\PluginInterface.cs" />
|
<Compile Include="Plugin\InfoPanel\PluginInterface.cs" />
|
||||||
<Compile Include="Plugin\InfoPanel\WindowsThumbnailProvider.cs" />
|
<Compile Include="Plugin\InfoPanel\WindowsThumbnailProvider.cs" />
|
||||||
<Compile Include="Plugin\IViewer.cs" />
|
<Compile Include="Plugin\IViewer.cs" />
|
||||||
<Compile Include="Plugin\ViewContentContainer.xaml.cs">
|
<Compile Include="Helpers\DpiHelpers.cs" />
|
||||||
|
<Compile Include="ViewContentContainer.xaml.cs">
|
||||||
<DependentUpon>ViewContentContainer.xaml</DependentUpon>
|
<DependentUpon>ViewContentContainer.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Utilities\WindowHelper.cs" />
|
<Compile Include="Plugin\ViewerObject.cs" />
|
||||||
|
<Compile Include="Helpers\WindowHelper.cs" />
|
||||||
<Compile Include="ViewWindowManager.cs" />
|
<Compile Include="ViewWindowManager.cs" />
|
||||||
<Page Include="Plugin\InfoPanel\InfoPanel.xaml">
|
<Page Include="Plugin\InfoPanel\InfoPanel.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
@@ -111,16 +116,20 @@
|
|||||||
<Compile Include="NativeMethods\Kernel32.cs" />
|
<Compile Include="NativeMethods\Kernel32.cs" />
|
||||||
<Compile Include="NativeMethods\User32.cs" />
|
<Compile Include="NativeMethods\User32.cs" />
|
||||||
<Compile Include="Properties\Annotations.cs" />
|
<Compile Include="Properties\Annotations.cs" />
|
||||||
<Compile Include="Utilities\AeroGlass.cs" />
|
<Compile Include="Helpers\AeroGlassHelper.cs" />
|
||||||
<Compile Include="GlobalKeyboardHook.cs" />
|
<Compile Include="GlobalKeyboardHook.cs" />
|
||||||
<Compile Include="MainWindow.xaml.cs">
|
<Compile Include="MainWindow.xaml.cs">
|
||||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Page Include="Plugin\ViewContentContainer.xaml">
|
<Page Include="ViewContentContainer.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Styles\BusyDecorator.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs">
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
|
23
QuickLook/Styles/BusyDecorator.xaml
Normal file
23
QuickLook/Styles/BusyDecorator.xaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<ResourceDictionary
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||||
|
xmlns:local="clr-namespace:QuickLook"
|
||||||
|
xmlns:controls="clr-namespace:QuickLook.Controls">
|
||||||
|
|
||||||
|
<Style TargetType="{x:Type controls:BusyDecorator}">
|
||||||
|
<Setter Property="BusyStyle">
|
||||||
|
<Setter.Value>
|
||||||
|
<Style TargetType="{x:Type Control}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Control}">
|
||||||
|
<fa:ImageAwesome Width="40" Height="40" Icon="Refresh" Spin="True" SpinDuration="1" />
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
@@ -1,4 +1,4 @@
|
|||||||
<UserControl x:Class="QuickLook.Plugin.ViewContentContainer"
|
<UserControl x:Class="QuickLook.ViewContentContainer"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
15
QuickLook/ViewContentContainer.xaml.cs
Normal file
15
QuickLook/ViewContentContainer.xaml.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace QuickLook
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ViewContentContainer.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ViewContentContainer : UserControl
|
||||||
|
{
|
||||||
|
public ViewContentContainer()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -4,8 +4,8 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using QuickLook.ExtensionMethods;
|
using QuickLook.ExtensionMethods;
|
||||||
|
using QuickLook.Helpers;
|
||||||
using QuickLook.Plugin;
|
using QuickLook.Plugin;
|
||||||
using QuickLook.Utilities;
|
|
||||||
|
|
||||||
namespace QuickLook
|
namespace QuickLook
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user