Skip to content

Commit

Permalink
Merge pull request #1514 from AdditionalPylons/restore-minimize-anima…
Browse files Browse the repository at this point in the history
…tions

Introduce restore and minimize animations
  • Loading branch information
flagbug committed Aug 24, 2014
2 parents 422cc7e + effbbaf commit d57d1e4
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 28 deletions.
30 changes: 27 additions & 3 deletions MahApps.Metro/Behaviours/BorderlessWindowBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ protected override void OnAttached()
windowChrome.IgnoreTaskbarOnMaximize = metroWindow.IgnoreTaskbarOnMaximize;
System.ComponentModel.DependencyPropertyDescriptor.FromProperty(MetroWindow.IgnoreTaskbarOnMaximizeProperty, typeof(MetroWindow))
.AddValueChanged(AssociatedObject, IgnoreTaskbarOnMaximizePropertyChangedCallback);
System.ComponentModel.DependencyPropertyDescriptor.FromProperty(MetroWindow.UseNoneWindowStyleProperty, typeof(MetroWindow))
.AddValueChanged(AssociatedObject, UseNoneWindowStylePropertyChangedCallback);
}

AssociatedObject.SetValue(WindowChrome.WindowChromeProperty, windowChrome);
Expand All @@ -52,7 +54,6 @@ protected override void OnAttached()
//For some reason, we can't determine if the window has loaded or not, so we swallow the exception.
}
}
AssociatedObject.WindowStyle = WindowStyle.None;
savedBorderThickness = AssociatedObject.BorderThickness;

AssociatedObject.Loaded += AssociatedObject_Loaded;
Expand All @@ -70,6 +71,17 @@ private void IgnoreTaskbarOnMaximizePropertyChangedCallback(object sender, Event
if (metroWindow != null && windowChrome != null)
{
windowChrome.IgnoreTaskbarOnMaximize = metroWindow.IgnoreTaskbarOnMaximize;
UpdateWindowStyle();
}
}

private void UseNoneWindowStylePropertyChangedCallback(object sender, EventArgs e)
{
var metroWindow = sender as MetroWindow;
if(metroWindow != null && windowChrome != null)
{
windowChrome.UseNoneWindowStyle = metroWindow.UseNoneWindowStyle;
UpdateWindowStyle();
}
}

Expand All @@ -86,6 +98,8 @@ private void Cleanup()
{
System.ComponentModel.DependencyPropertyDescriptor.FromProperty(MetroWindow.IgnoreTaskbarOnMaximizeProperty, typeof(MetroWindow))
.RemoveValueChanged(AssociatedObject, IgnoreTaskbarOnMaximizePropertyChangedCallback);
System.ComponentModel.DependencyPropertyDescriptor.FromProperty(MetroWindow.UseNoneWindowStyleProperty, typeof(MetroWindow))
.RemoveValueChanged(AssociatedObject, UseNoneWindowStylePropertyChangedCallback);
}
AssociatedObject.Loaded -= AssociatedObject_Loaded;
AssociatedObject.Unloaded -= AssociatedObject_Unloaded;
Expand Down Expand Up @@ -163,7 +177,8 @@ private void AssociatedObject_StateChanged(object sender, EventArgs e)

