Finish animation and PDF viewer, still need refinement

This commit is contained in:
Paddy Xu
2017-04-12 23:28:12 +03:00
parent 7e2001bc4d
commit 7388c3874a
27 changed files with 252 additions and 170 deletions

View File

@@ -15,7 +15,7 @@
<ProjectGuid>{D31EE321-C2B0-4984-B749-736F7DE509F1}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>QuickLookShell32Helper</RootNamespace>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
<ProjectName>QuickLook.Native.Shell32</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

View File

@@ -47,7 +47,8 @@ void Shell32::GetCurrentSelectionBuffer(PWCHAR buffer)
wcscpy_s(pos - 1, 1, L"");
}
void Shell32::SaveSelectedFromExplorer() {
void Shell32::SaveSelectedFromExplorer()
{
CoInitialize(nullptr);
CComPtr<IShellWindows> psw;
@@ -57,7 +58,8 @@ void Shell32::SaveSelectedFromExplorer() {
auto fFound = FALSE;
for (int i = 0; !fFound; i++) {
for (int i = 0; !fFound; i++)
{
VARIANT vi;
V_VT(&vi) = VT_I4;
V_I4(&vi) = i;
@@ -67,13 +69,16 @@ void Shell32::SaveSelectedFromExplorer() {
if (SUCCEEDED(psw->Item(vi, &pdisp)))
{
CComPtr<IWebBrowserApp> pwba;
if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, reinterpret_cast<void**>(&pwba)))) {
if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, reinterpret_cast<void**>(&pwba))))
{
HWND hwndWBA;
if (SUCCEEDED(pwba->get_HWND(reinterpret_cast<LONG_PTR*>(&hwndWBA))) && hwndWBA == hwndFGW) {
if (SUCCEEDED(pwba->get_HWND(reinterpret_cast<LONG_PTR*>(&hwndWBA))) && hwndWBA == hwndFGW)
{
fFound = TRUE;
CComPtr<IDispatch> ppdisp;
if (SUCCEEDED(pwba->get_Document(&ppdisp))) {
if (SUCCEEDED(pwba->get_Document(&ppdisp)))
{
CComPtr<IShellFolderViewDual2> pshvd;
if (SUCCEEDED(ppdisp->QueryInterface(IID_IShellFolderViewDual2, reinterpret_cast<void**>(&pshvd))))
{
@@ -164,7 +169,8 @@ void Shell32::SaveSelectedFromDesktop()
}
}
void Shell32::vectorFromDataObject(CComPtr<IDataObject> dao) {
void Shell32::vectorFromDataObject(CComPtr<IDataObject> dao)
{
FORMATETC formatetc;
STGMEDIUM medium;

View File

@@ -26,4 +26,3 @@ private:
static CComQIPtr<IWebBrowser2> AttachDesktopShellWindow();
static void vectorFromDataObject(CComPtr<IDataObject> dao);
};

View File

@@ -15,4 +15,3 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser
}
return TRUE;
}

View File

@@ -12,7 +12,6 @@
#include <windows.h>
// TODO: reference additional headers your program requires here
#include<atlcomcli.h>
#include<Exdisp.h>

View File

@@ -1,52 +1,40 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using MoonPdfLib;
using QuickLook.ExtensionMethods;
namespace QuickLook.Plugin.PDFViewer
{
public class Class1 : IViewer
{
public bool CanView(string path, byte[] sample)
public PluginType Type => PluginType.ByExtension | PluginType.ByContent;
public string[] SupportExtensions => new[] {".pdf"};
public bool CheckSupportByContent(byte[] sample)
{
if (String.IsNullOrEmpty(path))
return false;
if (Path.GetExtension(path).ToLower() == ".pdf")
return true;
if (Encoding.ASCII.GetString(sample.Take(4).ToArray()) == "%PDF")
return true;
return false;
return Encoding.ASCII.GetString(sample.Take(4).ToArray()) == "%PDF";
}
public void View(string path, ViewContentContainer container)
{
MoonPdfPanel pdfPanel = new MoonPdfPanel
var pdfPanel = new MoonPdfPanel
{
ViewType = ViewType.SinglePage,
PageRowDisplay = PageRowDisplayType.ContinuousPageRows,
PageMargin = new System.Windows.Thickness(0, 2, 4, 2),
PageMargin = new Thickness(0, 2, 4, 2),
Background = new SolidColorBrush(Colors.LightGray)
};
container.SetContent(pdfPanel);
Task.Delay(200).ContinueWith(t => container.Dispatcher.Invoke(() => pdfPanel.OpenFile(path)));
Task.Delay(400).ContinueWith(t => container.Dispatcher.Invoke(() => pdfPanel.ZoomToWidth()));
container.Dispatcher.Delay(100, o => pdfPanel.OpenFile(path));
//container.Dispatcher.Delay(200, o => pdfPanel.ZoomToWidth());
}
public void Close()
{
return;
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following

View File

@@ -20,6 +20,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MoonPdfLib-x86" version="0.3.0" targetFramework="net452" />
</packages>

View File

@@ -14,46 +14,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.PDFViewer"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
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|x64.ActiveCfg = Debug|Any CPU
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Debug|x64.Build.0 = 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}.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|x64.ActiveCfg = Release|Any CPU
{8B4A9CE5-67B5-4A94-81CB-3771F688FDEB}.Release|x64.Build.0 = 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
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Debug|Any CPU.ActiveCfg = Debug|Win32
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Debug|Any CPU.Build.0 = Debug|Win32
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Debug|x64.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}.Release|Any CPU.ActiveCfg = Release|Win32
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Release|Any CPU.Build.0 = Release|Win32
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Release|x64.ActiveCfg = Release|Win32
{D31EE321-C2B0-4984-B749-736F7DE509F1}.Release|x86.ActiveCfg = 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|x64.ActiveCfg = Debug|Any CPU
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Debug|x64.Build.0 = 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}.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|x64.ActiveCfg = Release|Any CPU
{A82AC69C-EDF5-4F0D-8CBD-8E5E3C06E64D}.Release|x64.Build.0 = 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
EndGlobalSection

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />

View File

@@ -2,7 +2,8 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:QuickLook"
Startup="Application_Startup">
Startup="Application_Startup"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
</Application.Resources>

View File

@@ -1,14 +1,6 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using QuickLook.Plugin;
using QuickLook.Utilities;
namespace QuickLook
{

View File

@@ -1,5 +1,6 @@
using System.Text;
using System.Threading;
using System;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using QuickLook.Utilities;
@@ -18,16 +19,20 @@ namespace QuickLook
private void HotkeyEventHandler(object sender, KeyEventArgs e)
{
string[] paths;
var paths = new string[0];
// communicate with COM in a separate thread
var tCom = new Thread(() => paths = GetCurrentSelection());
Task.Run(() => paths = GetCurrentSelection()).Wait();
tCom.Start();
tCom.Join();
var ddd = PathToPluginMatcher.FindMatch(paths);
var mw = new MainWindow();
ddd.View(paths[0], mw.ViewContentContainer);
mw.Show();
mw.ShowFinishLoadingAnimation(TimeSpan.FromMilliseconds(200));
}
private void InstallHook(KeyEventHandler handler)

View File

@@ -4,7 +4,7 @@ using System.Windows.Threading;
namespace QuickLook.ExtensionMethods
{
internal static class DispatcherExtensions
public static class DispatcherExtensions
{
public static void Delay(this Dispatcher disp, int delayMs,
Action<object> action, object parm = null)

View File

@@ -9,21 +9,61 @@
xmlns:plugin="clr-namespace:QuickLook.Plugin"
mc:Ignorable="d" x:Class="QuickLook.MainWindow" x:Name="mainWindow" AllowsTransparency="True" WindowStyle="None"
UseLayoutRounding="True"
Topmost="True" d:DesignWidth="624" d:DesignHeight="700" Width="624" Height="700" WindowStartupLocation="CenterScreen"
Topmost="True" d:DesignWidth="624" d:DesignHeight="700"
WindowStartupLocation="CenterScreen"
x:ClassModifier="internal">
<Window.Background>
<SolidColorBrush Color="#00FFFFFF" />
</Window.Background>
<Grid Name="WindowContainer">
<Grid.Background>
<SolidColorBrush Color="#AAB0B0B0" />
<SolidColorBrush Color="#FFFFFFFF" />
</Grid.Background>
<Grid>
<Grid>
<plugin:ViewContentContainer x:Name="ViewContentContainer" Width="624" Height="700" />
</Grid>
<DockPanel Name="Titlebar" Height="40" VerticalAlignment="Top" Opacity="0">
<DockPanel.Background>
<SolidColorBrush Color="#FFFFFFFF" />
</DockPanel.Background>
<DockPanel.Style>
<Style TargetType="{x:Type DockPanel}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Opacity"
To="1" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.6" Storyboard.TargetProperty="Opacity"
To="0" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</DockPanel.Style>
<fa:ImageAwesome DockPanel.Dock="Right" Name="Close" Icon="WindowClose" Height="20" Margin="10,0"
Cursor="Hand" MouseLeftButtonUp="Close_MouseLeftButtonUp" />
<Label Content="Filename placeholder" FontSize="16" HorizontalContentAlignment="Center"
VerticalContentAlignment="Center" />
</DockPanel>
</Grid>
<Grid Name="LoadingIconLayer">
<Grid.Background>
<SolidColorBrush Color="#FFFFFFFF" />
</Grid.Background>
<Grid Name="LoadingIcon" Height="50" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center">
<fa:ImageAwesome Icon="CircleOutlineNotch" Spin="True" SpinDuration="2" />
</Grid>
<Grid Name="ContentContainer" Width="624" Height="700">
<plugin:ViewContentContainer x:Name="ViewContentContainer"/>
</Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" />
</Grid>
</Window>

View File

@@ -1,30 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Channels;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using QuickLook.ExtensionMethods;
using QuickLook.Plugin;
using QuickLook.Utilities;
using MessageBox = System.Windows.MessageBox;
using Path = System.IO.Path;
namespace QuickLook
{
@@ -39,46 +18,83 @@ namespace QuickLook
WindowContainer.Width = LoadingIcon.Width;
WindowContainer.Height = LoadingIcon.Height;
ContentContainer.Visibility = Visibility.Hidden;
ViewContentContainer.Opacity = 0;
}
private void ZoomToPreferedSize()
internal new void Show()
{
Storyboard sb = new Storyboard { };
ParallelTimeline ptl = new ParallelTimeline();
Height = ViewContentContainer.Height;
Width = ViewContentContainer.Width;
DoubleAnimation animationWidth = new DoubleAnimation
base.Show();
}
internal void ShowFinishLoadingAnimation(TimeSpan delay = new TimeSpan())
{
var speed = 200;
var sb = new Storyboard();
var ptl = new ParallelTimeline {BeginTime = delay};
var aWidth = new DoubleAnimation
{
From = WindowContainer.Width,
To = ContentContainer.Width,
Duration = TimeSpan.FromSeconds(0.2),
To = ViewContentContainer.Width,
Duration = TimeSpan.FromMilliseconds(speed),
DecelerationRatio = 0.3
};
DoubleAnimation animationHeight = new DoubleAnimation
var aHeight = new DoubleAnimation
{
From = WindowContainer.Height,
To = ContentContainer.Height,
Duration = TimeSpan.FromSeconds(0.2),
To = ViewContentContainer.Height,
Duration = TimeSpan.FromMilliseconds(speed),
DecelerationRatio = 0.3
};
Storyboard.SetTarget(animationWidth, WindowContainer);
Storyboard.SetTarget(animationHeight, WindowContainer);
Storyboard.SetTargetProperty(animationWidth, new PropertyPath(WidthProperty));
Storyboard.SetTargetProperty(animationHeight, new PropertyPath(HeightProperty));
var aOpacity = new DoubleAnimation
{
From = 0,
To = 1,
BeginTime = TimeSpan.FromMilliseconds(speed * 0.25),
Duration = TimeSpan.FromMilliseconds(speed * 0.75)
};
ptl.Children.Add(animationWidth);
ptl.Children.Add(animationHeight);
var aOpacityR = new DoubleAnimation
{
From = 1,
To = 0,
Duration = TimeSpan.FromMilliseconds(speed * 2)
};
Storyboard.SetTarget(aWidth, WindowContainer);
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));
ptl.Children.Add(aWidth);
ptl.Children.Add(aHeight);
ptl.Children.Add(aOpacity);
ptl.Children.Add(aOpacityR);
sb.Children.Add(ptl);
sb.Begin();
Dispatcher.DelayWithPriority(speed * 2, o => LoadingIconLayer.Visibility = Visibility.Hidden, null,
DispatcherPriority.Render);
}
private void Button_Click(object sender, RoutedEventArgs e)
private void Close_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ZoomToPreferedSize();
Close();
// useless code to make everyone happy
GC.Collect();
}
}
}

View File

@@ -1,12 +1,58 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using QuickLook.Plugin;
namespace QuickLook
{
class PathToPluginMatcher
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);
});
}
}
}

