mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-14 12:19:08 +00:00
reuse viewer window
This commit is contained in:
@@ -56,6 +56,8 @@ namespace QuickLook.Plugin.VideoViewer
|
||||
mediaElement.Stop();
|
||||
|
||||
_context.ShowNotification("", "An error occurred while loading the video.");
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public void LoadAndPlay(string path)
|
||||
|
@@ -20,22 +20,27 @@
|
||||
</Window.Background>
|
||||
<Border x:Name="windowBorder" BorderThickness="1" BorderBrush="#FF7B7B7B">
|
||||
<Grid>
|
||||
<DockPanel x:Name="windowPanel" Opacity="1">
|
||||
<DockPanel x:Name="windowPanel">
|
||||
<DockPanel.Style>
|
||||
<Style TargetType="{x:Type DockPanel}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow}" Value="False">
|
||||
<DataTrigger Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow, Mode=OneWay}" Value="False">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity"
|
||||
From="0"
|
||||
To="1"
|
||||
BeginTime="0:0:0"
|
||||
Duration="0:0:0.1" />
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1"
|
||||
BeginTime="0:0:0" Duration="0:0:0.05" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0"
|
||||
BeginTime="0:0:0" Duration="0:0:0" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -52,37 +57,52 @@
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
<Grid>
|
||||
<local:ViewContentContainer x:Name="viewContentContainer" />
|
||||
<ContentControl x:Name="container" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
<Grid x:Name="busyIndicatorLayer" Visibility="Hidden">
|
||||
<Grid x:Name="busyIndicatorLayer">
|
||||
<Grid.Style>
|
||||
<Style TargetType="{x:Type Grid}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow}" Value="False">
|
||||
<DataTrigger Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow, Mode=OneWay}" Value="False">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ParallelTimeline>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity"
|
||||
From="1"
|
||||
To="0"
|
||||
BeginTime="0:0:0"
|
||||
Duration="0:0:0.1" />
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0"
|
||||
BeginTime="0:0:0" Duration="0:0:0.05" />
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0.1"
|
||||
Value="{x:Static Visibility.Collapsed}" />
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0.05"
|
||||
Value="{x:Static Visibility.Hidden}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</ParallelTimeline>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ParallelTimeline>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1"
|
||||
BeginTime="0:0:0" Duration="0:0:0" />
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0"
|
||||
Value="{x:Static Visibility.Visible}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</ParallelTimeline>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Grid.Style>
|
||||
<control:BusyDecorator x:Name="busyDecorator" IsBusyIndicatorShowing="True" VerticalAlignment="Center"
|
||||
<!--IsBusyIndicatorShowing="{Binding IsVisible, ElementName=busyIndicatorLayer}"-->
|
||||
<control:BusyDecorator x:Name="busyDecorator"
|
||||
IsBusyIndicatorShowing="True"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
@@ -2,7 +2,8 @@
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Threading;
|
||||
using QuickLook.ExtensionMethods;
|
||||
using QuickLook.Helpers;
|
||||
using QuickLook.Plugin;
|
||||
|
||||
@@ -11,7 +12,7 @@ namespace QuickLook
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
internal partial class MainWindow : Window, IDisposable
|
||||
internal partial class MainWindow : Window
|
||||
{
|
||||
internal MainWindow()
|
||||
{
|
||||
@@ -20,31 +21,23 @@ namespace QuickLook
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
// revert designer changes
|
||||
windowPanel.Opacity = 0d;
|
||||
busyIndicatorLayer.Visibility = Visibility.Visible;
|
||||
busyIndicatorLayer.Opacity = 1d;
|
||||
|
||||
// do not set TopMost property if we are now debugging. it makes debugging painful...
|
||||
if (!Debugger.IsAttached)
|
||||
Topmost = true;
|
||||
|
||||
// restore changes by Designer
|
||||
windowPanel.Opacity = 0d;
|
||||
busyIndicatorLayer.Visibility = Visibility.Visible;
|
||||
|
||||
Loaded += (sender, e) => AeroGlassHelper.EnableBlur(this);
|
||||
|
||||
buttonCloseWindow.MouseLeftButtonUp += (sender, e) => Close();
|
||||
buttonCloseWindow.MouseLeftButtonUp += (sender, e) => { Hide(); };
|
||||
|
||||
titleBarArea.PreviewMouseLeftButtonDown += DragMoveCurrentWindow;
|
||||
}
|
||||
|
||||
public ContextObject ContextObject { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
ContextObject?.Dispose();
|
||||
|
||||
// stop the background thread
|
||||
busyDecorator?.Dispose();
|
||||
}
|
||||
public ContextObject ContextObject { get; private set; }
|
||||
|
||||
private void DragMoveCurrentWindow(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
@@ -71,17 +64,37 @@ namespace QuickLook
|
||||
Width = ContextObject.PreferredSize.Width + windowBorder.BorderThickness.Left +
|
||||
windowBorder.BorderThickness.Right;
|
||||
|
||||
Left = (SystemParameters.VirtualScreenWidth - Width) / 2;
|
||||
Top = (SystemParameters.VirtualScreenHeight - Height) / 2;
|
||||
|
||||
ResizeMode = ContextObject.CanResize ? ResizeMode.CanResizeWithGrip : ResizeMode.NoResize;
|
||||
|
||||
base.Show();
|
||||
|
||||
if (!ContextObject.Focusable)
|
||||
WindowHelper.SetNoactivate(new WindowInteropHelper(this));
|
||||
//if (!ContextObject.Focusable)
|
||||
// WindowHelper.SetNoactivate(new WindowInteropHelper(this));
|
||||
}
|
||||
|
||||
private new void Hide()
|
||||
{
|
||||
container.Content = null;
|
||||
|
||||
// clean up plugin and refresh ContextObject for next use
|
||||
ContextObject.ViewerPlugin?.Dispose();
|
||||
ContextObject.Reset();
|
||||
|
||||
GC.Collect();
|
||||
|
||||
// revert UI changes
|
||||
ContextObject.IsBusy = true;
|
||||
|
||||
Left -= 10000;
|
||||
Dispatcher.Delay(100, _ => base.Hide());
|
||||
}
|
||||
|
||||
internal void BeginShow(IViewer matchedPlugin, string path)
|
||||
{
|
||||
ContextObject.CurrentContentContainer = viewContentContainer;
|
||||
ContextObject.CurrentContentContainer = container;
|
||||
ContextObject.ViewerPlugin = matchedPlugin;
|
||||
|
||||
// get window size before showing it
|
||||
@@ -89,12 +102,19 @@ namespace QuickLook
|
||||
|
||||
Show();
|
||||
|
||||
matchedPlugin.View(path, ContextObject);
|
||||
// load plugin, do not block UI
|
||||
Dispatcher.BeginInvoke(new Action(() => matchedPlugin.View(path, ContextObject)),
|
||||
DispatcherPriority.Render);
|
||||
}
|
||||
|
||||
~MainWindow()
|
||||
internal bool BeginHide()
|
||||
{
|
||||
Dispose();
|
||||
if (Visibility != Visibility.Visible)
|
||||
return false;
|
||||
|
||||
Hide();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using QuickLook.Annotations;
|
||||
|
||||
namespace QuickLook.Plugin
|
||||
@@ -9,12 +10,12 @@ namespace QuickLook.Plugin
|
||||
/// <summary>
|
||||
/// A runtime object which allows interaction between this plugin and QuickLook.
|
||||
/// </summary>
|
||||
public class ContextObject : INotifyPropertyChanged, IDisposable
|
||||
public class ContextObject : INotifyPropertyChanged
|
||||
{
|
||||
private bool _isBusy = true;
|
||||
|
||||
private string _title = "";
|
||||
internal ViewContentContainer CurrentContentContainer;
|
||||
internal ContentControl CurrentContentContainer;
|
||||
internal IViewer ViewerPlugin;
|
||||
|
||||
/// <summary>
|
||||
@@ -35,8 +36,8 @@ namespace QuickLook.Plugin
|
||||
/// </summary>
|
||||
public object ViewerContent
|
||||
{
|
||||
get => CurrentContentContainer.container.Content;
|
||||
set => CurrentContentContainer.container.Content = value;
|
||||
get => CurrentContentContainer.Content;
|
||||
set => CurrentContentContainer.Content = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -67,10 +68,8 @@ namespace QuickLook.Plugin
|
||||
/// </summary>
|
||||
public bool Focusable { get; set; } = false;
|
||||
|
||||
public void Dispose()
|
||||
public void DisposePlugin()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
ViewerPlugin?.Dispose();
|
||||
ViewerPlugin = null;
|
||||
}
|
||||
@@ -105,7 +104,6 @@ namespace QuickLook.Plugin
|
||||
var heightRatio = max.Height * maxRatio / size.Height;
|
||||
|
||||
var ratio = Math.Min(widthRatio, heightRatio);
|
||||
|
||||
if (ratio > 1) ratio = 1;
|
||||
|
||||
PreferredSize = new Size {Width = size.Width * ratio, Height = size.Height * ratio};
|
||||
@@ -121,15 +119,20 @@ namespace QuickLook.Plugin
|
||||
return new Size(SystemParameters.VirtualScreenWidth, SystemParameters.VirtualScreenHeight);
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Title = "";
|
||||
ViewerContent = null;
|
||||
IsBusy = true;
|
||||
PreferredSize = new Size();
|
||||
CanResize = true;
|
||||
Focusable = false;
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
~ContextObject()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@@ -101,9 +101,6 @@
|
||||
<Compile Include="Plugin\IViewer.cs" />
|
||||
<Compile Include="Helpers\DpiHelpers.cs" />
|
||||
<Compile Include="TrayIcon.cs" />
|
||||
<Compile Include="ViewContentContainer.xaml.cs">
|
||||
<DependentUpon>ViewContentContainer.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Plugin\ContextObject.cs" />
|
||||
<Compile Include="Helpers\WindowHelper.cs" />
|
||||
<Compile Include="ViewWindowManager.cs" />
|
||||
@@ -134,10 +131,6 @@
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="ViewContentContainer.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Styles\BusyDecorator.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
@@ -1,15 +0,0 @@
|
||||
<UserControl x:Class="QuickLook.ViewContentContainer"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:QuickLook"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<Grid>
|
||||
<ContentControl x:Name="container">
|
||||
<Label Content="ContentControl Placeholder" VerticalContentAlignment="Center"
|
||||
HorizontalContentAlignment="Center" Background="LightGray" />
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -1,15 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace QuickLook
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ViewContentContainer.xaml
|
||||
/// </summary>
|
||||
public partial class ViewContentContainer : UserControl
|
||||
{
|
||||
public ViewContentContainer()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,7 +15,31 @@ namespace QuickLook
|
||||
{
|
||||
private static ViewWindowManager _instance;
|
||||
|
||||
private MainWindow _viewWindow;
|
||||
private readonly MainWindow _viewWindow;
|
||||
|
||||
internal ViewWindowManager()
|
||||
{
|
||||
_viewWindow = new MainWindow();
|
||||
_viewWindow.Closed += (sender, e) =>
|
||||
{
|
||||
if (App.RunningAsViewer)
|
||||
Application.Current.Shutdown();
|
||||
};
|
||||
}
|
||||
|
||||
internal void InvokeRoutine()
|
||||
{
|
||||
if (!WindowHelper.IsFocusedControlExplorerItem())
|
||||
if (!WindowHelper.IsFocusedWindowSelf())
|
||||
return;
|
||||
|
||||
if (_viewWindow.BeginHide())
|
||||
return;
|
||||
|
||||
var path = GetCurrentSelection();
|
||||
|
||||
InvokeViewer(path);
|
||||
}
|
||||
|
||||
internal void InvokeViewer(string path)
|
||||
{
|
||||
@@ -29,43 +53,15 @@ namespace QuickLook
|
||||
BeginShowNewWindow(matchedPlugin, path);
|
||||
}
|
||||
|
||||
internal void InvokeRoutine()
|
||||
{
|
||||
if (!WindowHelper.IsFocusedControlExplorerItem())
|
||||
if (!WindowHelper.IsFocusedWindowSelf())
|
||||
return;
|
||||
|
||||
if (CloseCurrentWindow())
|
||||
return;
|
||||
|
||||
var path = GetCurrentSelection();
|
||||
|
||||
InvokeViewer(path);
|
||||
}
|
||||
|
||||
private void BeginShowNewWindow(IViewer matchedPlugin, string path)
|
||||
{
|
||||
_viewWindow = new MainWindow();
|
||||
_viewWindow.Closed += (sender2, e2) =>
|
||||
{
|
||||
if (App.RunningAsViewer)
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
_viewWindow.Dispose();
|
||||
_viewWindow = null;
|
||||
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
_viewWindow.BeginShow(matchedPlugin, path);
|
||||
}
|
||||
catch (Exception e) // if current plugin failed, switch to default one.
|
||||
{
|
||||
_viewWindow.Close();
|
||||
_viewWindow.BeginHide();
|
||||
|
||||
Debug.WriteLine(e.ToString());
|
||||
Debug.WriteLine(e.StackTrace);
|
||||
@@ -81,34 +77,6 @@ namespace QuickLook
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#pragma warning disable 1058
|
||||
catch // Catch SEH exceptions here.
|
||||
#pragma warning restore 1058
|
||||
{
|
||||
_viewWindow.Close();
|
||||
|
||||
if (matchedPlugin.GetType() != PluginManager.GetInstance().DefaultPlugin)
|
||||
{
|
||||
matchedPlugin.Dispose();
|
||||
matchedPlugin = PluginManager.GetInstance().DefaultPlugin.CreateInstance<IViewer>();
|
||||
BeginShowNewWindow(matchedPlugin, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CloseCurrentWindow()
|
||||
{
|
||||
if (_viewWindow != null)
|
||||
{
|
||||
_viewWindow.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private string GetCurrentSelection()
|
||||
|
Reference in New Issue
Block a user