private void HandleMaximize(bool handleOnlyMaximized = false)
{
if (AssociatedObject.WindowState == WindowState.Maximized)
var metroWindow = AssociatedObject as MetroWindow;
if (AssociatedObject.WindowState == WindowState.Maximized && metroWindow.IgnoreTaskbarOnMaximize)
{
// remove resize border and window border, so we can move the window from top monitor position
windowChrome.ResizeBorderThickness = new Thickness(0);
Expand All @@ -175,7 +190,6 @@ private void HandleMaximize(bool handleOnlyMaximized = false)
if (monitor != IntPtr.Zero) {
var monitorInfo = new MONITORINFO();
UnsafeNativeMethods.GetMonitorInfo(monitor, monitorInfo);
var metroWindow = AssociatedObject as MetroWindow;
var ignoreTaskBar = metroWindow != null && (metroWindow.IgnoreTaskbarOnMaximize || metroWindow.UseNoneWindowStyle);
var x = ignoreTaskBar ? monitorInfo.rcMonitor.left : monitorInfo.rcWork.left;
var y = ignoreTaskBar ? monitorInfo.rcMonitor.top : monitorInfo.rcWork.top;
Expand All @@ -201,6 +215,15 @@ private void HandleMaximize(bool handleOnlyMaximized = false)
}
}

private void UpdateWindowStyle()
{
var metroWindow = AssociatedObject as MetroWindow;
if(metroWindow != null)
{
metroWindow.WindowStyle = (metroWindow.IgnoreTaskbarOnMaximize || metroWindow.UseNoneWindowStyle) ? WindowStyle.None : WindowStyle.SingleBorderWindow;
}
}

private void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
{
MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));
Expand Down Expand Up @@ -318,6 +341,7 @@ private void AssociatedObject_SourceInitialized(object sender, EventArgs e)
AssociatedObject.SizeToContent = sizeToContent == SizeToContent.WidthAndHeight ? SizeToContent.Height : SizeToContent.Manual;
AssociatedObject.SizeToContent = sizeToContent;
AssociatedObject.SnapsToDevicePixels = snapsToDevicePixels;
UpdateWindowStyle();
}

private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
Expand Down
73 changes: 72 additions & 1 deletion MahApps.Metro/Behaviours/GlowWindowBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,93 @@
using System.Windows;
using System.Windows.Interactivity;
using MahApps.Metro.Controls;
using System.Windows.Threading;

namespace MahApps.Metro.Behaviours
{
public class GlowWindowBehavior : Behavior<Window>
{
private const int glowTimerDelay = 200; //200 ms delay, the same as VS2013
private GlowWindow left, right, top, bottom;

private DispatcherTimer makeGlowVisibleTimer;

protected override void OnAttached()
{
base.OnAttached();

this.AssociatedObject.Loaded += AssociatedObjectOnLoaded;
this.AssociatedObject.Unloaded += AssociatedObjectUnloaded;
this.AssociatedObject.StateChanged += AssociatedObjectStateChanged;
}

void AssociatedObjectStateChanged(object sender, EventArgs e)
{
makeGlowVisibleTimer.Stop();
if(AssociatedObject.WindowState != WindowState.Minimized)
{
if(AssociatedObject.WindowStyle == WindowStyle.None || !SystemParameters.MinimizeAnimation)
{
RestoreGlow();
}
else
{
makeGlowVisibleTimer.Start();
}
}
else
{
HideGlow();
}
}

void AssociatedObjectUnloaded(object sender, RoutedEventArgs e)
{
if(makeGlowVisibleTimer != null)
{
makeGlowVisibleTimer.Stop();
makeGlowVisibleTimer.Tick -= makeGlowVisibleTimer_Tick;
makeGlowVisibleTimer = null;
}
}

private void makeGlowVisibleTimer_Tick(object sender, EventArgs e)
{
if(makeGlowVisibleTimer != null)
{
makeGlowVisibleTimer.Stop();
}
RestoreGlow();
}

private void RestoreGlow()
{
if(left != null && top != null && right != null && bottom != null)
{
left.IsGlowing = top.IsGlowing = right.IsGlowing = bottom.IsGlowing = true;
Update();
}
}

private void HideGlow()
{
if (left != null && top != null && right != null && bottom != null)
{
left.IsGlowing = top.IsGlowing = right.IsGlowing = bottom.IsGlowing = false;
Update();
}
}

private void AssociatedObjectOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
if(makeGlowVisibleTimer == null)
{
makeGlowVisibleTimer = new DispatcherTimer()
{
Interval = TimeSpan.FromMilliseconds(glowTimerDelay)
};
makeGlowVisibleTimer.Tick += makeGlowVisibleTimer_Tick;
}

// now glow effect if UseNoneWindowStyle is true or GlowBrush not set
var metroWindow = this.AssociatedObject as MetroWindow;
if (metroWindow != null && (metroWindow.UseNoneWindowStyle || metroWindow.GlowBrush == null))
Expand Down
16 changes: 15 additions & 1 deletion MahApps.Metro/Controls/GlowWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public GlowWindow(Window owner, GlowDirection direction)
// windowChrome.GlassFrameThickness = new Thickness(-1);
// windowChrome.UseAeroCaptionButtons = false;
// this.SetValue(WindowChrome.WindowChromeProperty, windowChrome);
this.IsGlowing = true;
this.AllowsTransparency = true;

this.Owner = owner;
Expand Down Expand Up @@ -232,7 +233,7 @@ public void Update()
{
if (this.closing) return;

Visibility = Visibility.Visible;
Visibility = IsGlowing ? Visibility.Visible : Visibility.Collapsed;

UpdateCore();
}
Expand All @@ -242,6 +243,12 @@ public void Update()
}
}

