/*************************************************************************************
Extended WPF Toolkit
Copyright (C) 2007-2013 Xceed Software Inc.
This program is provided to you under the terms of the Microsoft Public
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
For more features, controls, and fast professional support,
pick up the Plus Edition at http://xceed.com/wpf_toolkit
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
***********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Windows.Controls;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Data;
using System.Windows.Media;
using Xceed.Wpf.AvalonDock.Layout;
using System.Diagnostics;
using System.Windows.Threading;
namespace Xceed.Wpf.AvalonDock.Controls
{
public class LayoutAutoHideWindowControl : HwndHost, ILayoutControl
{
static LayoutAutoHideWindowControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAutoHideWindowControl), new FrameworkPropertyMetadata(typeof(LayoutAutoHideWindowControl)));
UIElement.FocusableProperty.OverrideMetadata(typeof(LayoutAutoHideWindowControl), new FrameworkPropertyMetadata(true));
Control.IsTabStopProperty.OverrideMetadata(typeof(LayoutAutoHideWindowControl), new FrameworkPropertyMetadata(true));
VisibilityProperty.OverrideMetadata(typeof(LayoutAutoHideWindowControl), new FrameworkPropertyMetadata(Visibility.Hidden));
}
internal LayoutAutoHideWindowControl()
{
}
internal void Show(LayoutAnchorControl anchor)
{
if (_model != null)
throw new InvalidOperationException();
_anchor = anchor;
_model = anchor.Model as LayoutAnchorable;
_side = (anchor.Model.Parent.Parent as LayoutAnchorSide).Side;
_manager = _model.Root.Manager;
CreateInternalGrid();
_model.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(_model_PropertyChanged);
Visibility = System.Windows.Visibility.Visible;
InvalidateMeasure();
UpdateWindowPos();
Trace.WriteLine("LayoutAutoHideWindowControl.Show()");
}
internal void Hide()
{
if (_model == null)
return;
_model.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(_model_PropertyChanged);
RemoveInternalGrid();
_anchor = null;
_model = null;
_manager = null;
Visibility = System.Windows.Visibility.Hidden;
Trace.WriteLine("LayoutAutoHideWindowControl.Hide()");
}
LayoutAnchorControl _anchor;
LayoutAnchorable _model;
public ILayoutElement Model
{
get { return _model; }
}
HwndSource _internalHwndSource = null;
IntPtr parentWindowHandle;
protected override System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent)
{
parentWindowHandle = hwndParent.Handle;
_internalHwndSource = new HwndSource(new HwndSourceParameters()
{
ParentWindow = hwndParent.Handle,
WindowStyle = Win32Helper.WS_CHILD | Win32Helper.WS_VISIBLE | Win32Helper.WS_CLIPSIBLINGS | Win32Helper.WS_CLIPCHILDREN,
Width = 0,
Height = 0,
});
_internalHost_ContentRendered = false;
_internalHwndSource.ContentRendered += _internalHwndSource_ContentRendered;
_internalHwndSource.RootVisual = _internalHostPresenter;
AddLogicalChild(_internalHostPresenter);
Win32Helper.BringWindowToTop(_internalHwndSource.Handle);
return new HandleRef(this, _internalHwndSource.Handle);
}
private bool _internalHost_ContentRendered = false;
void _internalHwndSource_ContentRendered(object sender, EventArgs e)
{
_internalHost_ContentRendered = true;
}
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == Win32Helper.WM_WINDOWPOSCHANGING)
{
if (_internalHost_ContentRendered)
Win32Helper.SetWindowPos(_internalHwndSource.Handle, Win32Helper.HWND_TOP, 0, 0, 0, 0, Win32Helper.SetWindowPosFlags.IgnoreMove | Win32Helper.SetWindowPosFlags.IgnoreResize);
}
return base.WndProc(hwnd, msg, wParam, lParam, ref handled);
}
protected override void DestroyWindowCore(System.Runtime.InteropServices.HandleRef hwnd)
{
if (_internalHwndSource != null)
{
_internalHwndSource.ContentRendered -= _internalHwndSource_ContentRendered;
_internalHwndSource.Dispose();
_internalHwndSource = null;
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
ContentPresenter _internalHostPresenter = new ContentPresenter();
Grid _internalGrid = null;
LayoutAnchorableControl _internalHost = null;
AnchorSide _side;
LayoutGridResizerControl _resizer = null;
DockingManager _manager;
void _model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsAutoHidden")
{
if (!_model.IsAutoHidden)
{
_manager.HideAutoHideWindow(_anchor);
}
}
}
void CreateInternalGrid()
{
_internalGrid = new Grid() { FlowDirection = System.Windows.FlowDirection.LeftToRight};
_internalGrid.SetBinding(Grid.BackgroundProperty, new Binding("Background") { Source = this });
_internalHost = new LayoutAnchorableControl() { Model = _model, Style = AnchorableStyle };
_internalHost.SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this });
KeyboardNavigation.SetTabNavigation(_internalGrid, KeyboardNavigationMode.Cycle);
_resizer = new LayoutGridResizerControl();
_resizer.DragStarted += new System.Windows.Controls.Primitives.DragStartedEventHandler(OnResizerDragStarted);
_resizer.DragDelta += new System.Windows.Controls.Primitives.DragDeltaEventHandler(OnResizerDragDelta);
_resizer.DragCompleted += new System.Windows.Controls.Primitives.DragCompletedEventHandler(OnResizerDragCompleted);
if (_side == AnchorSide.Right)
{
_internalGrid.ColumnDefinitions.Add(new ColumnDefinition(){ Width = new GridLength(_manager.GridSplitterWidth)});
_internalGrid.ColumnDefinitions.Add(new ColumnDefinition(){
Width = _model.AutoHideWidth == 0.0 ? new GridLength(_model.AutoHideMinWidth) : new GridLength(_model.AutoHideWidth, GridUnitType.Pixel)});
Grid.SetColumn(_resizer, 0);
Grid.SetColumn(_internalHost, 1);
_resizer.Cursor = Cursors.SizeWE;
HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
}
else if (_side == AnchorSide.Left)
{
_internalGrid.ColumnDefinitions.Add(new ColumnDefinition()
{
Width = _model.AutoHideWidth == 0.0 ? new GridLength(_model.AutoHideMinWidth) : new GridLength(_model.AutoHideWidth, GridUnitType.Pixel),
});
_internalGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(_manager.GridSplitterWidth) });
Grid.SetColumn(_internalHost, 0);
Grid.SetColumn(_resizer, 1);
_resizer.Cursor = Cursors.SizeWE;
HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
}
else if (_side == AnchorSide.Top)
{
_internalGrid.RowDefinitions.Add(new RowDefinition()
{
Height = _model.AutoHideHeight == 0.0 ? new GridLength(_model.AutoHideMinHeight) : new GridLength(_model.AutoHideHeight, GridUnitType.Pixel),
});
_internalGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(_manager.GridSplitterHeight) });
Grid.SetRow(_internalHost, 0);
Grid.SetRow(_resizer, 1);
_resizer.Cursor = Cursors.SizeNS;
VerticalAlignment = System.Windows.VerticalAlignment.Top;
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
}
else if (_side == AnchorSide.Bottom)
{
_internalGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(_manager.GridSplitterHeight) });
_internalGrid.RowDefinitions.Add(new RowDefinition()
{
Height = _model.AutoHideHeight == 0.0 ? new GridLength(_model.AutoHideMinHeight) : new GridLength(_model.AutoHideHeight, GridUnitType.Pixel),
});
Grid.SetRow(_resizer, 0);
Grid.SetRow(_internalHost, 1);
_resizer.Cursor = Cursors.SizeNS;
VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
}
_internalGrid.Children.Add(_resizer);
_internalGrid.Children.Add(_internalHost);
_internalHostPresenter.Content = _internalGrid;
}
void RemoveInternalGrid()
{
_resizer.DragStarted -= new System.Windows.Controls.Primitives.DragStartedEventHandler(OnResizerDragStarted);
_resizer.DragDelta -= new System.Windows.Controls.Primitives.DragDeltaEventHandler(OnResizerDragDelta);
_resizer.DragCompleted -= new System.Windows.Controls.Primitives.DragCompletedEventHandler(OnResizerDragCompleted);
_internalHostPresenter.Content = null;
}
protected override bool HasFocusWithinCore()
{
return false;
}
#region Resizer
Border _resizerGhost = null;
Window _resizerWindowHost = null;
Vector _initialStartPoint;
void ShowResizerOverlayWindow(LayoutGridResizerControl splitter)
{
_resizerGhost = new Border()
{
Background = splitter.BackgroundWhileDragging,
Opacity = splitter.OpacityWhileDragging
};
var areaElement = _manager.GetAutoHideAreaElement();
var modelControlActualSize = this._internalHost.TransformActualSizeToAncestor();
Point ptTopLeftScreen = areaElement.PointToScreenDPIWithoutFlowDirection(new Point());
var managerSize = areaElement.TransformActualSizeToAncestor();
Size windowSize;
if (_side == AnchorSide.Right || _side == AnchorSide.Left)
{
windowSize = new Size(
managerSize.Width - 25.0 + splitter.ActualWidth,
managerSize.Height);
_resizerGhost.Width = splitter.ActualWidth;
_resizerGhost.Height = windowSize.Height;
ptTopLeftScreen.Offset(25, 0.0);
}
else
{
windowSize = new Size(
managerSize.Width,
managerSize.Height - _model.AutoHideMinHeight - 25.0 + splitter.ActualHeight);
_resizerGhost.Height = splitter.ActualHeight;
_resizerGhost.Width = windowSize.Width;
ptTopLeftScreen.Offset(0.0, 25.0);
}
_initialStartPoint = splitter.PointToScreenDPIWithoutFlowDirection(new Point()) - ptTopLeftScreen;
if (_side == AnchorSide.Right || _side == AnchorSide.Left)
{
Canvas.SetLeft(_resizerGhost, _initialStartPoint.X);
}
else
{
Canvas.SetTop(_resizerGhost, _initialStartPoint.Y);
}
Canvas panelHostResizer = new Canvas()
{
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
VerticalAlignment = System.Windows.VerticalAlignment.Stretch
};
panelHostResizer.Children.Add(_resizerGhost);
_resizerWindowHost = new Window()
{
ResizeMode = ResizeMode.NoResize,
WindowStyle = System.Windows.WindowStyle.None,
ShowInTaskbar = false,
AllowsTransparency = true,
Background = null,
Width = windowSize.Width,
Height = windowSize.Height,
Left = ptTopLeftScreen.X,
Top = ptTopLeftScreen.Y,
ShowActivated = false,
Owner = Window.GetWindow(this),
Content = panelHostResizer
};
_resizerWindowHost.Show();
}
void HideResizerOverlayWindow()
{
if (_resizerWindowHost != null)
{
_resizerWindowHost.Close();
_resizerWindowHost = null;
}
}
internal bool IsResizing
{
get;
private set;
}
void OnResizerDragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
{
LayoutGridResizerControl splitter = sender as LayoutGridResizerControl;
var rootVisual = this.FindVisualTreeRoot() as Visual;
var trToWnd = TransformToAncestor(rootVisual);
Vector transformedDelta = trToWnd.Transform(new Point(e.HorizontalChange, e.VerticalChange)) -
trToWnd.Transform(new Point());
double delta;
if (_side == AnchorSide.Right || _side == AnchorSide.Left)
delta = Canvas.GetLeft(_resizerGhost) - _initialStartPoint.X;
else
delta = Canvas.GetTop(_resizerGhost) - _initialStartPoint.Y;
if (_side == AnchorSide.Right)
{
if (_model.AutoHideWidth == 0.0)
_model.AutoHideWidth = _internalHost.ActualWidth - delta;
else
_model.AutoHideWidth -= delta;
_internalGrid.ColumnDefinitions[1].Width = new GridLength(_model.AutoHideWidth, GridUnitType.Pixel);
}
else if (_side == AnchorSide.Left)
{
if (_model.AutoHideWidth == 0.0)
_model.AutoHideWidth = _internalHost.ActualWidth + delta;
else
_model.AutoHideWidth += delta;
_internalGrid.ColumnDefinitions[0].Width = new GridLength(_model.AutoHideWidth, GridUnitType.Pixel);
}
else if (_side == AnchorSide.Top)
{
if (_model.AutoHideHeight == 0.0)
_model.AutoHideHeight = _internalHost.ActualHeight + delta;
else
_model.AutoHideHeight += delta;
_internalGrid.RowDefinitions[0].Height = new GridLength(_model.AutoHideHeight, GridUnitType.Pixel);
}
else if (_side == AnchorSide.Bottom)
{
if (_model.AutoHideHeight == 0.0)
_model.AutoHideHeight = _internalHost.ActualHeight - delta;
else
_model.AutoHideHeight -= delta;
_internalGrid.RowDefinitions[1].Height = new GridLength(_model.AutoHideHeight, GridUnitType.Pixel);
}
HideResizerOverlayWindow();
IsResizing = false;
InvalidateMeasure();
}
void OnResizerDragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
LayoutGridResizerControl splitter = sender as LayoutGridResizerControl;
var rootVisual = this.FindVisualTreeRoot() as Visual;
var trToWnd = TransformToAncestor(rootVisual);
Vector transformedDelta = trToWnd.Transform(new Point(e.HorizontalChange, e.VerticalChange)) -
trToWnd.Transform(new Point());
if (_side == AnchorSide.Right || _side == AnchorSide.Left)
{
if (FrameworkElement.GetFlowDirection(_internalHost) == System.Windows.FlowDirection.RightToLeft)
transformedDelta.X = -transformedDelta.X;
Canvas.SetLeft(_resizerGhost, MathHelper.MinMax(_initialStartPoint.X + transformedDelta.X, 0.0, _resizerWindowHost.Width - _resizerGhost.Width));
}
else
{
Canvas.SetTop(_resizerGhost, MathHelper.MinMax(_initialStartPoint.Y + transformedDelta.Y, 0.0, _resizerWindowHost.Height - _resizerGhost.Height));
}
}
void OnResizerDragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
var resizer = sender as LayoutGridResizerControl;
ShowResizerOverlayWindow(resizer);
IsResizing = true;
}
#endregion
protected override System.Collections.IEnumerator LogicalChildren
{
get
{
if (_internalHostPresenter == null)
return new UIElement[] { }.GetEnumerator();
return new UIElement[] { _internalHostPresenter }.GetEnumerator();
}
}
protected override Size MeasureOverride(Size constraint)
{
if (_internalHostPresenter == null)
return base.MeasureOverride(constraint);
_internalHostPresenter.Measure(constraint);
//return base.MeasureOverride(constraint);
return _internalHostPresenter.DesiredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
if (_internalHostPresenter == null)
return base.ArrangeOverride(finalSize);
_internalHostPresenter.Arrange(new Rect(finalSize));
return base.ArrangeOverride(finalSize);// new Size(_internalHostPresenter.ActualWidth, _internalHostPresenter.ActualHeight);
}
#region Background
///
/// Background Dependency Property
///
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.Register("Background", typeof(Brush), typeof(LayoutAutoHideWindowControl),
new FrameworkPropertyMetadata((Brush)null));
///
/// Gets or sets the Background property. This dependency property
/// indicates background of the autohide childwindow.
///
public Brush Background
{
get { return (Brush)GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
#endregion
internal bool IsWin32MouseOver
{
get
{
var ptMouse = new Win32Helper.Win32Point();
if (!Win32Helper.GetCursorPos(ref ptMouse))
return false;
Point location = this.PointToScreenDPI(new Point());
Rect rectWindow = this.GetScreenArea();
if (rectWindow.Contains(new Point(ptMouse.X, ptMouse.Y)))
return true;
var manager = Model.Root.Manager;
var anchor = manager.FindVisualChildren().Where(c => c.Model == Model).FirstOrDefault();
if (anchor == null)
return false;
location = anchor.PointToScreenDPI(new Point());
if (anchor.IsMouseOver)
return true;
return false;
}
}
#region AnchorableStyle
///
/// AnchorableStyle Dependency Property
///
public static readonly DependencyProperty AnchorableStyleProperty =
DependencyProperty.Register("AnchorableStyle", typeof(Style), typeof(LayoutAutoHideWindowControl),
new FrameworkPropertyMetadata((Style)null));
///
/// Gets or sets the AnchorableStyle property. This dependency property
/// indicates the style to apply to the LayoutAnchorableControl hosted in this auto hide window.
///
public Style AnchorableStyle
{
get { return (Style)GetValue(AnchorableStyleProperty); }
set { SetValue(AnchorableStyleProperty, value); }
}
#endregion
}
}