Skip to content

Commit b2fdd05

Browse files
committed
Fix #633: show preview at the screen of foreground window; macOS-style window alignment
1 parent 8faa152 commit b2fdd05

File tree

2 files changed

+73
-33
lines changed

2 files changed

+73
-33
lines changed

QuickLook/ViewerWindow.Actions.cs

+72-32
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@
1818
using System;
1919
using System.Diagnostics;
2020
using System.IO;
21-
using System.Linq;
2221
using System.Runtime.ExceptionServices;
2322
using System.Windows;
24-
using System.Windows.Documents;
2523
using System.Windows.Input;
2624
using System.Windows.Threading;
2725
using QuickLook.Common.Helpers;
@@ -62,49 +60,90 @@ internal void RunAndClose()
6260
BeginClose();
6361
}
6462

65-
private void ResizeAndCenter(Size size, bool canOldPluginResize, bool canNextPluginResize)
63+
private void ResizeAndCentre(Size size)
6664
{
67-
// resize to MinSize first
68-
size.Width = Math.Max(size.Width, MinWidth);
69-
size.Height = Math.Max(size.Height, MinHeight);
70-
7165
// if the window is now now maximized, do not move it
7266
if (WindowState == WindowState.Maximized)
7367
return;
7468

75-
var screen = WindowHelper.GetCurrentWindowRect();
76-
77-
// otherwise, resize it and place it to the old window center.
78-
var oldCenterX = Left + Width / 2;
79-
var oldCenterY = Top + Height / 2;
80-
81-
var newLeft = oldCenterX - size.Width / 2;
82-
var newTop = oldCenterY - size.Height / 2;
83-
84-
// ensure the new window is fully visible
85-
newLeft = Math.Max(newLeft, screen.Left); // left
86-
newTop = Math.Max(newTop, screen.Top); // top
87-
newLeft = newLeft + size.Width > screen.Right ? screen.Right - size.Width : newLeft; // right
88-
newTop = newTop + size.Height > screen.Bottom ? screen.Bottom - size.Height : newTop; // bottom
69+
var newRect = IsLoaded ? ResizeAndCentreExistingWindow(size) : ResizeAndCentreNewWindow(size);
8970

9071
if (IsLoaded)
9172
{
92-
this.MoveWindow(newLeft, newTop, size.Width, size.Height);
73+
this.MoveWindow(newRect.Left, newRect.Top, newRect.Width, newRect.Height);
9374
}
9475
else
9576
{
96-
// MoveWindow does not work for new windows
97-
Width = size.Width;
98-
Height = size.Height;
99-
Left = newLeft;
100-
Top = newTop;
101-
if (double.IsNaN(Left) || double.IsNaN(Top)) // first time showing
102-
WindowStartupLocation = WindowStartupLocation.CenterScreen;
103-
104-
Dispatcher.BeginInvoke(new Action(() => this.BringToFront(Topmost)), DispatcherPriority.Render);
77+
Top = newRect.Top;
78+
Left = newRect.Left;
79+
Width = newRect.Width;
80+
Height = newRect.Height;
10581
}
10682
}
10783

84+
private Rect ResizeAndCentreExistingWindow(Size size)
85+
{
86+
// align window just like in macOS ...
87+
//
88+
// |10%| 80% |10%|
89+
// |---|-----------|---|---
90+
// |TL | T |TR |10%
91+
// |---|-----------|---|---
92+
// | | | |
93+
// |L | C | R |80%
94+
// | | | |
95+
// |---|-----------|---|---
96+
// |LB | B |RB |10%
97+
// |---|-----------|---|---
98+
99+
const double limitPercentX = 0.1;
100+
const double limitPercentY = 0.1;
101+
102+
var oldRect = new Rect(Left, Top, Width, Height);
103+
104+
// scale to new size, maintain centre
105+
var newRect = Rect.Inflate(oldRect,
106+
(Math.Max(MinWidth, size.Width) - oldRect.Width) / 2,
107+
(Math.Max(MinHeight, size.Height) - oldRect.Height) / 2);
108+
109+
var desktopRect = WindowHelper.GetDesktopRectFromWindow(this);
110+
111+
var leftLimit = desktopRect.Left + desktopRect.Width * limitPercentX;
112+
var rightLimit = desktopRect.Right - desktopRect.Width * limitPercentX;
113+
var topLimit = desktopRect.Top + desktopRect.Height * limitPercentY;
114+
var bottomLimit = desktopRect.Bottom - desktopRect.Height * limitPercentY;
115+
116+
if (oldRect.Left < leftLimit && oldRect.Right < rightLimit) // L
117+
newRect.Location = new Point(Math.Max(oldRect.Left, desktopRect.Left), newRect.Top);
118+
else if (oldRect.Left > leftLimit && oldRect.Right > rightLimit) // R
119+
newRect.Location = new Point(Math.Min(oldRect.Right, desktopRect.Right) - newRect.Width, newRect.Top);
120+
else // C, fix window boundary
121+
newRect.Offset(
122+
Math.Max(0, desktopRect.Left - newRect.Left) + Math.Min(0, desktopRect.Right - newRect.Right), 0);
123+
124+
if (oldRect.Top < topLimit && oldRect.Bottom < bottomLimit) // T
125+
newRect.Location = new Point(newRect.Left, Math.Max(oldRect.Top, desktopRect.Top));
126+
else if (oldRect.Top > topLimit && oldRect.Bottom > bottomLimit) // B
127+
newRect.Location = new Point(newRect.Left,
128+
Math.Min(oldRect.Bottom, desktopRect.Bottom) - newRect.Height);
129+
else // C, fix window boundary
130+
newRect.Offset(0,
131+
Math.Max(0, desktopRect.Top - newRect.Top) + Math.Min(0, desktopRect.Bottom - newRect.Bottom));
132+
133+
return newRect;
134+
}
135+
136+
private Rect ResizeAndCentreNewWindow(Size size)
137+
{
138+
var desktopRect = WindowHelper.GetCurrentDesktopRect();
139+
140+
var newRect = Rect.Inflate(desktopRect,
141+
(Math.Max(MinWidth, size.Width) - desktopRect.Width) / 2,
142+
(Math.Max(MinHeight, size.Height) - desktopRect.Height) / 2);
143+
144+
return newRect;
145+
}
146+
108147
internal void UnloadPlugin()
109148
{
110149
// the focused element will not processed by GC: https://stackoverflow.com/questions/30848939/memory-leak-due-to-window-efectivevalues-retention
@@ -164,7 +203,8 @@ internal void BeginShow(IViewer matchedPlugin, string path,
164203
else
165204
_ignoreNextWindowSizeChange = true;
166205

167-
ResizeAndCenter(newSize, _canOldPluginResize, ContextObject.CanResize);
206+
ResizeAndCentre(newSize);
207+
Dispatcher.BeginInvoke(new Action(() => this.BringToFront(Topmost)), DispatcherPriority.Render);
168208

169209
if (Visibility != Visibility.Visible)
170210
Show();

0 commit comments

Comments
 (0)