mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-16 13:22:40 +00:00
Address #122: final solution for window resizing by bring macOS's logic
This commit is contained in:
@@ -68,13 +68,13 @@
|
||||
<DropShadowEffect ShadowDepth="0" BlurRadius="2" Opacity="0.7" Color="#B2FFFFFF" />
|
||||
</Grid.Effect>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="70" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="10" />
|
||||
<RowDefinition Height="4*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="15" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="6*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock x:Name="metaTitle" Grid.Row="1" FontSize="22" Padding="3"
|
||||
TextWrapping="Wrap"
|
||||
|
@@ -22,26 +22,22 @@ using System.Windows.Data;
|
||||
|
||||
namespace QuickLook.Converters
|
||||
{
|
||||
public sealed class BooleanAndWindowStateToThicknessConverter : DependencyObject, IMultiValueConverter
|
||||
public sealed class WindowStateToThicknessConverter : DependencyObject, IValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var zero = new Thickness();
|
||||
var def = parameter as Thickness? ?? new Thickness();
|
||||
|
||||
if (values == null || values.Length != 2)
|
||||
if (value == null)
|
||||
return zero;
|
||||
|
||||
var canResize = values[0] as bool? ?? false;
|
||||
var state = values[1] as WindowState? ?? WindowState.Normal;
|
||||
|
||||
if (!canResize)
|
||||
return zero;
|
||||
var state = value as WindowState? ?? WindowState.Normal;
|
||||
|
||||
return state == WindowState.Maximized ? zero : def;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
@@ -78,13 +78,12 @@ namespace QuickLook
|
||||
private int HookProc(int code, int wParam, ref User32.KeyboardHookStruct lParam)
|
||||
{
|
||||
if (code >= 0)
|
||||
{
|
||||
if (!IsWindowsKeyPressed())
|
||||
{
|
||||
var key = (Keys)lParam.vkCode;
|
||||
if (HookedKeys.Contains(key))
|
||||
var key = (Keys) lParam.vkCode;
|
||||
if (HookedKeys.Contains(key))
|
||||
{
|
||||
key = AddModifiers(key);
|
||||
key = AddModifiers(key);
|
||||
|
||||
var kea = new KeyEventArgs(key);
|
||||
if (wParam == User32.WM_KEYDOWN || wParam == User32.WM_SYSKEYDOWN)
|
||||
@@ -95,7 +94,6 @@ namespace QuickLook
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return User32.CallNextHookEx(_hhook, code, wParam, ref lParam);
|
||||
}
|
||||
|
||||
|
@@ -229,7 +229,7 @@ namespace QuickLook.Plugin
|
||||
var heightRatio = max.Height * maxRatio / size.Height;
|
||||
|
||||
var ratio = Math.Min(widthRatio, heightRatio);
|
||||
//if (ratio > 1) ratio = 1;
|
||||
if (ratio > 1) ratio = 1;
|
||||
|
||||
PreferredSize = new Size {Width = size.Width * ratio, Height = size.Height * ratio};
|
||||
|
||||
|
@@ -99,7 +99,7 @@ namespace QuickLook.Plugin.InfoPanel
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
FileHelper.CountFolder(path, ref _stop,
|
||||
out long totalDirsL, out long totalFilesL, out long totalSizeL);
|
||||
out var totalDirsL, out var totalFilesL, out var totalSizeL);
|
||||
|
||||
if (!Stop)
|
||||
Dispatcher.Invoke(() =>
|
||||
|
@@ -120,7 +120,7 @@
|
||||
<Compile Include="Controls\MainWindowBase.cs" />
|
||||
<Compile Include="Converters\BooleanToKeyTimeConverter.cs" />
|
||||
<Compile Include="Converters\BooleanToVisibilityCollapsedConverter.cs" />
|
||||
<Compile Include="Converters\BooleanToResizeBorderThicknessConverter.cs" />
|
||||
<Compile Include="Converters\WindowStateToThicknessConverter.cs" />
|
||||
<Compile Include="Converters\ScaledValueConverter.cs" />
|
||||
<Compile Include="ExtensionMethods\BitmapExtensions.cs" />
|
||||
<Compile Include="Controls\BusyDecorator\ControlExtensions.cs" />
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
<Thickness x:Key="MainWindowShadowMarginThinkness">1</Thickness>
|
||||
<Thickness x:Key="MainWindowResizeThinkness">6</Thickness>
|
||||
<Thickness x:Key="MainWindowShadowMarginThickness">1</Thickness>
|
||||
<Thickness x:Key="MainWindowResizeThickness">6</Thickness>
|
||||
<system:Double x:Key="MainWindowCaptionHeight">32</system:Double>
|
||||
<Color x:Key="MainWindowShadowColor">Gray</Color>
|
||||
<SolidColorBrush x:Key="MainWindowBackground" Color="#FFFAFAFA" />
|
||||
|
@@ -80,40 +80,36 @@ namespace QuickLook
|
||||
BeginClose();
|
||||
}
|
||||
|
||||
private static void ResizeAndCenter(Window window, Size size, bool canOldPluginResize, bool canNextPluginResize)
|
||||
private void ResizeAndCenter(Size size, bool canOldPluginResize, bool canNextPluginResize)
|
||||
{
|
||||
// resize to MinSize first
|
||||
size.Width = Math.Max(size.Width, window.MinWidth);
|
||||
size.Height = Math.Max(size.Height, window.MinHeight);
|
||||
size.Width = Math.Max(size.Width, MinWidth);
|
||||
size.Height = Math.Max(size.Height, MinHeight);
|
||||
|
||||
if (!window.IsLoaded)
|
||||
if (!IsLoaded)
|
||||
{
|
||||
// if the window is not loaded yet, just leave the problem to WPF
|
||||
window.Width = size.Width;
|
||||
window.Height = size.Height;
|
||||
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||
window.Dispatcher.BeginInvoke(new Action(window.BringToFront), DispatcherPriority.Render);
|
||||
Width = size.Width;
|
||||
Height = size.Height;
|
||||
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||
Dispatcher.BeginInvoke(new Action(this.BringToFront), DispatcherPriority.Render);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// is the window is now now maximized, do not move it
|
||||
if (window.WindowState == WindowState.Maximized)
|
||||
if (WindowState == WindowState.Maximized)
|
||||
return;
|
||||
|
||||
// if this is a new window, place it to top
|
||||
if (window.Visibility != Visibility.Visible)
|
||||
window.BringToFront();
|
||||
if (Visibility != Visibility.Visible)
|
||||
this.BringToFront();
|
||||
|
||||
var screen = WindowHelper.GetCurrentWindowRect();
|
||||
|
||||
// do not resize or reposition the window is it is visible - unless the next window is size-fixed
|
||||
if (window.Visibility == Visibility.Visible && canOldPluginResize && canNextPluginResize)
|
||||
return;
|
||||
|
||||
// otherwise, resize it and place it to the old window center.
|
||||
var oldCenterX = window.Left + window.Width / 2;
|
||||
var oldCenterY = window.Top + window.Height / 2;
|
||||
var oldCenterX = Left + Width / 2;
|
||||
var oldCenterY = Top + Height / 2;
|
||||
|
||||
var newLeft = oldCenterX - size.Width / 2;
|
||||
var newTop = oldCenterY - size.Height / 2;
|
||||
@@ -124,7 +120,7 @@ namespace QuickLook
|
||||
newLeft = newLeft + size.Width > screen.Right ? screen.Right - size.Width : newLeft; // right
|
||||
newTop = newTop + size.Height > screen.Bottom ? screen.Bottom - size.Height : newTop; // bottom
|
||||
|
||||
window.MoveWindow(newLeft, newTop, size.Width, size.Height);
|
||||
this.MoveWindow(newLeft, newTop, size.Width, size.Height);
|
||||
}
|
||||
|
||||
internal void UnloadPlugin()
|
||||
@@ -181,7 +177,14 @@ namespace QuickLook
|
||||
(ContextObject.TitlebarOverlap ? 0 : windowCaptionContainer.Height);
|
||||
var newWidth = ContextObject.PreferredSize.Width + margin;
|
||||
|
||||
ResizeAndCenter(this, new Size(newWidth, newHeight), _canOldPluginResize, ContextObject.CanResize);
|
||||
var newSize = new Size(newWidth, newHeight);
|
||||
// if use has adjusted the window size, keep it
|
||||
if (_customWindowSize != Size.Empty)
|
||||
newSize = _customWindowSize;
|
||||
else
|
||||
_ignoreNextWindowSizeChange = true;
|
||||
|
||||
ResizeAndCenter(newSize, _canOldPluginResize, ContextObject.CanResize);
|
||||
|
||||
if (Visibility != Visibility.Visible)
|
||||
Show();
|
||||
@@ -251,6 +254,10 @@ namespace QuickLook
|
||||
|
||||
internal void BeginHide()
|
||||
{
|
||||
// reset custom window size
|
||||
_customWindowSize = Size.Empty;
|
||||
_ignoreNextWindowSizeChange = true;
|
||||
|
||||
UnloadPlugin();
|
||||
|
||||
// if the this window is hidden in Max state, new show() will results in failure:
|
||||
|
@@ -20,48 +20,37 @@
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Styles/MainWindowStyles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<converters:BooleanAndWindowStateToThicknessConverter x:Key="BooleanAndWindowStateToThicknessConverter" />
|
||||
<converters:WindowStateToThicknessConverter x:Key="WindowStateToThicknessConverter" />
|
||||
<converters:BooleanToVisibilityCollapsedConverter x:Key="BooleanToVisibilityCollapsedConverter" />
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
</ResourceDictionary>
|
||||
</controls:MainWindowBase.Resources>
|
||||
<WindowChrome.WindowChrome>
|
||||
<WindowChrome CaptionHeight="0" CornerRadius="0" GlassFrameThickness="0,0,0,1"
|
||||
UseAeroCaptionButtons="False">
|
||||
<WindowChrome.ResizeBorderThickness>
|
||||
<MultiBinding Converter="{StaticResource BooleanAndWindowStateToThicknessConverter}" ConverterParameter="{StaticResource MainWindowResizeThinkness}">
|
||||
<Binding ElementName="mainWindow" Path="ContextObject.CanResize" />
|
||||
<Binding ElementName="mainWindow" Path="WindowState" />
|
||||
</MultiBinding>
|
||||
</WindowChrome.ResizeBorderThickness>
|
||||
</WindowChrome>
|
||||
ResizeBorderThickness="{Binding ElementName=mainWindow, Path=WindowState, Converter={StaticResource WindowStateToThicknessConverter}, ConverterParameter={StaticResource MainWindowResizeThickness}}"
|
||||
UseAeroCaptionButtons="False" />
|
||||
</WindowChrome.WindowChrome>
|
||||
<controls:MainWindowBase.Style>
|
||||
<Style TargetType="controls:MainWindowBase">
|
||||
<Setter Property="Foreground" Value="{DynamicResource WindowTextForeground}" />
|
||||
</Style>
|
||||
</controls:MainWindowBase.Style>
|
||||
<Grid x:Name="windowFrameContainer" Background="{DynamicResource CaptionBackground}">
|
||||
<Grid.Margin>
|
||||
<MultiBinding Converter="{StaticResource BooleanAndWindowStateToThicknessConverter}" ConverterParameter="{StaticResource MainWindowShadowMarginThinkness}">
|
||||
<Binding ElementName="mainWindow" Path="ContextObject.CanResize" />
|
||||
<Binding ElementName="mainWindow" Path="WindowState" />
|
||||
</MultiBinding>
|
||||
</Grid.Margin>
|
||||
<Grid x:Name="windowFrameContainer" Background="{DynamicResource CaptionBackground}"
|
||||
Margin="{Binding ElementName=mainWindow, Path=WindowState, Converter={StaticResource WindowStateToThicknessConverter}, ConverterParameter={StaticResource MainWindowShadowMarginThickness}}">
|
||||
<Grid x:Name="viewerRootContainer" ZIndex="190">
|
||||
<Grid x:Name="windowCaptionContainer" Height="{StaticResource MainWindowCaptionHeight}"
|
||||
VerticalAlignment="Top"
|
||||
ZIndex="100">
|
||||
VerticalAlignment="Top"
|
||||
ZIndex="100">
|
||||
<Grid.Resources>
|
||||
<Storyboard x:Key="ShowCaptionContainerStoryboard" Completed="AutoHideCaptionContainer">
|
||||
<DoubleAnimation
|
||||
Storyboard.Target="{Binding Source={x:Reference windowCaptionContainer}}"
|
||||
Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.05" />
|
||||
Storyboard.Target="{Binding Source={x:Reference windowCaptionContainer}}"
|
||||
Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.05" />
|
||||
</Storyboard>
|
||||
<Storyboard x:Key="HideCaptionContainerStoryboard">
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
Storyboard.Target="{Binding Source={x:Reference windowCaptionContainer}}"
|
||||
Storyboard.TargetProperty="Opacity">
|
||||
Storyboard.Target="{Binding Source={x:Reference windowCaptionContainer}}"
|
||||
Storyboard.TargetProperty="Opacity">
|
||||
<DoubleAnimationUsingKeyFrames.KeyFrames>
|
||||
<LinearDoubleKeyFrame Value="1" KeyTime="0:0:0" />
|
||||
<LinearDoubleKeyFrame Value="1" KeyTime="0:0:1" />
|
||||
@@ -71,24 +60,24 @@
|
||||
</Storyboard>
|
||||
</Grid.Resources>
|
||||
<glassLayer:GlassLayer OverlayColor="{DynamicResource CaptionBackground}"
|
||||
BlurredElement="{Binding ElementName=containerPanel}"
|
||||
ColorOverlayVisibility="{Binding ContextObject.TitlebarColourVisibility, ElementName=mainWindow, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
GlassVisibility="{Binding ContextObject.TitlebarBlurVisibility, ElementName=mainWindow, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
NoiseVisibility="Visible" />
|
||||
BlurredElement="{Binding ElementName=containerPanel}"
|
||||
ColorOverlayVisibility="{Binding ContextObject.TitlebarColourVisibility, ElementName=mainWindow, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
GlassVisibility="{Binding ContextObject.TitlebarBlurVisibility, ElementName=mainWindow, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
NoiseVisibility="Visible" />
|
||||
<DockPanel>
|
||||
<DockPanel.Effect>
|
||||
<DropShadowEffect ShadowDepth="0" BlurRadius="2" Opacity="0.7" Color="#B2FFFFFF" />
|
||||
</DockPanel.Effect>
|
||||
<Button DockPanel.Dock="Right" x:Name="buttonCloseWindow"
|
||||
Style="{StaticResource CaptionCloseButtonStyle}" Content="" />
|
||||
Style="{StaticResource CaptionCloseButtonStyle}" Content="" />
|
||||
<Button DockPanel.Dock="Right" x:Name="buttonWindowStatus"
|
||||
Visibility="{Binding ContextObject.CanResize, ElementName=mainWindow, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
Visibility="{Binding ContextObject.CanResize, ElementName=mainWindow, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<Button.Style>
|
||||
<Style TargetType="Button" BasedOn="{StaticResource CaptionButtonStyle}">
|
||||
<Setter Property="Content" Value="" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding WindowState, ElementName=mainWindow}"
|
||||
Value="Maximized">
|
||||
Value="Maximized">
|
||||
<Setter Property="Content" Value="" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
@@ -96,10 +85,10 @@
|
||||
</Button.Style>
|
||||
</Button>
|
||||
<Button x:Name="buttonOpenWith" DockPanel.Dock="Right"
|
||||
Style="{StaticResource CaptionTextButtonStyle}">
|
||||
Style="{StaticResource CaptionTextButtonStyle}">
|
||||
<Button.Content>
|
||||
<TextBlock x:Name="buttonOpenWithText" VerticalAlignment="Center">
|
||||
Open with <Bold>AppName</Bold>
|
||||
Open with <Bold>AppName</Bold>
|
||||
</TextBlock>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
@@ -146,27 +135,27 @@
|
||||
</Button.Style>
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Left" x:Name="buttonShare" Style="{StaticResource CaptionButtonStyle}"
|
||||
Content="" />
|
||||
Content="" />
|
||||
<Grid x:Name="titleArea" Background="Transparent">
|
||||
<TextBlock Text="{Binding ContextObject.Title, ElementName=mainWindow}" FontSize="12"
|
||||
HorizontalAlignment="Left" TextTrimming="CharacterEllipsis"
|
||||
VerticalAlignment="Center" Margin="5,0" />
|
||||
HorizontalAlignment="Left" TextTrimming="CharacterEllipsis"
|
||||
VerticalAlignment="Center" Margin="5,0" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<DockPanel x:Name="containerPanel" Background="{DynamicResource MainWindowBackground}" ZIndex="80">
|
||||
<Grid DockPanel.Dock="Top" Height="{StaticResource MainWindowCaptionHeight}"
|
||||
Visibility="{Binding ContextObject.TitlebarOverlap, ElementName=mainWindow, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}" />
|
||||
Visibility="{Binding ContextObject.TitlebarOverlap, ElementName=mainWindow, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}" />
|
||||
<ContentControl x:Name="container"
|
||||
Foreground="{DynamicResource WindowTextForeground}"
|
||||
Content="{Binding ContextObject.ViewerContent, ElementName=mainWindow}" />
|
||||
Foreground="{DynamicResource WindowTextForeground}"
|
||||
Content="{Binding ContextObject.ViewerContent, ElementName=mainWindow}" />
|
||||
<DockPanel.Style>
|
||||
<Style TargetType="{x:Type DockPanel}">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger
|
||||
Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow}"
|
||||
Value="True">
|
||||
Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow}"
|
||||
Value="True">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
@@ -180,17 +169,17 @@
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger
|
||||
Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow}"
|
||||
Value="True">
|
||||
Binding="{Binding ContextObject.IsBusy, ElementName=mainWindow}"
|
||||
Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Grid.Style>
|
||||
<busyDecorator:BusyDecorator x:Name="busyDecorator"
|
||||
IsBusyIndicatorShowing="True"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" />
|
||||
IsBusyIndicatorShowing="True"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</controls:MainWindowBase>
|
@@ -31,7 +31,9 @@ namespace QuickLook
|
||||
/// </summary>
|
||||
public partial class ViewerWindow : MainWindowBase
|
||||
{
|
||||
private string _path;
|
||||
private Size _customWindowSize = Size.Empty;
|
||||
private bool _ignoreNextWindowSizeChange;
|
||||
private string _path = string.Empty;
|
||||
private bool _restoreForDragMove;
|
||||
|
||||
internal ViewerWindow()
|
||||
@@ -43,6 +45,10 @@ namespace QuickLook
|
||||
|
||||
FontFamily = new FontFamily(TranslationHelper.GetString("UI_FontFamily", failsafe: "Segoe UI"));
|
||||
|
||||
SizeChanged += SaveWindowSizeOnSizeChanged;
|
||||
|
||||
StateChanged += (sender, e) => _ignoreNextWindowSizeChange = true;
|
||||
|
||||
windowCaptionContainer.MouseLeftButtonDown += WindowDragMoveStart;
|
||||
windowCaptionContainer.MouseMove += WindowDragMoving;
|
||||
windowCaptionContainer.MouseLeftButtonUp += WindowDragMoveEnd;
|
||||
@@ -87,6 +93,22 @@ namespace QuickLook
|
||||
buttonShare.Click += Share;
|
||||
}
|
||||
|
||||
private void SaveWindowSizeOnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
// first shown?
|
||||
if (e.PreviousSize == new Size(0, 0))
|
||||
return;
|
||||
// resize when switching preview?
|
||||
if (_ignoreNextWindowSizeChange)
|
||||
{
|
||||
_ignoreNextWindowSizeChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// by user?
|
||||
_customWindowSize = new Size(Width, Height);
|
||||
}
|
||||
|
||||
private void ShowWindowCaptionContainer(object sender, MouseEventArgs e)
|
||||
{
|
||||
var show = (Storyboard) windowCaptionContainer.FindResource("ShowCaptionContainerStoryboard");
|
||||
|
Reference in New Issue
Block a user