mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-13 19:19:10 +00:00
Use own Pdf viewer implementation. wip on universal InfoPanel
This commit is contained in:
40
QuickLook.Plugin.LastResort/Extensions.cs
Normal file
40
QuickLook.Plugin.LastResort/Extensions.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.LastResort
|
||||||
|
{
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
[DllImport("gdi32")]
|
||||||
|
private static extern int DeleteObject(IntPtr o);
|
||||||
|
|
||||||
|
public static BitmapSource ToBitmapSource(this Bitmap source)
|
||||||
|
{
|
||||||
|
var ip = source.GetHbitmap();
|
||||||
|
BitmapSource bs = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
|
||||||
|
ImageLockMode.ReadOnly, source.PixelFormat);
|
||||||
|
|
||||||
|
bs = BitmapSource.Create(source.Width, source.Height, source.HorizontalResolution,
|
||||||
|
source.VerticalResolution, PixelFormats.Bgra32, null,
|
||||||
|
data.Scan0, data.Stride * source.Height, data.Stride);
|
||||||
|
|
||||||
|
source.UnlockBits(data);
|
||||||
|
|
||||||
|
bs.Freeze();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DeleteObject(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
255
QuickLook.Plugin.LastResort/IconHelper.cs
Normal file
255
QuickLook.Plugin.LastResort/IconHelper.cs
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.LastResort
|
||||||
|
{
|
||||||
|
public class IconHelper
|
||||||
|
{
|
||||||
|
public enum IconSizeEnum
|
||||||
|
{
|
||||||
|
SmallIcon16 = SHGFI_SMALLICON,
|
||||||
|
MediumIcon32 = SHGFI_LARGEICON,
|
||||||
|
LargeIcon48 = SHIL_EXTRALARGE,
|
||||||
|
ExtraLargeIcon = SHIL_JUMBO
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int SHGFI_SMALLICON = 0x1;
|
||||||
|
private const int SHGFI_LARGEICON = 0x0;
|
||||||
|
private const int SHIL_JUMBO = 0x4;
|
||||||
|
private const int SHIL_EXTRALARGE = 0x2;
|
||||||
|
private const int WM_CLOSE = 0x0010;
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
private static extern
|
||||||
|
IntPtr SendMessage(
|
||||||
|
IntPtr handle,
|
||||||
|
int Msg,
|
||||||
|
IntPtr wParam,
|
||||||
|
IntPtr lParam);
|
||||||
|
|
||||||
|
|
||||||
|
[DllImport("shell32.dll")]
|
||||||
|
private static extern int SHGetImageList(
|
||||||
|
int iImageList,
|
||||||
|
ref Guid riid,
|
||||||
|
out IImageList ppv);
|
||||||
|
|
||||||
|
[DllImport("Shell32.dll")]
|
||||||
|
private static extern int SHGetFileInfo(
|
||||||
|
string pszPath,
|
||||||
|
int dwFileAttributes,
|
||||||
|
ref SHFILEINFO psfi,
|
||||||
|
int cbFileInfo,
|
||||||
|
uint uFlags);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
private static extern int DestroyIcon(
|
||||||
|
IntPtr hIcon);
|
||||||
|
|
||||||
|
public static Bitmap GetBitmapFromFolderPath(
|
||||||
|
string filepath, IconSizeEnum iconsize)
|
||||||
|
{
|
||||||
|
var hIcon = GetIconHandleFromFolderPath(filepath, iconsize);
|
||||||
|
return getBitmapFromIconHandle(hIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap GetBitmapFromFilePath(
|
||||||
|
string filepath, IconSizeEnum iconsize)
|
||||||
|
{
|
||||||
|
var hIcon = GetIconHandleFromFilePath(filepath, iconsize);
|
||||||
|
return getBitmapFromIconHandle(hIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap GetBitmapFromPath(
|
||||||
|
string filepath, IconSizeEnum iconsize)
|
||||||
|
{
|
||||||
|
var hIcon = IntPtr.Zero;
|
||||||
|
if (Directory.Exists(filepath))
|
||||||
|
{
|
||||||
|
hIcon = GetIconHandleFromFolderPath(filepath, iconsize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (File.Exists(filepath))
|
||||||
|
hIcon = GetIconHandleFromFilePath(filepath, iconsize);
|
||||||
|
}
|
||||||
|
return getBitmapFromIconHandle(hIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Bitmap getBitmapFromIconHandle(IntPtr hIcon)
|
||||||
|
{
|
||||||
|
if (hIcon == IntPtr.Zero) throw new FileNotFoundException();
|
||||||
|
var myIcon = Icon.FromHandle(hIcon);
|
||||||
|
var bitmap = myIcon.ToBitmap();
|
||||||
|
myIcon.Dispose();
|
||||||
|
DestroyIcon(hIcon);
|
||||||
|
SendMessage(hIcon, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr GetIconHandleFromFilePath(string filepath, IconSizeEnum iconsize)
|
||||||
|
{
|
||||||
|
var shinfo = new SHFILEINFO();
|
||||||
|
const uint SHGFI_SYSICONINDEX = 0x4000;
|
||||||
|
const int FILE_ATTRIBUTE_NORMAL = 0x80;
|
||||||
|
var flags = SHGFI_SYSICONINDEX;
|
||||||
|
return getIconHandleFromFilePathWithFlags(filepath, iconsize, ref shinfo, FILE_ATTRIBUTE_NORMAL, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr GetIconHandleFromFolderPath(string folderpath, IconSizeEnum iconsize)
|
||||||
|
{
|
||||||
|
var shinfo = new SHFILEINFO();
|
||||||
|
|
||||||
|
const uint SHGFI_ICON = 0x000000100;
|
||||||
|
const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
|
||||||
|
const int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
|
||||||
|
var flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;
|
||||||
|
return getIconHandleFromFilePathWithFlags(folderpath, iconsize, ref shinfo, FILE_ATTRIBUTE_DIRECTORY,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr getIconHandleFromFilePathWithFlags(
|
||||||
|
string filepath, IconSizeEnum iconsize,
|
||||||
|
ref SHFILEINFO shinfo, int fileAttributeFlag, uint flags)
|
||||||
|
{
|
||||||
|
const int ILD_TRANSPARENT = 1;
|
||||||
|
var retval = SHGetFileInfo(filepath, fileAttributeFlag, ref shinfo, Marshal.SizeOf(shinfo), flags);
|
||||||
|
if (retval == 0) throw new FileNotFoundException();
|
||||||
|
var iconIndex = shinfo.iIcon;
|
||||||
|
var iImageListGuid = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
|
||||||
|
IImageList iml;
|
||||||
|
var hres = SHGetImageList((int) iconsize, ref iImageListGuid, out iml);
|
||||||
|
var hIcon = IntPtr.Zero;
|
||||||
|
hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, ref hIcon);
|
||||||
|
return hIcon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport]
|
||||||
|
[Guid("46EB5926-582E-4017-9FDF-E8998DAA0950")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IImageList
|
||||||
|
{
|
||||||
|
[PreserveSig]
|
||||||
|
int Add(
|
||||||
|
IntPtr hbmImage,
|
||||||
|
IntPtr hbmMask,
|
||||||
|
ref int pi);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int ReplaceIcon(
|
||||||
|
int i,
|
||||||
|
IntPtr hicon,
|
||||||
|
ref int pi);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int SetOverlayImage(
|
||||||
|
int iImage,
|
||||||
|
int iOverlay);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Replace(
|
||||||
|
int i,
|
||||||
|
IntPtr hbmImage,
|
||||||
|
IntPtr hbmMask);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int AddMasked(
|
||||||
|
IntPtr hbmImage,
|
||||||
|
int crMask,
|
||||||
|
ref int pi);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Draw(
|
||||||
|
ref IMAGELISTDRAWPARAMS pimldp);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Remove(
|
||||||
|
int i);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetIcon(
|
||||||
|
int i,
|
||||||
|
int flags,
|
||||||
|
ref IntPtr picon);
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGEINFO
|
||||||
|
{
|
||||||
|
public IntPtr hbmImage;
|
||||||
|
public IntPtr hbmMask;
|
||||||
|
public int Unused1;
|
||||||
|
public int Unused2;
|
||||||
|
public RECT rcImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct IMAGELISTDRAWPARAMS
|
||||||
|
{
|
||||||
|
public int cbSize;
|
||||||
|
public IntPtr himl;
|
||||||
|
public int i;
|
||||||
|
public IntPtr hdcDst;
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
public int cx;
|
||||||
|
public int cy;
|
||||||
|
public int xBitmap;
|
||||||
|
public int yBitmap;
|
||||||
|
public int rgbBk;
|
||||||
|
public int rgbFg;
|
||||||
|
public int fStyle;
|
||||||
|
public int dwRop;
|
||||||
|
public int fState;
|
||||||
|
public int Frame;
|
||||||
|
public int crEffect;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct POINT
|
||||||
|
{
|
||||||
|
private int X;
|
||||||
|
private int Y;
|
||||||
|
|
||||||
|
public POINT(int x, int y)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public POINT(Point pt) : this(pt.X, pt.Y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Point(POINT p)
|
||||||
|
{
|
||||||
|
return new Point(p.X, p.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator POINT(Point p)
|
||||||
|
{
|
||||||
|
return new POINT(p.X, p.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct RECT
|
||||||
|
{
|
||||||
|
public int Left;
|
||||||
|
public int Top;
|
||||||
|
public int Right;
|
||||||
|
public int Bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct SHFILEINFO
|
||||||
|
{
|
||||||
|
public IntPtr hIcon;
|
||||||
|
public int iIcon;
|
||||||
|
public uint dwAttributes;
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 254)] public string szDisplayName;
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szTypeName;
|
||||||
|
}
|
||||||
|
}
|
12
QuickLook.Plugin.LastResort/InfoPanel.xaml
Normal file
12
QuickLook.Plugin.LastResort/InfoPanel.xaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<UserControl x:Class="QuickLook.Plugin.LastResort.InfoPanel"
|
||||||
|
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"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:QuickLook.Plugin.LastResort"
|
||||||
|
|
||||||
|
mc:Ignorable="d" Width="450" Height="250" UseLayoutRounding="True">
|
||||||
|
<Grid>
|
||||||
|
<Image x:Name="image" Width="128" Height="128"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
31
QuickLook.Plugin.LastResort/InfoPanel.xaml.cs
Normal file
31
QuickLook.Plugin.LastResort/InfoPanel.xaml.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.LastResort
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for InfoPanel.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class InfoPanel : UserControl
|
||||||
|
{
|
||||||
|
public InfoPanel()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
QuickLook.Plugin.LastResort/Plugin.cs
Normal file
33
QuickLook.Plugin.LastResort/Plugin.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Windows;
|
||||||
|
using Size = System.Windows.Size;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.LastResort
|
||||||
|
{
|
||||||
|
public class Plugin : IViewer
|
||||||
|
{
|
||||||
|
private InfoPanel ip;
|
||||||
|
public int Priority => -9999;
|
||||||
|
|
||||||
|
public bool CanHandle(string sample)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void View(string path, ViewContentContainer container)
|
||||||
|
{
|
||||||
|
var s = IconHelper.GetBitmapFromPath(path, IconHelper.IconSizeEnum.ExtraLargeIcon).ToBitmapSource();
|
||||||
|
|
||||||
|
ip = new InfoPanel();
|
||||||
|
ip.image.Source = s;
|
||||||
|
|
||||||
|
container.SetContent(ip);
|
||||||
|
container.PreferedSize = new Size {Width = ip.Width, Height = ip.Height};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
//ip.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
QuickLook.Plugin.LastResort/Properties/AssemblyInfo.cs
Normal file
36
QuickLook.Plugin.LastResort/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("QuickLook.Plugin.LastResort")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("QuickLook.Plugin.LastResort")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("b9a5a4f6-813e-40ce-ad32-dc5c1356215d")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>QuickLook.Plugin.LastResort</RootNamespace>
|
||||||
|
<AssemblyName>QuickLook.Plugin.LastResort</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>..\Build\Debug\Plugins\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>..\Build\Release\Plugins\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="PresentationFramework" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xaml" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Extensions.cs" />
|
||||||
|
<Compile Include="InfoPanel.xaml.cs">
|
||||||
|
<DependentUpon>InfoPanel.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Plugin.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="IconHelper.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\QuickLook\QuickLook.csproj">
|
||||||
|
<Project>{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}</Project>
|
||||||
|
<Name>QuickLook</Name>
|
||||||
|
<Private>False</Private>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Include="InfoPanel.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
@@ -1,40 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using MoonPdfLib;
|
|
||||||
using QuickLook.ExtensionMethods;
|
|
||||||
|
|
||||||
namespace QuickLook.Plugin.PDFViewer
|
|
||||||
{
|
|
||||||
public class Class1 : IViewer
|
|
||||||
{
|
|
||||||
public PluginType Type => PluginType.ByExtension | PluginType.ByContent;
|
|
||||||
|
|
||||||
public string[] SupportExtensions => new[] {".pdf"};
|
|
||||||
|
|
||||||
public bool CheckSupportByContent(byte[] sample)
|
|
||||||
{
|
|
||||||
return Encoding.ASCII.GetString(sample.Take(4).ToArray()) == "%PDF";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void View(string path, ViewContentContainer container)
|
|
||||||
{
|
|
||||||
var pdfPanel = new MoonPdfPanel
|
|
||||||
{
|
|
||||||
ViewType = ViewType.SinglePage,
|
|
||||||
PageRowDisplay = PageRowDisplayType.ContinuousPageRows,
|
|
||||||
PageMargin = new Thickness(0, 2, 4, 2),
|
|
||||||
Background = new SolidColorBrush(Colors.LightGray)
|
|
||||||
};
|
|
||||||
container.SetContent(pdfPanel);
|
|
||||||
|
|
||||||
container.Dispatcher.Delay(100, o => pdfPanel.OpenFile(path));
|
|
||||||
//container.Dispatcher.Delay(200, o => pdfPanel.ZoomToWidth());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
46
QuickLook.Plugin.PDFViewer/DpiHelpers.cs
Normal file
46
QuickLook.Plugin.PDFViewer/DpiHelpers.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.PDFViewer
|
||||||
|
{
|
||||||
|
internal static class DpiHelper
|
||||||
|
{
|
||||||
|
public const float DEFAULT_DPI = 96;
|
||||||
|
|
||||||
|
public static Dpi GetCurrentDpi()
|
||||||
|
{
|
||||||
|
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
|
||||||
|
IntPtr 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);
|
||||||
|
|
||||||
|
public enum DeviceCap
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Logical pixels inch in X
|
||||||
|
/// </summary>
|
||||||
|
LOGPIXELSX = 88,
|
||||||
|
/// <summary>
|
||||||
|
/// Logical pixels inch in Y
|
||||||
|
/// </summary>
|
||||||
|
LOGPIXELSY = 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class Dpi
|
||||||
|
{
|
||||||
|
public float HorizontalDpi { get; set; }
|
||||||
|
public float VerticalDpi { get; set; }
|
||||||
|
}
|
||||||
|
}
|
68
QuickLook.Plugin.PDFViewer/Extensions.cs
Normal file
68
QuickLook.Plugin.PDFViewer/Extensions.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.PDFViewer
|
||||||
|
{
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
|
||||||
|
{
|
||||||
|
foreach (var item in enumeration)
|
||||||
|
action(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T GetDescendantByType<T>(this Visual element) where T : class
|
||||||
|
{
|
||||||
|
if (element == null)
|
||||||
|
return default(T);
|
||||||
|
if (element.GetType() == typeof(T))
|
||||||
|
return element as T;
|
||||||
|
|
||||||
|
T foundElement = null;
|
||||||
|
(element as FrameworkElement)?.ApplyTemplate();
|
||||||
|
|
||||||
|
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
|
||||||
|
{
|
||||||
|
var visual = VisualTreeHelper.GetChild(element, i) as Visual;
|
||||||
|
foundElement = visual.GetDescendantByType<T>();
|
||||||
|
if (foundElement != null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return foundElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("gdi32")]
|
||||||
|
private static extern int DeleteObject(IntPtr o);
|
||||||
|
|
||||||
|
public static BitmapSource ToBitmapSource(this Bitmap source)
|
||||||
|
{
|
||||||
|
var ip = source.GetHbitmap();
|
||||||
|
BitmapSource bs = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height),
|
||||||
|
ImageLockMode.ReadOnly, source.PixelFormat);
|
||||||
|
|
||||||
|
bs = BitmapSource.Create(source.Width, source.Height, source.HorizontalResolution,
|
||||||
|
source.VerticalResolution, PixelFormats.Bgr24, null,
|
||||||
|
data.Scan0, data.Stride * source.Height, data.Stride);
|
||||||
|
|
||||||
|
source.UnlockBits(data);
|
||||||
|
|
||||||
|
bs.Freeze();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DeleteObject(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
181
QuickLook.Plugin.PDFViewer/LibMuPdf.cs
Normal file
181
QuickLook.Plugin.PDFViewer/LibMuPdf.cs
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.PDFViewer
|
||||||
|
{
|
||||||
|
internal class LibMuPdf
|
||||||
|
{
|
||||||
|
public static Bitmap RenderPage(IntPtr context, IntPtr document, IntPtr page, double zoomFactor)
|
||||||
|
{
|
||||||
|
var pageBound = new Rectangle();
|
||||||
|
|
||||||
|
var ctm = new Matrix();
|
||||||
|
var pix = IntPtr.Zero;
|
||||||
|
var dev = IntPtr.Zero;
|
||||||
|
|
||||||
|
NativeMethods.BoundPage(document, page, ref pageBound);
|
||||||
|
|
||||||
|
var currentDpi = DpiHelper.GetCurrentDpi();
|
||||||
|
var zoomX = zoomFactor * (currentDpi.HorizontalDpi / DpiHelper.DEFAULT_DPI);
|
||||||
|
var zoomY = zoomFactor * (currentDpi.VerticalDpi / DpiHelper.DEFAULT_DPI);
|
||||||
|
|
||||||
|
// gets the size of the page and multiplies it with zoom factors
|
||||||
|
var width = (int) (pageBound.Width * zoomX);
|
||||||
|
var height = (int) (pageBound.Height * zoomY);
|
||||||
|
|
||||||
|
// sets the matrix as a scaling matrix (zoomX,0,0,zoomY,0,0)
|
||||||
|
ctm.A = (float)zoomX;
|
||||||
|
ctm.D = (float)zoomY;
|
||||||
|
|
||||||
|
// creates a pixmap the same size as the width and height of the page
|
||||||
|
pix = NativeMethods.NewPixmap(context, NativeMethods.LookupDeviceColorSpace(context, "DeviceRGB"), width,
|
||||||
|
height);
|
||||||
|
// sets white color as the background color of the pixmap
|
||||||
|
NativeMethods.ClearPixmap(context, pix, 0xFF);
|
||||||
|
|
||||||
|
// creates a drawing device
|
||||||
|
dev = NativeMethods.NewDrawDevice(context, pix);
|
||||||
|
// draws the page on the device created from the pixmap
|
||||||
|
NativeMethods.RunPage(document, page, dev, ref ctm, IntPtr.Zero);
|
||||||
|
|
||||||
|
NativeMethods.FreeDevice(dev); // frees the resources consumed by the device
|
||||||
|
dev = IntPtr.Zero;
|
||||||
|
|
||||||
|
// creates a colorful bitmap of the same size of the pixmap
|
||||||
|
var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
|
||||||
|
var imageData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.ReadWrite,
|
||||||
|
bmp.PixelFormat);
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
// converts the pixmap data to Bitmap data
|
||||||
|
var ptrSrc = (byte*) NativeMethods.GetSamples(context, pix); // gets the rendered data from the pixmap
|
||||||
|
var ptrDest = (byte*) imageData.Scan0;
|
||||||
|
for (var y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
var pl = ptrDest;
|
||||||
|
var sl = ptrSrc;
|
||||||
|
for (var x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
//Swap these here instead of in MuPDF because most pdf images will be rgb or cmyk.
|
||||||
|
//Since we are going through the pixels one by one anyway swap here to save a conversion from rgb to bgr.
|
||||||
|
pl[2] = sl[0]; //b-r
|
||||||
|
pl[1] = sl[1]; //g-g
|
||||||
|
pl[0] = sl[2]; //r-b
|
||||||
|
//sl[3] is the alpha channel, we will skip it here
|
||||||
|
pl += 3;
|
||||||
|
sl += 4;
|
||||||
|
}
|
||||||
|
ptrDest += imageData.Stride;
|
||||||
|
ptrSrc += width * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bmp.UnlockBits(imageData);
|
||||||
|
NativeMethods.DropPixmap(context, pix);
|
||||||
|
|
||||||
|
bmp.SetResolution(currentDpi.HorizontalDpi, currentDpi.VerticalDpi);
|
||||||
|
|
||||||
|
return bmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Rectangle
|
||||||
|
{
|
||||||
|
public float Left, Top, Right, Bottom;
|
||||||
|
|
||||||
|
public float Width => Right - Left;
|
||||||
|
public float Height => Bottom - Top;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Matrix
|
||||||
|
{
|
||||||
|
public float A, B, C, D, E, F;
|
||||||
|
|
||||||
|
public Matrix(float a, float b, float c, float d, float e, float f)
|
||||||
|
{
|
||||||
|
A = a;
|
||||||
|
B = b;
|
||||||
|
C = c;
|
||||||
|
D = d;
|
||||||
|
E = e;
|
||||||
|
F = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal struct NativePage
|
||||||
|
{
|
||||||
|
public Matrix Ctm;
|
||||||
|
public Rectangle MediaBox;
|
||||||
|
public int Rotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal class NativeMethods
|
||||||
|
{
|
||||||
|
private const uint FZ_STORE_DEFAULT = 256 << 20;
|
||||||
|
private const string DLL = "libmupdf.dll";
|
||||||
|
// please modify the version number to match the FZ_VERSION definition in "fitz\version.h" file
|
||||||
|
private const string MuPDFVersion = "1.6";
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_new_context_imp", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr NewContext(IntPtr alloc, IntPtr locks, uint max_store, string version);
|
||||||
|
|
||||||
|
public static IntPtr NewContext()
|
||||||
|
{
|
||||||
|
return NewContext(IntPtr.Zero, IntPtr.Zero, FZ_STORE_DEFAULT, MuPDFVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_free_context", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr FreeContext(IntPtr ctx);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_open_file_w", CharSet = CharSet.Unicode,
|
||||||
|
CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr OpenFile(IntPtr ctx, string fileName);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "pdf_open_document_with_stream", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr OpenDocumentStream(IntPtr ctx, IntPtr stm);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_close", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr CloseStream(IntPtr stm);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "pdf_close_document", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr CloseDocument(IntPtr doc);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "pdf_count_pages", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int CountPages(IntPtr doc);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "pdf_bound_page", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void BoundPage(IntPtr doc, IntPtr page, ref Rectangle bound);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_clear_pixmap_with_value", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void ClearPixmap(IntPtr ctx, IntPtr pix, int byteValue);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_lookup_device_colorspace", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr LookupDeviceColorSpace(IntPtr ctx, string colorspace);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_free_device", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void FreeDevice(IntPtr dev);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "pdf_free_page", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void FreePage(IntPtr doc, IntPtr page);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "pdf_load_page", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr LoadPage(IntPtr doc, int pageNumber);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_new_draw_device", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr NewDrawDevice(IntPtr ctx, IntPtr pix);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_new_pixmap", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr NewPixmap(IntPtr ctx, IntPtr colorspace, int width, int height);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "pdf_run_page", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void RunPage(IntPtr doc, IntPtr page, IntPtr dev, ref Matrix transform, IntPtr cookie);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_drop_pixmap", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void DropPixmap(IntPtr ctx, IntPtr pix);
|
||||||
|
|
||||||
|
[DllImport(DLL, EntryPoint = "fz_pixmap_samples", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr GetSamples(IntPtr ctx, IntPtr pix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
QuickLook.Plugin.PDFViewer/MouseWheelMonitor.cs
Normal file
113
QuickLook.Plugin.PDFViewer/MouseWheelMonitor.cs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.PDFViewer
|
||||||
|
{
|
||||||
|
public sealed class PreviewMouseWheelMonitor : IDisposable
|
||||||
|
{
|
||||||
|
private readonly UIElement _canvas;
|
||||||
|
private readonly Dispatcher _dispatcher;
|
||||||
|
private readonly int _sensitivity;
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
private volatile bool _inactive;
|
||||||
|
private AutoResetEvent _resetMonitorEvent;
|
||||||
|
private volatile bool _stopped;
|
||||||
|
|
||||||
|
public PreviewMouseWheelMonitor(UIElement canvas, int sensitivity)
|
||||||
|
{
|
||||||
|
_canvas = canvas;
|
||||||
|
_canvas.PreviewMouseWheel += (s, e) => RaisePreviewMouseWheel(e);
|
||||||
|
|
||||||
|
_sensitivity = sensitivity;
|
||||||
|
_dispatcher = Dispatcher.CurrentDispatcher;
|
||||||
|
_resetMonitorEvent = new AutoResetEvent(false);
|
||||||
|
|
||||||
|
_disposed = false;
|
||||||
|
_inactive = true;
|
||||||
|
_stopped = true;
|
||||||
|
|
||||||
|
var monitor = new Thread(Monitor) {IsBackground = true};
|
||||||
|
monitor.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
_disposed = true;
|
||||||
|
DetachEventHandlers();
|
||||||
|
if (_resetMonitorEvent != null)
|
||||||
|
{
|
||||||
|
_resetMonitorEvent.Close();
|
||||||
|
_resetMonitorEvent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<MouseWheelEventArgs> PreviewMouseWheel;
|
||||||
|
public event EventHandler<EventArgs> PreviewMouseWheelStarted;
|
||||||
|
public event EventHandler<EventArgs> PreviewMouseWheelStopped;
|
||||||
|
|
||||||
|
private void Monitor()
|
||||||
|
{
|
||||||
|
while (!_disposed)
|
||||||
|
{
|
||||||
|
if (_inactive) // if wheel is still inactive...
|
||||||
|
{
|
||||||
|
_resetMonitorEvent.WaitOne(_sensitivity / 10); // ...wait negligibly small quantity of time...
|
||||||
|
continue; // ...and check again
|
||||||
|
}
|
||||||
|
// otherwise, if wheel is active...
|
||||||
|
_inactive = true; // ...purposely change the state to inactive
|
||||||
|
_resetMonitorEvent.WaitOne(_sensitivity); // wait...
|
||||||
|
if (_inactive
|
||||||
|
) // ...and after specified time check if the state is still not re-activated inside mouse wheel event
|
||||||
|
RaiseMouseWheelStopped();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaisePreviewMouseWheel(MouseWheelEventArgs args)
|
||||||
|
{
|
||||||
|
if (_stopped)
|
||||||
|
RaiseMouseWheelStarted();
|
||||||
|
|
||||||
|
_inactive = false;
|
||||||
|
if (PreviewMouseWheel != null)
|
||||||
|
PreviewMouseWheel(_canvas, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseMouseWheelStarted()
|
||||||
|
{
|
||||||
|
_stopped = false;
|
||||||
|
if (PreviewMouseWheelStarted != null)
|
||||||
|
PreviewMouseWheelStarted(_canvas, new EventArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseMouseWheelStopped()
|
||||||
|
{
|
||||||
|
_stopped = true;
|
||||||
|
if (PreviewMouseWheelStopped != null)
|
||||||
|
_dispatcher.Invoke(() => PreviewMouseWheelStopped(_canvas,
|
||||||
|
new
|
||||||
|
EventArgs())); // invoked on cached dispatcher for convenience (because fired from non-UI thread)
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetachEventHandlers()
|
||||||
|
{
|
||||||
|
if (PreviewMouseWheel != null)
|
||||||
|
foreach (var handler in PreviewMouseWheel.GetInvocationList().Cast<EventHandler<MouseWheelEventArgs>>())
|
||||||
|
PreviewMouseWheel -= handler;
|
||||||
|
if (PreviewMouseWheelStarted != null)
|
||||||
|
foreach (var handler in PreviewMouseWheelStarted.GetInvocationList().Cast<EventHandler<EventArgs>>())
|
||||||
|
PreviewMouseWheelStarted -= handler;
|
||||||
|
if (PreviewMouseWheelStopped != null)
|
||||||
|
foreach (var handler in PreviewMouseWheelStopped.GetInvocationList().Cast<EventHandler<EventArgs>>())
|
||||||
|
PreviewMouseWheelStopped -= handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
QuickLook.Plugin.PDFViewer/PageIdToImageConverter.cs
Normal file
32
QuickLook.Plugin.PDFViewer/PageIdToImageConverter.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.PDFViewer
|
||||||
|
{
|
||||||
|
public sealed class PageIdToImageConverter : IMultiValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (values.Length < 2)
|
||||||
|
throw new Exception("PageIdToImageConverter");
|
||||||
|
|
||||||
|
var zoom = 0.5f;
|
||||||
|
if (parameter != null)
|
||||||
|
float.TryParse((string) parameter, out zoom);
|
||||||
|
|
||||||
|
var handle = values[0] as PdfFile;
|
||||||
|
if (handle == null) return null;
|
||||||
|
|
||||||
|
var pageId = (int) values[1];
|
||||||
|
if (pageId < 0) return null;
|
||||||
|
|
||||||
|
return handle.GetPage(pageId, zoom).ToBitmapSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
QuickLook.Plugin.PDFViewer/PdfFile.cs
Normal file
73
QuickLook.Plugin.PDFViewer/PdfFile.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using Size = System.Windows.Size;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.PDFViewer
|
||||||
|
{
|
||||||
|
public class PdfFile : IDisposable
|
||||||
|
{
|
||||||
|
private readonly IntPtr _ctx;
|
||||||
|
private readonly IntPtr _doc;
|
||||||
|
private readonly IntPtr _stm;
|
||||||
|
|
||||||
|
public PdfFile(string path)
|
||||||
|
{
|
||||||
|
_ctx = LibMuPdf.NativeMethods.NewContext();
|
||||||
|
_stm = LibMuPdf.NativeMethods.OpenFile(_ctx, path);
|
||||||
|
_doc = LibMuPdf.NativeMethods.OpenDocumentStream(_ctx, _stm);
|
||||||
|
|
||||||
|
TotalPages = LibMuPdf.NativeMethods.CountPages(_doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TotalPages { get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
LibMuPdf.NativeMethods.CloseDocument(_doc);
|
||||||
|
LibMuPdf.NativeMethods.CloseStream(_stm);
|
||||||
|
LibMuPdf.NativeMethods.FreeContext(_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsLastPage(int pageId)
|
||||||
|
{
|
||||||
|
return pageId >= TotalPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Size GetPageSize(int pageId, double zoomFactor)
|
||||||
|
{
|
||||||
|
if (pageId < 0 || pageId >= TotalPages)
|
||||||
|
throw new OverflowException(
|
||||||
|
$"Page id {pageId} should greater or equal than 0 and less than total page count {TotalPages}.");
|
||||||
|
|
||||||
|
var p = LibMuPdf.NativeMethods.LoadPage(_doc, pageId);
|
||||||
|
|
||||||
|
var realSize = new LibMuPdf.Rectangle();
|
||||||
|
LibMuPdf.NativeMethods.BoundPage(_doc, p, ref realSize);
|
||||||
|
|
||||||
|
var size = new Size
|
||||||
|
{
|
||||||
|
Width = realSize.Right * zoomFactor,
|
||||||
|
Height = realSize.Bottom * zoomFactor
|
||||||
|
};
|
||||||
|
|
||||||
|
LibMuPdf.NativeMethods.FreePage(_doc, p);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap GetPage(int pageId, double zoomFactor)
|
||||||
|
{
|
||||||
|
if (pageId < 0 || pageId >= TotalPages)
|
||||||
|
throw new OverflowException(
|
||||||
|
$"Page id {pageId} should greater or equal than 0 and less than total page count {TotalPages}.");
|
||||||
|
|
||||||
|
var p = LibMuPdf.NativeMethods.LoadPage(_doc, pageId);
|
||||||
|
|
||||||
|
var bmp = LibMuPdf.RenderPage(_ctx, _doc, p, zoomFactor);
|
||||||
|
|
||||||
|
LibMuPdf.NativeMethods.FreePage(_doc, p);
|
||||||
|
|
||||||
|
return bmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml
Normal file
71
QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<UserControl x:Class="QuickLook.Plugin.PDFViewer.PdfViewerControl"
|
||||||
|
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"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:QuickLook.Plugin.PDFViewer"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:Name="thisPdfViewer"
|
||||||
|
UseLayoutRounding="True"
|
||||||
|
d:DesignHeight="476.974"
|
||||||
|
d:DesignWidth="720.29">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<local:PageIdToImageConverter x:Key="PageIdToImageConverter" />
|
||||||
|
<Style x:Key="ListBoxItemStyleNoFocusedBorder" TargetType="{x:Type ListBoxItem}">
|
||||||
|
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="150" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ListBox x:Name="listThumbnails" Grid.Column="0" VirtualizingPanel.ScrollUnit="Item"
|
||||||
|
ScrollViewer.IsDeferredScrollingEnabled="False"
|
||||||
|
SelectedIndex="0"
|
||||||
|
Focusable="False"
|
||||||
|
Background="#9FFFFFFF"
|
||||||
|
ItemsSource="{Binding PageIds, ElementName=thisPdfViewer}"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0,0,1,0"
|
||||||
|
ItemContainerStyle="{Binding Mode=OneWay, Source={StaticResource ListBoxItemStyleNoFocusedBorder}}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid MaxHeight="150"
|
||||||
|
MaxWidth="{Binding ViewportWidth, Mode=Default, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}}}">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="10" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="10" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="10" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="10" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Border Grid.Row="1" Grid.Column="1" BorderThickness="1" BorderBrush="#FFE1E1E1">
|
||||||
|
<Image>
|
||||||
|
<Image.Source>
|
||||||
|
<MultiBinding Converter="{StaticResource PageIdToImageConverter}">
|
||||||
|
<Binding Path="PdfHandleForThumbnails" ElementName="thisPdfViewer" />
|
||||||
|
<Binding />
|
||||||
|
</MultiBinding>
|
||||||
|
</Image.Source>
|
||||||
|
</Image>
|
||||||
|
</Border>
|
||||||
|
<!--
|
||||||
|
<Label Grid.Row="1" Grid.Column="1" Content="{Binding Mode=OneWay, Converter={StaticResource MathConverter}, ConverterParameter=@VALUE+1}" FontSize="14" />
|
||||||
|
-->
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
<Grid Grid.Column="1" Background="#DFEFEFEF">
|
||||||
|
<ScrollViewer x:Name="pageViewPanel" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Focusable="False">
|
||||||
|
<Image x:Name="pageViewPanelImage" Stretch="None" RenderOptions.BitmapScalingMode="NearestNeighbor">
|
||||||
|
</Image>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
253
QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml.cs
Normal file
253
QuickLook.Plugin.PDFViewer/PdfViewerControl.xaml.cs
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.PDFViewer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for PdfViewer.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class PdfViewerControl : UserControl, INotifyPropertyChanged, IDisposable
|
||||||
|
{
|
||||||
|
private PreviewMouseWheelMonitor _whellMonitor;
|
||||||
|
|
||||||
|
public PdfViewerControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
DataContext = this;
|
||||||
|
|
||||||
|
PageIds = new ObservableCollection<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<int> PageIds { get; set; }
|
||||||
|
|
||||||
|
public PdfFile PdfHandleForThumbnails { get; private set; }
|
||||||
|
|
||||||
|
public PdfFile PdfHandle { get; private set; }
|
||||||
|
|
||||||
|
public bool PdfLoaded { get; private set; }
|
||||||
|
|
||||||
|
public double ZoomFactor { get; set; }
|
||||||
|
|
||||||
|
public int TotalPages => PdfHandle.TotalPages;
|
||||||
|
|
||||||
|
public int CurrectPage
|
||||||
|
{
|
||||||
|
get => listThumbnails.SelectedIndex;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
listThumbnails.SelectedIndex = value;
|
||||||
|
listThumbnails.ScrollIntoView(listThumbnails.SelectedItem);
|
||||||
|
|
||||||
|
CurrentPageChanged?.Invoke(this, new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_whellMonitor.Dispose();
|
||||||
|
PdfHandleForThumbnails?.Dispose();
|
||||||
|
PdfHandle?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
public event EventHandler CurrentPageChanged;
|
||||||
|
|
||||||
|
private void NavigatePage(object sender, MouseWheelEventArgs e)
|
||||||
|
{
|
||||||
|
if (!PdfLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Keyboard.Modifiers != ModifierKeys.None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (e.Delta > 0) // up
|
||||||
|
{
|
||||||
|
if (pageViewPanel.VerticalOffset != 0) return;
|
||||||
|
|
||||||
|
PrevPage();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
else // down
|
||||||
|
{
|
||||||
|
if (pageViewPanel.VerticalOffset != pageViewPanel.ScrollableHeight) return;
|
||||||
|
|
||||||
|
NextPage();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NextPage()
|
||||||
|
{
|
||||||
|
if (CurrectPage < PdfHandle.TotalPages - 1)
|
||||||
|
{
|
||||||
|
CurrectPage++;
|
||||||
|
pageViewPanel.ScrollToTop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrevPage()
|
||||||
|
{
|
||||||
|
if (CurrectPage > 0)
|
||||||
|
{
|
||||||
|
CurrectPage--;
|
||||||
|
pageViewPanel.ScrollToBottom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReRenderCurrentPageLowQuality(double viewZoom, bool fromCenter)
|
||||||
|
{
|
||||||
|
if (pageViewPanelImage.Source == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var position = fromCenter
|
||||||
|
? new Point(pageViewPanelImage.Source.Width / 2, pageViewPanelImage.Source.Height / 2)
|
||||||
|
: Mouse.GetPosition(pageViewPanelImage);
|
||||||
|
|
||||||
|
pageViewPanelImage.LayoutTransform = new ScaleTransform(viewZoom, viewZoom);
|
||||||
|
|
||||||
|
// critical for calcuating offset
|
||||||
|
pageViewPanel.ScrollToHorizontalOffset(0);
|
||||||
|
pageViewPanel.ScrollToVerticalOffset(0);
|
||||||
|
UpdateLayout();
|
||||||
|
|
||||||
|
var offset = pageViewPanelImage.TranslatePoint(position, pageViewPanel) - Mouse.GetPosition(pageViewPanel);
|
||||||
|
pageViewPanel.ScrollToHorizontalOffset(offset.X);
|
||||||
|
pageViewPanel.ScrollToVerticalOffset(offset.Y);
|
||||||
|
UpdateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ReRenderCurrentPage()
|
||||||
|
{
|
||||||
|
if (!PdfLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var image = PdfHandle.GetPage(CurrectPage, ZoomFactor).ToBitmapSource();
|
||||||
|
|
||||||
|
pageViewPanelImage.Source = image;
|
||||||
|
pageViewPanelImage.Width = pageViewPanelImage.Source.Width;
|
||||||
|
pageViewPanelImage.Height = pageViewPanelImage.Source.Height;
|
||||||
|
|
||||||
|
// reset view zoom factor
|
||||||
|
pageViewPanelImage.LayoutTransform = new ScaleTransform();
|
||||||
|
|
||||||
|
GC.Collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePageViewWhenSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!PdfLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (CurrectPage == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ReRenderCurrentPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ZoomToFit()
|
||||||
|
{
|
||||||
|
if (!PdfLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var size = PdfHandle.GetPageSize(CurrectPage, 1d);
|
||||||
|
|
||||||
|
var factor = Math.Min(pageViewPanel.ActualWidth / size.Width, pageViewPanel.ActualHeight / size.Height);
|
||||||
|
|
||||||
|
ZoomFactor = factor;
|
||||||
|
|
||||||
|
ReRenderCurrentPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Size GetDesiredControlSizeByFirstPage(string path)
|
||||||
|
{
|
||||||
|
var tempHandle = new PdfFile(path);
|
||||||
|
|
||||||
|
var size = tempHandle.GetPageSize(0, 1d);
|
||||||
|
tempHandle.Dispose();
|
||||||
|
|
||||||
|
size.Width += /*listThumbnails.ActualWidth*/ 150 + 1;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadPdf(string path)
|
||||||
|
{
|
||||||
|
PageIds.Clear();
|
||||||
|
_whellMonitor?.Dispose();
|
||||||
|
|
||||||
|
PdfHandleForThumbnails = new PdfFile(path);
|
||||||
|
PdfHandle = new PdfFile(path);
|
||||||
|
PdfLoaded = true;
|
||||||
|
|
||||||
|
// fill thumbnails list
|
||||||
|
Enumerable.Range(0, PdfHandle.TotalPages).ForEach(PageIds.Add);
|
||||||
|
OnPropertyChanged(nameof(PageIds));
|
||||||
|
|
||||||
|
CurrectPage = 0;
|
||||||
|
|
||||||
|
// calculate zoom factor for first page
|
||||||
|
ZoomToFit();
|
||||||
|
|
||||||
|
// register events
|
||||||
|
listThumbnails.SelectionChanged += UpdatePageViewWhenSelectionChanged;
|
||||||
|
//pageViewPanel.SizeChanged += ReRenderCurrentPageWhenSizeChanged;
|
||||||
|
pageViewPanel.PreviewMouseWheel += NavigatePage;
|
||||||
|
StartMouseWhellDelayedZoomMonitor(pageViewPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartMouseWhellDelayedZoomMonitor(UIElement ui)
|
||||||
|
{
|
||||||
|
if (_whellMonitor == null)
|
||||||
|
_whellMonitor = new PreviewMouseWheelMonitor(ui, 100);
|
||||||
|
|
||||||
|
var newZoom = 1d;
|
||||||
|
var scrolling = false;
|
||||||
|
|
||||||
|
_whellMonitor.PreviewMouseWheelStarted += (sender, e) =>
|
||||||
|
{
|
||||||
|
if ((Keyboard.Modifiers & ModifierKeys.Control) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
newZoom = ZoomFactor;
|
||||||
|
scrolling = true;
|
||||||
|
};
|
||||||
|
_whellMonitor.PreviewMouseWheel += (sender, e) =>
|
||||||
|
{
|
||||||
|
if ((Keyboard.Modifiers & ModifierKeys.Control) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
|
||||||
|
newZoom = newZoom + e.Delta / 120 * 0.1;
|
||||||
|
|
||||||
|
newZoom = Math.Max(newZoom, 0.2);
|
||||||
|
newZoom = Math.Min(newZoom, 3);
|
||||||
|
|
||||||
|
ReRenderCurrentPageLowQuality(newZoom / ZoomFactor, false);
|
||||||
|
};
|
||||||
|
_whellMonitor.PreviewMouseWheelStopped += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (!scrolling)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ZoomFactor = newZoom;
|
||||||
|
ReRenderCurrentPage();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
QuickLook.Plugin.PDFViewer/Plugin.cs
Normal file
53
QuickLook.Plugin.PDFViewer/Plugin.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.PDFViewer
|
||||||
|
{
|
||||||
|
public class Plugin : IViewer
|
||||||
|
{
|
||||||
|
private PdfViewerControl _pdfControl;
|
||||||
|
public int Priority => 9999;
|
||||||
|
|
||||||
|
public bool CanHandle(string path)
|
||||||
|
{
|
||||||
|
if (Directory.Exists(path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (File.Exists(path) && Path.GetExtension(path).ToLower() == ".pdf")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
using (var br = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
|
||||||
|
{
|
||||||
|
return Encoding.ASCII.GetString(br.ReadBytes(4)) == "%PDF";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void View(string path, ViewContentContainer container)
|
||||||
|
{
|
||||||
|
_pdfControl = new PdfViewerControl();
|
||||||
|
|
||||||
|
var desiredSize = _pdfControl.GetDesiredControlSizeByFirstPage(path);
|
||||||
|
|
||||||
|
desiredSize.Width += 150; // add thumbnails column
|
||||||
|
|
||||||
|
container.SetPreferedSizeFit(desiredSize, 0.7);
|
||||||
|
|
||||||
|
container.SetContent(_pdfControl);
|
||||||
|
|
||||||
|
_pdfControl.Loaded += (sender, e) =>
|
||||||
|
{
|
||||||
|
_pdfControl.LoadPdf(path);
|
||||||
|
|
||||||
|
container.Title = $"{Path.GetFileName(path)} (1 / {_pdfControl.TotalPages})";
|
||||||
|
_pdfControl.CurrentPageChanged += (sender2, e2) => container.Title =
|
||||||
|
$"{Path.GetFileName(path)} ({_pdfControl.CurrectPage + 1} / {_pdfControl.TotalPages})";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
_pdfControl.Dispose();
|
||||||
|
_pdfControl = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,31 +16,29 @@
|
|||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>..\Build\Debug\Plugins\PDFViewer\</OutputPath>
|
<OutputPath>..\Build\Debug\Plugins\QuickLook.Plugin.PDFViewer\</OutputPath>
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>..\Build\Release\Plugins\PDFViewer\</OutputPath>
|
<OutputPath>..\Build\Release\Plugins\QuickLook.Plugin.PDFViewer\</OutputPath>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="MoonPdfLib, Version=0.3.0.0, Culture=neutral, processorArchitecture=x86">
|
|
||||||
<HintPath>..\packages\MoonPdfLib-x86.0.3.0\lib\MoonPdfLib.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="MouseKeyboardActivityMonitor, Version=3.0.1.29653, Culture=neutral, processorArchitecture=x86">
|
|
||||||
<HintPath>..\packages\MoonPdfLib-x86.0.3.0\lib\MouseKeyboardActivityMonitor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="PresentationCore" />
|
<Reference Include="PresentationCore" />
|
||||||
<Reference Include="PresentationFramework" />
|
<Reference Include="PresentationFramework" />
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Xaml" />
|
<Reference Include="System.Xaml" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
@@ -51,7 +49,16 @@
|
|||||||
<Reference Include="WindowsBase" />
|
<Reference Include="WindowsBase" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Class1.cs" />
|
<Compile Include="PdfViewerControl.xaml.cs">
|
||||||
|
<DependentUpon>PdfViewerControl.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Plugin.cs" />
|
||||||
|
<Compile Include="DpiHelpers.cs" />
|
||||||
|
<Compile Include="Extensions.cs" />
|
||||||
|
<Compile Include="LibMuPdf.cs" />
|
||||||
|
<Compile Include="MouseWheelMonitor.cs" />
|
||||||
|
<Compile Include="PageIdToImageConverter.cs" />
|
||||||
|
<Compile Include="PdfFile.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -62,13 +69,15 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="MoonPdfLib\README" />
|
<Content Include="LibMuPdf.dll">
|
||||||
<None Include="packages.config" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="libmupdf.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Include="PdfViewerControl.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
Binary file not shown.
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<packages>
|
|
||||||
<package id="MoonPdfLib-x86" version="0.3.0" targetFramework="net452" />
|
|
||||||
</packages>
|
|
@@ -10,26 +10,48 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook", "QuickLook\Quic
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickLook.Native.Shell32", "QuickLook.Native.Shell32\QuickLook.Native.Shell32.vcxproj", "{D31EE321-C2B0-4984-B749-736F7DE509F1}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickLook.Native.Shell32", "QuickLook.Native.Shell32\QuickLook.Native.Shell32.vcxproj", "{D31EE321-C2B0-4984-B749-736F7DE509F1}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.PDFViewer", "QuickLook.Plugin.PDFViewer\QuickLook.Plugin.PDFViewer.csproj", "{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.PdfViewer", "QuickLook.Plugin.PDFViewer\QuickLook.Plugin.PdfViewer.csproj", "{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.LastResort", "QuickLook.Plugin.LastResort\QuickLook.Plugin.LastResort.csproj", "{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Debug|x86 = Debug|x86
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
Release|x86 = Release|x86
|
Release|x86 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Debug|x86.Build.0 = Debug|Any CPU
|
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Release|x86.ActiveCfg = Release|Any CPU
|
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Release|x86.Build.0 = Release|Any CPU
|
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||||
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Debug|x86.ActiveCfg = Debug|Win32
|
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Debug|x86.Build.0 = Debug|Win32
|
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||||
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Release|x86.ActiveCfg = Release|Win32
|
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Release|x86.ActiveCfg = Release|Win32
|
||||||
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Release|x86.Build.0 = Release|Win32
|
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Debug|x86.Build.0 = Debug|Any CPU
|
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Release|x86.ActiveCfg = Release|Any CPU
|
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Release|x86.Build.0 = Release|Any CPU
|
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B9A5A4F6-813E-40CE-AD32-DC5C1356215D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=QuickLook_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Default: Reformat Code</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Default: Reformat Code</s:String>
|
||||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_AUTO_PROPERTY/@EntryValue">0</s:Int64>
|
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_AUTO_PROPERTY/@EntryValue">0</s:Int64>
|
||||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_FIELD/@EntryValue">0</s:Int64>
|
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_FIELD/@EntryValue">0</s:Int64>
|
||||||
|
@@ -5,6 +5,10 @@
|
|||||||
Startup="Application_Startup"
|
Startup="Application_Startup"
|
||||||
ShutdownMode="OnExplicitShutdown">
|
ShutdownMode="OnExplicitShutdown">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="Styles/ScrollBarStyleDictionary.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
@@ -12,6 +13,8 @@ namespace QuickLook
|
|||||||
|
|
||||||
private GlobalKeyboardHook _hook;
|
private GlobalKeyboardHook _hook;
|
||||||
|
|
||||||
|
private MainWindow _showingWindow;
|
||||||
|
|
||||||
protected BackgroundListener()
|
protected BackgroundListener()
|
||||||
{
|
{
|
||||||
InstallHook(HotkeyEventHandler);
|
InstallHook(HotkeyEventHandler);
|
||||||
@@ -19,20 +22,46 @@ namespace QuickLook
|
|||||||
|
|
||||||
private void HotkeyEventHandler(object sender, KeyEventArgs e)
|
private void HotkeyEventHandler(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
var paths = new string[0];
|
if (_showingWindow != null)
|
||||||
|
{
|
||||||
|
_showingWindow.Close();
|
||||||
|
_showingWindow = null;
|
||||||
|
|
||||||
|
GC.Collect();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = String.Empty;
|
||||||
|
|
||||||
// communicate with COM in a separate thread
|
// communicate with COM in a separate thread
|
||||||
Task.Run(() => paths = GetCurrentSelection()).Wait();
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var paths = GetCurrentSelection();
|
||||||
|
|
||||||
var ddd = PathToPluginMatcher.FindMatch(paths);
|
if (paths.Any())
|
||||||
|
path = paths.First();
|
||||||
|
|
||||||
var mw = new MainWindow();
|
}).Wait();
|
||||||
|
|
||||||
ddd.View(paths[0], mw.ViewContentContainer);
|
if (String.IsNullOrEmpty(path))
|
||||||
|
return;
|
||||||
|
|
||||||
mw.Show();
|
var matched = PluginManager.FindMatch(path);
|
||||||
|
|
||||||
mw.ShowFinishLoadingAnimation(TimeSpan.FromMilliseconds(200));
|
if (matched == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_showingWindow = new MainWindow();
|
||||||
|
|
||||||
|
_showingWindow.Closed += (sender2, e2) => { _showingWindow = null; };
|
||||||
|
|
||||||
|
_showingWindow.viewContentContainer.ViewerPlugin = matched;
|
||||||
|
matched.View(path, _showingWindow.viewContentContainer);
|
||||||
|
|
||||||
|
_showingWindow.Show();
|
||||||
|
|
||||||
|
_showingWindow.ShowFinishLoadingAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InstallHook(KeyEventHandler handler)
|
private void InstallHook(KeyEventHandler handler)
|
||||||
|
@@ -11,23 +11,19 @@
|
|||||||
UseLayoutRounding="True"
|
UseLayoutRounding="True"
|
||||||
Topmost="True" d:DesignWidth="624" d:DesignHeight="700"
|
Topmost="True" d:DesignWidth="624" d:DesignHeight="700"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
|
ResizeMode="CanResizeWithGrip"
|
||||||
x:ClassModifier="internal">
|
x:ClassModifier="internal">
|
||||||
<Window.Background>
|
<Window.Background>
|
||||||
<SolidColorBrush Color="#00FFFFFF" />
|
<SolidColorBrush Color="#7FFFFFFF" />
|
||||||
</Window.Background>
|
</Window.Background>
|
||||||
<Grid Name="WindowContainer">
|
<Border BorderThickness="1" BorderBrush="#FF7B7B7B">
|
||||||
<Grid.Background>
|
|
||||||
<SolidColorBrush Color="#FFFFFFFF" />
|
|
||||||
</Grid.Background>
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid>
|
<DockPanel Opacity="1">
|
||||||
<plugin:ViewContentContainer x:Name="ViewContentContainer" Width="624" Height="700" />
|
<DockPanel x:Name="titlebar" Height="28" Dock="Top">
|
||||||
</Grid>
|
|
||||||
<DockPanel Name="Titlebar" Height="40" VerticalAlignment="Top" Opacity="0">
|
|
||||||
<DockPanel.Background>
|
<DockPanel.Background>
|
||||||
<SolidColorBrush Color="#FFFFFFFF" />
|
<SolidColorBrush Color="#FFB8B8B8" />
|
||||||
</DockPanel.Background>
|
</DockPanel.Background>
|
||||||
<DockPanel.Style>
|
<!--<DockPanel.Style>
|
||||||
<Style TargetType="{x:Type DockPanel}">
|
<Style TargetType="{x:Type DockPanel}">
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<Trigger Property="IsMouseOver" Value="True">
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
@@ -50,20 +46,24 @@
|
|||||||
</Trigger>
|
</Trigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</DockPanel.Style>
|
</DockPanel.Style>-->
|
||||||
<fa:ImageAwesome DockPanel.Dock="Right" Name="Close" Icon="WindowClose" Height="20" Margin="10,0"
|
<fa:ImageAwesome DockPanel.Dock="Right" x:Name="buttonCloseWindow" Icon="WindowClose" Height="15" Margin="10,0"
|
||||||
Cursor="Hand" MouseLeftButtonUp="Close_MouseLeftButtonUp" />
|
Cursor="Hand" />
|
||||||
<Label Content="Filename placeholder" FontSize="16" HorizontalContentAlignment="Center"
|
<Label x:Name="titlebarTitleArea" Content="{Binding Title, ElementName=viewContentContainer}" FontSize="14" HorizontalContentAlignment="Center"
|
||||||
VerticalContentAlignment="Center" />
|
VerticalContentAlignment="Center" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
<Grid>
|
||||||
|
<plugin:ViewContentContainer x:Name="viewContentContainer"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid Name="LoadingIconLayer">
|
</DockPanel>
|
||||||
|
<Grid x:Name="loadingIconLayer" Opacity="0.3">
|
||||||
<Grid.Background>
|
<Grid.Background>
|
||||||
<SolidColorBrush Color="#FFFFFFFF" />
|
<SolidColorBrush Color="#FFFFFFFF" />
|
||||||
</Grid.Background>
|
</Grid.Background>
|
||||||
<Grid Name="LoadingIcon" Height="50" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center">
|
<Grid x:Name="loadingIcon" Height="50" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
<fa:ImageAwesome Icon="CircleOutlineNotch" Spin="True" SpinDuration="2" />
|
<fa:ImageAwesome Icon="CircleOutlineNotch" Spin="True" SpinDuration="1" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Border>
|
||||||
</Window>
|
</Window>
|
@@ -1,100 +1,88 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.Remoting.Channels;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media.Animation;
|
using System.Windows.Media.Animation;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
using QuickLook.Annotations;
|
||||||
using QuickLook.ExtensionMethods;
|
using QuickLook.ExtensionMethods;
|
||||||
|
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
|
internal partial class MainWindow : Window, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
internal MainWindow()
|
internal MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
WindowContainer.Width = LoadingIcon.Width;
|
DataContext = this;
|
||||||
WindowContainer.Height = LoadingIcon.Height;
|
|
||||||
ViewContentContainer.Opacity = 0;
|
ContentRendered += (sender, e) => AeroGlass.EnableBlur(this);
|
||||||
|
Closed += MainWindow_Closed;
|
||||||
|
|
||||||
|
buttonCloseWindow.MouseLeftButtonUp += CloseCurrentWindow;
|
||||||
|
titlebarTitleArea.MouseDown += (sender, e) => DragMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainWindow_Closed(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
viewContentContainer.ViewerPlugin.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal new void Show()
|
internal new void Show()
|
||||||
{
|
{
|
||||||
Height = ViewContentContainer.Height;
|
loadingIconLayer.Opacity = 1;
|
||||||
Width = ViewContentContainer.Width;
|
|
||||||
|
Height = viewContentContainer.PreferedSize.Height + titlebar.Height;
|
||||||
|
Width = viewContentContainer.PreferedSize.Width;
|
||||||
|
|
||||||
base.Show();
|
base.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ShowFinishLoadingAnimation(TimeSpan delay = new TimeSpan())
|
internal void ShowFinishLoadingAnimation()
|
||||||
{
|
{
|
||||||
var speed = 200;
|
var speed = 100;
|
||||||
|
|
||||||
var sb = new Storyboard();
|
var sb = new Storyboard();
|
||||||
var ptl = new ParallelTimeline {BeginTime = delay};
|
var ptl = new ParallelTimeline();
|
||||||
|
|
||||||
var aWidth = new DoubleAnimation
|
|
||||||
{
|
|
||||||
From = WindowContainer.Width,
|
|
||||||
To = ViewContentContainer.Width,
|
|
||||||
Duration = TimeSpan.FromMilliseconds(speed),
|
|
||||||
DecelerationRatio = 0.3
|
|
||||||
};
|
|
||||||
|
|
||||||
var aHeight = new DoubleAnimation
|
|
||||||
{
|
|
||||||
From = WindowContainer.Height,
|
|
||||||
To = ViewContentContainer.Height,
|
|
||||||
Duration = TimeSpan.FromMilliseconds(speed),
|
|
||||||
DecelerationRatio = 0.3
|
|
||||||
};
|
|
||||||
|
|
||||||
var aOpacity = new DoubleAnimation
|
|
||||||
{
|
|
||||||
From = 0,
|
|
||||||
To = 1,
|
|
||||||
BeginTime = TimeSpan.FromMilliseconds(speed * 0.25),
|
|
||||||
Duration = TimeSpan.FromMilliseconds(speed * 0.75)
|
|
||||||
};
|
|
||||||
|
|
||||||
var aOpacityR = new DoubleAnimation
|
var aOpacityR = new DoubleAnimation
|
||||||
{
|
{
|
||||||
From = 1,
|
From = 1,
|
||||||
To = 0,
|
To = 0,
|
||||||
Duration = TimeSpan.FromMilliseconds(speed * 2)
|
Duration = TimeSpan.FromMilliseconds(speed)
|
||||||
};
|
};
|
||||||
|
|
||||||
Storyboard.SetTarget(aWidth, WindowContainer);
|
Storyboard.SetTarget(aOpacityR, loadingIconLayer);
|
||||||
Storyboard.SetTarget(aHeight, WindowContainer);
|
|
||||||
Storyboard.SetTarget(aOpacity, ViewContentContainer);
|
|
||||||
Storyboard.SetTarget(aOpacityR, LoadingIconLayer);
|
|
||||||
Storyboard.SetTargetProperty(aWidth, new PropertyPath(WidthProperty));
|
|
||||||
Storyboard.SetTargetProperty(aHeight, new PropertyPath(HeightProperty));
|
|
||||||
Storyboard.SetTargetProperty(aOpacity, new PropertyPath(OpacityProperty));
|
|
||||||
Storyboard.SetTargetProperty(aOpacityR, new PropertyPath(OpacityProperty));
|
Storyboard.SetTargetProperty(aOpacityR, new PropertyPath(OpacityProperty));
|
||||||
|
|
||||||
ptl.Children.Add(aWidth);
|
|
||||||
ptl.Children.Add(aHeight);
|
|
||||||
ptl.Children.Add(aOpacity);
|
|
||||||
ptl.Children.Add(aOpacityR);
|
ptl.Children.Add(aOpacityR);
|
||||||
|
|
||||||
sb.Children.Add(ptl);
|
sb.Children.Add(ptl);
|
||||||
|
|
||||||
sb.Begin();
|
sb.Begin();
|
||||||
|
|
||||||
Dispatcher.DelayWithPriority(speed * 2, o => LoadingIconLayer.Visibility = Visibility.Hidden, null,
|
Dispatcher.DelayWithPriority(speed, o => loadingIconLayer.Visibility = Visibility.Hidden, null,
|
||||||
DispatcherPriority.Render);
|
DispatcherPriority.Render);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Close_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
private void CloseCurrentWindow(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
// useless code to make everyone happy
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
GC.Collect();
|
|
||||||
|
[NotifyPropertyChangedInvocator]
|
||||||
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,58 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using QuickLook.Plugin;
|
|
||||||
|
|
||||||
namespace QuickLook
|
|
||||||
{
|
|
||||||
internal static class PathToPluginMatcher
|
|
||||||
{
|
|
||||||
internal static IViewer FindMatch(string[] paths)
|
|
||||||
{
|
|
||||||
if (paths.Length == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
//TODO: Handle multiple files?
|
|
||||||
var path = paths.First();
|
|
||||||
|
|
||||||
return FindByExtension(path) ?? FindByContent(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IViewer FindByExtension(string path)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var ext = Path.GetExtension(path).ToLower();
|
|
||||||
|
|
||||||
return PluginManager.GetInstance()
|
|
||||||
.LoadedPlugins.FirstOrDefault(plugin =>
|
|
||||||
{
|
|
||||||
if ((plugin.Type & PluginType.ByExtension) == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return plugin.SupportExtensions.Any(e => e == ext);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IViewer FindByContent(string path)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] sample;
|
|
||||||
using (var br = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
|
|
||||||
{
|
|
||||||
sample = br.ReadBytes(256);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PluginManager.GetInstance()
|
|
||||||
.LoadedPlugins.FirstOrDefault(plugin =>
|
|
||||||
{
|
|
||||||
if ((plugin.Type & PluginType.ByContent) == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return plugin.CheckSupportByContent(sample);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,9 +2,8 @@
|
|||||||
{
|
{
|
||||||
public interface IViewer
|
public interface IViewer
|
||||||
{
|
{
|
||||||
PluginType Type { get; }
|
int Priority { get; }
|
||||||
string[] SupportExtensions { get; }
|
bool CanHandle(string sample);
|
||||||
bool CheckSupportByContent(byte[] sample);
|
|
||||||
void View(string path, ViewContentContainer container);
|
void View(string path, ViewContentContainer container);
|
||||||
void Close();
|
void Close();
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
d:DesignHeight="300" d:DesignWidth="300">
|
||||||
<Grid>
|
<Grid>
|
||||||
<ContentControl Name="Container">
|
<ContentControl x:Name="container">
|
||||||
<Label Content="ContentControl Placeholder" VerticalContentAlignment="Center"
|
<Label Content="ContentControl Placeholder" VerticalContentAlignment="Center"
|
||||||
HorizontalContentAlignment="Center" Background="LightGray" />
|
HorizontalContentAlignment="Center" Background="LightGray" />
|
||||||
</ContentControl>
|
</ContentControl>
|
||||||
|
@@ -1,20 +1,71 @@
|
|||||||
using System.Windows.Controls;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using QuickLook.Annotations;
|
||||||
|
|
||||||
namespace QuickLook.Plugin
|
namespace QuickLook.Plugin
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for ViewContentContainer.xaml
|
/// Interaction logic for ViewContentContainer.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class ViewContentContainer : UserControl
|
public partial class ViewContentContainer : UserControl,INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
|
private string _title = String.Empty;
|
||||||
|
|
||||||
public ViewContentContainer()
|
public ViewContentContainer()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_title = value;
|
||||||
|
OnPropertyChanged(nameof(Title));
|
||||||
|
}
|
||||||
|
get => _title;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetContent(object content)
|
public void SetContent(object content)
|
||||||
{
|
{
|
||||||
Container.Content = 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);
|
||||||
|
|
||||||
|
PreferedSize = new Size {Width = size.Width * ratio, Height = size.Height * ratio};
|
||||||
|
|
||||||
|
return ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IViewer ViewerPlugin { get; set; }
|
||||||
|
|
||||||
|
public Size PreferedSize { get; set; }
|
||||||
|
|
||||||
|
public Size GetMaximumDisplayBound()
|
||||||
|
{
|
||||||
|
return new Size(SystemParameters.VirtualScreenWidth, SystemParameters.VirtualScreenHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
[NotifyPropertyChangedInvocator]
|
||||||
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -11,18 +11,27 @@ namespace QuickLook
|
|||||||
{
|
{
|
||||||
private static PluginManager _instance;
|
private static PluginManager _instance;
|
||||||
|
|
||||||
internal PluginManager()
|
private PluginManager()
|
||||||
{
|
{
|
||||||
LoadPlugins();
|
LoadPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal List<IViewer> LoadedPlugins { get; } = new List<IViewer>();
|
internal List<IViewer> LoadedPlugins { get; private set; } = new List<IViewer>();
|
||||||
|
|
||||||
internal static PluginManager GetInstance()
|
internal static PluginManager GetInstance()
|
||||||
{
|
{
|
||||||
return _instance ?? (_instance = new PluginManager());
|
return _instance ?? (_instance = new PluginManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static IViewer FindMatch(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return GetInstance()
|
||||||
|
.LoadedPlugins.FirstOrDefault(plugin => plugin.CanHandle(path));
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadPlugins()
|
private void LoadPlugins()
|
||||||
{
|
{
|
||||||
Directory.GetFiles(Path.Combine(App.AppPath, "Plugins\\"), "QuickLook.Plugin.*.dll",
|
Directory.GetFiles(Path.Combine(App.AppPath, "Plugins\\"), "QuickLook.Plugin.*.dll",
|
||||||
@@ -37,6 +46,8 @@ namespace QuickLook
|
|||||||
select t).ToList()
|
select t).ToList()
|
||||||
.ForEach(type => LoadedPlugins.Add((IViewer) Activator.CreateInstance(type)));
|
.ForEach(type => LoadedPlugins.Add((IViewer) Activator.CreateInstance(type)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
LoadedPlugins = LoadedPlugins.OrderByDescending(i => i.Priority).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
1048
QuickLook/Properties/Annotations.cs
Normal file
1048
QuickLook/Properties/Annotations.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -73,13 +73,16 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</ApplicationDefinition>
|
</ApplicationDefinition>
|
||||||
<Compile Include="PathToPluginMatcher.cs" />
|
|
||||||
<Compile Include="PluginManager.cs" />
|
<Compile Include="PluginManager.cs" />
|
||||||
<Compile Include="Plugin\IViewer.cs" />
|
<Compile Include="Plugin\IViewer.cs" />
|
||||||
<Compile Include="Plugin\PluginPriority.cs" />
|
<Compile Include="Plugin\PluginPriority.cs" />
|
||||||
<Compile Include="Plugin\ViewContentContainer.xaml.cs">
|
<Compile Include="Plugin\ViewContentContainer.xaml.cs">
|
||||||
<DependentUpon>ViewContentContainer.xaml</DependentUpon>
|
<DependentUpon>ViewContentContainer.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Page Include="Styles\ScrollBarStyleDictionary.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="MainWindow.xaml">
|
<Page Include="MainWindow.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
@@ -92,6 +95,8 @@
|
|||||||
<Compile Include="BackgroundListener.cs" />
|
<Compile Include="BackgroundListener.cs" />
|
||||||
<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="Utilities\AeroGlass.cs" />
|
||||||
<Compile Include="Utilities\GlobalKeyboardHook.cs" />
|
<Compile Include="Utilities\GlobalKeyboardHook.cs" />
|
||||||
<Compile Include="MainWindow.xaml.cs">
|
<Compile Include="MainWindow.xaml.cs">
|
||||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
|
181
QuickLook/Styles/ScrollBarStyleDictionary.xaml
Normal file
181
QuickLook/Styles/ScrollBarStyleDictionary.xaml
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<SolidColorBrush x:Key="StandardBorderBrush" Color="#888" />
|
||||||
|
<SolidColorBrush x:Key="StandardBackgroundBrush" Color="#FFF" />
|
||||||
|
<SolidColorBrush x:Key="HoverBorderBrush" Color="#DDD" />
|
||||||
|
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="Gray" />
|
||||||
|
<SolidColorBrush x:Key="SelectedForegroundBrush" Color="White" />
|
||||||
|
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
|
||||||
|
<SolidColorBrush x:Key="NormalBrush" Color="#888" />
|
||||||
|
<SolidColorBrush x:Key="NormalBorderBrush" Color="#888" />
|
||||||
|
<SolidColorBrush x:Key="HorizontalNormalBrush" Color="#888" />
|
||||||
|
<SolidColorBrush x:Key="HorizontalNormalBorderBrush" Color="#888" />
|
||||||
|
<LinearGradientBrush x:Key="ListBoxBackgroundBrush"
|
||||||
|
StartPoint="0,0" EndPoint="1,0.001">
|
||||||
|
<GradientBrush.GradientStops>
|
||||||
|
<GradientStopCollection>
|
||||||
|
<GradientStop Color="White" Offset="0.0" />
|
||||||
|
<GradientStop Color="White" Offset="0.6" />
|
||||||
|
<GradientStop Color="#DDDDDD" Offset="1.2" />
|
||||||
|
</GradientStopCollection>
|
||||||
|
</GradientBrush.GradientStops>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
<LinearGradientBrush x:Key="StandardBrush"
|
||||||
|
StartPoint="0,0" EndPoint="0,1">
|
||||||
|
<GradientBrush.GradientStops>
|
||||||
|
<GradientStopCollection>
|
||||||
|
<GradientStop Color="#FFF" Offset="0.0" />
|
||||||
|
<GradientStop Color="#CCC" Offset="1.0" />
|
||||||
|
</GradientStopCollection>
|
||||||
|
</GradientBrush.GradientStops>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
|
||||||
|
<LinearGradientBrush x:Key="PressedBrush"
|
||||||
|
StartPoint="0,0" EndPoint="0,1">
|
||||||
|
<GradientBrush.GradientStops>
|
||||||
|
<GradientStopCollection>
|
||||||
|
<GradientStop Color="#BBB" Offset="0.0" />
|
||||||
|
<GradientStop Color="#EEE" Offset="0.1" />
|
||||||
|
<GradientStop Color="#EEE" Offset="0.9" />
|
||||||
|
<GradientStop Color="#FFF" Offset="1.0" />
|
||||||
|
</GradientStopCollection>
|
||||||
|
</GradientBrush.GradientStops>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
|
||||||
|
<!-- SrollViewer ScrollBar Repeat Buttons (at each end) -->
|
||||||
|
<Style x:Key="ScrollBarLineButton" TargetType="{x:Type RepeatButton}">
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||||
|
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||||
|
<Setter Property="Focusable" Value="false" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type RepeatButton}">
|
||||||
|
<Border Name="Border" Margin="1" CornerRadius="2" Background="{StaticResource NormalBrush}"
|
||||||
|
BorderBrush="{StaticResource NormalBorderBrush}" BorderThickness="0.25">
|
||||||
|
<Path HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||||
|
Fill="{StaticResource GlyphBrush}"
|
||||||
|
Data="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsPressed" Value="true">
|
||||||
|
<Setter TargetName="Border" Property="Background"
|
||||||
|
Value="{StaticResource PressedBrush}" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsEnabled" Value="false">
|
||||||
|
<Setter Property="Foreground"
|
||||||
|
Value="{StaticResource DisabledForegroundBrush}" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<!-- SrollViewer ScrollBar Repeat Buttons (The part in the middle,
|
||||||
|
not the thumb the long area between the buttons ) -->
|
||||||
|
<Style x:Key="ScrollBarPageButton" TargetType="{x:Type RepeatButton}">
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||||
|
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||||
|
<Setter Property="IsTabStop" Value="false" />
|
||||||
|
<Setter Property="Focusable" Value="false" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type RepeatButton}">
|
||||||
|
<Border Background="Transparent" />
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<!-- ScrollViewer ScrollBar Thumb, that part that can be dragged
|
||||||
|
up/down or left/right Buttons -->
|
||||||
|
<Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}">
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||||
|
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||||
|
<Setter Property="IsTabStop" Value="false" />
|
||||||
|
<Setter Property="Focusable" Value="false" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||||
|
<Border CornerRadius="2" Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0.25" />
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<ControlTemplate x:Key="VerticalScrollBar"
|
||||||
|
TargetType="{x:Type ScrollBar}">
|
||||||
|
<Grid Width="6">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Border Grid.RowSpan="3" CornerRadius="2" Background="Transparent" />
|
||||||
|
<Track Name="PART_Track" Grid.Row="0" IsDirectionReversed="true">
|
||||||
|
<Track.DecreaseRepeatButton>
|
||||||
|
<RepeatButton Style="{StaticResource ScrollBarPageButton}" Command="ScrollBar.PageUpCommand" />
|
||||||
|
</Track.DecreaseRepeatButton>
|
||||||
|
<Track.Thumb>
|
||||||
|
<Thumb Style="{StaticResource ScrollBarThumb}" Margin="0,0,0,0"
|
||||||
|
Background="{StaticResource HorizontalNormalBrush}"
|
||||||
|
BorderBrush="{StaticResource HorizontalNormalBorderBrush}" />
|
||||||
|
</Track.Thumb>
|
||||||
|
<Track.IncreaseRepeatButton>
|
||||||
|
<RepeatButton Style="{StaticResource ScrollBarPageButton}" Command="ScrollBar.PageDownCommand" />
|
||||||
|
</Track.IncreaseRepeatButton>
|
||||||
|
</Track>
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
<!-- HorizontalScrollBar Template using the previously created Templates -->
|
||||||
|
<ControlTemplate x:Key="HorizontalScrollBar"
|
||||||
|
TargetType="{x:Type ScrollBar}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Border
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
CornerRadius="2"
|
||||||
|
Background="#F0F0F0" />
|
||||||
|
<Track
|
||||||
|
Name="PART_Track"
|
||||||
|
Grid.Column="0"
|
||||||
|
IsDirectionReversed="False">
|
||||||
|
<Track.DecreaseRepeatButton>
|
||||||
|
<RepeatButton
|
||||||
|
Style="{StaticResource ScrollBarPageButton}"
|
||||||
|
Command="ScrollBar.PageLeftCommand" />
|
||||||
|
</Track.DecreaseRepeatButton>
|
||||||
|
<Track.Thumb>
|
||||||
|
<Thumb
|
||||||
|
Style="{StaticResource ScrollBarThumb}"
|
||||||
|
Margin="0,2"
|
||||||
|
Background="{StaticResource NormalBrush}"
|
||||||
|
BorderBrush="{StaticResource NormalBorderBrush}" />
|
||||||
|
</Track.Thumb>
|
||||||
|
<Track.IncreaseRepeatButton>
|
||||||
|
<RepeatButton
|
||||||
|
Style="{StaticResource ScrollBarPageButton}"
|
||||||
|
Command="ScrollBar.PageRightCommand" />
|
||||||
|
</Track.IncreaseRepeatButton>
|
||||||
|
</Track>
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
<!-- Style for overall ScrollBar -->
|
||||||
|
<Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}">
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||||
|
<Setter Property="OverridesDefaultStyle" Value="true" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="Orientation" Value="Horizontal">
|
||||||
|
<Setter Property="Width" Value="Auto" />
|
||||||
|
<Setter Property="Height" Value="10" />
|
||||||
|
<Setter Property="Template"
|
||||||
|
Value="{StaticResource HorizontalScrollBar}" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="Orientation" Value="Vertical">
|
||||||
|
<Setter Property="Width" Value="10" />
|
||||||
|
<Setter Property="Height" Value="Auto" />
|
||||||
|
<Setter Property="Template"
|
||||||
|
Value="{StaticResource VerticalScrollBar}" />
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
67
QuickLook/Utilities/AeroGlass.cs
Normal file
67
QuickLook/Utilities/AeroGlass.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
|
||||||
|
namespace QuickLook.Utilities
|
||||||
|
{
|
||||||
|
internal class AeroGlass
|
||||||
|
{
|
||||||
|
internal static void EnableBlur(Window window)
|
||||||
|
{
|
||||||
|
var windowHelper = new WindowInteropHelper(window);
|
||||||
|
|
||||||
|
var accent = new AccentPolicy();
|
||||||
|
var accentStructSize = Marshal.SizeOf(accent);
|
||||||
|
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
|
||||||
|
|
||||||
|
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
|
||||||
|
Marshal.StructureToPtr(accent, accentPtr, false);
|
||||||
|
|
||||||
|
var data = new WindowCompositionAttributeData();
|
||||||
|
data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
|
||||||
|
data.SizeOfData = accentStructSize;
|
||||||
|
data.Data = accentPtr;
|
||||||
|
|
||||||
|
SetWindowCompositionAttribute(windowHelper.Handle, ref data);
|
||||||
|
|
||||||
|
Marshal.FreeHGlobal(accentPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct WindowCompositionAttributeData
|
||||||
|
{
|
||||||
|
public WindowCompositionAttribute Attribute;
|
||||||
|
public IntPtr Data;
|
||||||
|
public int SizeOfData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum WindowCompositionAttribute
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
WCA_ACCENT_POLICY = 19
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum AccentState
|
||||||
|
{
|
||||||
|
ACCENT_DISABLED = 0,
|
||||||
|
ACCENT_ENABLE_GRADIENT = 1,
|
||||||
|
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
||||||
|
ACCENT_ENABLE_BLURBEHIND = 3,
|
||||||
|
ACCENT_INVALID_STATE = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct AccentPolicy
|
||||||
|
{
|
||||||
|
public AccentState AccentState;
|
||||||
|
public int AccentFlags;
|
||||||
|
public int GradientColor;
|
||||||
|
public int AnimationId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user