mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-11 17:59:17 +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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
container.SetContent(_panel);
|
||||
container.Title = $"{Path.GetFileName(path)}";
|
||||
context.ViewerContent = _panel;
|
||||
context.Title = $"{Path.GetFileName(path)}";
|
||||
|
||||
context.IsBusy = false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
container.SetContent(_ip);
|
||||
container.Title = $"{Path.GetFileName(path)} ({_imageSize.Width} × {_imageSize.Height})";
|
||||
context.ViewerContent = _ip;
|
||||
context.Title = $"{Path.GetFileName(path)} ({_imageSize.Width} × {_imageSize.Height})";
|
||||
|
||||
context.IsBusy = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@@ -31,12 +31,12 @@ namespace QuickLook.Plugin.OfficeViewer
|
||||
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))
|
||||
{
|
||||
@@ -59,12 +59,14 @@ namespace QuickLook.Plugin.OfficeViewer
|
||||
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})";
|
||||
|
||||
container.SetContent(_pdfViewer);
|
||||
context.ViewerContent = _pdfViewer;
|
||||
|
||||
context.IsBusy = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@@ -7,6 +7,7 @@ namespace QuickLook.Plugin.PDFViewer
|
||||
public class Plugin : IViewer
|
||||
{
|
||||
private PdfViewerControl _pdfControl;
|
||||
|
||||
public int Priority => int.MaxValue;
|
||||
|
||||
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();
|
||||
|
||||
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.LoadPdf(path);
|
||||
|
||||
container.Title = $"{Path.GetFileName(path)} (1 / {_pdfControl.TotalPages})";
|
||||
_pdfControl.CurrentPageChanged += (sender2, e2) => container.Title =
|
||||
context.Title = $"{Path.GetFileName(path)} (1 / {_pdfControl.TotalPages})";
|
||||
_pdfControl.CurrentPageChanged += (sender2, e2) => context.Title =
|
||||
$"{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);
|
||||
|
||||
container.SetContent(_tvp);
|
||||
container.Title = $"{Path.GetFileName(path)}";
|
||||
context.ViewerContent = _tvp;
|
||||
context.Title = $"{Path.GetFileName(path)}";
|
||||
|
||||
context.IsBusy = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@@ -8,6 +8,7 @@
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Styles/ScrollBarStyleDictionary.xaml" />
|
||||
<ResourceDictionary Source="Styles/BusyDecorator.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</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.Interop;
|
||||
|
||||
namespace QuickLook.Utilities
|
||||
namespace QuickLook.Helpers
|
||||
{
|
||||
internal static class AeroGlass
|
||||
internal static class AeroGlassHelper
|
||||
{
|
||||
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 QuickLook.NativeMethods;
|
||||
|
||||
namespace QuickLook.Utilities
|
||||
namespace QuickLook.Helpers
|
||||
{
|
||||
internal static class WindowHelper
|
||||
{
|
@@ -2,72 +2,84 @@
|
||||
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:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:local="clr-namespace:QuickLook"
|
||||
xmlns:control="clr-namespace:QuickLook.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
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"
|
||||
UseLayoutRounding="True"
|
||||
Topmost="True" d:DesignWidth="624" d:DesignHeight="700"
|
||||
d:DesignWidth="624" d:DesignHeight="700"
|
||||
MinWidth="275" MinHeight="150"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
x:ClassModifier="internal" Focusable="False"
|
||||
ShowActivated="False" ShowInTaskbar="False" WindowStyle="None"
|
||||
ResizeMode="CanResizeWithGrip" AllowsTransparency="True">
|
||||
<Window.Background>
|
||||
<SolidColorBrush Color="#DFFFFFFF" />
|
||||
<SolidColorBrush Color="#E5FAFAFA" />
|
||||
</Window.Background>
|
||||
<Border x:Name="windowBorder" BorderThickness="1" BorderBrush="#FF7B7B7B">
|
||||
<Grid>
|
||||
<DockPanel Opacity="1">
|
||||
<DockPanel x:Name="titlebar" Height="28" Dock="Top">
|
||||
<DockPanel.Background>
|
||||
<SolidColorBrush Color="#00B8B8B8" />
|
||||
</DockPanel.Background>
|
||||
<!--<DockPanel.Style>
|
||||
<DockPanel x:Name="windowPanel" Opacity="1">
|
||||
<DockPanel.Style>
|
||||
<Style TargetType="{x:Type DockPanel}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Trigger.EnterActions>
|
||||
<DataTrigger Binding="{Binding ViewerObject.IsBusy, ElementName=mainWindow}" Value="False">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Opacity"
|
||||
To="1" />
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity"
|
||||
From="0"
|
||||
To="1"
|
||||
BeginTime="0:0:0.1"
|
||||
Duration="0:0:0.2" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.EnterActions>
|
||||
<Trigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Duration="0:0:0.6" Storyboard.TargetProperty="Opacity"
|
||||
To="0" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.ExitActions>
|
||||
</Trigger>
|
||||
</DataTrigger.EnterActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DockPanel.Style>-->
|
||||
<fa:ImageAwesome DockPanel.Dock="Right" x:Name="buttonCloseWindow" Icon="WindowClose" Height="15"
|
||||
Margin="10,0"
|
||||
</DockPanel.Style>
|
||||
<DockPanel x:Name="titlebar" Height="28" Dock="Top">
|
||||
<fa:ImageAwesome DockPanel.Dock="Right" x:Name="buttonCloseWindow" Icon="TimesCircle"
|
||||
Height="15" Margin="10,0" Foreground="Gray"
|
||||
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"
|
||||
VerticalContentAlignment="Center" />
|
||||
</DockPanel>
|
||||
<Grid>
|
||||
<plugin:ViewContentContainer x:Name="viewContentContainer" />
|
||||
<local:ViewContentContainer x:Name="viewContentContainer" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
<Grid x:Name="loadingIconLayer" Opacity="0.3">
|
||||
<Grid.Background>
|
||||
<SolidColorBrush Color="#FFFFFFFF" />
|
||||
</Grid.Background>
|
||||
<Grid x:Name="loadingIcon" Height="50" Width="50" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<fa:ImageAwesome Icon="CircleOutlineNotch" Spin="True" SpinDuration="1" />
|
||||
</Grid>
|
||||
<Grid x:Name="busyIndicatorLayer" Visibility="Hidden">
|
||||
<Grid.Style>
|
||||
<Style TargetType="{x:Type Grid}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ViewerObject.IsBusy, ElementName=mainWindow}" Value="False">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<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>
|
||||
</Border>
|
||||
|
@@ -1,54 +1,74 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Threading;
|
||||
using QuickLook.Annotations;
|
||||
using QuickLook.ExtensionMethods;
|
||||
using QuickLook.Helpers;
|
||||
using QuickLook.Plugin;
|
||||
using QuickLook.Utilities;
|
||||
|
||||
namespace QuickLook
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
internal partial class MainWindow : Window, INotifyPropertyChanged, IDisposable
|
||||
internal partial class MainWindow : Window, IDisposable
|
||||
{
|
||||
internal MainWindow()
|
||||
{
|
||||
// this object should be initialized before loading UI components, because many of which are binding to it.
|
||||
ViewerObject = new ViewerObject();
|
||||
|
||||
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;
|
||||
titlebarTitleArea.MouseLeftButtonDown += (sender, e) => DragMove();
|
||||
Loaded += (sender, e) => AeroGlassHelper.EnableBlur(this);
|
||||
|
||||
buttonCloseWindow.MouseLeftButtonUp += (sender, e) => Close();
|
||||
titlebarTitleArea.MouseLeftButtonDown += DragMoveCurrentWindow;
|
||||
}
|
||||
|
||||
public ViewerObject ViewerObject { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
viewContentContainer?.Dispose();
|
||||
ViewerObject?.Dispose();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
internal new void Show()
|
||||
private void DragMoveCurrentWindow(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
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;
|
||||
Width = viewContentContainer.PreferedSize.Width + windowBorder.BorderThickness.Left +
|
||||
Width = ViewerObject.PreferredSize.Width + windowBorder.BorderThickness.Left +
|
||||
windowBorder.BorderThickness.Right;
|
||||
|
||||
ResizeMode = viewContentContainer.CanResize ? ResizeMode.CanResizeWithGrip : ResizeMode.NoResize;
|
||||
ResizeMode = ViewerObject.CanResize ? ResizeMode.CanResizeWithGrip : ResizeMode.NoResize;
|
||||
|
||||
base.Show();
|
||||
|
||||
@@ -57,54 +77,15 @@ namespace QuickLook
|
||||
|
||||
internal void BeginShow(IViewer matchedPlugin, string path)
|
||||
{
|
||||
viewContentContainer.ViewerPlugin = matchedPlugin;
|
||||
ViewerObject.CurrentContentContainer = viewContentContainer;
|
||||
ViewerObject.ViewerPlugin = matchedPlugin;
|
||||
|
||||
// get window size before showing it
|
||||
matchedPlugin.Prepare(path, viewContentContainer);
|
||||
matchedPlugin.BoundViewSize(path, ViewerObject);
|
||||
|
||||
Show();
|
||||
|
||||
matchedPlugin.View(path, viewContentContainer);
|
||||
|
||||
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));
|
||||
matchedPlugin.View(path, ViewerObject);
|
||||
}
|
||||
|
||||
~MainWindow()
|
||||
|
@@ -1,11 +1,40 @@
|
||||
namespace QuickLook.Plugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface implemented by every QuickLook.Plugin
|
||||
/// </summary>
|
||||
public interface IViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Set the priority of this plugin. A plugin with a higher priority may override one with lower priority.
|
||||
/// Set this to int.MaxValue for a maximum priority, int.MinValue for minimum.
|
||||
/// </summary>
|
||||
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);
|
||||
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();
|
||||
}
|
||||
}
|
@@ -14,19 +14,21 @@ namespace QuickLook.Plugin.InfoPanel
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Prepare(string path, ViewContentContainer container)
|
||||
public void BoundViewSize(string path, ViewerObject context)
|
||||
{
|
||||
_ip = new InfoPanel();
|
||||
|
||||
container.CanResize = false;
|
||||
container.PreferedSize = new Size {Width = _ip.Width, Height = _ip.Height};
|
||||
context.CanResize = false;
|
||||
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);
|
||||
|
||||
container.SetContent(_ip);
|
||||
context.ViewerContent = _ip;
|
||||
|
||||
context.IsBusy = false;
|
||||
}
|
||||
|
||||
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>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Controls\BackgroundVisualHost.cs" />
|
||||
<Compile Include="Controls\BusyDecorator.cs" />
|
||||
<Compile Include="Controls\VisualTargetPresentationSource.cs" />
|
||||
<Compile Include="ExtensionMethods\TypeExtensions.cs" />
|
||||
<Compile Include="PluginManager.cs" />
|
||||
<Compile Include="Plugin\InfoPanel\Extensions.cs" />
|
||||
@@ -85,10 +88,12 @@
|
||||
<Compile Include="Plugin\InfoPanel\PluginInterface.cs" />
|
||||
<Compile Include="Plugin\InfoPanel\WindowsThumbnailProvider.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>
|
||||
</Compile>
|
||||
<Compile Include="Utilities\WindowHelper.cs" />
|
||||
<Compile Include="Plugin\ViewerObject.cs" />
|
||||
<Compile Include="Helpers\WindowHelper.cs" />
|
||||
<Compile Include="ViewWindowManager.cs" />
|
||||
<Page Include="Plugin\InfoPanel\InfoPanel.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -111,16 +116,20 @@
|
||||
<Compile Include="NativeMethods\Kernel32.cs" />
|
||||
<Compile Include="NativeMethods\User32.cs" />
|
||||
<Compile Include="Properties\Annotations.cs" />
|
||||
<Compile Include="Utilities\AeroGlass.cs" />
|
||||
<Compile Include="Helpers\AeroGlassHelper.cs" />
|
||||
<Compile Include="GlobalKeyboardHook.cs" />
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="Plugin\ViewContentContainer.xaml">
|
||||
<Page Include="ViewContentContainer.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Styles\BusyDecorator.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
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.Threading.Tasks;
|
||||
using QuickLook.ExtensionMethods;
|
||||
using QuickLook.Helpers;
|
||||
using QuickLook.Plugin;
|
||||
using QuickLook.Utilities;
|
||||
|
||||
namespace QuickLook
|
||||
{
|
||||
|
Reference in New Issue
Block a user