View File

@@ -2,7 +2,9 @@
{
public interface IViewer
{
bool CanView(string path, byte[] sample);
PluginType Type { get; }
string[] SupportExtensions { get; }
bool CheckSupportByContent(byte[] sample);
void View(string path, ViewContentContainer container);
void Close();
}

View File

@@ -0,0 +1,11 @@
using System;
namespace QuickLook.Plugin
{
[Flags]
public enum PluginType
{
ByExtension = 0x01,
ByContent = 0x10
}
}

View File

@@ -8,7 +8,8 @@
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<ContentControl Name="Container">
<Label Content="ContentControl Placeholder" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Background="LightGray" />
<Label Content="ContentControl Placeholder" VerticalContentAlignment="Center"
HorizontalContentAlignment="Center" Background="LightGray" />
</ContentControl>
</Grid>
</UserControl>

View File

@@ -1,6 +1,4 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;

View File

@@ -1,4 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />

View File

@@ -76,6 +76,7 @@
<Compile Include="PathToPluginMatcher.cs" />
<Compile Include="PluginManager.cs" />
<Compile Include="Plugin\IViewer.cs" />
<Compile Include="Plugin\PluginPriority.cs" />
<Compile Include="Plugin\ViewContentContainer.xaml.cs">
<DependentUpon>ViewContentContainer.xaml</DependentUpon>
</Compile>

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FontAwesome.WPF" version="4.7.0.9" targetFramework="net452" />
</packages>