public bool IsGlowing
{
set;
get;
}

private void UpdateCore()
{
if (ownerHandle == IntPtr.Zero)
Expand All @@ -261,6 +268,13 @@ private void UpdateCore()

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == (int)WM.SHOWWINDOW)
{
if((int)lParam == 3 && this.Visibility != Visibility.Visible) // 3 == SW_PARENTOPENING
{
handled = true; //handle this message so window isn't shown until we want it to
}
}
if (msg == (int)WM.MOUSEACTIVATE)
{
handled = true;
Expand Down
36 changes: 36 additions & 0 deletions MahApps.Metro/Microsoft.Windows.Shell/Standard/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2323,6 +2323,21 @@ internal struct WNDCLASSEX
public IntPtr hIconSm;
}

[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWINFO
{
public int cbSize;
public RECT rcWindow;
public RECT rcClient;
public int dwStyle;
public int dwExStyle;
public uint dwWindowStatus;
public uint cxWindowBorders;
public uint cyWindowBorders;
public ushort atomWindowType;
public ushort wCreatorVersion;
}

[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT
{
Expand Down Expand Up @@ -2567,6 +2582,10 @@ public static HRESULT ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFL
return HRESULT.S_OK;
}

[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
[DllImport("user32.dll", CharSet = CharSet.None, SetLastError = true, EntryPoint = "ClientToScreen")]
public static extern bool ClientToScreen(IntPtr hWnd, ref POINT point);

[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
[DllImport("gdi32.dll")]
public static extern CombineRgnResult CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2, RGN fnCombineMode);
Expand Down Expand Up @@ -3063,6 +3082,23 @@ public static IntPtr GetStockObject(StockObject fnObject)
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(SM nIndex);

[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
[DllImport("user32.dll", CharSet = CharSet.None, SetLastError = true, EntryPoint = "GetWindowInfo")]
private static extern bool _GetWindowInfo(IntPtr hWnd, ref WINDOWINFO pwi);

public static WINDOWINFO GetWindowInfo(IntPtr hWnd)
{
WINDOWINFO info = new WINDOWINFO()
{
cbSize = Marshal.SizeOf(typeof(WINDOWINFO))
};
if (!_GetWindowInfo(hWnd, ref info))
{
HRESULT.ThrowLastError();
}
return info;
}

// This is aliased as a macro in 32bit Windows.
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static IntPtr GetWindowLongPtr(IntPtr hwnd, GWL nIndex)
Expand Down
11 changes: 11 additions & 0 deletions MahApps.Metro/Microsoft.Windows.Shell/WindowChrome.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,17 @@ public bool IgnoreTaskbarOnMaximize
set { SetValue(IgnoreTaskbarOnMaximizeProperty, value); }
}

public static readonly DependencyProperty UseNoneWindowStyleProperty = DependencyProperty.Register(
"UseNoneWindowStyle",
typeof(bool),
typeof(WindowChrome),
new FrameworkPropertyMetadata(false));
public bool UseNoneWindowStyle
{
get { return (bool)GetValue(UseNoneWindowStyleProperty); }
set { SetValue(UseNoneWindowStyleProperty, value); }
}

public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
"CornerRadius",
typeof(CornerRadius),
Expand Down
Loading

0 comments on commit d57d1e4

Please sign in to comment.