commit 4a3813687a5cba8d45541737a6d7be48e0d8699e Author: Sean Kessler Date: Fri Feb 23 07:03:56 2024 -0500 Init diff --git a/Libs/READ_ME.txt b/Libs/READ_ME.txt new file mode 100644 index 0000000..69a49c7 --- /dev/null +++ b/Libs/READ_ME.txt @@ -0,0 +1,2 @@ +The file Xceed.Wpf.Samples.SampleData.dll has been created from Xceed.Silverlight.Samples.SampleData.dll of the Silverlight ListBox. +Only the Silverlight has been changed to Wpf. \ No newline at end of file diff --git a/Libs/Xceed.Wpf.Samples.SampleData.dll b/Libs/Xceed.Wpf.Samples.SampleData.dll new file mode 100644 index 0000000..050b99d Binary files /dev/null and b/Libs/Xceed.Wpf.Samples.SampleData.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfo.cs b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfo.cs new file mode 100644 index 0000000..e67c8f8 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfo.cs @@ -0,0 +1,32 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +#pragma warning disable 0436 +[assembly: System.Reflection.AssemblyVersion( _XceedVersionInfo.Version )] +#pragma warning restore 0436 + +internal static class _XceedVersionInfo +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string BaseVersion = "3.1"; + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string Version = BaseVersion + + ".0.0"; + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string PublicKeyToken = "ba83ff368b7563c6"; + + +} diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfoCommon.cs b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfoCommon.cs new file mode 100644 index 0000000..49ee168 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfoCommon.cs @@ -0,0 +1,22 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +internal static class _XceedVersionInfoCommon +{ +[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string Build = ".*"; + +} diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Brushes.xaml b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Brushes.xaml new file mode 100644 index 0000000..a431060 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Brushes.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableBottom.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableBottom.png new file mode 100644 index 0000000..a786a61 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableBottom.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableLeft.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableLeft.png new file mode 100644 index 0000000..1499c43 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableLeft.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableRight.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableRight.png new file mode 100644 index 0000000..e6802ba Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableRight.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableTop.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableTop.png new file mode 100644 index 0000000..cd79f57 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockAnchorableTop.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableBottom.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableBottom.png new file mode 100644 index 0000000..00436bb Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableBottom.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableLeft.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableLeft.png new file mode 100644 index 0000000..6500b08 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableLeft.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableRight.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableRight.png new file mode 100644 index 0000000..a71a8c5 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableRight.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableTop.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableTop.png new file mode 100644 index 0000000..2ac7765 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentAsAnchorableTop.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentBottom.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentBottom.png new file mode 100644 index 0000000..c5bed34 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentBottom.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentInside.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentInside.png new file mode 100644 index 0000000..038ac8b Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentInside.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentLeft.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentLeft.png new file mode 100644 index 0000000..d77a43f Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentLeft.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentRight.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentRight.png new file mode 100644 index 0000000..8332220 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentRight.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentTop.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentTop.png new file mode 100644 index 0000000..f8e075d Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockDocumentTop.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockPaneEmpty.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockPaneEmpty.png new file mode 100644 index 0000000..8ad1176 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockPaneEmpty.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockPaneLargeEmpty.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockPaneLargeEmpty.png new file mode 100644 index 0000000..8205a03 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/DockPaneLargeEmpty.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/HTabGroup.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/HTabGroup.png new file mode 100644 index 0000000..4c50d26 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/HTabGroup.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/Locked.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/Locked.png new file mode 100644 index 0000000..b8f6ced Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/Locked.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinAutoHide.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinAutoHide.png new file mode 100644 index 0000000..abefd96 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinAutoHide.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinAutoHide_Black.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinAutoHide_Black.png new file mode 100644 index 0000000..87b66ce Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinAutoHide_Black.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinAutoHide_Dark.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinAutoHide_Dark.png new file mode 100644 index 0000000..470548d Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinAutoHide_Dark.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinClose.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinClose.png new file mode 100644 index 0000000..132bdfa Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinClose.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinClose_Black.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinClose_Black.png new file mode 100644 index 0000000..abf709c Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinClose_Black.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinClose_Dark.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinClose_Dark.png new file mode 100644 index 0000000..575e4fd Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinClose_Dark.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinDocMenu.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinDocMenu.png new file mode 100644 index 0000000..86db307 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinDocMenu.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinDocMenu_Black.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinDocMenu_Black.png new file mode 100644 index 0000000..be08192 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinDocMenu_Black.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMaximize.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMaximize.png new file mode 100644 index 0000000..79d8c2d Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMaximize.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMaximize_Black.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMaximize_Black.png new file mode 100644 index 0000000..42ae679 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMaximize_Black.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMaximize_Dark.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMaximize_Dark.png new file mode 100644 index 0000000..e28e060 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMaximize_Dark.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMenu.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMenu.png new file mode 100644 index 0000000..653373c Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMenu.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMenu_Black.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMenu_Black.png new file mode 100644 index 0000000..31e2f10 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMenu_Black.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMenu_Dark.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMenu_Dark.png new file mode 100644 index 0000000..25a4767 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinMenu_Dark.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinRestore.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinRestore.png new file mode 100644 index 0000000..1bccead Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinRestore.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinRestore_Black.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinRestore_Black.png new file mode 100644 index 0000000..7c7e003 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinRestore_Black.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinRestore_Dark.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinRestore_Dark.png new file mode 100644 index 0000000..f3ebfe4 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/PinRestore_Dark.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/VTabGroup.png b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/VTabGroup.png new file mode 100644 index 0000000..c3f279f Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Images/VTabGroup.png differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/MetroTheme.cs b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/MetroTheme.cs new file mode 100644 index 0000000..780bec5 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/MetroTheme.cs @@ -0,0 +1,33 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Themes +{ + public class MetroTheme : Theme + { + public override Uri GetResourceUri() + { + return new Uri( + "/Xceed.Wpf.AvalonDock.Themes.Metro;component/Theme.xaml", + UriKind.Relative); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Properties/AssemblyInfo.cs b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8668f24 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Properties/AssemblyInfo.cs @@ -0,0 +1,69 @@ +/************************************************************************************* + + 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.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Markup; +using System; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle( "Xceed Toolkit for WPF - AvalonDock Metro Theme" )] +[assembly: AssemblyDescription( "This assembly implements the Metro Theme for the AvalonDock layout system." )] + +[assembly: AssemblyCompany( "Xceed Software Inc." )] +[assembly: AssemblyProduct( "Xceed Toolkit for WPF - AvalonDock" )] +[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2016" )] + + + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] +[assembly: CLSCompliant( true )] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/avalondock", "Xceed.Wpf.AvalonDock.Themes" )] + +#pragma warning disable 1699 +[assembly: AssemblyDelaySign( false )] +[assembly: AssemblyKeyFile( @"..\..\sn.snk" )] +[assembly: AssemblyKeyName( "" )] +#pragma warning restore 1699 diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml new file mode 100644 index 0000000..d15205e --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml @@ -0,0 +1,1489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Xceed.Wpf.AvalonDock.Themes.Metro.csproj b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Xceed.Wpf.AvalonDock.Themes.Metro.csproj new file mode 100644 index 0000000..ce95dfb --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Xceed.Wpf.AvalonDock.Themes.Metro.csproj @@ -0,0 +1,124 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {89286EB4-B4A1-418C-839A-067B00F442D8} + library + Properties + Xceed.Wpf.AvalonDock.Themes.Metro + Xceed.Wpf.AvalonDock.Themes.Metro + v4.6.1 + + + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + 4.0 + + + + + + + + + + Code + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {DB81988F-E0F2-45A0-A1FD-8C37F3D35244} + Xceed.Wpf.AvalonDock + + + + + \ No newline at end of file diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.dll new file mode 100644 index 0000000..03eba55 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.pdb b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.pdb new file mode 100644 index 0000000..6449f70 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.pdb differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.dll new file mode 100644 index 0000000..3ab5383 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.pdb b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.pdb new file mode 100644 index 0000000..41e2d42 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/Xceed.Wpf.AvalonDock.pdb differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/de/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/de/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..120d576 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/de/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/es/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/es/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..94e9486 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/es/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/fr/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/fr/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..e4c938e Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/fr/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/hu/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/hu/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..383c569 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/hu/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/it/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/it/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..c0b5666 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/it/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/pt-BR/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/pt-BR/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..b0ff7a9 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/pt-BR/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/ro/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/ro/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..c4d78e2 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/ro/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/ru/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/ru/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..1dfa39c Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/ru/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/sv/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/sv/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..04ebed8 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/sv/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/zh-Hans/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/zh-Hans/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..5ce3a1b Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/bin/Debug/zh-Hans/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Brushes.baml b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Brushes.baml new file mode 100644 index 0000000..2a3b152 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Brushes.baml differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..ba1912a Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Theme.baml b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Theme.baml new file mode 100644 index 0000000..0e627d6 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Theme.baml differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.csproj.FileListAbsolute.txt b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..ce01cee --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.csproj.FileListAbsolute.txt @@ -0,0 +1,22 @@ +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.pdb +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\Xceed.Wpf.AvalonDock.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\Xceed.Wpf.AvalonDock.pdb +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.csprojResolveAssemblyReference.cache +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Brushes.baml +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.cache +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Theme.baml +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.g.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.pdb diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.csprojResolveAssemblyReference.cache b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.csprojResolveAssemblyReference.cache new file mode 100644 index 0000000..2a3ee02 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.csprojResolveAssemblyReference.cache differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.dll b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.dll new file mode 100644 index 0000000..03eba55 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.g.resources b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.g.resources new file mode 100644 index 0000000..a72729f Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.g.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.pdb b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.pdb new file mode 100644 index 0000000..6449f70 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.pdb differ diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.cache b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.cache new file mode 100644 index 0000000..e5c6673 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.cache @@ -0,0 +1,20 @@ +Xceed.Wpf.AvalonDock.Themes.Metro + + +library +C# +.cs +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\ +Xceed.Wpf.AvalonDock.Themes.Metro +none +false +DEBUG;TRACE + +2-109355679 + +4559672327 +1335344989 +Brushes.xaml;Theme.xaml; + +False + diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.i.cache b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.i.cache new file mode 100644 index 0000000..209395b --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.i.cache @@ -0,0 +1,20 @@ +Xceed.Wpf.AvalonDock.Themes.Metro + + +library +C# +.cs +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\ +Xceed.Wpf.AvalonDock.Themes.Metro +none +false +DEBUG;TRACE + +2-109355679 + +8-649181370 +1335344989 +Brushes.xaml;Theme.xaml; + +False + diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref new file mode 100644 index 0000000..ed535c7 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref @@ -0,0 +1,4 @@ + + +FC:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock.Themes.Metro\Theme.xaml;; + diff --git a/Src/Xceed.Wpf.AvalonDock.Themes.Metro/sn.snk b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/sn.snk new file mode 100644 index 0000000..1bdc912 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock.Themes.Metro/sn.snk differ diff --git a/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfo.cs b/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfo.cs new file mode 100644 index 0000000..e67c8f8 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfo.cs @@ -0,0 +1,32 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +#pragma warning disable 0436 +[assembly: System.Reflection.AssemblyVersion( _XceedVersionInfo.Version )] +#pragma warning restore 0436 + +internal static class _XceedVersionInfo +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string BaseVersion = "3.1"; + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string Version = BaseVersion + + ".0.0"; + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string PublicKeyToken = "ba83ff368b7563c6"; + + +} diff --git a/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfoCommon.cs b/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfoCommon.cs new file mode 100644 index 0000000..49ee168 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfoCommon.cs @@ -0,0 +1,22 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +internal static class _XceedVersionInfoCommon +{ +[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string Build = ".*"; + +} diff --git a/Src/Xceed.Wpf.AvalonDock/Commands/RelayCommand.cs b/Src/Xceed.Wpf.AvalonDock/Commands/RelayCommand.cs new file mode 100644 index 0000000..75e6810 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Commands/RelayCommand.cs @@ -0,0 +1,71 @@ +/************************************************************************************* + + 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.Input; + +namespace Xceed.Wpf.AvalonDock.Commands +{ + internal class RelayCommand : ICommand + { + #region Fields + + readonly Action _execute; + readonly Predicate _canExecute; + + #endregion // Fields + + #region Constructors + + public RelayCommand(Action execute) + : this(execute, null) + { + } + + public RelayCommand(Action execute, Predicate canExecute) + { + if (execute == null) + throw new ArgumentNullException("execute"); + + _execute = execute; + _canExecute = canExecute; + } + #endregion // Constructors + + #region ICommand Members + + public bool CanExecute(object parameter) + { + return _canExecute == null ? true : _canExecute(parameter); + } + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public void Execute(object parameter) + { + _execute(parameter); + } + + #endregion // ICommand Members + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneControlOverlayArea.cs b/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneControlOverlayArea.cs new file mode 100644 index 0000000..55ef920 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneControlOverlayArea.cs @@ -0,0 +1,43 @@ +/************************************************************************************* + + 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; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class AnchorablePaneControlOverlayArea : OverlayArea + { + internal AnchorablePaneControlOverlayArea( + IOverlayWindow overlayWindow, + LayoutAnchorablePaneControl anchorablePaneControl) + : base(overlayWindow) + { + + _anchorablePaneControl = anchorablePaneControl; + base.SetScreenDetectionArea(new Rect( + _anchorablePaneControl.PointToScreenDPI(new Point()), + _anchorablePaneControl.TransformActualSizeToAncestor())); + + } + + LayoutAnchorablePaneControl _anchorablePaneControl; + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneDropTarget.cs b/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneDropTarget.cs new file mode 100644 index 0000000..100cf94 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneDropTarget.cs @@ -0,0 +1,336 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal class AnchorablePaneDropTarget : DropTarget + { + internal AnchorablePaneDropTarget(LayoutAnchorablePaneControl paneControl, Rect detectionRect, DropTargetType type) + : base(paneControl, detectionRect, type) + { + _targetPane = paneControl; + } + + internal AnchorablePaneDropTarget(LayoutAnchorablePaneControl paneControl, Rect detectionRect, DropTargetType type, int tabIndex) + : base(paneControl, detectionRect, type) + { + _targetPane = paneControl; + _tabIndex = tabIndex; + } + + + LayoutAnchorablePaneControl _targetPane; + + int _tabIndex = -1; + + protected override void Drop(LayoutAnchorableFloatingWindow floatingWindow) + { + ILayoutAnchorablePane targetModel = _targetPane.Model as ILayoutAnchorablePane; + LayoutAnchorable anchorableActive = floatingWindow.Descendents().OfType().FirstOrDefault(); + + switch (Type) + { + case DropTargetType.AnchorablePaneDockBottom: + #region DropTargetType.AnchorablePaneDockBottom + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); + + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Vertical && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + if (layoutAnchorablePaneGroup != null && + (layoutAnchorablePaneGroup.Children.Count == 1 || + layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical)) + { + var anchorablesToMove = layoutAnchorablePaneGroup.Children.ToArray(); + for (int i = 0; i < anchorablesToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + 1 + i, anchorablesToMove[i]); + } + else + parentModel.InsertChildAt(insertToIndex + 1, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutAnchorablePaneGroup() + { + Orientation = System.Windows.Controls.Orientation.Vertical, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Add(floatingWindow.RootPanel); + + } + } + break; + #endregion + case DropTargetType.AnchorablePaneDockTop: + #region DropTargetType.AnchorablePaneDockTop + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); + + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Vertical && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + if (layoutAnchorablePaneGroup != null && + (layoutAnchorablePaneGroup.Children.Count == 1 || + layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical)) + { + var anchorablesToMove = layoutAnchorablePaneGroup.Children.ToArray(); + for (int i = 0; i < anchorablesToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + i, anchorablesToMove[i]); + } + else + parentModel.InsertChildAt(insertToIndex, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutAnchorablePaneGroup() + { + Orientation = System.Windows.Controls.Orientation.Vertical, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + //the floating window must be added after the target modal as it could be raise a CollectGarbage call + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Insert(0, floatingWindow.RootPanel); + + } + } + break; + #endregion + case DropTargetType.AnchorablePaneDockLeft: + #region DropTargetType.AnchorablePaneDockLeft + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); + + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Horizontal && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + if (layoutAnchorablePaneGroup != null && + (layoutAnchorablePaneGroup.Children.Count == 1 || + layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal)) + { + var anchorablesToMove = layoutAnchorablePaneGroup.Children.ToArray(); + for (int i = 0; i < anchorablesToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + i, anchorablesToMove[i]); + } + else + parentModel.InsertChildAt(insertToIndex, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutAnchorablePaneGroup() + { + Orientation = System.Windows.Controls.Orientation.Horizontal, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + //the floating window must be added after the target modal as it could be raise a CollectGarbage call + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Insert(0, floatingWindow.RootPanel); + + } + } + break; + #endregion + case DropTargetType.AnchorablePaneDockRight: + #region DropTargetType.AnchorablePaneDockRight + { + var parentModel = targetModel.Parent as ILayoutGroup; + var parentModelOrientable = targetModel.Parent as ILayoutOrientableGroup; + int insertToIndex = parentModel.IndexOfChild(targetModel); + + if (parentModelOrientable.Orientation != System.Windows.Controls.Orientation.Horizontal && + parentModel.ChildrenCount == 1) + parentModelOrientable.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (parentModelOrientable.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + if (layoutAnchorablePaneGroup != null && + (layoutAnchorablePaneGroup.Children.Count == 1 || + layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal)) + { + var anchorablesToMove = layoutAnchorablePaneGroup.Children.ToArray(); + for (int i = 0; i < anchorablesToMove.Length; i++) + parentModel.InsertChildAt(insertToIndex + 1 + i, anchorablesToMove[i]); + } + else + parentModel.InsertChildAt(insertToIndex + 1, floatingWindow.RootPanel); + } + else + { + var targetModelAsPositionableElement = targetModel as ILayoutPositionableElement; + var newOrientedPanel = new LayoutAnchorablePaneGroup() + { + Orientation = System.Windows.Controls.Orientation.Horizontal, + DockWidth = targetModelAsPositionableElement.DockWidth, + DockHeight = targetModelAsPositionableElement.DockHeight, + }; + + parentModel.InsertChildAt(insertToIndex, newOrientedPanel); + newOrientedPanel.Children.Add(targetModel); + newOrientedPanel.Children.Add(floatingWindow.RootPanel); + + } + } + break; + #endregion + + + case DropTargetType.AnchorablePaneDockInside: + #region DropTargetType.AnchorablePaneDockInside + { + var paneModel = targetModel as LayoutAnchorablePane; + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + + int i = _tabIndex == -1 ? 0 : _tabIndex; + foreach (var anchorableToImport in + layoutAnchorablePaneGroup.Descendents().OfType().ToArray()) + { + paneModel.Children.Insert(i, anchorableToImport); + i++; + } + + } + break; + #endregion + + + } + + anchorableActive.IsActive = true; + + base.Drop(floatingWindow); + } + + public override System.Windows.Media.Geometry GetPreviewPath(OverlayWindow overlayWindow, LayoutFloatingWindow floatingWindowModel) + { + //var anchorablePaneDropTarget = target as AnchorablePaneDropTarget; + var anchorableFloatingWindowModel = floatingWindowModel as LayoutAnchorableFloatingWindow; + var layoutAnchorablePane = anchorableFloatingWindowModel.RootPanel as ILayoutPositionableElement; + var layoutAnchorablePaneWithActualSize = anchorableFloatingWindowModel.RootPanel as ILayoutPositionableElementWithActualSize; + + switch (Type) + { + case DropTargetType.AnchorablePaneDockBottom: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + + targetScreenRect.Offset(0.0, targetScreenRect.Height / 2.0); + targetScreenRect.Height /= 2.0; + + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.AnchorablePaneDockTop: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + + targetScreenRect.Height /= 2.0; + + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.AnchorablePaneDockLeft: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + + targetScreenRect.Width /= 2.0; + + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.AnchorablePaneDockRight: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + + targetScreenRect.Offset(targetScreenRect.Width / 2.0, 0.0); + targetScreenRect.Width /= 2.0; + + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.AnchorablePaneDockInside: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + + if (_tabIndex == -1) + { + return new RectangleGeometry(targetScreenRect); + } + else + { + var translatedDetectionRect = new Rect(DetectionRects[0].TopLeft, DetectionRects[0].BottomRight); + translatedDetectionRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + var pathFigure = new PathFigure(); + pathFigure.StartPoint = targetScreenRect.TopLeft; + pathFigure.Segments.Add(new LineSegment() { Point = new Point(targetScreenRect.Left, translatedDetectionRect.Top) }); + pathFigure.Segments.Add(new LineSegment() { Point = translatedDetectionRect.TopLeft }); + pathFigure.Segments.Add(new LineSegment() { Point = translatedDetectionRect.BottomLeft }); + pathFigure.Segments.Add(new LineSegment() { Point = translatedDetectionRect.BottomRight }); + pathFigure.Segments.Add(new LineSegment() { Point = translatedDetectionRect.TopRight }); + pathFigure.Segments.Add(new LineSegment() { Point = new Point(targetScreenRect.Right, translatedDetectionRect.Top) }); + pathFigure.Segments.Add(new LineSegment() { Point = targetScreenRect.TopRight }); + pathFigure.IsClosed = true; + pathFigure.IsFilled = true; + pathFigure.Freeze(); + return new PathGeometry(new PathFigure[] { pathFigure }); + } + } + } + + return null; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneTabPanel.cs b/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneTabPanel.cs new file mode 100644 index 0000000..1dfe53e --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneTabPanel.cs @@ -0,0 +1,107 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class AnchorablePaneTabPanel : Panel + { + public AnchorablePaneTabPanel() + { + FlowDirection = System.Windows.FlowDirection.LeftToRight; + } + + + protected override Size MeasureOverride(Size availableSize) + { + double totWidth = 0; + double maxHeight = 0; + var visibleChildren = Children.Cast().Where(ch => ch.Visibility != System.Windows.Visibility.Collapsed); + foreach (FrameworkElement child in visibleChildren) + { + child.Measure(new Size(double.PositiveInfinity, availableSize.Height)); + totWidth += child.DesiredSize.Width; + maxHeight = Math.Max(maxHeight, child.DesiredSize.Height); + } + + if (totWidth > availableSize.Width) + { + double childFinalDesideredWidth = availableSize.Width / visibleChildren.Count(); + foreach (FrameworkElement child in visibleChildren) + { + child.Measure(new Size(childFinalDesideredWidth, availableSize.Height)); + } + } + + return new Size(Math.Min(availableSize.Width, totWidth), maxHeight); + } + + protected override Size ArrangeOverride(Size finalSize) + { + var visibleChildren = Children.Cast().Where(ch => ch.Visibility != System.Windows.Visibility.Collapsed); + + + double finalWidth = finalSize.Width; + double desideredWidth = visibleChildren.Sum(ch => ch.DesiredSize.Width); + double offsetX = 0.0; + + if (finalWidth > desideredWidth) + { + foreach (FrameworkElement child in visibleChildren) + { + double childFinalWidth = child.DesiredSize.Width ; + child.Arrange(new Rect(offsetX, 0, childFinalWidth, finalSize.Height)); + + offsetX += childFinalWidth; + } + } + else + { + double childFinalWidth = finalWidth / visibleChildren.Count(); + foreach (FrameworkElement child in visibleChildren) + { + child.Arrange(new Rect(offsetX, 0, childFinalWidth, finalSize.Height)); + + offsetX += childFinalWidth; + } + } + + return finalSize; + } + + protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e) + { + if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed && + LayoutAnchorableTabItem.IsDraggingItem()) + { + var contentModel = LayoutAnchorableTabItem.GetDraggingItem().Model as LayoutAnchorable; + var manager = contentModel.Root.Manager; + LayoutAnchorableTabItem.ResetDraggingItem(); + + manager.StartDraggingFloatingWindowForContent(contentModel); + } + + base.OnMouseLeave(e); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneTitle.cs b/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneTitle.cs new file mode 100644 index 0000000..3269a2d --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/AnchorablePaneTitle.cs @@ -0,0 +1,189 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using System.Windows.Input; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + + public class AnchorablePaneTitle : Control + { + static AnchorablePaneTitle() + { + IsHitTestVisibleProperty.OverrideMetadata(typeof(AnchorablePaneTitle), new FrameworkPropertyMetadata(true)); + FocusableProperty.OverrideMetadata(typeof(AnchorablePaneTitle), new FrameworkPropertyMetadata(false)); + DefaultStyleKeyProperty.OverrideMetadata(typeof(AnchorablePaneTitle), new FrameworkPropertyMetadata(typeof(AnchorablePaneTitle))); + } + + + public AnchorablePaneTitle() + { + + } + + #region Model + + /// + /// Model Dependency Property + /// + public static readonly DependencyProperty ModelProperty = + DependencyProperty.Register("Model", typeof(LayoutAnchorable), typeof(AnchorablePaneTitle), + new FrameworkPropertyMetadata((LayoutAnchorable)null, new PropertyChangedCallback(_OnModelChanged))); + + /// + /// Gets or sets the Model property. This dependency property + /// indicates model attached to this view. + /// + public LayoutAnchorable Model + { + get { return (LayoutAnchorable)GetValue(ModelProperty); } + set { SetValue(ModelProperty, value); } + } + + static void _OnModelChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + ((AnchorablePaneTitle)sender).OnModelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Model property. + /// + protected virtual void OnModelChanged(DependencyPropertyChangedEventArgs e) + { + if (Model != null) + SetLayoutItem(Model.Root.Manager.GetLayoutItemFromModel(Model)); + else + SetLayoutItem(null); + } + + #endregion + + + #region LayoutItem + + /// + /// LayoutItem Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey LayoutItemPropertyKey + = DependencyProperty.RegisterReadOnly("LayoutItem", typeof(LayoutItem), typeof(AnchorablePaneTitle), + new FrameworkPropertyMetadata((LayoutItem)null)); + + public static readonly DependencyProperty LayoutItemProperty + = LayoutItemPropertyKey.DependencyProperty; + + /// + /// Gets the LayoutItem property. This dependency property + /// indicates the LayoutItem attached to this tag item. + /// + public LayoutItem LayoutItem + { + get { return (LayoutItem)GetValue(LayoutItemProperty); } + } + + /// + /// Provides a secure method for setting the LayoutItem property. + /// This dependency property indicates the LayoutItem attached to this tag item. + /// + /// The new value for the property. + protected void SetLayoutItem(LayoutItem value) + { + SetValue(LayoutItemPropertyKey, value); + } + + #endregion + + + private void OnHide() + { + Model.Hide(); + } + + private void OnToggleAutoHide() + { + Model.ToggleAutoHide(); + } + + protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e) + { + if (e.LeftButton != MouseButtonState.Pressed) + { + _isMouseDown = false; + } + + base.OnMouseMove(e); + } + + protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e) + { + base.OnMouseLeave(e); + + if (_isMouseDown && e.LeftButton == MouseButtonState.Pressed) + { + var pane = this.FindVisualAncestor(); + if (pane != null) + { + var paneModel = pane.Model as LayoutAnchorablePane; + var manager = paneModel.Root.Manager; + + manager.StartDraggingFloatingWindowForPane(paneModel); + } + } + + _isMouseDown = false; + } + + bool _isMouseDown = false; + protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + if (!e.Handled) + { + bool attachFloatingWindow = false; + var parentFloatingWindow = Model.FindParent(); + if (parentFloatingWindow != null) + { + attachFloatingWindow = parentFloatingWindow.Descendents().OfType().Count() == 1; + } + + if (attachFloatingWindow) + { + //the pane is hosted inside a floating window that contains only an anchorable pane so drag the floating window itself + var floatingWndControl = Model.Root.Manager.FloatingWindows.Single(fwc => fwc.Model == parentFloatingWindow); + floatingWndControl.AttachDrag(false); + } + else + _isMouseDown = true;//normal drag + } + } + + protected override void OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs e) + { + _isMouseDown = false; + base.OnMouseLeftButtonUp(e); + + if (Model != null) + Model.IsActive = true;//FocusElementManager.SetFocusOnLastElement(Model); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/AutoHideWindowManager.cs b/Src/Xceed.Wpf.AvalonDock/Controls/AutoHideWindowManager.cs new file mode 100644 index 0000000..ba359aa --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/AutoHideWindowManager.cs @@ -0,0 +1,90 @@ +/************************************************************************************* + + 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.Threading; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + class AutoHideWindowManager + { + DockingManager _manager; + + internal AutoHideWindowManager(DockingManager manager) + { + _manager = manager; + SetupCloseTimer(); + } + + + WeakReference _currentAutohiddenAnchor = null; + + public void ShowAutoHideWindow(LayoutAnchorControl anchor) + { + if( _currentAutohiddenAnchor.GetValueOrDefault() != anchor ) + { + StopCloseTimer(); + _currentAutohiddenAnchor = new WeakReference( anchor ); + _manager.AutoHideWindow.Show( anchor ); + StartCloseTimer(); + } + } + + public void HideAutoWindow(LayoutAnchorControl anchor = null) + { + if (anchor == null || + anchor == _currentAutohiddenAnchor.GetValueOrDefault()) + { + StopCloseTimer(); + } + else + System.Diagnostics.Debug.Assert(false); + } + + DispatcherTimer _closeTimer = null; + void SetupCloseTimer() + { + _closeTimer = new DispatcherTimer(DispatcherPriority.Background); + _closeTimer.Interval = TimeSpan.FromMilliseconds(1500); + _closeTimer.Tick += (s, e) => + { + if (_manager.AutoHideWindow.IsWin32MouseOver || + ((LayoutAnchorable)_manager.AutoHideWindow.Model).IsActive || + _manager.AutoHideWindow.IsResizing) + return; + + StopCloseTimer(); + }; + } + + void StartCloseTimer() + { + _closeTimer.Start(); + + } + + void StopCloseTimer() + { + _closeTimer.Stop(); + _manager.AutoHideWindow.Hide(); + _currentAutohiddenAnchor = null; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/BindingHelper.cs b/Src/Xceed.Wpf.AvalonDock/Controls/BindingHelper.cs new file mode 100644 index 0000000..9314600 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/BindingHelper.cs @@ -0,0 +1,55 @@ +/************************************************************************************* + + 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; +using System.ComponentModel; +using System.Windows.Data; +using System.Windows.Threading; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + class BindingHelper + { + public static void RebindInactiveBindings(DependencyObject dependencyObject) + { + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(dependencyObject.GetType())) + { + var dpd = DependencyPropertyDescriptor.FromProperty(property); + if (dpd != null) + { + BindingExpressionBase binding = BindingOperations.GetBindingExpressionBase(dependencyObject, dpd.DependencyProperty); + if (binding != null) + { + //if (property.Name == "DataContext" || binding.HasError || binding.Status != BindingStatus.Active) + { + // Ensure that no pending calls are in the dispatcher queue + Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.SystemIdle, (Action)delegate + { + // Remove and add the binding to re-trigger the binding error + dependencyObject.ClearValue(dpd.DependencyProperty); + BindingOperations.SetBinding(dependencyObject, dpd.DependencyProperty, binding.ParentBindingBase); + }); + } + } + } + } + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/ContextMenuEx.cs b/Src/Xceed.Wpf.AvalonDock/Controls/ContextMenuEx.cs new file mode 100644 index 0000000..318fe0a --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/ContextMenuEx.cs @@ -0,0 +1,52 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows.Data; +using System.Windows; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class ContextMenuEx : ContextMenu + { + static ContextMenuEx() + { + } + + public ContextMenuEx() + { + + } + + protected override System.Windows.DependencyObject GetContainerForItemOverride() + { + return new MenuItemEx(); + } + + protected override void OnOpened(System.Windows.RoutedEventArgs e) + { + BindingOperations.GetBindingExpression(this, ItemsSourceProperty).UpdateTarget(); + + base.OnOpened(e); + } + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DockingManagerDropTarget.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DockingManagerDropTarget.cs new file mode 100644 index 0000000..8772aaa --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DockingManagerDropTarget.cs @@ -0,0 +1,248 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal class DockingManagerDropTarget : DropTarget + { + internal DockingManagerDropTarget(DockingManager manager, Rect detectionRect, DropTargetType type) + : base(manager, detectionRect, type) + { + _manager = manager; + } + + DockingManager _manager; + + protected override void Drop(LayoutAnchorableFloatingWindow floatingWindow) + { + switch (Type) + { + case DropTargetType.DockingManagerDockLeft: + #region DropTargetType.DockingManagerDockLeft + { + if (_manager.Layout.RootPanel.Orientation != System.Windows.Controls.Orientation.Horizontal && + _manager.Layout.RootPanel.Children.Count == 1) + _manager.Layout.RootPanel.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (_manager.Layout.RootPanel.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + if (layoutAnchorablePaneGroup != null && + layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var childrenToTransfer = layoutAnchorablePaneGroup.Children.ToArray(); + for (int i = 0; i < childrenToTransfer.Length; i++) + _manager.Layout.RootPanel.Children.Insert(i, childrenToTransfer[i]); + } + else + _manager.Layout.RootPanel.Children.Insert(0, floatingWindow.RootPanel); + } + else + { + var newOrientedPanel = new LayoutPanel() + { + Orientation = System.Windows.Controls.Orientation.Horizontal + }; + + newOrientedPanel.Children.Add(floatingWindow.RootPanel); + newOrientedPanel.Children.Add(_manager.Layout.RootPanel); + + _manager.Layout.RootPanel = newOrientedPanel; + } + } + break; + #endregion + case DropTargetType.DockingManagerDockRight: + #region DropTargetType.DockingManagerDockRight + { + if (_manager.Layout.RootPanel.Orientation != System.Windows.Controls.Orientation.Horizontal && + _manager.Layout.RootPanel.Children.Count == 1) + _manager.Layout.RootPanel.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (_manager.Layout.RootPanel.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + if (layoutAnchorablePaneGroup != null && + layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + var childrenToTransfer = layoutAnchorablePaneGroup.Children.ToArray(); + for (int i = 0; i < childrenToTransfer.Length; i++) + _manager.Layout.RootPanel.Children.Add(childrenToTransfer[i]); + } + else + _manager.Layout.RootPanel.Children.Add(floatingWindow.RootPanel); + } + else + { + var newOrientedPanel = new LayoutPanel() + { + Orientation = System.Windows.Controls.Orientation.Horizontal + }; + + newOrientedPanel.Children.Add(_manager.Layout.RootPanel); + newOrientedPanel.Children.Add(floatingWindow.RootPanel); + + _manager.Layout.RootPanel = newOrientedPanel; + } + } + break; + #endregion + case DropTargetType.DockingManagerDockTop: + #region DropTargetType.DockingManagerDockTop + { + if (_manager.Layout.RootPanel.Orientation != System.Windows.Controls.Orientation.Vertical && + _manager.Layout.RootPanel.Children.Count == 1) + _manager.Layout.RootPanel.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (_manager.Layout.RootPanel.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + if (layoutAnchorablePaneGroup != null && + layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var childrenToTransfer = layoutAnchorablePaneGroup.Children.ToArray(); + for (int i = 0; i < childrenToTransfer.Length; i++) + _manager.Layout.RootPanel.Children.Insert(i, childrenToTransfer[i]); + } + else + _manager.Layout.RootPanel.Children.Insert(0, floatingWindow.RootPanel); + } + else + { + var newOrientedPanel = new LayoutPanel() + { + Orientation = System.Windows.Controls.Orientation.Vertical + }; + + newOrientedPanel.Children.Add(floatingWindow.RootPanel); + newOrientedPanel.Children.Add(_manager.Layout.RootPanel); + + _manager.Layout.RootPanel = newOrientedPanel; + } + } + break; + #endregion + case DropTargetType.DockingManagerDockBottom: + #region DropTargetType.DockingManagerDockBottom + { + if (_manager.Layout.RootPanel.Orientation != System.Windows.Controls.Orientation.Vertical && + _manager.Layout.RootPanel.Children.Count == 1) + _manager.Layout.RootPanel.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (_manager.Layout.RootPanel.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + if (layoutAnchorablePaneGroup != null && + layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical) + { + var childrenToTransfer = layoutAnchorablePaneGroup.Children.ToArray(); + for (int i = 0; i < childrenToTransfer.Length; i++) + _manager.Layout.RootPanel.Children.Add(childrenToTransfer[i]); + + } + else + _manager.Layout.RootPanel.Children.Add(floatingWindow.RootPanel); + } + else + { + var newOrientedPanel = new LayoutPanel() + { + Orientation = System.Windows.Controls.Orientation.Vertical + }; + + newOrientedPanel.Children.Add(_manager.Layout.RootPanel); + newOrientedPanel.Children.Add(floatingWindow.RootPanel); + + _manager.Layout.RootPanel = newOrientedPanel; + } + } + break; + #endregion + } + + + base.Drop(floatingWindow); + } + + public override System.Windows.Media.Geometry GetPreviewPath(OverlayWindow overlayWindow, LayoutFloatingWindow floatingWindowModel) + { + var anchorableFloatingWindowModel = floatingWindowModel as LayoutAnchorableFloatingWindow; + var layoutAnchorablePane = anchorableFloatingWindowModel.RootPanel as ILayoutPositionableElement; + var layoutAnchorablePaneWithActualSize = anchorableFloatingWindowModel.RootPanel as ILayoutPositionableElementWithActualSize; + + var targetScreenRect = TargetElement.GetScreenArea(); + + switch (Type) + { + case DropTargetType.DockingManagerDockLeft: + { + var desideredWidth = layoutAnchorablePane.DockWidth.IsAbsolute ? layoutAnchorablePane.DockWidth.Value : layoutAnchorablePaneWithActualSize.ActualWidth; + var previewBoxRect = new Rect( + targetScreenRect.Left - overlayWindow.Left, + targetScreenRect.Top - overlayWindow.Top, + Math.Min(desideredWidth, targetScreenRect.Width / 2.0), + targetScreenRect.Height); + + return new RectangleGeometry(previewBoxRect); + } + case DropTargetType.DockingManagerDockTop: + { + var desideredHeight = layoutAnchorablePane.DockHeight.IsAbsolute ? layoutAnchorablePane.DockHeight.Value : layoutAnchorablePaneWithActualSize.ActualHeight; + var previewBoxRect = new Rect( + targetScreenRect.Left - overlayWindow.Left, + targetScreenRect.Top - overlayWindow.Top, + targetScreenRect.Width, + Math.Min(desideredHeight, targetScreenRect.Height / 2.0)); + + return new RectangleGeometry(previewBoxRect); + } + case DropTargetType.DockingManagerDockRight: + { + var desideredWidth = layoutAnchorablePane.DockWidth.IsAbsolute ? layoutAnchorablePane.DockWidth.Value : layoutAnchorablePaneWithActualSize.ActualWidth; + var previewBoxRect = new Rect( + targetScreenRect.Right - overlayWindow.Left - Math.Min(desideredWidth, targetScreenRect.Width / 2.0), + targetScreenRect.Top - overlayWindow.Top, + Math.Min(desideredWidth, targetScreenRect.Width / 2.0), + targetScreenRect.Height); + + return new RectangleGeometry(previewBoxRect); + } + case DropTargetType.DockingManagerDockBottom: + { + var desideredHeight = layoutAnchorablePane.DockHeight.IsAbsolute ? layoutAnchorablePane.DockHeight.Value : layoutAnchorablePaneWithActualSize.ActualHeight; + var previewBoxRect = new Rect( + targetScreenRect.Left - overlayWindow.Left, + targetScreenRect.Bottom - overlayWindow.Top - Math.Min(desideredHeight, targetScreenRect.Height / 2.0), + targetScreenRect.Width, + Math.Min(desideredHeight, targetScreenRect.Height / 2.0)); + + return new RectangleGeometry(previewBoxRect); + } + } + + + throw new InvalidOperationException(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DockingManagerOverlayArea.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DockingManagerOverlayArea.cs new file mode 100644 index 0000000..d1ebb58 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DockingManagerOverlayArea.cs @@ -0,0 +1,40 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class DockingManagerOverlayArea : OverlayArea + { + internal DockingManagerOverlayArea(IOverlayWindow overlayWindow, DockingManager manager) + : base(overlayWindow) + { + _manager = manager; + + base.SetScreenDetectionArea(new Rect( + _manager.PointToScreenDPI(new Point()), + _manager.TransformActualSizeToAncestor())); + } + + DockingManager _manager; + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneControlOverlayArea.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneControlOverlayArea.cs new file mode 100644 index 0000000..71b47e3 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneControlOverlayArea.cs @@ -0,0 +1,44 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class DocumentPaneControlOverlayArea : OverlayArea + { + + + internal DocumentPaneControlOverlayArea( + IOverlayWindow overlayWindow, + LayoutDocumentPaneControl documentPaneControl) + : base(overlayWindow) + { + _documentPaneControl = documentPaneControl; + base.SetScreenDetectionArea(new Rect( + _documentPaneControl.PointToScreenDPI(new Point()), + _documentPaneControl.TransformActualSizeToAncestor())); + } + + LayoutDocumentPaneControl _documentPaneControl; + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneDropAsAnchorableTarget.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneDropAsAnchorableTarget.cs new file mode 100644 index 0000000..4d9be2f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneDropAsAnchorableTarget.cs @@ -0,0 +1,277 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; +using System.Diagnostics; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal class DocumentPaneDropAsAnchorableTarget : DropTarget + { + internal DocumentPaneDropAsAnchorableTarget(LayoutDocumentPaneControl paneControl, Rect detectionRect, DropTargetType type) + : base(paneControl, detectionRect, type) + { + _targetPane = paneControl; + } + + internal DocumentPaneDropAsAnchorableTarget(LayoutDocumentPaneControl paneControl, Rect detectionRect, DropTargetType type, int tabIndex) + : base(paneControl, detectionRect, type) + { + _targetPane = paneControl; + _tabIndex = tabIndex; + } + + + LayoutDocumentPaneControl _targetPane; + + int _tabIndex = -1; + + protected override void Drop(LayoutAnchorableFloatingWindow floatingWindow) + { + ILayoutDocumentPane targetModel = _targetPane.Model as ILayoutDocumentPane; + LayoutDocumentPaneGroup parentGroup; + LayoutPanel parentGroupPanel; + FindParentLayoutDocumentPane(targetModel, out parentGroup, out parentGroupPanel); + + switch (Type) + { + case DropTargetType.DocumentPaneDockAsAnchorableBottom: + #region DropTargetType.DocumentPaneDockAsAnchorableBottom + { + if (parentGroupPanel != null && + parentGroupPanel.ChildrenCount == 1) + parentGroupPanel.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (parentGroupPanel != null && + parentGroupPanel.Orientation == System.Windows.Controls.Orientation.Vertical) + { + parentGroupPanel.Children.Insert( + parentGroupPanel.IndexOfChild(parentGroup != null ? parentGroup : targetModel) + 1, + floatingWindow.RootPanel); + } + else if (parentGroupPanel != null) + { + var newParentPanel = new LayoutPanel() { Orientation = System.Windows.Controls.Orientation.Vertical }; + parentGroupPanel.ReplaceChild(parentGroup != null ? parentGroup : targetModel, newParentPanel); + newParentPanel.Children.Add(parentGroup != null ? parentGroup : targetModel); + newParentPanel.Children.Add(floatingWindow.RootPanel); + } + else + { + throw new NotImplementedException(); + } + + + } + break; + #endregion + case DropTargetType.DocumentPaneDockAsAnchorableTop: + #region DropTargetType.DocumentPaneDockAsAnchorableTop + { + if (parentGroupPanel != null && + parentGroupPanel.ChildrenCount == 1) + parentGroupPanel.Orientation = System.Windows.Controls.Orientation.Vertical; + + if (parentGroupPanel != null && + parentGroupPanel.Orientation == System.Windows.Controls.Orientation.Vertical) + { + parentGroupPanel.Children.Insert( + parentGroupPanel.IndexOfChild(parentGroup != null ? parentGroup : targetModel), + floatingWindow.RootPanel); + } + else if (parentGroupPanel != null) + { + var newParentPanel = new LayoutPanel() { Orientation = System.Windows.Controls.Orientation.Vertical }; + parentGroupPanel.ReplaceChild(parentGroup != null ? parentGroup : targetModel, newParentPanel); + newParentPanel.Children.Add(parentGroup != null ? parentGroup : targetModel); + newParentPanel.Children.Insert(0, floatingWindow.RootPanel); + } + else + { + throw new NotImplementedException(); + } + + } + break; + #endregion + case DropTargetType.DocumentPaneDockAsAnchorableLeft: + #region DropTargetType.DocumentPaneDockAsAnchorableLeft + { + if (parentGroupPanel != null && + parentGroupPanel.ChildrenCount == 1) + parentGroupPanel.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (parentGroupPanel != null && + parentGroupPanel.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + parentGroupPanel.Children.Insert( + parentGroupPanel.IndexOfChild(parentGroup != null ? parentGroup : targetModel), + floatingWindow.RootPanel); + } + else if (parentGroupPanel != null) + { + var newParentPanel = new LayoutPanel() { Orientation = System.Windows.Controls.Orientation.Horizontal }; + parentGroupPanel.ReplaceChild(parentGroup != null ? parentGroup : targetModel, newParentPanel); + newParentPanel.Children.Add(parentGroup != null ? parentGroup : targetModel); + newParentPanel.Children.Insert(0, floatingWindow.RootPanel); + } + else + { + throw new NotImplementedException(); + } + } + break; + #endregion + case DropTargetType.DocumentPaneDockAsAnchorableRight: + #region DropTargetType.DocumentPaneDockAsAnchorableRight + { + if (parentGroupPanel != null && + parentGroupPanel.ChildrenCount == 1) + parentGroupPanel.Orientation = System.Windows.Controls.Orientation.Horizontal; + + if (parentGroupPanel != null && + parentGroupPanel.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + parentGroupPanel.Children.Insert( + parentGroupPanel.IndexOfChild(parentGroup != null ? parentGroup : targetModel) + 1, + floatingWindow.RootPanel); + } + else if (parentGroupPanel != null) + { + var newParentPanel = new LayoutPanel() { Orientation = System.Windows.Controls.Orientation.Horizontal }; + parentGroupPanel.ReplaceChild(parentGroup != null ? parentGroup : targetModel, newParentPanel); + newParentPanel.Children.Add(parentGroup != null ? parentGroup : targetModel); + newParentPanel.Children.Add(floatingWindow.RootPanel); + } + else + { + throw new NotImplementedException(); + } + } + break; + #endregion + } + + base.Drop(floatingWindow); + } + + public override System.Windows.Media.Geometry GetPreviewPath(OverlayWindow overlayWindow, LayoutFloatingWindow floatingWindowModel) + { + Rect targetScreenRect; + ILayoutDocumentPane targetModel = _targetPane.Model as ILayoutDocumentPane; + var manager = targetModel.Root.Manager; + + //ILayoutDocumentPane targetModel = _targetPane.Model as ILayoutDocumentPane; + LayoutDocumentPaneGroup parentGroup; + LayoutPanel parentGroupPanel; + if (!FindParentLayoutDocumentPane(targetModel, out parentGroup, out parentGroupPanel)) + return null; + + //if (targetModel.Parent is LayoutDocumentPaneGroup) + //{ + // var parentGroup = targetModel.Parent as LayoutDocumentPaneGroup; + // var documentPaneGroupControl = manager.FindLogicalChildren().First(d => d.Model == parentGroup); + // targetScreenRect = documentPaneGroupControl.GetScreenArea(); + //} + //else + //{ + // var documentPaneControl = manager.FindLogicalChildren().First(d => d.Model == targetModel); + // targetScreenRect = documentPaneControl.GetScreenArea(); + //} + + //var parentPanel = targetModel.FindParent(); + var documentPaneControl = manager.FindLogicalChildren().OfType().First(d => parentGroup != null ? d.Model == parentGroup : d.Model == parentGroupPanel) as FrameworkElement; + targetScreenRect = documentPaneControl.GetScreenArea(); + + switch (Type) + { + case DropTargetType.DocumentPaneDockAsAnchorableBottom: + { + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + targetScreenRect.Offset(0.0, targetScreenRect.Height - targetScreenRect.Height / 3.0); + targetScreenRect.Height /= 3.0; + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.DocumentPaneDockAsAnchorableTop: + { + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + targetScreenRect.Height /= 3.0; + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.DocumentPaneDockAsAnchorableRight: + { + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + targetScreenRect.Offset(targetScreenRect.Width - targetScreenRect.Width / 3.0, 0.0); + targetScreenRect.Width /= 3.0; + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.DocumentPaneDockAsAnchorableLeft: + { + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + targetScreenRect.Width /= 3.0; + return new RectangleGeometry(targetScreenRect); + } + } + + return null; + } + + + + bool FindParentLayoutDocumentPane(ILayoutDocumentPane documentPane, out LayoutDocumentPaneGroup containerPaneGroup, out LayoutPanel containerPanel) + { + containerPaneGroup = null; + containerPanel = null; + + if (documentPane.Parent is LayoutPanel) + { + containerPaneGroup = null; + containerPanel = documentPane.Parent as LayoutPanel; + return true; + } + else if (documentPane.Parent is LayoutDocumentPaneGroup) + { + var currentDocumentPaneGroup = documentPane.Parent as LayoutDocumentPaneGroup; + while (!(currentDocumentPaneGroup.Parent is LayoutPanel)) + { + currentDocumentPaneGroup = currentDocumentPaneGroup.Parent as LayoutDocumentPaneGroup; + + if (currentDocumentPaneGroup == null) + break; + } + + if (currentDocumentPaneGroup == null) + return false; + + containerPaneGroup = currentDocumentPaneGroup; + containerPanel = currentDocumentPaneGroup.Parent as LayoutPanel; + return true; + } + + return false; + + + + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneDropTarget.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneDropTarget.cs new file mode 100644 index 0000000..0d08e51 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneDropTarget.cs @@ -0,0 +1,503 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; +using System.Diagnostics; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal class DocumentPaneDropTarget : DropTarget + { + internal DocumentPaneDropTarget(LayoutDocumentPaneControl paneControl, Rect detectionRect, DropTargetType type) + : base(paneControl, detectionRect, type) + { + _targetPane = paneControl; + } + + internal DocumentPaneDropTarget(LayoutDocumentPaneControl paneControl, Rect detectionRect, DropTargetType type, int tabIndex) + : base(paneControl, detectionRect, type) + { + _targetPane = paneControl; + _tabIndex = tabIndex; + } + + + LayoutDocumentPaneControl _targetPane; + + int _tabIndex = -1; + + protected override void Drop(LayoutDocumentFloatingWindow floatingWindow) + { + ILayoutDocumentPane targetModel = _targetPane.Model as ILayoutDocumentPane; + + switch (Type) + { + case DropTargetType.DocumentPaneDockBottom: + #region DropTargetType.DocumentPaneDockBottom + { + var newLayoutDocumentPane = new LayoutDocumentPane(floatingWindow.RootDocument); + var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + + if (parentModel == null) + { + var parentContainer = targetModel.Parent as ILayoutContainer; + var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical}; + parentContainer.ReplaceChild(targetModel, newParentModel); + newParentModel.Children.Add(targetModel as LayoutDocumentPane); + newParentModel.Children.Add(newLayoutDocumentPane); + } + else + { + var manager = parentModel.Root.Manager; + if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Vertical) + { + parentModel.Orientation = System.Windows.Controls.Orientation.Vertical; + int targetPaneIndex = parentModel.IndexOfChild(targetModel); + parentModel.Children.Insert(targetPaneIndex + 1, newLayoutDocumentPane); + } + else + { + LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); + newChildGroup.Orientation = System.Windows.Controls.Orientation.Vertical; + parentModel.ReplaceChild(targetModel, newChildGroup); + newChildGroup.Children.Add(targetModel); + newChildGroup.Children.Add(newLayoutDocumentPane); + } + + } + } + break; + #endregion + case DropTargetType.DocumentPaneDockTop: + #region DropTargetType.DocumentPaneDockTop + { + var newLayoutDocumentPane = new LayoutDocumentPane(floatingWindow.RootDocument); + var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + + if (parentModel == null) + { + var parentContainer = targetModel.Parent as ILayoutContainer; + var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; + parentContainer.ReplaceChild(targetModel, newParentModel); + newParentModel.Children.Add(targetModel as LayoutDocumentPane); + newParentModel.Children.Insert(0, newLayoutDocumentPane); + } + else + { + var manager = parentModel.Root.Manager; + if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Vertical) + { + parentModel.Orientation = System.Windows.Controls.Orientation.Vertical; + int targetPaneIndex = parentModel.IndexOfChild(targetModel); + parentModel.Children.Insert(targetPaneIndex, newLayoutDocumentPane); + } + else + { + LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); + newChildGroup.Orientation = System.Windows.Controls.Orientation.Vertical; + parentModel.ReplaceChild(targetModel, newChildGroup); + newChildGroup.Children.Add(newLayoutDocumentPane); + newChildGroup.Children.Add(targetModel); + } + + } + } + break; + #endregion + case DropTargetType.DocumentPaneDockLeft: + #region DropTargetType.DocumentPaneDockLeft + { + var newLayoutDocumentPane = new LayoutDocumentPane(floatingWindow.RootDocument); + var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + + if (parentModel == null) + { + var parentContainer = targetModel.Parent as ILayoutContainer; + var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; + parentContainer.ReplaceChild(targetModel, newParentModel); + newParentModel.Children.Add(targetModel); + newParentModel.Children.Insert(0, newLayoutDocumentPane); + } + else + { + var manager = parentModel.Root.Manager; + if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + parentModel.Orientation = System.Windows.Controls.Orientation.Horizontal; + int targetPaneIndex = parentModel.IndexOfChild(targetModel); + parentModel.Children.Insert(targetPaneIndex, newLayoutDocumentPane); + } + else + { + LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); + newChildGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; + parentModel.ReplaceChild(targetModel, newChildGroup); + newChildGroup.Children.Add(newLayoutDocumentPane); + newChildGroup.Children.Add(targetModel); + } + } + } + break; + #endregion + case DropTargetType.DocumentPaneDockRight: + #region DropTargetType.DocumentPaneDockRight + { + var newLayoutDocumentPane = new LayoutDocumentPane(floatingWindow.RootDocument); + var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + + if (parentModel == null) + { + var parentContainer = targetModel.Parent as ILayoutContainer; + var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; + parentContainer.ReplaceChild(targetModel, newParentModel); + newParentModel.Children.Add(targetModel as LayoutDocumentPane); + newParentModel.Children.Add(newLayoutDocumentPane); + } + else + { + var manager = parentModel.Root.Manager; + if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + parentModel.Orientation = System.Windows.Controls.Orientation.Horizontal; + int targetPaneIndex = parentModel.IndexOfChild(targetModel); + parentModel.Children.Insert(targetPaneIndex + 1, newLayoutDocumentPane); + } + else + { + LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); + newChildGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; + parentModel.ReplaceChild(targetModel, newChildGroup); + newChildGroup.Children.Add(targetModel); + newChildGroup.Children.Add(newLayoutDocumentPane); + } + + } + } + break; + #endregion + + case DropTargetType.DocumentPaneDockInside: + #region DropTargetType.DocumentPaneDockInside + { + var paneModel = targetModel as LayoutDocumentPane; + var sourceModel = floatingWindow.RootDocument; + + int i = 0; + if( _tabIndex != -1 ) + { + i = _tabIndex; + } + else + { + var previousContainer = ((ILayoutPreviousContainer)sourceModel).PreviousContainer; + if( object.ReferenceEquals( previousContainer, targetModel ) && (sourceModel.PreviousContainerIndex != -1) ) + { + i = sourceModel.PreviousContainerIndex; + } + } + sourceModel.IsActive = false; + paneModel.Children.Insert(i, sourceModel); + sourceModel.IsActive = true; + } + break; + #endregion + + + } + + base.Drop(floatingWindow); + } + + protected override void Drop(LayoutAnchorableFloatingWindow floatingWindow) + { + ILayoutDocumentPane targetModel = _targetPane.Model as ILayoutDocumentPane; + + switch (Type) + { + case DropTargetType.DocumentPaneDockBottom: + #region DropTargetType.DocumentPaneDockBottom + { + var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + var newLayoutDocumentPane = new LayoutDocumentPane(); + + if (parentModel == null) + { + var parentContainer = targetModel.Parent as ILayoutContainer; + var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; + parentContainer.ReplaceChild(targetModel, newParentModel); + newParentModel.Children.Add(targetModel as LayoutDocumentPane); + newParentModel.Children.Add(newLayoutDocumentPane); + } + else + { + var manager = parentModel.Root.Manager; + if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Vertical) + { + parentModel.Orientation = System.Windows.Controls.Orientation.Vertical; + int targetPaneIndex = parentModel.IndexOfChild(targetModel); + parentModel.Children.Insert(targetPaneIndex + 1, newLayoutDocumentPane); + } + else + { + LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); + newChildGroup.Orientation = System.Windows.Controls.Orientation.Vertical; + parentModel.ReplaceChild(targetModel, newChildGroup); + newChildGroup.Children.Add(targetModel); + newChildGroup.Children.Add(newLayoutDocumentPane); + } + } + + foreach (var cntToTransfer in floatingWindow.RootPanel.Descendents().OfType().ToArray()) + newLayoutDocumentPane.Children.Add(cntToTransfer); + + } + break; + #endregion + case DropTargetType.DocumentPaneDockTop: + #region DropTargetType.DocumentPaneDockTop + { + var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + var newLayoutDocumentPane = new LayoutDocumentPane(); + + if (parentModel == null) + { + var parentContainer = targetModel.Parent as ILayoutContainer; + var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; + parentContainer.ReplaceChild(targetModel, newParentModel); + newParentModel.Children.Add(newLayoutDocumentPane); + newParentModel.Children.Add(targetModel as LayoutDocumentPane); + } + else + { + var manager = parentModel.Root.Manager; + if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Vertical) + { + parentModel.Orientation = System.Windows.Controls.Orientation.Vertical; + int targetPaneIndex = parentModel.IndexOfChild(targetModel); + parentModel.Children.Insert(targetPaneIndex, newLayoutDocumentPane); + } + else + { + LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); + newChildGroup.Orientation = System.Windows.Controls.Orientation.Vertical; + parentModel.ReplaceChild(targetModel, newChildGroup); + newChildGroup.Children.Add(newLayoutDocumentPane); + newChildGroup.Children.Add(targetModel); + } + } + + foreach (var cntToTransfer in floatingWindow.RootPanel.Descendents().OfType().ToArray()) + newLayoutDocumentPane.Children.Add(cntToTransfer); + + } + break; + #endregion + case DropTargetType.DocumentPaneDockLeft: + #region DropTargetType.DocumentPaneDockLeft + { + var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + var newLayoutDocumentPane = new LayoutDocumentPane(); + + if (parentModel == null) + { + var parentContainer = targetModel.Parent as ILayoutContainer; + var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; + parentContainer.ReplaceChild(targetModel, newParentModel); + newParentModel.Children.Add(newLayoutDocumentPane); + newParentModel.Children.Add(targetModel as LayoutDocumentPane); + } + else + { + var manager = parentModel.Root.Manager; + if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + parentModel.Orientation = System.Windows.Controls.Orientation.Horizontal; + int targetPaneIndex = parentModel.IndexOfChild(targetModel); + parentModel.Children.Insert(targetPaneIndex, newLayoutDocumentPane); + } + else + { + LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); + newChildGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; + parentModel.ReplaceChild(targetModel, newChildGroup); + newChildGroup.Children.Add(newLayoutDocumentPane); + newChildGroup.Children.Add(targetModel); + } + + } + + foreach (var cntToTransfer in floatingWindow.RootPanel.Descendents().OfType().ToArray()) + newLayoutDocumentPane.Children.Add(cntToTransfer); + + } + break; + #endregion + case DropTargetType.DocumentPaneDockRight: + #region DropTargetType.DocumentPaneDockRight + { + var parentModel = targetModel.Parent as LayoutDocumentPaneGroup; + var newLayoutDocumentPane = new LayoutDocumentPane(); + + if (parentModel == null) + { + var parentContainer = targetModel.Parent as ILayoutContainer; + var newParentModel = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; + parentContainer.ReplaceChild(targetModel, newParentModel); + newParentModel.Children.Add(targetModel as LayoutDocumentPane); + newParentModel.Children.Add(newLayoutDocumentPane); + } + else + { + var manager = parentModel.Root.Manager; + if (!manager.AllowMixedOrientation || parentModel.Orientation == System.Windows.Controls.Orientation.Horizontal) + { + parentModel.Orientation = System.Windows.Controls.Orientation.Horizontal; + int targetPaneIndex = parentModel.IndexOfChild(targetModel); + parentModel.Children.Insert(targetPaneIndex + 1, newLayoutDocumentPane); + } + else + { + LayoutDocumentPaneGroup newChildGroup = new LayoutDocumentPaneGroup(); + newChildGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; + parentModel.ReplaceChild(targetModel, newChildGroup); + newChildGroup.Children.Add(targetModel); + newChildGroup.Children.Add(newLayoutDocumentPane); + } + } + + foreach (var cntToTransfer in floatingWindow.RootPanel.Descendents().OfType().ToArray()) + newLayoutDocumentPane.Children.Add(cntToTransfer); + + } + break; + #endregion + case DropTargetType.DocumentPaneDockInside: + #region DropTargetType.DocumentPaneDockInside + { + var paneModel = targetModel as LayoutDocumentPane; + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + + bool checkPreviousContainer = true; + int i = 0; + if( _tabIndex != -1 ) + { + i = _tabIndex; + checkPreviousContainer = false; + } + LayoutAnchorable anchorableToActivate = null; + + foreach (var anchorableToImport in layoutAnchorablePaneGroup.Descendents().OfType().ToArray()) + { + if( checkPreviousContainer ) + { + var previousContainer = ((ILayoutPreviousContainer)anchorableToImport).PreviousContainer; + if( object.ReferenceEquals( previousContainer, targetModel ) && (anchorableToImport.PreviousContainerIndex != -1) ) + { + i = anchorableToImport.PreviousContainerIndex; + } + checkPreviousContainer = false; + } + + paneModel.Children.Insert(i, anchorableToImport); + i++; + anchorableToActivate = anchorableToImport; + } + + anchorableToActivate.IsActive = true; + } + break; + #endregion + } + + base.Drop(floatingWindow); + } + + public override System.Windows.Media.Geometry GetPreviewPath(OverlayWindow overlayWindow, LayoutFloatingWindow floatingWindowModel) + { + switch (Type) + { + case DropTargetType.DocumentPaneDockInside: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + + if (_tabIndex == -1) + { + return new RectangleGeometry(targetScreenRect); + } + else + { + var translatedDetectionRect = new Rect(DetectionRects[0].TopLeft, DetectionRects[0].BottomRight); + translatedDetectionRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + + var pathFigure = new PathFigure(); + pathFigure.StartPoint = targetScreenRect.BottomRight; + pathFigure.Segments.Add(new LineSegment() { Point = new Point(targetScreenRect.Right, translatedDetectionRect.Bottom) }); + pathFigure.Segments.Add(new LineSegment() { Point = translatedDetectionRect.BottomRight }); + pathFigure.Segments.Add(new LineSegment() { Point = translatedDetectionRect.TopRight }); + pathFigure.Segments.Add(new LineSegment() { Point = translatedDetectionRect.TopLeft }); + pathFigure.Segments.Add(new LineSegment() { Point = translatedDetectionRect.BottomLeft }); + pathFigure.Segments.Add(new LineSegment() { Point = new Point(targetScreenRect.Left, translatedDetectionRect.Bottom) }); + pathFigure.Segments.Add(new LineSegment() { Point = targetScreenRect.BottomLeft }); + pathFigure.IsClosed = true; + pathFigure.IsFilled = true; + pathFigure.Freeze(); + return new PathGeometry(new PathFigure[] { pathFigure }); + } + } + case DropTargetType.DocumentPaneDockBottom: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + targetScreenRect.Offset(0.0, targetScreenRect.Height / 2.0); + targetScreenRect.Height /= 2.0; + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.DocumentPaneDockTop: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + targetScreenRect.Height /= 2.0; + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.DocumentPaneDockLeft: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + targetScreenRect.Width /= 2.0; + return new RectangleGeometry(targetScreenRect); + } + case DropTargetType.DocumentPaneDockRight: + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + targetScreenRect.Offset(targetScreenRect.Width / 2.0, 0.0); + targetScreenRect.Width /= 2.0; + return new RectangleGeometry(targetScreenRect); + } + } + + return null; + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneGroupDropTarget.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneGroupDropTarget.cs new file mode 100644 index 0000000..463c7cf --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneGroupDropTarget.cs @@ -0,0 +1,105 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; +using System.Diagnostics; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal class DocumentPaneGroupDropTarget : DropTarget + { + internal DocumentPaneGroupDropTarget(LayoutDocumentPaneGroupControl paneControl, Rect detectionRect, DropTargetType type) + : base(paneControl, detectionRect, type) + { + _targetPane = paneControl; + } + + LayoutDocumentPaneGroupControl _targetPane; + + protected override void Drop(LayoutDocumentFloatingWindow floatingWindow) + { + ILayoutPane targetModel = _targetPane.Model as ILayoutPane; + + switch (Type) + { + case DropTargetType.DocumentPaneGroupDockInside: + #region DropTargetType.DocumentPaneGroupDockInside + { + var paneGroupModel = targetModel as LayoutDocumentPaneGroup; + var paneModel = paneGroupModel.Children[0] as LayoutDocumentPane; + var sourceModel = floatingWindow.RootDocument; + + paneModel.Children.Insert(0, sourceModel); + } + break; + #endregion + } + base.Drop(floatingWindow); + } + + protected override void Drop(LayoutAnchorableFloatingWindow floatingWindow) + { + ILayoutPane targetModel = _targetPane.Model as ILayoutPane; + + switch (Type) + { + case DropTargetType.DocumentPaneGroupDockInside: + #region DropTargetType.DocumentPaneGroupDockInside + { + var paneGroupModel = targetModel as LayoutDocumentPaneGroup; + var paneModel = paneGroupModel.Children[0] as LayoutDocumentPane; + var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup; + + int i = 0; + foreach (var anchorableToImport in layoutAnchorablePaneGroup.Descendents().OfType().ToArray()) + { + paneModel.Children.Insert(i, anchorableToImport); + i++; + } + } + break; + #endregion + } + + base.Drop(floatingWindow); + } + + public override System.Windows.Media.Geometry GetPreviewPath(OverlayWindow overlayWindow, LayoutFloatingWindow floatingWindowModel) + { + switch (Type) + { + case DropTargetType.DocumentPaneGroupDockInside: + #region DropTargetType.DocumentPaneGroupDockInside + { + var targetScreenRect = TargetElement.GetScreenArea(); + targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top); + + return new RectangleGeometry(targetScreenRect); + } + #endregion + } + + return null; + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneTabPanel.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneTabPanel.cs new file mode 100644 index 0000000..cadc4e2 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DocumentPaneTabPanel.cs @@ -0,0 +1,106 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class DocumentPaneTabPanel : Panel + { + public DocumentPaneTabPanel() + { + FlowDirection = System.Windows.FlowDirection.LeftToRight; + } + + protected override Size MeasureOverride(Size availableSize) + { + var visibleChildren = Children.Cast().Where(ch => ch.Visibility != System.Windows.Visibility.Collapsed); + + Size desideredSize = new Size(); + foreach (FrameworkElement child in Children) + { + child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + desideredSize.Width += child.DesiredSize.Width; + + desideredSize.Height = Math.Max(desideredSize.Height, child.DesiredSize.Height); + } + + return new Size(Math.Min(desideredSize.Width, availableSize.Width), desideredSize.Height); + } + + protected override Size ArrangeOverride(Size finalSize) + { + var visibleChildren = Children.Cast().Where( ch => ch.Visibility != System.Windows.Visibility.Collapsed ); + var offset = 0.0; + var skipAllOthers = false; + foreach( TabItem doc in visibleChildren ) + { + var layoutContent = doc.Content as LayoutContent; + if( skipAllOthers || offset + doc.DesiredSize.Width > finalSize.Width ) + { + if( layoutContent.IsSelected && !doc.IsVisible ) + { + var parentContainer = layoutContent.Parent as ILayoutContainer; + var parentSelector = layoutContent.Parent as ILayoutContentSelector; + var parentPane = layoutContent.Parent as ILayoutPane; + int contentIndex = parentSelector.IndexOf( layoutContent ); + if( contentIndex > 0 && + parentContainer.ChildrenCount > 1 ) + { + parentPane.MoveChild( contentIndex, 0 ); + parentSelector.SelectedContentIndex = 0; + return ArrangeOverride( finalSize ); + } + } + doc.Visibility = System.Windows.Visibility.Hidden; + skipAllOthers = true; + } + else + { + doc.Visibility = System.Windows.Visibility.Visible; + doc.Arrange( new Rect( offset, 0.0, doc.DesiredSize.Width, finalSize.Height ) ); + offset += doc.ActualWidth + doc.Margin.Left + doc.Margin.Right; + } + } + return finalSize; + + } + + + protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e) + { + //if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed && + // LayoutDocumentTabItem.IsDraggingItem()) + //{ + // var contentModel = LayoutDocumentTabItem.GetDraggingItem().Model; + // var manager = contentModel.Root.Manager; + // LayoutDocumentTabItem.ResetDraggingItem(); + // System.Diagnostics.Trace.WriteLine("OnMouseLeave()"); + + + // manager.StartDraggingFloatingWindowForContent(contentModel); + //} + + base.OnMouseLeave(e); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DragService.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DragService.cs new file mode 100644 index 0000000..4f1dc3a --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DragService.cs @@ -0,0 +1,190 @@ +/************************************************************************************* + + 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.Input; +using System.Windows; +using System.Diagnostics; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + class DragService + { + DockingManager _manager; + LayoutFloatingWindowControl _floatingWindow; + + public DragService(LayoutFloatingWindowControl floatingWindow) + { + _floatingWindow = floatingWindow; + _manager = floatingWindow.Model.Root.Manager; + + + GetOverlayWindowHosts(); + } + + List _overlayWindowHosts = new List(); + void GetOverlayWindowHosts() + { + _overlayWindowHosts.AddRange(_manager.GetFloatingWindowsByZOrder().OfType().Where(fw => fw != _floatingWindow && fw.IsVisible)); + _overlayWindowHosts.Add(_manager); + } + + IOverlayWindowHost _currentHost; + IOverlayWindow _currentWindow; + List _currentWindowAreas = new List(); + IDropTarget _currentDropTarget; + + public void UpdateMouseLocation(Point dragPosition) + { + var floatingWindowModel = _floatingWindow.Model as LayoutFloatingWindow; + + var newHost = _overlayWindowHosts.FirstOrDefault(oh => oh.HitTest(dragPosition)); + + if (_currentHost != null || _currentHost != newHost) + { + //is mouse still inside current overlay window host? + if ((_currentHost != null && !_currentHost.HitTest(dragPosition)) || + _currentHost != newHost) + { + //esit drop target + if (_currentDropTarget != null) + _currentWindow.DragLeave(_currentDropTarget); + _currentDropTarget = null; + + //exit area + _currentWindowAreas.ForEach(a => + _currentWindow.DragLeave(a)); + _currentWindowAreas.Clear(); + + //hide current overlay window + if (_currentWindow != null) + _currentWindow.DragLeave(_floatingWindow); + if (_currentHost != null) + _currentHost.HideOverlayWindow(); + _currentHost = null; + } + + if (_currentHost != newHost) + { + _currentHost = newHost; + _currentWindow = _currentHost.ShowOverlayWindow(_floatingWindow); + _currentWindow.DragEnter(_floatingWindow); + } + } + + if (_currentHost == null) + return; + + if (_currentDropTarget != null && + !_currentDropTarget.HitTest(dragPosition)) + { + _currentWindow.DragLeave(_currentDropTarget); + _currentDropTarget = null; + } + + List areasToRemove = new List(); + _currentWindowAreas.ForEach(a => + { + //is mouse still inside this area? + if (!a.DetectionRect.Contains(dragPosition)) + { + _currentWindow.DragLeave(a); + areasToRemove.Add(a); + } + }); + + areasToRemove.ForEach(a => + _currentWindowAreas.Remove(a)); + + + var areasToAdd = + _currentHost.GetDropAreas(_floatingWindow).Where(cw => !_currentWindowAreas.Contains(cw) && cw.DetectionRect.Contains(dragPosition)).ToList(); + + _currentWindowAreas.AddRange(areasToAdd); + + areasToAdd.ForEach(a => + _currentWindow.DragEnter(a)); + + if (_currentDropTarget == null) + { + _currentWindowAreas.ForEach(wa => + { + if (_currentDropTarget != null) + return; + + _currentDropTarget = _currentWindow.GetTargets().FirstOrDefault(dt => dt.HitTest(dragPosition)); + if (_currentDropTarget != null) + { + _currentWindow.DragEnter(_currentDropTarget); + return; + } + }); + } + + } + + public void Drop(Point dropLocation, out bool dropHandled) + { + dropHandled = false; + + UpdateMouseLocation(dropLocation); + + var floatingWindowModel = _floatingWindow.Model as LayoutFloatingWindow; + var root = floatingWindowModel.Root; + + if (_currentHost != null) + _currentHost.HideOverlayWindow(); + + if (_currentDropTarget != null) + { + _currentWindow.DragDrop(_currentDropTarget); + root.CollectGarbage(); + dropHandled = true; + } + + + _currentWindowAreas.ForEach(a => _currentWindow.DragLeave(a)); + + if (_currentDropTarget != null) + _currentWindow.DragLeave(_currentDropTarget); + if (_currentWindow != null) + _currentWindow.DragLeave(_floatingWindow); + _currentWindow = null; + + _currentHost = null; + } + + internal void Abort() + { + var floatingWindowModel = _floatingWindow.Model as LayoutFloatingWindow; + + _currentWindowAreas.ForEach(a => _currentWindow.DragLeave(a)); + + if (_currentDropTarget != null) + _currentWindow.DragLeave(_currentDropTarget); + if (_currentWindow != null) + _currentWindow.DragLeave(_floatingWindow); + _currentWindow = null; + if (_currentHost != null) + _currentHost.HideOverlayWindow(); + _currentHost = null; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DropArea.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DropArea.cs new file mode 100644 index 0000000..d925a7b --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DropArea.cs @@ -0,0 +1,77 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public enum DropAreaType + { + DockingManager, + + DocumentPane, + + DocumentPaneGroup, + + AnchorablePane, + + } + + + public interface IDropArea + { + Rect DetectionRect { get; } + DropAreaType Type { get; } + } + + public class DropArea : IDropArea where T : FrameworkElement + { + internal DropArea(T areaElement, DropAreaType type) + { + _element = areaElement; + _detectionRect = areaElement.GetScreenArea(); + _type = type; + } + + Rect _detectionRect; + + public Rect DetectionRect + { + get { return _detectionRect; } + } + + DropAreaType _type; + + public DropAreaType Type + { + get { return _type; } + } + + T _element; + public T AreaElement + { + get + { + return _element; + } + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DropDownButton.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DropDownButton.cs new file mode 100644 index 0000000..5e1a896 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DropDownButton.cs @@ -0,0 +1,132 @@ +/************************************************************************************* + + 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.Controls.Primitives; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Diagnostics; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class DropDownButton : ToggleButton + { + public DropDownButton() + { + this.Unloaded += new RoutedEventHandler(DropDownButton_Unloaded); + } + + #region DropDownContextMenu + + /// + /// DropDownContextMenu Dependency Property + /// + public static readonly DependencyProperty DropDownContextMenuProperty = + DependencyProperty.Register("DropDownContextMenu", typeof(ContextMenu), typeof(DropDownButton), + new FrameworkPropertyMetadata((ContextMenu)null, + new PropertyChangedCallback(OnDropDownContextMenuChanged))); + + /// + /// Gets or sets the DropDownContextMenu property. This dependency property + /// indicates drop down menu to show up when user click on an anchorable menu pin. + /// + public ContextMenu DropDownContextMenu + { + get { return (ContextMenu)GetValue(DropDownContextMenuProperty); } + set { SetValue(DropDownContextMenuProperty, value); } + } + + /// + /// Handles changes to the DropDownContextMenu property. + /// + private static void OnDropDownContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DropDownButton)d).OnDropDownContextMenuChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DropDownContextMenu property. + /// + protected virtual void OnDropDownContextMenuChanged(DependencyPropertyChangedEventArgs e) + { + var oldContextMenu = e.OldValue as ContextMenu; + if (oldContextMenu != null && IsChecked.GetValueOrDefault()) + oldContextMenu.Closed -= new RoutedEventHandler(OnContextMenuClosed); + } + + #endregion + + #region DropDownContextMenuDataContext + + /// + /// DropDownContextMenuDataContext Dependency Property + /// + public static readonly DependencyProperty DropDownContextMenuDataContextProperty = + DependencyProperty.Register("DropDownContextMenuDataContext", typeof(object), typeof(DropDownButton), + new FrameworkPropertyMetadata((object)null)); + + /// + /// Gets or sets the DropDownContextMenuDataContext property. This dependency property + /// indicates data context to set for drop down context menu. + /// + public object DropDownContextMenuDataContext + { + get { return (object)GetValue(DropDownContextMenuDataContextProperty); } + set { SetValue(DropDownContextMenuDataContextProperty, value); } + } + + #endregion + + protected override void OnClick() + { + if (DropDownContextMenu != null) + { + //IsChecked = true; + DropDownContextMenu.PlacementTarget = this; + DropDownContextMenu.Placement = PlacementMode.Bottom; + DropDownContextMenu.DataContext = DropDownContextMenuDataContext; + DropDownContextMenu.Closed += new RoutedEventHandler(OnContextMenuClosed); + DropDownContextMenu.IsOpen = true; + } + + base.OnClick(); + } + + void OnContextMenuClosed(object sender, RoutedEventArgs e) + { + //Debug.Assert(IsChecked.GetValueOrDefault()); + var ctxMenu = sender as ContextMenu; + ctxMenu.Closed -= new RoutedEventHandler(OnContextMenuClosed); + IsChecked = false; + } + + void DropDownButton_Unloaded(object sender, RoutedEventArgs e) + { + // When changing theme, Unloaded event is called, erasing the DropDownContextMenu. + // Prevent this on theme changes. + if( this.IsLoaded ) + { + DropDownContextMenu = null; + } + } + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DropDownControlArea.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DropDownControlArea.cs new file mode 100644 index 0000000..37164ab --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DropDownControlArea.cs @@ -0,0 +1,118 @@ +/************************************************************************************* + + 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; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Media; +using System.Windows.Input; +using System.Diagnostics; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class DropDownControlArea : UserControl + { + //static DropDownControlArea() + //{ + // //IsHitTestVisibleProperty.OverrideMetadata(typeof(DropDownControlArea), new FrameworkPropertyMetadata(true)); + //} + + public DropDownControlArea() + { + + } + + #region DropDownContextMenu + + /// + /// DropDownContextMenu Dependency Property + /// + public static readonly DependencyProperty DropDownContextMenuProperty = + DependencyProperty.Register("DropDownContextMenu", typeof(ContextMenu), typeof(DropDownControlArea), + new FrameworkPropertyMetadata((ContextMenu)null)); + + /// + /// Gets or sets the DropDownContextMenu property. This dependency property + /// indicates context menu to show when a right click is detected over the area occpied by the control. + /// + public ContextMenu DropDownContextMenu + { + get { return (ContextMenu)GetValue(DropDownContextMenuProperty); } + set { SetValue(DropDownContextMenuProperty, value); } + } + + #endregion + + #region DropDownContextMenuDataContext + + /// + /// DropDownContextMenuDataContext Dependency Property + /// + public static readonly DependencyProperty DropDownContextMenuDataContextProperty = + DependencyProperty.Register("DropDownContextMenuDataContext", typeof(object), typeof(DropDownControlArea), + new FrameworkPropertyMetadata((object)null)); + + /// + /// Gets or sets the DropDownContextMenuDataContext property. This dependency property + /// indicates data context to attach when context menu is shown. + /// + public object DropDownContextMenuDataContext + { + get { return (object)GetValue(DropDownContextMenuDataContextProperty); } + set { SetValue(DropDownContextMenuDataContextProperty, value); } + } + + #endregion + + protected override void OnMouseRightButtonDown(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnMouseRightButtonDown(e); + + + } + + protected override void OnPreviewMouseRightButtonUp(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnPreviewMouseRightButtonUp(e); + + if (!e.Handled) + { + if (DropDownContextMenu != null) + { + DropDownContextMenu.PlacementTarget = null; + DropDownContextMenu.Placement = PlacementMode.MousePoint; + DropDownContextMenu.DataContext = DropDownContextMenuDataContext; + DropDownContextMenu.IsOpen = true; + // e.Handled = true; + } + } + } + + + //protected override System.Windows.Media.HitTestResult HitTestCore(System.Windows.Media.PointHitTestParameters hitTestParameters) + //{ + // var hitResult = base.HitTestCore(hitTestParameters); + // if (hitResult == null) + // return new PointHitTestResult(this, hitTestParameters.HitPoint); + + // return hitResult; + //} + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DropTarget.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DropTarget.cs new file mode 100644 index 0000000..f86608f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DropTarget.cs @@ -0,0 +1,115 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; +using Xceed.Wpf.AvalonDock.Layout; +using System.Windows.Threading; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal abstract class DropTarget : DropTargetBase, IDropTarget where T : FrameworkElement + { + protected DropTarget(T targetElement, Rect detectionRect, DropTargetType type) + { + _targetElement = targetElement; + _detectionRect = new Rect[] { detectionRect }; + _type = type; + } + + protected DropTarget(T targetElement, IEnumerable detectionRects, DropTargetType type) + { + _targetElement = targetElement; + _detectionRect = detectionRects.ToArray(); + _type = type; + } + + Rect[] _detectionRect; + + public Rect[] DetectionRects + { + get { return _detectionRect; } + } + + + T _targetElement; + public T TargetElement + { + get { return _targetElement; } + } + + DropTargetType _type; + + public DropTargetType Type + { + get { return _type; } + } + + protected virtual void Drop(LayoutAnchorableFloatingWindow floatingWindow) + { } + + protected virtual void Drop(LayoutDocumentFloatingWindow floatingWindow) + { } + + + public void Drop(LayoutFloatingWindow floatingWindow) + { + var root = floatingWindow.Root; + var currentActiveContent = floatingWindow.Root.ActiveContent; + var fwAsAnchorable = floatingWindow as LayoutAnchorableFloatingWindow; + + if (fwAsAnchorable != null) + { + this.Drop(fwAsAnchorable); + } + else + { + var fwAsDocument = floatingWindow as LayoutDocumentFloatingWindow; + this.Drop(fwAsDocument); + } + + Dispatcher.BeginInvoke(new Action(() => + { + currentActiveContent.IsSelected = false; + currentActiveContent.IsActive = false; + currentActiveContent.IsActive = true; + }), DispatcherPriority.Background); + } + + public virtual bool HitTest(Point dragPoint) + { + return _detectionRect.Any(dr => dr.Contains(dragPoint)); + } + + public abstract Geometry GetPreviewPath(OverlayWindow overlayWindow, LayoutFloatingWindow floatingWindow); + + + + public void DragEnter() + { + SetIsDraggingOver(TargetElement, true); + } + + public void DragLeave() + { + SetIsDraggingOver(TargetElement, false); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DropTargetBase.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DropTargetBase.cs new file mode 100644 index 0000000..9fad475 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DropTargetBase.cs @@ -0,0 +1,56 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + abstract class DropTargetBase : DependencyObject + { + #region IsDraggingOver + + /// + /// IsDraggingOver Attached Dependency Property + /// + public static readonly DependencyProperty IsDraggingOverProperty = + DependencyProperty.RegisterAttached("IsDraggingOver", typeof(bool), typeof(DropTargetBase), + new FrameworkPropertyMetadata((bool)false)); + + /// + /// Gets the IsDraggingOver property. This dependency property + /// indicates if user is dragging a window over the target element. + /// + public static bool GetIsDraggingOver(DependencyObject d) + { + return (bool)d.GetValue(IsDraggingOverProperty); + } + + /// + /// Sets the IsDraggingOver property. This dependency property + /// indicates if user is dragging away a window from the target element. + /// + public static void SetIsDraggingOver(DependencyObject d, bool value) + { + d.SetValue(IsDraggingOverProperty, value); + } + + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/DropTargetType.cs b/Src/Xceed.Wpf.AvalonDock/Controls/DropTargetType.cs new file mode 100644 index 0000000..e5738ea --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/DropTargetType.cs @@ -0,0 +1,50 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public enum DropTargetType + { + DockingManagerDockLeft, + DockingManagerDockTop, + DockingManagerDockRight, + DockingManagerDockBottom, + + DocumentPaneDockLeft, + DocumentPaneDockTop, + DocumentPaneDockRight, + DocumentPaneDockBottom, + DocumentPaneDockInside, + + DocumentPaneGroupDockInside, + + AnchorablePaneDockLeft, + AnchorablePaneDockTop, + AnchorablePaneDockRight, + AnchorablePaneDockBottom, + AnchorablePaneDockInside, + + DocumentPaneDockAsAnchorableLeft, + DocumentPaneDockAsAnchorableTop, + DocumentPaneDockAsAnchorableRight, + DocumentPaneDockAsAnchorableBottom, + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Extentions.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Extentions.cs new file mode 100644 index 0000000..676b915 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Extentions.cs @@ -0,0 +1,120 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; +using System.Windows.Media.Media3D; +using System.Runtime.InteropServices; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public static class Extentions + { + public static IEnumerable FindVisualChildren(this DependencyObject depObj) where T : DependencyObject + { + if (depObj != null) + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) + { + DependencyObject child = VisualTreeHelper.GetChild(depObj, i); + if (child != null && child is T) + { + yield return (T)child; + } + + foreach (T childOfChild in FindVisualChildren(child)) + { + yield return childOfChild; + } + } + } + } + + public static IEnumerable FindLogicalChildren(this DependencyObject depObj) where T : DependencyObject + { + if (depObj != null) + { + foreach (DependencyObject child in LogicalTreeHelper.GetChildren(depObj).OfType()) + { + if (child != null && child is T) + { + yield return (T)child; + } + + foreach (T childOfChild in FindLogicalChildren(child)) + { + yield return childOfChild; + } + } + } + } + + public static DependencyObject FindVisualTreeRoot(this DependencyObject initial) + { + DependencyObject current = initial; + DependencyObject result = initial; + + while (current != null) + { + result = current; + if (current is Visual || current is Visual3D) + { + current = VisualTreeHelper.GetParent(current); + } + else + { + // If we're in Logical Land then we must walk + // up the logical tree until we find a + // Visual/Visual3D to get us back to Visual Land. + current = LogicalTreeHelper.GetParent(current); + } + } + + return result; + } + + public static T FindVisualAncestor(this DependencyObject dependencyObject) where T : class + { + DependencyObject target = dependencyObject; + do + { + target = VisualTreeHelper.GetParent(target); + } + while (target != null && !(target is T)); + return target as T; + } + + public static T FindLogicalAncestor(this DependencyObject dependencyObject) where T : class + { + DependencyObject target = dependencyObject; + do + { + var current = target; + target = LogicalTreeHelper.GetParent(target); + if (target == null) + target = VisualTreeHelper.GetParent(current); + + } + while (target != null && !(target is T)); + return target as T; + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/FocusElementManager.cs b/Src/Xceed.Wpf.AvalonDock/Controls/FocusElementManager.cs new file mode 100644 index 0000000..9c924f5 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/FocusElementManager.cs @@ -0,0 +1,268 @@ +/************************************************************************************* + + 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.Input; +using System.Windows.Interop; +using System.Windows; +using System.Diagnostics; +using Xceed.Wpf.AvalonDock.Layout; +using System.Windows.Media; +using System.Windows.Threading; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal static class FocusElementManager + { + #region Focus Management + static List _managers = new List(); + internal static void SetupFocusManagement(DockingManager manager) + { + if (_managers.Count == 0) + { + //InputManager.Current.EnterMenuMode += new EventHandler(InputManager_EnterMenuMode); + //InputManager.Current.LeaveMenuMode += new EventHandler(InputManager_LeaveMenuMode); + _windowHandler = new WindowHookHandler(); + _windowHandler.FocusChanged += new EventHandler(WindowFocusChanging); + //_windowHandler.Activate += new EventHandler(WindowActivating); + _windowHandler.Attach(); + + if (Application.Current != null) + Application.Current.Exit += new ExitEventHandler(Current_Exit); + } + + manager.PreviewGotKeyboardFocus += new KeyboardFocusChangedEventHandler(manager_PreviewGotKeyboardFocus); + _managers.Add(manager); + } + + internal static void FinalizeFocusManagement(DockingManager manager) + { + manager.PreviewGotKeyboardFocus -= new KeyboardFocusChangedEventHandler(manager_PreviewGotKeyboardFocus); + _managers.Remove(manager); + + if (_managers.Count == 0) + { + //InputManager.Current.EnterMenuMode -= new EventHandler(InputManager_EnterMenuMode); + //InputManager.Current.LeaveMenuMode -= new EventHandler(InputManager_LeaveMenuMode); + if (_windowHandler != null) + { + _windowHandler.FocusChanged -= new EventHandler(WindowFocusChanging); + //_windowHandler.Activate -= new EventHandler(WindowActivating); + _windowHandler.Detach(); + _windowHandler = null; + } + } + + } + + private static void Current_Exit(object sender, ExitEventArgs e) + { + Application.Current.Exit -= new ExitEventHandler(Current_Exit); + if (_windowHandler != null) + { + _windowHandler.FocusChanged -= new EventHandler(WindowFocusChanging); + //_windowHandler.Activate -= new EventHandler(WindowActivating); + _windowHandler.Detach(); + _windowHandler = null; + } + } + + static void manager_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) + { + var focusedElement = e.NewFocus as Visual; + if (focusedElement != null && + !(focusedElement is LayoutAnchorableTabItem || focusedElement is LayoutDocumentTabItem)) + //Avoid tracking focus for elements like this + { + var parentAnchorable = focusedElement.FindVisualAncestor(); + if (parentAnchorable != null) + { + _modelFocusedElement[parentAnchorable.Model] = e.NewFocus; + } + else + { + var parentDocument = focusedElement.FindVisualAncestor(); + if (parentDocument != null) + { + _modelFocusedElement[parentDocument.Model] = e.NewFocus; + } + } + } + } + + static FullWeakDictionary _modelFocusedElement = new FullWeakDictionary(); + static WeakDictionary _modelFocusedWindowHandle = new WeakDictionary(); + + /// + /// Get the input element that was focused before user left the layout element + /// + /// Element to look for + /// Input element + internal static IInputElement GetLastFocusedElement(ILayoutElement model) + { + IInputElement objectWithFocus; + if (_modelFocusedElement.GetValue(model, out objectWithFocus)) + return objectWithFocus; + + return null; + } + + + /// + /// Get the last window handle focused before user left the element passed as argument + /// + /// + /// + internal static IntPtr GetLastWindowHandle(ILayoutElement model) + { + IntPtr handleWithFocus; + if (_modelFocusedWindowHandle.GetValue(model, out handleWithFocus)) + return handleWithFocus; + + return IntPtr.Zero; + } + static WeakReference _lastFocusedElement; + + /// + /// Given a layout element tries to set the focus of the keyword where it was before user moved to another element + /// + /// + internal static void SetFocusOnLastElement(ILayoutElement model) + { + bool focused = false; + IInputElement objectToFocus; + if (_modelFocusedElement.GetValue(model, out objectToFocus)) + { + focused = objectToFocus == Keyboard.Focus(objectToFocus); + } + + IntPtr handleToFocus; + if (_modelFocusedWindowHandle.GetValue(model, out handleToFocus)) + focused = IntPtr.Zero != Win32Helper.SetFocus(handleToFocus); + + + if (focused) + { + _lastFocusedElement = new WeakReference(model); + } + + } + + static WindowHookHandler _windowHandler = null; + + static void WindowFocusChanging(object sender, FocusChangeEventArgs e) + { + foreach (var manager in _managers) + { + var hostContainingFocusedHandle = manager.FindLogicalChildren().FirstOrDefault(hw => Win32Helper.IsChild(hw.Handle, e.GotFocusWinHandle)); + + if (hostContainingFocusedHandle != null) + { + var parentAnchorable = hostContainingFocusedHandle.FindVisualAncestor(); + if (parentAnchorable != null) + { + _modelFocusedWindowHandle[parentAnchorable.Model] = e.GotFocusWinHandle; + if (parentAnchorable.Model != null) + parentAnchorable.Model.IsActive = true; + } + else + { + var parentDocument = hostContainingFocusedHandle.FindVisualAncestor(); + if (parentDocument != null) + { + _modelFocusedWindowHandle[parentDocument.Model] = e.GotFocusWinHandle; + if (parentDocument.Model != null) + parentDocument.Model.IsActive = true; + } + } + } + } + } + + static DispatcherOperation _setFocusAsyncOperation; + + static void WindowActivating(object sender, WindowActivateEventArgs e) + { + if (Keyboard.FocusedElement == null && + _lastFocusedElement != null && + _lastFocusedElement.IsAlive) + { + var elementToSetFocus = _lastFocusedElement.Target as ILayoutElement; + if (elementToSetFocus != null) + { + var manager = elementToSetFocus.Root.Manager; + if (manager == null) + return; + + IntPtr parentHwnd; + if (!manager.GetParentWindowHandle(out parentHwnd)) + return; + + if (e.HwndActivating != parentHwnd) + return; + + _setFocusAsyncOperation = Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => + { + try + { + SetFocusOnLastElement(elementToSetFocus); + } + finally + { + _setFocusAsyncOperation = null; + } + }), DispatcherPriority.Input); + } + } + } + + + static WeakReference _lastFocusedElementBeforeEnterMenuMode = null; + static void InputManager_EnterMenuMode(object sender, EventArgs e) + { + if (Keyboard.FocusedElement == null) + return; + + var lastfocusDepObj = Keyboard.FocusedElement as DependencyObject; + if (lastfocusDepObj.FindLogicalAncestor() == null) + { + _lastFocusedElementBeforeEnterMenuMode = null; + return; + } + + _lastFocusedElementBeforeEnterMenuMode = new WeakReference(Keyboard.FocusedElement); + } + static void InputManager_LeaveMenuMode(object sender, EventArgs e) + { + if (_lastFocusedElementBeforeEnterMenuMode != null && + _lastFocusedElementBeforeEnterMenuMode.IsAlive) + { + var lastFocusedInputElement = _lastFocusedElementBeforeEnterMenuMode.GetValueOrDefault(); + if (lastFocusedInputElement != null) + { + if (lastFocusedInputElement != Keyboard.Focus(lastFocusedInputElement)) + Debug.WriteLine("Unable to activate the element"); + } + } + } + + #endregion + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/FullWeakDictionary.cs b/Src/Xceed.Wpf.AvalonDock/Controls/FullWeakDictionary.cs new file mode 100644 index 0000000..e6e4834 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/FullWeakDictionary.cs @@ -0,0 +1,106 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + class FullWeakDictionary where K : class + { + public FullWeakDictionary() + {} + + List _keys = new List(); + List _values = new List(); + + public V this[K key] + { + get + { + V valueToReturn; + if (!GetValue(key, out valueToReturn)) + throw new ArgumentException(); + return valueToReturn; + } + set + { + SetValue(key, value); + } + } + + public bool ContainsKey(K key) + { + CollectGarbage(); + return -1 != _keys.FindIndex(k => k.GetValueOrDefault() == key); + } + + public void SetValue(K key, V value) + { + CollectGarbage(); + int vIndex = _keys.FindIndex(k => k.GetValueOrDefault() == key); + if (vIndex > -1) + _values[vIndex] = new WeakReference(value); + else + { + _values.Add(new WeakReference(value)); + _keys.Add(new WeakReference(key)); + } + } + + public bool GetValue(K key, out V value) + { + CollectGarbage(); + int vIndex = _keys.FindIndex(k => k.GetValueOrDefault() == key); + value = default(V); + if (vIndex == -1) + return false; + value = _values[vIndex].GetValueOrDefault(); + return true; + } + + + void CollectGarbage() + { + int vIndex = 0; + + do + { + vIndex = _keys.FindIndex(vIndex, k => !k.IsAlive); + if (vIndex >= 0) + { + _keys.RemoveAt(vIndex); + _values.RemoveAt(vIndex); + } + } + while (vIndex >= 0); + + vIndex = 0; + do + { + vIndex = _values.FindIndex(vIndex, v => !v.IsAlive); + if (vIndex >= 0) + { + _values.RemoveAt(vIndex); + _keys.RemoveAt(vIndex); + } + } + while (vIndex >= 0); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/IDropTarget.cs b/Src/Xceed.Wpf.AvalonDock/Controls/IDropTarget.cs new file mode 100644 index 0000000..cd8722f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/IDropTarget.cs @@ -0,0 +1,41 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal interface IDropTarget + { + Geometry GetPreviewPath(OverlayWindow overlayWindow, LayoutFloatingWindow floatingWindow); + + bool HitTest(Point dragPoint); + + DropTargetType Type { get; } + + void Drop(LayoutFloatingWindow floatingWindow); + + void DragEnter(); + + void DragLeave(); + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindow.cs b/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindow.cs new file mode 100644 index 0000000..d2ae307 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindow.cs @@ -0,0 +1,38 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal interface IOverlayWindow + { + IEnumerable GetTargets(); + + void DragEnter(LayoutFloatingWindowControl floatingWindow); + void DragLeave(LayoutFloatingWindowControl floatingWindow); + + void DragEnter(IDropArea area); + void DragLeave(IDropArea area); + + void DragEnter(IDropTarget target); + void DragLeave(IDropTarget target); + void DragDrop(IDropTarget target); + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindowArea.cs b/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindowArea.cs new file mode 100644 index 0000000..08b17c7 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindowArea.cs @@ -0,0 +1,29 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal interface IOverlayWindowArea + { + Rect ScreenDetectionArea { get; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindowDropTarget.cs b/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindowDropTarget.cs new file mode 100644 index 0000000..d6b398e --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindowDropTarget.cs @@ -0,0 +1,31 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + interface IOverlayWindowDropTarget + { + Rect ScreenDetectionArea { get; } + + OverlayWindowDropTargetType Type { get; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindowHost.cs b/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindowHost.cs new file mode 100644 index 0000000..9d60c14 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/IOverlayWindowHost.cs @@ -0,0 +1,37 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal interface IOverlayWindowHost + { + bool HitTest(Point dragPoint); + + IOverlayWindow ShowOverlayWindow(LayoutFloatingWindowControl draggingWindow); + + void HideOverlayWindow(); + + IEnumerable GetDropAreas(LayoutFloatingWindowControl draggingWindow); + + DockingManager Manager { get; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorControl.cs new file mode 100644 index 0000000..394717f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorControl.cs @@ -0,0 +1,184 @@ +/************************************************************************************* + + 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; +using System.Windows.Controls; +using Xceed.Wpf.AvalonDock.Layout; +using System.Windows.Threading; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutAnchorControl : Control, ILayoutControl + { + static LayoutAnchorControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAnchorControl), new FrameworkPropertyMetadata(typeof(LayoutAnchorControl))); + Control.IsHitTestVisibleProperty.AddOwner(typeof(LayoutAnchorControl), new FrameworkPropertyMetadata(true)); + } + + + internal LayoutAnchorControl(LayoutAnchorable model) + { + _model = model; + _model.IsActiveChanged += new EventHandler(_model_IsActiveChanged); + _model.IsSelectedChanged += new EventHandler(_model_IsSelectedChanged); + + SetSide(_model.FindParent().Side); + } + + void _model_IsSelectedChanged(object sender, EventArgs e) + { + if (!_model.IsAutoHidden) + _model.IsSelectedChanged -= new EventHandler(_model_IsSelectedChanged); + else if (_model.IsSelected) + { + _model.Root.Manager.ShowAutoHideWindow(this); + _model.IsSelected = false; + } + } + + void _model_IsActiveChanged(object sender, EventArgs e) + { + if (!_model.IsAutoHidden) + _model.IsActiveChanged -= new EventHandler(_model_IsActiveChanged); + else if (_model.IsActive) + _model.Root.Manager.ShowAutoHideWindow(this); + } + + LayoutAnchorable _model; + + public ILayoutElement Model + { + get { return _model; } + } + + //protected override void OnVisualParentChanged(DependencyObject oldParent) + //{ + // base.OnVisualParentChanged(oldParent); + + // var contentModel = _model; + + // if (oldParent != null && contentModel != null && contentModel.Content is UIElement) + // { + // var oldParentPaneControl = oldParent.FindVisualAncestor(); + // if (oldParentPaneControl != null) + // { + // ((ILogicalChildrenContainer)oldParentPaneControl).InternalRemoveLogicalChild(contentModel.Content); + // } + // } + + // if (contentModel.Content != null && contentModel.Content is UIElement) + // { + // var oldLogicalParentPaneControl = LogicalTreeHelper.GetParent(contentModel.Content as UIElement) + // as ILogicalChildrenContainer; + // if (oldLogicalParentPaneControl != null) + // oldLogicalParentPaneControl.InternalRemoveLogicalChild(contentModel.Content); + // } + + // if (contentModel != null && contentModel.Content != null && contentModel.Root != null && contentModel.Content is UIElement) + // { + // ((ILogicalChildrenContainer)contentModel.Root.Manager).InternalAddLogicalChild(contentModel.Content); + // } + //} + + + protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnMouseDown(e); + + if (!e.Handled) + { + _model.Root.Manager.ShowAutoHideWindow(this); + _model.IsActive = true; + } + } + + + DispatcherTimer _openUpTimer = null; + + protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e) + { + base.OnMouseEnter(e); + + if (!e.Handled) + { + _openUpTimer = new DispatcherTimer(DispatcherPriority.ApplicationIdle); + _openUpTimer.Interval = TimeSpan.FromMilliseconds(400); + _openUpTimer.Tick += new EventHandler(_openUpTimer_Tick); + _openUpTimer.Start(); + } + } + + void _openUpTimer_Tick(object sender, EventArgs e) + { + _openUpTimer.Tick -= new EventHandler(_openUpTimer_Tick); + _openUpTimer.Stop(); + _openUpTimer = null; + _model.Root.Manager.ShowAutoHideWindow(this); + } + + protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e) + { + if (_openUpTimer != null) + { + _openUpTimer.Tick -= new EventHandler(_openUpTimer_Tick); + _openUpTimer.Stop(); + _openUpTimer = null; + } + base.OnMouseLeave(e); + } + + + #region Side + + /// + /// Side Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey SidePropertyKey + = DependencyProperty.RegisterReadOnly("Side", typeof(AnchorSide), typeof(LayoutAnchorControl), + new FrameworkPropertyMetadata((AnchorSide)AnchorSide.Left)); + + public static readonly DependencyProperty SideProperty + = SidePropertyKey.DependencyProperty; + + /// + /// Gets the Side property. This dependency property + /// indicates the anchor side of the control. + /// + public AnchorSide Side + { + get { return (AnchorSide)GetValue(SideProperty); } + } + + /// + /// Provides a secure method for setting the Side property. + /// This dependency property indicates the anchor side of the control. + /// + /// The new value for the property. + protected void SetSide(AnchorSide value) + { + SetValue(SidePropertyKey, value); + } + + #endregion + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorGroupControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorGroupControl.cs new file mode 100644 index 0000000..e93af0f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorGroupControl.cs @@ -0,0 +1,99 @@ +/************************************************************************************* + + 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.Controls; +using System.Collections.ObjectModel; +using Xceed.Wpf.AvalonDock.Layout; +using System.Windows; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutAnchorGroupControl : Control, ILayoutControl + { + static LayoutAnchorGroupControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAnchorGroupControl), new FrameworkPropertyMetadata(typeof(LayoutAnchorGroupControl))); + } + + + internal LayoutAnchorGroupControl(LayoutAnchorGroup model) + { + _model = model; + CreateChildrenViews(); + + _model.Children.CollectionChanged += (s, e) => OnModelChildrenCollectionChanged(e); + } + + private void CreateChildrenViews() + { + var manager = _model.Root.Manager; + foreach (var childModel in _model.Children) + { + _childViews.Add(new LayoutAnchorControl(childModel) { Template = manager.AnchorTemplate }); + } + } + + private void OnModelChildrenCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.OldItems != null) + { + { + foreach (var childModel in e.OldItems) + _childViews.Remove(_childViews.First(cv => cv.Model == childModel)); + } + } + } + + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset) + _childViews.Clear(); + + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.NewItems != null) + { + var manager = _model.Root.Manager; + int insertIndex = e.NewStartingIndex; + foreach (LayoutAnchorable childModel in e.NewItems) + { + _childViews.Insert(insertIndex++, new LayoutAnchorControl(childModel) { Template = manager.AnchorTemplate }); + } + } + } + } + + ObservableCollection _childViews = new ObservableCollection(); + + public ObservableCollection Children + { + get { return _childViews; } + } + + + LayoutAnchorGroup _model; + public ILayoutElement Model + { + get { return _model; } + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorSideControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorSideControl.cs new file mode 100644 index 0000000..6357d08 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorSideControl.cs @@ -0,0 +1,252 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using System.Collections.ObjectModel; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutAnchorSideControl : Control, ILayoutControl + { + static LayoutAnchorSideControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAnchorSideControl), new FrameworkPropertyMetadata(typeof(LayoutAnchorSideControl))); + } + + + internal LayoutAnchorSideControl(LayoutAnchorSide model) + { + if (model == null) + throw new ArgumentNullException("model"); + + + _model = model; + + CreateChildrenViews(); + + _model.Children.CollectionChanged += (s, e) => OnModelChildrenCollectionChanged(e); + + UpdateSide(); + } + + private void CreateChildrenViews() + { + var manager = _model.Root.Manager; + foreach (var childModel in _model.Children) + { + _childViews.Add(manager.CreateUIElementForModel(childModel) as LayoutAnchorGroupControl); + } + } + + private void OnModelChildrenCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.OldItems != null && + (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) + { + foreach (var childModel in e.OldItems) + _childViews.Remove(_childViews.First(cv => cv.Model == childModel)); + } + + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset) + _childViews.Clear(); + + if (e.NewItems != null && + (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) + { + var manager = _model.Root.Manager; + int insertIndex = e.NewStartingIndex; + foreach (LayoutAnchorGroup childModel in e.NewItems) + { + _childViews.Insert(insertIndex++, manager.CreateUIElementForModel(childModel) as LayoutAnchorGroupControl); + } + } + } + + LayoutAnchorSide _model = null; + public ILayoutElement Model + { + get { return _model; } + } + + ObservableCollection _childViews = new ObservableCollection(); + + public ObservableCollection Children + { + get { return _childViews; } + } + + void UpdateSide() + { + switch (_model.Side) + { + case AnchorSide.Left: + SetIsLeftSide(true); + break; + case AnchorSide.Top: + SetIsTopSide(true); + break; + case AnchorSide.Right: + SetIsRightSide(true); + break; + case AnchorSide.Bottom: + SetIsBottomSide(true); + break; + } + } + + #region IsLeftSide + + /// + /// IsLeftSide Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsLeftSidePropertyKey + = DependencyProperty.RegisterReadOnly("IsLeftSide", typeof(bool), typeof(LayoutAnchorSideControl), + new FrameworkPropertyMetadata((bool)false)); + + public static readonly DependencyProperty IsLeftSideProperty + = IsLeftSidePropertyKey.DependencyProperty; + + /// + /// Gets the IsLeftSide property. This dependency property + /// indicates this control is anchored to left side. + /// + public bool IsLeftSide + { + get { return (bool)GetValue(IsLeftSideProperty); } + } + + /// + /// Provides a secure method for setting the IsLeftSide property. + /// This dependency property indicates this control is anchored to left side. + /// + /// The new value for the property. + protected void SetIsLeftSide(bool value) + { + SetValue(IsLeftSidePropertyKey, value); + } + + #endregion + + #region IsTopSide + + /// + /// IsTopSide Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsTopSidePropertyKey + = DependencyProperty.RegisterReadOnly("IsTopSide", typeof(bool), typeof(LayoutAnchorSideControl), + new FrameworkPropertyMetadata((bool)false)); + + public static readonly DependencyProperty IsTopSideProperty + = IsTopSidePropertyKey.DependencyProperty; + + /// + /// Gets the IsTopSide property. This dependency property + /// indicates this control is anchored to top side. + /// + public bool IsTopSide + { + get { return (bool)GetValue(IsTopSideProperty); } + } + + /// + /// Provides a secure method for setting the IsTopSide property. + /// This dependency property indicates this control is anchored to top side. + /// + /// The new value for the property. + protected void SetIsTopSide(bool value) + { + SetValue(IsTopSidePropertyKey, value); + } + + #endregion + + #region IsRightSide + + /// + /// IsRightSide Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsRightSidePropertyKey + = DependencyProperty.RegisterReadOnly("IsRightSide", typeof(bool), typeof(LayoutAnchorSideControl), + new FrameworkPropertyMetadata((bool)false)); + + public static readonly DependencyProperty IsRightSideProperty + = IsRightSidePropertyKey.DependencyProperty; + + /// + /// Gets the IsRightSide property. This dependency property + /// indicates this control is anchored to right side. + /// + public bool IsRightSide + { + get { return (bool)GetValue(IsRightSideProperty); } + } + + /// + /// Provides a secure method for setting the IsRightSide property. + /// This dependency property indicates this control is anchored to right side. + /// + /// The new value for the property. + protected void SetIsRightSide(bool value) + { + SetValue(IsRightSidePropertyKey, value); + } + + #endregion + + #region IsBottomSide + + /// + /// IsBottomSide Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsBottomSidePropertyKey + = DependencyProperty.RegisterReadOnly("IsBottomSide", typeof(bool), typeof(LayoutAnchorSideControl), + new FrameworkPropertyMetadata((bool)false)); + + public static readonly DependencyProperty IsBottomSideProperty + = IsBottomSidePropertyKey.DependencyProperty; + + /// + /// Gets the IsBottomSide property. This dependency property + /// indicates if this panel is anchored to bottom side. + /// + public bool IsBottomSide + { + get { return (bool)GetValue(IsBottomSideProperty); } + } + + /// + /// Provides a secure method for setting the IsBottomSide property. + /// This dependency property indicates if this panel is anchored to bottom side. + /// + /// The new value for the property. + protected void SetIsBottomSide(bool value) + { + SetValue(IsBottomSidePropertyKey, value); + } + + #endregion + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableControl.cs new file mode 100644 index 0000000..17735aa --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableControl.cs @@ -0,0 +1,160 @@ +/************************************************************************************* + + 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; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutAnchorableControl : Control + { + static LayoutAnchorableControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAnchorableControl), new FrameworkPropertyMetadata(typeof(LayoutAnchorableControl))); + FocusableProperty.OverrideMetadata(typeof(LayoutAnchorableControl), new FrameworkPropertyMetadata(false)); + } + + public LayoutAnchorableControl() + { + //SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this }); + } + + + #region Model + + /// + /// Model Dependency Property + /// + public static readonly DependencyProperty ModelProperty = + DependencyProperty.Register("Model", typeof(LayoutAnchorable), typeof(LayoutAnchorableControl), + new FrameworkPropertyMetadata((LayoutAnchorable)null, + new PropertyChangedCallback(OnModelChanged))); + + /// + /// Gets or sets the Model property. This dependency property + /// indicates the model attached to this view. + /// + public LayoutAnchorable Model + { + get { return (LayoutAnchorable)GetValue(ModelProperty); } + set { SetValue(ModelProperty, value); } + } + + /// + /// Handles changes to the Model property. + /// + private static void OnModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutAnchorableControl)d).OnModelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Model property. + /// + protected virtual void OnModelChanged(DependencyPropertyChangedEventArgs e) + { + if( e.OldValue != null ) + { + ((LayoutContent)e.OldValue).PropertyChanged -= Model_PropertyChanged; + } + + if( Model != null ) + { + Model.PropertyChanged += Model_PropertyChanged; + SetLayoutItem( Model.Root.Manager.GetLayoutItemFromModel( Model ) ); + } + else + SetLayoutItem( null ); + } + + private void Model_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e ) + { + if( e.PropertyName == "IsEnabled" ) + { + if( Model != null ) + { + IsEnabled = Model.IsEnabled; + if( !IsEnabled && Model.IsActive ) + { + if( (Model.Parent != null) && (Model.Parent is LayoutAnchorablePane) ) + { + ((LayoutAnchorablePane)Model.Parent).SetNextSelectedIndex(); + } + } + } + } + } + + #endregion + + #region LayoutItem + + /// + /// LayoutItem Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey LayoutItemPropertyKey + = DependencyProperty.RegisterReadOnly("LayoutItem", typeof(LayoutItem), typeof(LayoutAnchorableControl), + new FrameworkPropertyMetadata((LayoutItem)null)); + + public static readonly DependencyProperty LayoutItemProperty + = LayoutItemPropertyKey.DependencyProperty; + + /// + /// Gets the LayoutItem property. This dependency property + /// indicates the LayoutItem attached to this tag item. + /// + public LayoutItem LayoutItem + { + get { return (LayoutItem)GetValue(LayoutItemProperty); } + } + + /// + /// Provides a secure method for setting the LayoutItem property. + /// This dependency property indicates the LayoutItem attached to this tag item. + /// + /// The new value for the property. + protected void SetLayoutItem(LayoutItem value) + { + SetValue(LayoutItemPropertyKey, value); + } + + #endregion + + + protected override void OnGotKeyboardFocus(System.Windows.Input.KeyboardFocusChangedEventArgs e) + { + if (Model != null) + Model.IsActive = true; + + base.OnGotKeyboardFocus(e); + } + + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs new file mode 100644 index 0000000..a1fafcc --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs @@ -0,0 +1,366 @@ +/************************************************************************************* + + 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; +using System.Runtime.InteropServices; +using System.Windows.Interop; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Media; +using System.Windows.Input; +using Xceed.Wpf.AvalonDock.Layout; +using Xceed.Wpf.AvalonDock.Converters; +using System.Diagnostics; +using System.Windows.Controls.Primitives; +using Xceed.Wpf.AvalonDock.Commands; +using Microsoft.Windows.Shell; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutAnchorableFloatingWindowControl : LayoutFloatingWindowControl, IOverlayWindowHost + { + static LayoutAnchorableFloatingWindowControl() + { + DefaultStyleKeyProperty.OverrideMetadata( typeof( LayoutAnchorableFloatingWindowControl ), new FrameworkPropertyMetadata( typeof( LayoutAnchorableFloatingWindowControl ) ) ); + } + + + internal LayoutAnchorableFloatingWindowControl( LayoutAnchorableFloatingWindow model ) + : base( model ) + { + _model = model; + HideWindowCommand = new RelayCommand( ( p ) => OnExecuteHideWindowCommand( p ), ( p ) => CanExecuteHideWindowCommand( p ) ); + UpdateThemeResources(); + } + + internal override void UpdateThemeResources( Xceed.Wpf.AvalonDock.Themes.Theme oldTheme = null ) + { + base.UpdateThemeResources( oldTheme ); + + if( _overlayWindow != null ) + _overlayWindow.UpdateThemeResources( oldTheme ); + } + + LayoutAnchorableFloatingWindow _model; + + public override ILayoutElement Model + { + get + { + return _model; + } + } + + #region SingleContentLayoutItem + + /// + /// SingleContentLayoutItem Dependency Property + /// + public static readonly DependencyProperty SingleContentLayoutItemProperty = + DependencyProperty.Register( "SingleContentLayoutItem", typeof( LayoutItem ), typeof( LayoutAnchorableFloatingWindowControl ), + new FrameworkPropertyMetadata( ( LayoutItem )null, + new PropertyChangedCallback( OnSingleContentLayoutItemChanged ) ) ); + + /// + /// Gets or sets the SingleContentLayoutItem property. This dependency property + /// indicates the layout item of the selected content when is shown a single anchorable pane. + /// + public LayoutItem SingleContentLayoutItem + { + get + { + return ( LayoutItem )GetValue( SingleContentLayoutItemProperty ); + } + set + { + SetValue( SingleContentLayoutItemProperty, value ); + } + } + + /// + /// Handles changes to the SingleContentLayoutItem property. + /// + private static void OnSingleContentLayoutItemChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutAnchorableFloatingWindowControl )d ).OnSingleContentLayoutItemChanged( e ); + } + + /// + /// Provides derived classes an opportunity to handle changes to the SingleContentLayoutItem property. + /// + protected virtual void OnSingleContentLayoutItemChanged( DependencyPropertyChangedEventArgs e ) + { + } + + #endregion + + + + protected override void OnInitialized( EventArgs e ) + { + base.OnInitialized( e ); + + var manager = _model.Root.Manager; + + Content = manager.CreateUIElementForModel( _model.RootPanel ); + + //SetBinding(VisibilityProperty, new Binding("IsVisible") { Source = _model, Converter = new BoolToVisibilityConverter(), Mode = BindingMode.OneWay, ConverterParameter = Visibility.Hidden }); + + //Issue: http://avalondock.codeplex.com/workitem/15036 + IsVisibleChanged += ( s, args ) => + { + var visibilityBinding = GetBindingExpression( VisibilityProperty ); + if( IsVisible && ( visibilityBinding == null ) ) + { + SetBinding( VisibilityProperty, new Binding( "IsVisible" ) { Source = _model, Converter = new BoolToVisibilityConverter(), Mode = BindingMode.OneWay, ConverterParameter = Visibility.Hidden } ); + } + }; + + SetBinding( SingleContentLayoutItemProperty, new Binding( "Model.SinglePane.SelectedContent" ) { Source = this, Converter = new LayoutItemFromLayoutModelConverter() } ); + + _model.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler( _model_PropertyChanged ); + } + + + void _model_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e ) + { + if( e.PropertyName == "RootPanel" && + _model.RootPanel == null ) + { + InternalClose(); + } + } + + + bool IOverlayWindowHost.HitTest( Point dragPoint ) + { + Rect detectionRect = new Rect( this.PointToScreenDPIWithoutFlowDirection( new Point() ), this.TransformActualSizeToAncestor() ); + return detectionRect.Contains( dragPoint ); + } + + DockingManager IOverlayWindowHost.Manager + { + get + { + return _model.Root.Manager; + } + } + + OverlayWindow _overlayWindow = null; + void CreateOverlayWindow() + { + if( _overlayWindow == null ) + _overlayWindow = new OverlayWindow( this ); + Rect rectWindow = new Rect( this.PointToScreenDPIWithoutFlowDirection( new Point() ), this.TransformActualSizeToAncestor() ); + _overlayWindow.Left = rectWindow.Left; + _overlayWindow.Top = rectWindow.Top; + _overlayWindow.Width = rectWindow.Width; + _overlayWindow.Height = rectWindow.Height; + } + + IOverlayWindow IOverlayWindowHost.ShowOverlayWindow( LayoutFloatingWindowControl draggingWindow ) + { + CreateOverlayWindow(); + _overlayWindow.Owner = draggingWindow; + _overlayWindow.EnableDropTargets(); + _overlayWindow.Show(); + + return _overlayWindow; + } + + void IOverlayWindowHost.HideOverlayWindow() + { + _dropAreas = null; + _overlayWindow.Owner = null; + _overlayWindow.HideDropTargets(); + } + + List _dropAreas = null; + IEnumerable IOverlayWindowHost.GetDropAreas( LayoutFloatingWindowControl draggingWindow ) + { + if( _dropAreas != null ) + return _dropAreas; + + _dropAreas = new List(); + + if( draggingWindow.Model is LayoutDocumentFloatingWindow ) + return _dropAreas; + + var rootVisual = ( Content as FloatingWindowContentHost ).RootVisual; + + foreach( var areaHost in rootVisual.FindVisualChildren() ) + { + _dropAreas.Add( new DropArea( + areaHost, + DropAreaType.AnchorablePane ) ); + } + foreach( var areaHost in rootVisual.FindVisualChildren() ) + { + _dropAreas.Add( new DropArea( + areaHost, + DropAreaType.DocumentPane ) ); + } + + return _dropAreas; + } + + protected override void OnClosed( EventArgs e ) + { + var root = Model.Root; + root.Manager.RemoveFloatingWindow( this ); + root.CollectGarbage(); + if( _overlayWindow != null ) + { + _overlayWindow.Close(); + _overlayWindow = null; + } + + base.OnClosed( e ); + + if( !CloseInitiatedByUser ) + { + root.FloatingWindows.Remove( _model ); + } + + _model.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler( _model_PropertyChanged ); + } + + protected override void OnClosing( System.ComponentModel.CancelEventArgs e ) + { + if( CloseInitiatedByUser && !KeepContentVisibleOnClose ) + { + e.Cancel = true; + _model.Descendents().OfType().ToArray().ForEach( ( a ) => a.Hide() ); + } + + base.OnClosing( e ); + } + + protected override IntPtr FilterMessage( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled ) + { + switch( msg ) + { + case Win32Helper.WM_NCLBUTTONDOWN: //Left button down on title -> start dragging over docking manager + if( wParam.ToInt32() == Win32Helper.HT_CAPTION ) + { + _model.Descendents().OfType().First( p => p.ChildrenCount > 0 && p.SelectedContent != null ).SelectedContent.IsActive = true; + handled = true; + } + break; + case Win32Helper.WM_NCRBUTTONUP: + if( wParam.ToInt32() == Win32Helper.HT_CAPTION ) + { + if( OpenContextMenu() ) + handled = true; + + if( _model.Root.Manager.ShowSystemMenu ) + WindowChrome.GetWindowChrome( this ).ShowSystemMenu = !handled; + else + WindowChrome.GetWindowChrome( this ).ShowSystemMenu = false; + } + break; + + } + + return base.FilterMessage( hwnd, msg, wParam, lParam, ref handled ); + } + + bool OpenContextMenu() + { + var ctxMenu = _model.Root.Manager.AnchorableContextMenu; + if( ctxMenu != null && SingleContentLayoutItem != null ) + { + ctxMenu.PlacementTarget = null; + ctxMenu.Placement = PlacementMode.MousePoint; + ctxMenu.DataContext = SingleContentLayoutItem; + ctxMenu.IsOpen = true; + return true; + } + + return false; + } + + bool IsContextMenuOpen() + { + var ctxMenu = _model.Root.Manager.AnchorableContextMenu; + if( ctxMenu != null && SingleContentLayoutItem != null ) + { + return ctxMenu.IsOpen; + } + + return false; + } + + #region HideWindowCommand + public ICommand HideWindowCommand + { + get; + private set; + } + + private bool CanExecuteHideWindowCommand( object parameter ) + { + if( Model == null ) + return false; + + var root = Model.Root; + if( root == null ) + return false; + + var manager = root.Manager; + if( manager == null ) + return false; + + bool canExecute = false; + foreach( var anchorable in this.Model.Descendents().OfType().ToArray() ) + { + if( !anchorable.CanHide ) + { + canExecute = false; + break; + } + + var anchorableLayoutItem = manager.GetLayoutItemFromModel( anchorable ) as LayoutAnchorableItem; + if( anchorableLayoutItem == null || + anchorableLayoutItem.HideCommand == null || + !anchorableLayoutItem.HideCommand.CanExecute( parameter ) ) + { + canExecute = false; + break; + } + + canExecute = true; + } + + return canExecute; + } + + private void OnExecuteHideWindowCommand( object parameter ) + { + var manager = Model.Root.Manager; + foreach( var anchorable in this.Model.Descendents().OfType().ToArray() ) + { + var anchorableLayoutItem = manager.GetLayoutItemFromModel( anchorable ) as LayoutAnchorableItem; + anchorableLayoutItem.HideCommand.Execute( parameter ); + } + } + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableItem.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableItem.cs new file mode 100644 index 0000000..d04454b --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableItem.cs @@ -0,0 +1,366 @@ +/************************************************************************************* + + 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 Xceed.Wpf.AvalonDock.Layout; +using System.Windows.Input; +using System.Windows; +using Xceed.Wpf.AvalonDock.Commands; +using System.Windows.Data; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutAnchorableItem : LayoutItem + { + LayoutAnchorable _anchorable; + internal LayoutAnchorableItem() + { + + } + + internal override void Attach(LayoutContent model) + { + _anchorable = model as LayoutAnchorable; + _anchorable.IsVisibleChanged += new EventHandler(_anchorable_IsVisibleChanged); + + base.Attach(model); + } + + internal override void Detach() + { + _anchorable.IsVisibleChanged -= new EventHandler(_anchorable_IsVisibleChanged); + _anchorable = null; + base.Detach(); + } + + protected override void Close() + { + if( (_anchorable.Root != null) && (_anchorable.Root.Manager != null) ) + { + var dockingManager = _anchorable.Root.Manager; + dockingManager._ExecuteCloseCommand( _anchorable ); + } + } + + ICommand _defaultHideCommand; + ICommand _defaultAutoHideCommand; + ICommand _defaultDockCommand; + + protected override void InitDefaultCommands() + { + _defaultHideCommand = new RelayCommand((p) => ExecuteHideCommand(p), (p) => CanExecuteHideCommand(p)); + _defaultAutoHideCommand = new RelayCommand((p) => ExecuteAutoHideCommand(p), (p) => CanExecuteAutoHideCommand(p)); + _defaultDockCommand = new RelayCommand((p) => ExecuteDockCommand(p), (p) => CanExecuteDockCommand(p)); + + base.InitDefaultCommands(); + } + + protected override void ClearDefaultBindings() + { + if (HideCommand == _defaultHideCommand) + BindingOperations.ClearBinding(this, HideCommandProperty); + if (AutoHideCommand == _defaultAutoHideCommand) + BindingOperations.ClearBinding(this, AutoHideCommandProperty); + if (DockCommand == _defaultDockCommand) + BindingOperations.ClearBinding(this, DockCommandProperty); + + base.ClearDefaultBindings(); + } + + protected override void SetDefaultBindings() + { + if (HideCommand == null) + HideCommand = _defaultHideCommand; + if (AutoHideCommand == null) + AutoHideCommand = _defaultAutoHideCommand; + if (DockCommand == null) + DockCommand = _defaultDockCommand; + + Visibility = _anchorable.IsVisible ? Visibility.Visible : System.Windows.Visibility.Hidden; + base.SetDefaultBindings(); + } + + + #region HideCommand + + /// + /// HideCommand Dependency Property + /// + public static readonly DependencyProperty HideCommandProperty = + DependencyProperty.Register("HideCommand", typeof(ICommand), typeof(LayoutAnchorableItem), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnHideCommandChanged), + new CoerceValueCallback(CoerceHideCommandValue))); + + /// + /// Gets or sets the HideCommand property. This dependency property + /// indicates the command to execute when an anchorable is hidden. + /// + public ICommand HideCommand + { + get { return (ICommand)GetValue(HideCommandProperty); } + set { SetValue(HideCommandProperty, value); } + } + + /// + /// Handles changes to the HideCommand property. + /// + private static void OnHideCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutAnchorableItem)d).OnHideCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the HideCommand property. + /// + protected virtual void OnHideCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the HideCommand value. + /// + private static object CoerceHideCommandValue(DependencyObject d, object value) + { + return value; + } + + + private bool CanExecuteHideCommand(object parameter) + { + if (LayoutElement == null) + return false; + return _anchorable.CanHide; + } + + private void ExecuteHideCommand(object parameter) + { + if (_anchorable != null && _anchorable.Root != null && _anchorable.Root.Manager != null) + _anchorable.Root.Manager._ExecuteHideCommand(_anchorable); + } + + #endregion + + #region AutoHideCommand + + /// + /// AutoHideCommand Dependency Property + /// + public static readonly DependencyProperty AutoHideCommandProperty = + DependencyProperty.Register("AutoHideCommand", typeof(ICommand), typeof(LayoutAnchorableItem), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnAutoHideCommandChanged), + new CoerceValueCallback(CoerceAutoHideCommandValue))); + + /// + /// Gets or sets the AutoHideCommand property. This dependency property + /// indicates the command to execute when user click the auto hide button. + /// + /// By default this command toggles auto hide state for an anchorable. + public ICommand AutoHideCommand + { + get { return (ICommand)GetValue(AutoHideCommandProperty); } + set { SetValue(AutoHideCommandProperty, value); } + } + + /// + /// Handles changes to the AutoHideCommand property. + /// + private static void OnAutoHideCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutAnchorableItem)d).OnAutoHideCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AutoHideCommand property. + /// + protected virtual void OnAutoHideCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the AutoHideCommand value. + /// + private static object CoerceAutoHideCommandValue(DependencyObject d, object value) + { + return value; + } + + private bool CanExecuteAutoHideCommand(object parameter) + { + if (LayoutElement == null) + return false; + + if (LayoutElement.FindParent() != null) + return false;//is floating + + return _anchorable.CanAutoHide; + } + + private void ExecuteAutoHideCommand(object parameter) + { + if (_anchorable != null && _anchorable.Root != null && _anchorable.Root.Manager != null) + _anchorable.Root.Manager._ExecuteAutoHideCommand(_anchorable); + } + + #endregion + + #region DockCommand + + /// + /// DockCommand Dependency Property + /// + public static readonly DependencyProperty DockCommandProperty = + DependencyProperty.Register("DockCommand", typeof(ICommand), typeof(LayoutAnchorableItem), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnDockCommandChanged), + new CoerceValueCallback(CoerceDockCommandValue))); + + /// + /// Gets or sets the DockCommand property. This dependency property + /// indicates the command to execute when user click the Dock button. + /// + /// By default this command moves the anchorable inside the container pane which previously hosted the object. + public ICommand DockCommand + { + get { return (ICommand)GetValue(DockCommandProperty); } + set { SetValue(DockCommandProperty, value); } + } + + /// + /// Handles changes to the DockCommand property. + /// + private static void OnDockCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutAnchorableItem)d).OnDockCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DockCommand property. + /// + protected virtual void OnDockCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the DockCommand value. + /// + private static object CoerceDockCommandValue(DependencyObject d, object value) + { + return value; + } + + private bool CanExecuteDockCommand(object parameter) + { + if (LayoutElement == null) + return false; + return LayoutElement.FindParent() != null; + } + + private void ExecuteDockCommand(object parameter) + { + LayoutElement.Root.Manager._ExecuteDockCommand(_anchorable); + } + + #endregion + + #region Visibility + ReentrantFlag _visibilityReentrantFlag = new ReentrantFlag(); + + protected override void OnVisibilityChanged() + { + if (_anchorable != null && _anchorable.Root != null) + { + if (_visibilityReentrantFlag.CanEnter) + { + using (_visibilityReentrantFlag.Enter()) + { + if (Visibility == System.Windows.Visibility.Hidden) + _anchorable.Hide(false); + else if (Visibility == System.Windows.Visibility.Visible) + _anchorable.Show(); + } + } + } + + base.OnVisibilityChanged(); + } + + + void _anchorable_IsVisibleChanged(object sender, EventArgs e) + { + if (_anchorable != null && _anchorable.Root != null) + { + if (_visibilityReentrantFlag.CanEnter) + { + using (_visibilityReentrantFlag.Enter()) + { + if (_anchorable.IsVisible) + Visibility = Visibility.Visible; + else + Visibility = Visibility.Hidden; + } + } + } + } + + #endregion + + #region CanHide + + /// + /// CanHide Dependency Property + /// + public static readonly DependencyProperty CanHideProperty = + DependencyProperty.Register("CanHide", typeof(bool), typeof(LayoutAnchorableItem), + new FrameworkPropertyMetadata((bool)true, + new PropertyChangedCallback(OnCanHideChanged))); + + /// + /// Gets or sets the CanHide property. This dependency property + /// indicates if user can hide the anchorable item. + /// + public bool CanHide + { + get { return (bool)GetValue(CanHideProperty); } + set { SetValue(CanHideProperty, value); } + } + + /// + /// Handles changes to the CanHide property. + /// + private static void OnCanHideChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutAnchorableItem)d).OnCanHideChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the CanHide property. + /// + protected virtual void OnCanHideChanged(DependencyPropertyChangedEventArgs e) + { + if (_anchorable != null) + _anchorable.CanHide = (bool)e.NewValue; + } + + #endregion + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneControl.cs new file mode 100644 index 0000000..7bb4dba --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneControl.cs @@ -0,0 +1,88 @@ +/************************************************************************************* + + 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.Collections.ObjectModel; +using System.Windows.Controls; +using System.Windows; +using System.Windows.Data; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutAnchorablePaneControl : TabControl, ILayoutControl//, ILogicalChildrenContainer + { + static LayoutAnchorablePaneControl() + { + FocusableProperty.OverrideMetadata(typeof(LayoutAnchorablePaneControl), new FrameworkPropertyMetadata(false)); + } + + public LayoutAnchorablePaneControl(LayoutAnchorablePane model) + { + if (model == null) + throw new ArgumentNullException("model"); + + _model = model; + + SetBinding(ItemsSourceProperty, new Binding("Model.Children") { Source = this }); + SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this }); + + this.LayoutUpdated += new EventHandler(OnLayoutUpdated); + } + + void OnLayoutUpdated(object sender, EventArgs e) + { + var modelWithAtcualSize = _model as ILayoutPositionableElementWithActualSize; + modelWithAtcualSize.ActualWidth = ActualWidth; + modelWithAtcualSize.ActualHeight = ActualHeight; + } + + LayoutAnchorablePane _model; + + public ILayoutElement Model + { + get { return _model; } + } + + protected override void OnGotKeyboardFocus(System.Windows.Input.KeyboardFocusChangedEventArgs e) + { + _model.SelectedContent.IsActive = true; + + base.OnGotKeyboardFocus(e); + } + + protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + if (!e.Handled && _model.SelectedContent != null) + _model.SelectedContent.IsActive = true; + } + + protected override void OnMouseRightButtonDown(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnMouseRightButtonDown(e); + + if (!e.Handled && _model.SelectedContent != null) + _model.SelectedContent.IsActive = true; + + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneGroupControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneGroupControl.cs new file mode 100644 index 0000000..46bb37d --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneGroupControl.cs @@ -0,0 +1,67 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using Xceed.Wpf.AvalonDock.Layout; + + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutAnchorablePaneGroupControl : LayoutGridControl, ILayoutControl + { + internal LayoutAnchorablePaneGroupControl(LayoutAnchorablePaneGroup model) + : base(model, model.Orientation) + { + _model = model; + } + + LayoutAnchorablePaneGroup _model; + + protected override void OnFixChildrenDockLengths() + { + #region Setup DockWidth/Height for children + if (_model.Orientation == Orientation.Horizontal) + { + for (int i = 0; i < _model.Children.Count; i++) + { + var childModel = _model.Children[i] as ILayoutPositionableElement; + if (!childModel.DockWidth.IsStar) + { + childModel.DockWidth = new GridLength(1.0, GridUnitType.Star); + } + } + } + else + { + for (int i = 0; i < _model.Children.Count; i++) + { + var childModel = _model.Children[i] as ILayoutPositionableElement; + if (!childModel.DockHeight.IsStar) + { + childModel.DockHeight = new GridLength(1.0, GridUnitType.Star); + } + } + } + #endregion + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableTabItem.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableTabItem.cs new file mode 100644 index 0000000..c355390 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableTabItem.cs @@ -0,0 +1,204 @@ +/************************************************************************************* + + 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; +using System.Collections.ObjectModel; +using System.Windows.Controls; +using System.Windows.Input; +using Xceed.Wpf.AvalonDock.Layout; +using System.Reflection; +using System.Diagnostics; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutAnchorableTabItem : Control + { + static LayoutAnchorableTabItem() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAnchorableTabItem), new FrameworkPropertyMetadata(typeof(LayoutAnchorableTabItem))); + } + + public LayoutAnchorableTabItem() + { + } + + + + #region Model + + /// + /// Model Dependency Property + /// + public static readonly DependencyProperty ModelProperty = + DependencyProperty.Register("Model", typeof(LayoutContent), typeof(LayoutAnchorableTabItem), + new FrameworkPropertyMetadata((LayoutContent)null, + new PropertyChangedCallback(OnModelChanged))); + + /// + /// Gets or sets the Model property. This dependency property + /// indicates model attached to the anchorable tab item. + /// + public LayoutContent Model + { + get { return (LayoutContent)GetValue(ModelProperty); } + set { SetValue(ModelProperty, value); } + } + + /// + /// Handles changes to the Model property. + /// + private static void OnModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutAnchorableTabItem)d).OnModelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Model property. + /// + protected virtual void OnModelChanged(DependencyPropertyChangedEventArgs e) + { + if (Model != null) + SetLayoutItem(Model.Root.Manager.GetLayoutItemFromModel(Model)); + else + SetLayoutItem(null); + //UpdateLogicalParent(); + } + + #endregion + + #region LayoutItem + + /// + /// LayoutItem Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey LayoutItemPropertyKey + = DependencyProperty.RegisterReadOnly("LayoutItem", typeof(LayoutItem), typeof(LayoutAnchorableTabItem), + new FrameworkPropertyMetadata((LayoutItem)null)); + + public static readonly DependencyProperty LayoutItemProperty + = LayoutItemPropertyKey.DependencyProperty; + + /// + /// Gets the LayoutItem property. This dependency property + /// indicates the LayoutItem attached to this tag item. + /// + public LayoutItem LayoutItem + { + get { return (LayoutItem)GetValue(LayoutItemProperty); } + } + + /// + /// Provides a secure method for setting the LayoutItem property. + /// This dependency property indicates the LayoutItem attached to this tag item. + /// + /// The new value for the property. + protected void SetLayoutItem(LayoutItem value) + { + SetValue(LayoutItemPropertyKey, value); + } + + #endregion + + bool _isMouseDown = false; + static LayoutAnchorableTabItem _draggingItem = null; + + internal static bool IsDraggingItem() + { + return _draggingItem != null; + } + + internal static LayoutAnchorableTabItem GetDraggingItem() + { + return _draggingItem; + } + internal static void ResetDraggingItem() + { + _draggingItem = null; + } + + protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + _isMouseDown = true; + _draggingItem = this; + } + + protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e) + { + base.OnMouseMove(e); + + if (e.LeftButton != MouseButtonState.Pressed) + { + _isMouseDown = false; + _draggingItem = null; + } + } + + protected override void OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs e) + { + _isMouseDown = false; + + base.OnMouseLeftButtonUp(e); + + Model.IsActive = true; + } + + protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e) + { + base.OnMouseLeave(e); + + if (_isMouseDown && e.LeftButton == MouseButtonState.Pressed) + { + _draggingItem = this; + } + + _isMouseDown = false; + } + + protected override void OnMouseEnter(MouseEventArgs e) + { + base.OnMouseEnter(e); + + if (_draggingItem != null && + _draggingItem != this && + e.LeftButton == MouseButtonState.Pressed) + { + var model = Model; + var container = model.Parent as ILayoutContainer; + var containerPane = model.Parent as ILayoutPane; + + if( (containerPane is LayoutAnchorablePane) && !((LayoutAnchorablePane)containerPane).CanRepositionItems ) + return; + if( (containerPane.Parent != null) && (containerPane.Parent is LayoutAnchorablePaneGroup) && !((LayoutAnchorablePaneGroup)containerPane.Parent).CanRepositionItems ) + return; + + var childrenList = container.Children.ToList(); + containerPane.MoveChild( childrenList.IndexOf( _draggingItem.Model ), childrenList.IndexOf( model ) ); + } + } + + protected override void OnPreviewGotKeyboardFocus(KeyboardFocusChangedEventArgs e) + { + base.OnPreviewGotKeyboardFocus(e); + + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAutoHideWindowControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAutoHideWindowControl.cs new file mode 100644 index 0000000..b619156 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAutoHideWindowControl.cs @@ -0,0 +1,552 @@ +/************************************************************************************* + + 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(); + } + + 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; + } + + 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 + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentControl.cs new file mode 100644 index 0000000..9e2f844 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentControl.cs @@ -0,0 +1,171 @@ +/************************************************************************************* + + 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.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutDocumentControl : Control + { + static LayoutDocumentControl() + { + DefaultStyleKeyProperty.OverrideMetadata( typeof( LayoutDocumentControl ), new FrameworkPropertyMetadata( typeof( LayoutDocumentControl ) ) ); + FocusableProperty.OverrideMetadata( typeof( LayoutDocumentControl ), new FrameworkPropertyMetadata( true ) ); + } + + #region Model + + /// + /// Model Dependency Property + /// + public static readonly DependencyProperty ModelProperty = DependencyProperty.Register( "Model", + typeof( LayoutContent ), + typeof( LayoutDocumentControl ), + new FrameworkPropertyMetadata( null, OnModelChanged ) ); + + /// + /// Gets or sets the Model property. This dependency property + /// indicates the model attached to this view. + /// + public LayoutContent Model + { + get + { + return ( LayoutContent )GetValue( ModelProperty ); + } + set + { + SetValue( ModelProperty, value ); + } + } + + /// + /// Handles changes to the Model property. + /// + private static void OnModelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutDocumentControl )d ).OnModelChanged( e ); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Model property. + /// + protected virtual void OnModelChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.OldValue != null ) + { + ( ( LayoutContent )e.OldValue ).PropertyChanged -= Model_PropertyChanged; + } + + if( Model != null ) + { + Model.PropertyChanged += Model_PropertyChanged; + SetLayoutItem( Model.Root.Manager.GetLayoutItemFromModel( Model ) ); + } + else + { + SetLayoutItem( null ); + } + } + + private void Model_PropertyChanged( object sender, PropertyChangedEventArgs e ) + { + if( e.PropertyName == "IsEnabled" ) + { + if( Model != null ) + { + IsEnabled = Model.IsEnabled; + if( !IsEnabled && Model.IsActive ) + { + if( ( Model.Parent != null ) && ( Model.Parent is LayoutDocumentPane ) ) + { + ( ( LayoutDocumentPane )Model.Parent ).SetNextSelectedIndex(); + } + } + } + } + } + + #endregion + + #region LayoutItem + + /// + /// LayoutItem Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey LayoutItemPropertyKey = DependencyProperty.RegisterReadOnly( "LayoutItem", + typeof( LayoutItem ), + typeof( LayoutDocumentControl ), + new FrameworkPropertyMetadata( + ( LayoutItem )null ) ); + + public static readonly DependencyProperty LayoutItemProperty = LayoutItemPropertyKey.DependencyProperty; + + /// + /// Gets the LayoutItem property. This dependency property + /// indicates the LayoutItem attached to this tag item. + /// + public LayoutItem LayoutItem + { + get + { + return ( LayoutItem )GetValue( LayoutItemProperty ); + } + } + + /// + /// Provides a secure method for setting the LayoutItem property. + /// This dependency property indicates the LayoutItem attached to this tag item. + /// + /// The new value for the property. + protected void SetLayoutItem( LayoutItem value ) + { + SetValue( LayoutItemPropertyKey, value ); + } + + #endregion + + protected override void OnPreviewGotKeyboardFocus( KeyboardFocusChangedEventArgs e ) + { + this.SetIsActive(); + base.OnPreviewGotKeyboardFocus( e ); + } + + protected override void OnMouseLeftButtonDown( MouseButtonEventArgs e ) + { + this.SetIsActive(); + base.OnMouseLeftButtonDown( e ); + } + + protected override void OnMouseRightButtonDown( MouseButtonEventArgs e ) + { + this.SetIsActive(); + base.OnMouseLeftButtonDown( e ); + } + + private void SetIsActive() + { + if( this.Model != null ) + { + this.Model.IsActive = true; + } + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs new file mode 100644 index 0000000..00fe60b --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs @@ -0,0 +1,150 @@ +/************************************************************************************* + + 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.Data; +using Xceed.Wpf.AvalonDock.Layout; +using System.Windows; +using System.Windows.Controls.Primitives; +using System.Windows.Media; +using Microsoft.Windows.Shell; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutDocumentFloatingWindowControl : LayoutFloatingWindowControl + { + static LayoutDocumentFloatingWindowControl() + { + DefaultStyleKeyProperty.OverrideMetadata( typeof( LayoutDocumentFloatingWindowControl ), new FrameworkPropertyMetadata( typeof( LayoutDocumentFloatingWindowControl ) ) ); + } + + internal LayoutDocumentFloatingWindowControl( LayoutDocumentFloatingWindow model ) + : base( model ) + { + _model = model; + UpdateThemeResources(); + } + + + LayoutDocumentFloatingWindow _model; + + public override ILayoutElement Model + { + get + { + return _model; + } + } + + public LayoutItem RootDocumentLayoutItem + { + get + { + return _model.Root.Manager.GetLayoutItemFromModel( _model.RootDocument ); + } + } + + protected override void OnInitialized( EventArgs e ) + { + base.OnInitialized( e ); + + if( _model.RootDocument == null ) + { + InternalClose(); + } + else + { + var manager = _model.Root.Manager; + + Content = manager.CreateUIElementForModel( _model.RootDocument ); + + _model.RootDocumentChanged += new EventHandler( _model_RootDocumentChanged ); + } + } + + void _model_RootDocumentChanged( object sender, EventArgs e ) + { + if( _model.RootDocument == null ) + { + InternalClose(); + } + } + + protected override IntPtr FilterMessage( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled ) + { + switch( msg ) + { + case Win32Helper.WM_NCLBUTTONDOWN: //Left button down on title -> start dragging over docking manager + if( wParam.ToInt32() == Win32Helper.HT_CAPTION ) + { + if( _model.RootDocument != null ) + _model.RootDocument.IsActive = true; + } + break; + case Win32Helper.WM_NCRBUTTONUP: + if( wParam.ToInt32() == Win32Helper.HT_CAPTION ) + { + if( OpenContextMenu() ) + handled = true; + if( _model.Root.Manager.ShowSystemMenu ) + WindowChrome.GetWindowChrome( this ).ShowSystemMenu = !handled; + else + WindowChrome.GetWindowChrome( this ).ShowSystemMenu = false; + } + break; + + } + + return base.FilterMessage( hwnd, msg, wParam, lParam, ref handled ); + } + + bool OpenContextMenu() + { + var ctxMenu = _model.Root.Manager.DocumentContextMenu; + if( ctxMenu != null && RootDocumentLayoutItem != null ) + { + ctxMenu.PlacementTarget = null; + ctxMenu.Placement = PlacementMode.MousePoint; + ctxMenu.DataContext = RootDocumentLayoutItem; + ctxMenu.IsOpen = true; + return true; + } + + return false; + } + + + protected override void OnClosed( EventArgs e ) + { + var root = Model.Root; + root.Manager.RemoveFloatingWindow( this ); + root.CollectGarbage(); + + base.OnClosed( e ); + + if( !CloseInitiatedByUser ) + { + root.FloatingWindows.Remove( _model ); + } + + _model.RootDocumentChanged -= new EventHandler( _model_RootDocumentChanged ); + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentItem.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentItem.cs new file mode 100644 index 0000000..e7068dc --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentItem.cs @@ -0,0 +1,93 @@ +/************************************************************************************* + + 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 Xceed.Wpf.AvalonDock.Layout; +using System.Windows; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutDocumentItem : LayoutItem + { + LayoutDocument _document; + internal LayoutDocumentItem() + { + + } + + internal override void Attach(LayoutContent model) + { + _document = model as LayoutDocument; + base.Attach(model); + } + + protected override void Close() + { + if( (_document.Root != null) && (_document.Root.Manager != null) ) + { + var dockingManager = _document.Root.Manager; + dockingManager._ExecuteCloseCommand( _document ); + } + } + + #region Description + + /// + /// Description Dependency Property + /// + public static readonly DependencyProperty DescriptionProperty = + DependencyProperty.Register("Description", typeof(string), typeof(LayoutDocumentItem), + new FrameworkPropertyMetadata((string)null, + new PropertyChangedCallback(OnDescriptionChanged))); + + /// + /// Gets or sets the Description property. This dependency property + /// indicates the description to display for the document item. + /// + public string Description + { + get { return (string)GetValue(DescriptionProperty); } + set { SetValue(DescriptionProperty, value); } + } + + /// + /// Handles changes to the Description property. + /// + private static void OnDescriptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutDocumentItem)d).OnDescriptionChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Description property. + /// + protected virtual void OnDescriptionChanged(DependencyPropertyChangedEventArgs e) + { + _document.Description = (string)e.NewValue; + } + + #endregion + + internal override void Detach() + { + _document = null; + base.Detach(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs new file mode 100644 index 0000000..8e84124 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs @@ -0,0 +1,98 @@ +/************************************************************************************* + + 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; +using System.Collections.ObjectModel; +using System.Windows.Controls; +using System.Windows.Data; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutDocumentPaneControl : TabControl, ILayoutControl//, ILogicalChildrenContainer + { + static LayoutDocumentPaneControl() + { + FocusableProperty.OverrideMetadata(typeof(LayoutDocumentPaneControl), new FrameworkPropertyMetadata(false)); + } + + + internal LayoutDocumentPaneControl(LayoutDocumentPane model) + { + if (model == null) + throw new ArgumentNullException("model"); + + _model = model; + SetBinding(ItemsSourceProperty, new Binding("Model.Children") { Source = this }); + SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this }); + + this.LayoutUpdated += new EventHandler(OnLayoutUpdated); + } + + void OnLayoutUpdated(object sender, EventArgs e) + { + var modelWithAtcualSize = _model as ILayoutPositionableElementWithActualSize; + modelWithAtcualSize.ActualWidth = ActualWidth; + modelWithAtcualSize.ActualHeight = ActualHeight; + } + + protected override void OnSelectionChanged(SelectionChangedEventArgs e) + { + base.OnSelectionChanged(e); + + if (_model.SelectedContent != null) + _model.SelectedContent.IsActive = true; + } + + List _logicalChildren = new List(); + + protected override System.Collections.IEnumerator LogicalChildren + { + get + { + return _logicalChildren.GetEnumerator(); + } + } + + LayoutDocumentPane _model; + + public ILayoutElement Model + { + get { return _model; } + } + + protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + if (!e.Handled && _model.SelectedContent != null) + _model.SelectedContent.IsActive = true; + } + + protected override void OnMouseRightButtonDown(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnMouseRightButtonDown(e); + + if (!e.Handled && _model.SelectedContent != null) + _model.SelectedContent.IsActive = true; + + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneGroupControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneGroupControl.cs new file mode 100644 index 0000000..e11fcb0 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneGroupControl.cs @@ -0,0 +1,66 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutDocumentPaneGroupControl : LayoutGridControl, ILayoutControl + { + internal LayoutDocumentPaneGroupControl(LayoutDocumentPaneGroup model) + :base(model, model.Orientation) + { + _model = model; + } + + LayoutDocumentPaneGroup _model; + + protected override void OnFixChildrenDockLengths() + { + #region Setup DockWidth/Height for children + if (_model.Orientation == Orientation.Horizontal) + { + for (int i = 0; i < _model.Children.Count; i++) + { + var childModel = _model.Children[i] as ILayoutPositionableElement; + if (!childModel.DockWidth.IsStar) + { + childModel.DockWidth = new GridLength(1.0, GridUnitType.Star); + } + } + } + else + { + for (int i = 0; i < _model.Children.Count; i++) + { + var childModel = _model.Children[i] as ILayoutPositionableElement; + if (!childModel.DockHeight.IsStar) + { + childModel.DockHeight = new GridLength(1.0, GridUnitType.Star); + } + } + } + #endregion + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentTabItem.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentTabItem.cs new file mode 100644 index 0000000..850f872 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentTabItem.cs @@ -0,0 +1,234 @@ +/************************************************************************************* + + 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; +using System.Windows.Controls; +using System.Windows.Input; +using Xceed.Wpf.AvalonDock.Layout; +using System.Diagnostics; +using System.Windows.Media; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutDocumentTabItem : Control + { + static LayoutDocumentTabItem() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutDocumentTabItem), new FrameworkPropertyMetadata(typeof(LayoutDocumentTabItem))); + } + + public LayoutDocumentTabItem() + { + } + + #region Model + + /// + /// Model Dependency Property + /// + public static readonly DependencyProperty ModelProperty = + DependencyProperty.Register("Model", typeof(LayoutContent), typeof(LayoutDocumentTabItem), + new FrameworkPropertyMetadata((LayoutContent)null, + new PropertyChangedCallback(OnModelChanged))); + + /// + /// Gets or sets the Model property. This dependency property + /// indicates the layout content model attached to the tab item. + /// + public LayoutContent Model + { + get { return (LayoutContent)GetValue(ModelProperty); } + set { SetValue(ModelProperty, value); } + } + + /// + /// Handles changes to the Model property. + /// + private static void OnModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutDocumentTabItem)d).OnModelChanged(e); + } + + + /// + /// Provides derived classes an opportunity to handle changes to the Model property. + /// + protected virtual void OnModelChanged(DependencyPropertyChangedEventArgs e) + { + if (Model != null) + SetLayoutItem(Model.Root.Manager.GetLayoutItemFromModel(Model)); + else + SetLayoutItem(null); + //UpdateLogicalParent(); + } + + #endregion + + #region LayoutItem + + /// + /// LayoutItem Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey LayoutItemPropertyKey + = DependencyProperty.RegisterReadOnly("LayoutItem", typeof(LayoutItem), typeof(LayoutDocumentTabItem), + new FrameworkPropertyMetadata((LayoutItem)null)); + + public static readonly DependencyProperty LayoutItemProperty + = LayoutItemPropertyKey.DependencyProperty; + + /// + /// Gets the LayoutItem property. This dependency property + /// indicates the LayoutItem attached to this tag item. + /// + public LayoutItem LayoutItem + { + get { return (LayoutItem)GetValue(LayoutItemProperty); } + } + + /// + /// Provides a secure method for setting the LayoutItem property. + /// This dependency property indicates the LayoutItem attached to this tag item. + /// + /// The new value for the property. + protected void SetLayoutItem(LayoutItem value) + { + SetValue(LayoutItemPropertyKey, value); + } + + #endregion + + List _otherTabsScreenArea = null; + List _otherTabs = null; + Rect _parentDocumentTabPanelScreenArea; + DocumentPaneTabPanel _parentDocumentTabPanel; + bool _isMouseDown = false; + Point _mouseDownPoint; + + void UpdateDragDetails() + { + _parentDocumentTabPanel = this.FindLogicalAncestor(); + _parentDocumentTabPanelScreenArea = _parentDocumentTabPanel.GetScreenArea(); + _otherTabs = _parentDocumentTabPanel.Children.Cast().Where(ch => + ch.Visibility != System.Windows.Visibility.Collapsed).ToList(); + Rect currentTabScreenArea = this.FindLogicalAncestor().GetScreenArea(); + _otherTabsScreenArea = _otherTabs.Select(ti => + { + var screenArea = ti.GetScreenArea(); + return new Rect(screenArea.Left, screenArea.Top, currentTabScreenArea.Width, screenArea.Height); + }).ToList(); + } + + protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + Model.IsActive = true; + + if (e.ClickCount == 1) + { + _mouseDownPoint = e.GetPosition(this); + _isMouseDown = true; + } + } + + protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e) + { + base.OnMouseMove(e); + + if (_isMouseDown) + { + Point ptMouseMove = e.GetPosition(this); + + if (Math.Abs(ptMouseMove.X - _mouseDownPoint.X) > SystemParameters.MinimumHorizontalDragDistance || + Math.Abs(ptMouseMove.Y - _mouseDownPoint.Y) > SystemParameters.MinimumVerticalDragDistance) + { + UpdateDragDetails(); + CaptureMouse(); + _isMouseDown = false; + } + } + + if (IsMouseCaptured) + { + var mousePosInScreenCoord = this.PointToScreenDPI(e.GetPosition(this)); + if (!_parentDocumentTabPanelScreenArea.Contains(mousePosInScreenCoord)) + { + ReleaseMouseCapture(); + var manager = Model.Root.Manager; + manager.StartDraggingFloatingWindowForContent(Model); + } + else + { + int indexOfTabItemWithMouseOver = _otherTabsScreenArea.FindIndex(r => r.Contains(mousePosInScreenCoord)); + if (indexOfTabItemWithMouseOver >= 0) + { + var targetModel = _otherTabs[indexOfTabItemWithMouseOver].Content as LayoutContent; + var container = Model.Parent as ILayoutContainer; + var containerPane = Model.Parent as ILayoutPane; + + if( (containerPane is LayoutDocumentPane) && !((LayoutDocumentPane)containerPane).CanRepositionItems ) + return; + if( (containerPane.Parent != null) && (containerPane.Parent is LayoutDocumentPaneGroup) && !((LayoutDocumentPaneGroup)containerPane.Parent).CanRepositionItems ) + return; + + var childrenList = container.Children.ToList(); + containerPane.MoveChild( childrenList.IndexOf( Model ), childrenList.IndexOf( targetModel ) ); + Model.IsActive = true; + _parentDocumentTabPanel.UpdateLayout(); + UpdateDragDetails(); + } + } + } + + } + + protected override void OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs e) + { + if (IsMouseCaptured) + ReleaseMouseCapture(); + _isMouseDown = false; + + base.OnMouseLeftButtonUp(e); + } + + protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e) + { + base.OnMouseLeave(e); + _isMouseDown = false; + } + + protected override void OnMouseEnter(MouseEventArgs e) + { + base.OnMouseEnter(e); + _isMouseDown = false; + } + + protected override void OnMouseDown(MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Middle) + { + if (LayoutItem.CloseCommand.CanExecute(null)) + LayoutItem.CloseCommand.Execute(null); + } + + base.OnMouseDown(e); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs new file mode 100644 index 0000000..3855f9d --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs @@ -0,0 +1,547 @@ +/************************************************************************************* + + 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; +using System.Runtime.InteropServices; +using System.Windows.Interop; +using System.Windows.Input; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Media; +using Xceed.Wpf.AvalonDock.Layout; +using System.Diagnostics; +using System.Windows.Documents; +using Xceed.Wpf.AvalonDock.Themes; +using Microsoft.Windows.Shell; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public abstract class LayoutFloatingWindowControl : Window, ILayoutControl + { + private ResourceDictionary currentThemeResourceDictionary; // = null + + static LayoutFloatingWindowControl() + { + LayoutFloatingWindowControl.ContentProperty.OverrideMetadata( typeof( LayoutFloatingWindowControl ), new FrameworkPropertyMetadata( null, null, new CoerceValueCallback( CoerceContentValue ) ) ); + AllowsTransparencyProperty.OverrideMetadata( typeof( LayoutFloatingWindowControl ), new FrameworkPropertyMetadata( false ) ); + ShowInTaskbarProperty.OverrideMetadata( typeof( LayoutFloatingWindowControl ), new FrameworkPropertyMetadata( false ) ); + } + + static object CoerceContentValue( DependencyObject sender, object content ) + { + return new FloatingWindowContentHost( sender as LayoutFloatingWindowControl ) { Content = content as UIElement }; + } + + protected class FloatingWindowContentHost : HwndHost + { + LayoutFloatingWindowControl _owner; + public FloatingWindowContentHost( LayoutFloatingWindowControl owner ) + { + _owner = owner; + var manager = _owner.Model.Root.Manager; + } + + + HwndSource _wpfContentHost = null; + Border _rootPresenter = null; + DockingManager _manager = null; + + protected override System.Runtime.InteropServices.HandleRef BuildWindowCore( System.Runtime.InteropServices.HandleRef hwndParent ) + { + _wpfContentHost = new HwndSource( new HwndSourceParameters() + { + ParentWindow = hwndParent.Handle, + WindowStyle = Win32Helper.WS_CHILD | Win32Helper.WS_VISIBLE | Win32Helper.WS_CLIPSIBLINGS | Win32Helper.WS_CLIPCHILDREN, + Width = 1, + Height = 1 + } ); + + _rootPresenter = new Border() { Child = new AdornerDecorator() { Child = Content }, Focusable = true }; + _rootPresenter.SetBinding( Border.BackgroundProperty, new Binding( "Background" ) { Source = _owner } ); + _wpfContentHost.RootVisual = _rootPresenter; + _wpfContentHost.SizeToContent = SizeToContent.Manual; + _manager = _owner.Model.Root.Manager; + _manager.InternalAddLogicalChild( _rootPresenter ); + + return new HandleRef( this, _wpfContentHost.Handle ); + } + + + protected override void DestroyWindowCore( HandleRef hwnd ) + { + _manager.InternalRemoveLogicalChild( _rootPresenter ); + if( _wpfContentHost != null ) + { + _wpfContentHost.Dispose(); + _wpfContentHost = null; + } + } + + public Visual RootVisual + { + get + { + return _rootPresenter; + } + } + + protected override Size MeasureOverride( Size constraint ) + { + if( Content == null ) + return base.MeasureOverride( constraint ); + + Content.Measure( constraint ); + return Content.DesiredSize; + } + + #region Content + + /// + /// Content Dependency Property + /// + public static readonly DependencyProperty ContentProperty = + DependencyProperty.Register( "Content", typeof( UIElement ), typeof( FloatingWindowContentHost ), + new FrameworkPropertyMetadata( ( UIElement )null, + new PropertyChangedCallback( OnContentChanged ) ) ); + + /// + /// Gets or sets the Content property. This dependency property + /// indicates .... + /// + public UIElement Content + { + get + { + return ( UIElement )GetValue( ContentProperty ); + } + set + { + SetValue( ContentProperty, value ); + } + } + + /// + /// Handles changes to the Content property. + /// + private static void OnContentChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( FloatingWindowContentHost )d ).OnContentChanged( e ); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Content property. + /// + protected virtual void OnContentChanged( DependencyPropertyChangedEventArgs e ) + { + if( _rootPresenter != null ) + _rootPresenter.Child = Content; + } + + #endregion + } + + ILayoutElement _model; + + protected LayoutFloatingWindowControl( ILayoutElement model ) + { + this.Loaded += new RoutedEventHandler( OnLoaded ); + this.Unloaded += new RoutedEventHandler( OnUnloaded ); + _model = model; + } + + internal virtual void UpdateThemeResources( Theme oldTheme = null ) + { + if( oldTheme != null ) + { + if( oldTheme is DictionaryTheme ) + { + if( currentThemeResourceDictionary != null ) + { + Resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); + currentThemeResourceDictionary = null; + } + } + else + { + var resourceDictionaryToRemove = + Resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); + if( resourceDictionaryToRemove != null ) + Resources.MergedDictionaries.Remove( + resourceDictionaryToRemove ); + } + } + + var manager = _model.Root.Manager; + if( manager.Theme != null ) + { + if( manager.Theme is DictionaryTheme ) + { + currentThemeResourceDictionary = ( ( DictionaryTheme )manager.Theme ).ThemeResourceDictionary; + Resources.MergedDictionaries.Add( currentThemeResourceDictionary ); + } + else + { + Resources.MergedDictionaries.Add( new ResourceDictionary() { Source = manager.Theme.GetResourceUri() } ); + } + } + } + + protected override void OnClosed( EventArgs e ) + { + if( Content != null ) + { + var host = Content as FloatingWindowContentHost; + host.Dispose(); + + if( _hwndSrc != null ) + { + _hwndSrc.RemoveHook( _hwndSrcHook ); + _hwndSrc.Dispose(); + _hwndSrc = null; + } + } + + base.OnClosed( e ); + } + + bool _attachDrag = false; + internal void AttachDrag( bool onActivated = true ) + { + if( onActivated ) + { + _attachDrag = true; + this.Activated += new EventHandler( OnActivated ); + } + else + { + IntPtr windowHandle = new WindowInteropHelper( this ).Handle; + IntPtr lParam = new IntPtr( ( ( int )Left & ( int )0xFFFF ) | ( ( ( int )Top ) << 16 ) ); + Win32Helper.SendMessage( windowHandle, Win32Helper.WM_NCLBUTTONDOWN, new IntPtr( Win32Helper.HT_CAPTION ), lParam ); + } + } + + HwndSource _hwndSrc; + HwndSourceHook _hwndSrcHook; + + void OnLoaded( object sender, RoutedEventArgs e ) + { + this.Loaded -= new RoutedEventHandler( OnLoaded ); + + this.SetParentToMainWindowOf( Model.Root.Manager ); + + _hwndSrc = HwndSource.FromDependencyObject( this ) as HwndSource; + _hwndSrcHook = new HwndSourceHook( FilterMessage ); + _hwndSrc.AddHook( _hwndSrcHook ); + + // Restore maximize state + var maximized = Model.Descendents().OfType().Any( l => l.IsMaximized ); + UpdateMaximizedState( maximized ); + } + + void OnUnloaded( object sender, RoutedEventArgs e ) + { + this.Unloaded -= new RoutedEventHandler( OnUnloaded ); + + if( _hwndSrc != null ) + { + _hwndSrc.RemoveHook( _hwndSrcHook ); + InternalClose(); + } + } + + void OnActivated( object sender, EventArgs e ) + { + this.Activated -= new EventHandler( OnActivated ); + + if( _attachDrag && Mouse.LeftButton == MouseButtonState.Pressed ) + { + IntPtr windowHandle = new WindowInteropHelper( this ).Handle; + var mousePosition = this.PointToScreenDPI( Mouse.GetPosition( this ) ); + var clientArea = Win32Helper.GetClientRect( windowHandle ); + var windowArea = Win32Helper.GetWindowRect( windowHandle ); + + Left = mousePosition.X - windowArea.Width / 2.0; + Top = mousePosition.Y - ( windowArea.Height - clientArea.Height ) / 2.0; + _attachDrag = false; + + IntPtr lParam = new IntPtr( ( ( int )mousePosition.X & ( int )0xFFFF ) | ( ( ( int )mousePosition.Y ) << 16 ) ); + Win32Helper.SendMessage( windowHandle, Win32Helper.WM_NCLBUTTONDOWN, new IntPtr( Win32Helper.HT_CAPTION ), lParam ); + } + } + + + protected override void OnInitialized( EventArgs e ) + { + CommandBindings.Add( new CommandBinding( Microsoft.Windows.Shell.SystemCommands.CloseWindowCommand, + new ExecutedRoutedEventHandler( ( s, args ) => Microsoft.Windows.Shell.SystemCommands.CloseWindow( ( Window )args.Parameter ) ) ) ); + CommandBindings.Add( new CommandBinding( Microsoft.Windows.Shell.SystemCommands.MaximizeWindowCommand, + new ExecutedRoutedEventHandler( ( s, args ) => Microsoft.Windows.Shell.SystemCommands.MaximizeWindow( ( Window )args.Parameter ) ) ) ); + CommandBindings.Add( new CommandBinding( Microsoft.Windows.Shell.SystemCommands.MinimizeWindowCommand, + new ExecutedRoutedEventHandler( ( s, args ) => Microsoft.Windows.Shell.SystemCommands.MinimizeWindow( ( Window )args.Parameter ) ) ) ); + CommandBindings.Add( new CommandBinding( Microsoft.Windows.Shell.SystemCommands.RestoreWindowCommand, + new ExecutedRoutedEventHandler( ( s, args ) => Microsoft.Windows.Shell.SystemCommands.RestoreWindow( ( Window )args.Parameter ) ) ) ); + //Debug.Assert(this.Owner != null); + base.OnInitialized( e ); + } + + public abstract ILayoutElement Model + { + get; + } + + + #region IsDragging + + /// + /// IsDragging Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsDraggingPropertyKey + = DependencyProperty.RegisterReadOnly( "IsDragging", typeof( bool ), typeof( LayoutFloatingWindowControl ), + new FrameworkPropertyMetadata( ( bool )false, + new PropertyChangedCallback( OnIsDraggingChanged ) ) ); + + public static readonly DependencyProperty IsDraggingProperty + = IsDraggingPropertyKey.DependencyProperty; + + /// + /// Gets the IsDragging property. This dependency property + /// indicates that this floating window is being dragged. + /// + public bool IsDragging + { + get + { + return ( bool )GetValue( IsDraggingProperty ); + } + } + + /// + /// Provides a secure method for setting the IsDragging property. + /// This dependency property indicates that this floating window is being dragged. + /// + /// The new value for the property. + protected void SetIsDragging( bool value ) + { + SetValue( IsDraggingPropertyKey, value ); + } + + /// + /// Handles changes to the IsDragging property. + /// + private static void OnIsDraggingChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutFloatingWindowControl )d ).OnIsDraggingChanged( e ); + } + + /// + /// Provides derived classes an opportunity to handle changes to the IsDragging property. + /// + protected virtual void OnIsDraggingChanged( DependencyPropertyChangedEventArgs e ) + { + if( ( bool )e.NewValue ) + { + CaptureMouse(); + } + else + { + ReleaseMouseCapture(); + } + } + + #endregion + + DragService _dragService = null; + + void UpdatePositionAndSizeOfPanes() + { + foreach( var posElement in Model.Descendents().OfType() ) + { + posElement.FloatingLeft = Left; + posElement.FloatingTop = Top; + posElement.FloatingWidth = Width; + posElement.FloatingHeight = Height; + } + } + + void UpdateMaximizedState( bool isMaximized ) + { + foreach( var posElement in Model.Descendents().OfType() ) + { + posElement.IsMaximized = isMaximized; + } + IsMaximized = isMaximized; + WindowState = isMaximized ? WindowState.Maximized : WindowState.Normal; + } + + + protected virtual IntPtr FilterMessage( + IntPtr hwnd, + int msg, + IntPtr wParam, + IntPtr lParam, + ref bool handled + ) + { + handled = false; + + switch( msg ) + { + case Win32Helper.WM_ACTIVATE: + if( ( ( int )wParam & 0xFFFF ) == Win32Helper.WA_INACTIVE ) + { + if( lParam == this.GetParentWindowHandle() ) + { + Win32Helper.SetActiveWindow( _hwndSrc.Handle ); + handled = true; + } + } + break; + case Win32Helper.WM_EXITSIZEMOVE: + UpdatePositionAndSizeOfPanes(); + + if( _dragService != null ) + { + bool dropFlag; + var mousePosition = this.TransformToDeviceDPI( Win32Helper.GetMousePosition() ); + _dragService.Drop( mousePosition, out dropFlag ); + _dragService = null; + SetIsDragging( false ); + + if( dropFlag ) + InternalClose(); + } + + break; + case Win32Helper.WM_MOVING: + { + UpdateDragPosition(); + if( this.IsMaximized ) + { + this.UpdateMaximizedState( false ); + } + } + break; + case Win32Helper.WM_LBUTTONUP: //set as handled right button click on title area (after showing context menu) + if( _dragService != null && Mouse.LeftButton == MouseButtonState.Released ) + { + _dragService.Abort(); + _dragService = null; + SetIsDragging( false ); + } + break; + case Win32Helper.WM_SYSCOMMAND: + int command = ( int )wParam & 0xFFF0; + if( command == Win32Helper.SC_MAXIMIZE || command == Win32Helper.SC_RESTORE ) + { + UpdateMaximizedState( command == Win32Helper.SC_MAXIMIZE ); + } + break; + } + + + + return IntPtr.Zero; + } + + private void UpdateDragPosition() + { + if( _dragService == null ) + { + _dragService = new DragService( this ); + SetIsDragging( true ); + } + + var mousePosition = this.TransformToDeviceDPI( Win32Helper.GetMousePosition() ); + _dragService.UpdateMouseLocation( mousePosition ); + } + + bool _internalCloseFlag = false; + + internal void InternalClose() + { + _internalCloseFlag = true; + Close(); + } + + + protected bool CloseInitiatedByUser + { + get + { + return !_internalCloseFlag; + } + } + + internal bool KeepContentVisibleOnClose + { + get; + set; + } + + #region IsMaximized + + /// + /// IsMaximized Dependency Property + /// + public static readonly DependencyProperty IsMaximizedProperty + = DependencyProperty.Register( "IsMaximized", typeof( bool ), typeof( LayoutFloatingWindowControl ), + new FrameworkPropertyMetadata( ( bool )false ) ); + + /// + /// Gets/sets the IsMaximized property. This dependency property + /// indicates if the window is maximized. + /// + public bool IsMaximized + { + get + { + return ( bool )GetValue( IsMaximizedProperty ); + } + private set + { + SetValue( IsMaximizedProperty, value ); + UpdatePositionAndSizeOfPanes(); + } + } + + /// + /// Provides a secure method for setting the IsMaximized property. + /// This dependency property indicates if the window is maximized. + /// + /// The new value for the property. + + protected override void OnStateChanged( EventArgs e ) + { + //Windows sometimes send unwanted state changes (when minimizing application for instance) + //We force internal state to be used + WindowState = IsMaximized ? WindowState.Maximized : WindowState.Normal; + base.OnStateChanged( e ); + } + + #endregion + + + + + + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutGridControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutGridControl.cs new file mode 100644 index 0000000..4ab7888 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutGridControl.cs @@ -0,0 +1,556 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; +using Xceed.Wpf.AvalonDock.Layout; +using System.Diagnostics; +using System.Windows.Threading; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public abstract class LayoutGridControl : Grid, ILayoutControl where T : class, ILayoutPanelElement + { + static LayoutGridControl() + { + } + + internal LayoutGridControl(LayoutPositionableGroup model, Orientation orientation) + { + if (model == null) + throw new ArgumentNullException("model"); + + _model = model; + _orientation = orientation; + + FlowDirection = System.Windows.FlowDirection.LeftToRight; + } + + LayoutPositionableGroup _model; + public ILayoutElement Model + { + get { return _model; } + } + + Orientation _orientation; + + public Orientation Orientation + { + get { return (_model as ILayoutOrientableGroup).Orientation; } + } + + bool _initialized; + ChildrenTreeChange? _asyncRefreshCalled; + + bool AsyncRefreshCalled + { + get { return _asyncRefreshCalled != null; } + } + + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + + _model.ChildrenTreeChanged += (s, args) => + { + if (_asyncRefreshCalled.HasValue && + _asyncRefreshCalled.Value == args.Change) + return; + _asyncRefreshCalled = args.Change; + Dispatcher.BeginInvoke(new Action(() => + { + _asyncRefreshCalled = null; + UpdateChildren(); + }), DispatcherPriority.Normal, null); + }; + + this.LayoutUpdated += new EventHandler(OnLayoutUpdated); + } + + void OnLayoutUpdated(object sender, EventArgs e) + { + var modelWithAtcualSize = _model as ILayoutPositionableElementWithActualSize; + modelWithAtcualSize.ActualWidth = ActualWidth; + modelWithAtcualSize.ActualHeight = ActualHeight; + + if (!_initialized) + { + _initialized = true; + UpdateChildren(); + } + } + + void UpdateChildren() + { + var alreadyContainedChildren = Children.OfType().ToArray(); + + DetachOldSplitters(); + DetachPropertChangeHandler(); + + Children.Clear(); + ColumnDefinitions.Clear(); + RowDefinitions.Clear(); + + if (_model == null || + _model.Root == null) + return; + + var manager = _model.Root.Manager; + if (manager == null) + return; + + + foreach (ILayoutElement child in _model.Children) + { + var foundContainedChild = alreadyContainedChildren.FirstOrDefault(chVM => chVM.Model == child); + if (foundContainedChild != null) + Children.Add(foundContainedChild as UIElement); + else + Children.Add(manager.CreateUIElementForModel(child)); + } + + CreateSplitters(); + + UpdateRowColDefinitions(); + + AttachNewSplitters(); + AttachPropertyChangeHandler(); + } + + private void AttachPropertyChangeHandler() + { + foreach (var child in InternalChildren.OfType()) + { + child.Model.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(this.OnChildModelPropertyChanged); + } + } + + private void DetachPropertChangeHandler() + { + foreach (var child in InternalChildren.OfType()) + { + child.Model.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(this.OnChildModelPropertyChanged); + } + } + + void OnChildModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (AsyncRefreshCalled) + return; + + if (_fixingChildrenDockLengths.CanEnter && e.PropertyName == "DockWidth" && Orientation == System.Windows.Controls.Orientation.Horizontal) + { + if (ColumnDefinitions.Count == InternalChildren.Count) + { + var changedElement = sender as ILayoutPositionableElement; + var childFromModel = InternalChildren.OfType().First(ch => ch.Model == changedElement) as UIElement; + int indexOfChild = InternalChildren.IndexOf(childFromModel); + ColumnDefinitions[indexOfChild].Width = changedElement.DockWidth; + } + } + else if (_fixingChildrenDockLengths.CanEnter && e.PropertyName == "DockHeight" && Orientation == System.Windows.Controls.Orientation.Vertical) + { + if (RowDefinitions.Count == InternalChildren.Count) + { + var changedElement = sender as ILayoutPositionableElement; + var childFromModel = InternalChildren.OfType().First(ch => ch.Model == changedElement) as UIElement; + int indexOfChild = InternalChildren.IndexOf(childFromModel); + RowDefinitions[indexOfChild].Height = changedElement.DockHeight; + } + } + else if (e.PropertyName == "IsVisible") + { + UpdateRowColDefinitions(); + } + } + + + void UpdateRowColDefinitions() + { + var root = _model.Root; + if (root == null) + return; + var manager = root.Manager; + if (manager == null) + return; + + FixChildrenDockLengths(); + + //Debug.Assert(InternalChildren.Count == _model.ChildrenCount + (_model.ChildrenCount - 1)); + + #region Setup GridRows/Cols + RowDefinitions.Clear(); + ColumnDefinitions.Clear(); + if (Orientation == Orientation.Horizontal) + { + int iColumn = 0; + int iChild = 0; + for (int iChildModel = 0; iChildModel < _model.Children.Count; iChildModel++, iColumn++, iChild++) + { + var childModel = _model.Children[iChildModel] as ILayoutPositionableElement; + ColumnDefinitions.Add(new ColumnDefinition() + { + Width = childModel.IsVisible ? childModel.DockWidth : new GridLength(0.0, GridUnitType.Pixel), + MinWidth = childModel.IsVisible ? childModel.DockMinWidth : 0.0 + }); + Grid.SetColumn(InternalChildren[iChild], iColumn); + + //append column for splitter + if (iChild < InternalChildren.Count - 1) + { + iChild++; + iColumn++; + + bool nextChildModelVisibleExist = false; + for (int i = iChildModel + 1; i < _model.Children.Count; i++) + { + var nextChildModel = _model.Children[i] as ILayoutPositionableElement; + if (nextChildModel.IsVisible) + { + nextChildModelVisibleExist = true; + break; + } + } + + ColumnDefinitions.Add(new ColumnDefinition() + { + Width = childModel.IsVisible && nextChildModelVisibleExist ? new GridLength(manager.GridSplitterWidth) : new GridLength(0.0, GridUnitType.Pixel) + }); + Grid.SetColumn(InternalChildren[iChild], iColumn); + } + } + } + else //if (_model.Orientation == Orientation.Vertical) + { + int iRow = 0; + int iChild = 0; + for (int iChildModel = 0; iChildModel < _model.Children.Count; iChildModel++, iRow++, iChild++) + { + var childModel = _model.Children[iChildModel] as ILayoutPositionableElement; + RowDefinitions.Add(new RowDefinition() + { + Height = childModel.IsVisible ? childModel.DockHeight : new GridLength(0.0, GridUnitType.Pixel), + MinHeight = childModel.IsVisible ? childModel.DockMinHeight : 0.0 + }); + Grid.SetRow(InternalChildren[iChild], iRow); + + //if (RowDefinitions.Last().Height.Value == 0.0) + // System.Diagnostics.Debugger.Break(); + + //append row for splitter (if necessary) + if (iChild < InternalChildren.Count - 1) + { + iChild++; + iRow++; + + bool nextChildModelVisibleExist = false; + for (int i = iChildModel + 1; i < _model.Children.Count; i++) + { + var nextChildModel = _model.Children[i] as ILayoutPositionableElement; + if (nextChildModel.IsVisible) + { + nextChildModelVisibleExist = true; + break; + } + } + + RowDefinitions.Add(new RowDefinition() + { + Height = childModel.IsVisible && nextChildModelVisibleExist ? new GridLength(manager.GridSplitterHeight) : new GridLength(0.0, GridUnitType.Pixel) + }); + //if (RowDefinitions.Last().Height.Value == 0.0) + // System.Diagnostics.Debugger.Break(); + Grid.SetRow(InternalChildren[iChild], iRow); + } + } + } + + #endregion + } + + ReentrantFlag _fixingChildrenDockLengths = new ReentrantFlag(); + protected void FixChildrenDockLengths() + { + using (_fixingChildrenDockLengths.Enter()) + OnFixChildrenDockLengths(); + } + + protected abstract void OnFixChildrenDockLengths(); + + #region Splitters + + void CreateSplitters() + { + for (int iChild = 1; iChild < Children.Count; iChild++) + { + var splitter = new LayoutGridResizerControl(); + splitter.Cursor = this.Orientation == Orientation.Horizontal ? Cursors.SizeWE : Cursors.SizeNS; + Children.Insert(iChild, splitter); + iChild++; + } + } + + void DetachOldSplitters() + { + foreach (var splitter in Children.OfType()) + { + splitter.DragStarted -= new System.Windows.Controls.Primitives.DragStartedEventHandler(OnSplitterDragStarted); + splitter.DragDelta -= new System.Windows.Controls.Primitives.DragDeltaEventHandler(OnSplitterDragDelta); + splitter.DragCompleted -= new System.Windows.Controls.Primitives.DragCompletedEventHandler(OnSplitterDragCompleted); + } + } + + void AttachNewSplitters() + { + foreach (var splitter in Children.OfType()) + { + splitter.DragStarted += new System.Windows.Controls.Primitives.DragStartedEventHandler(OnSplitterDragStarted); + splitter.DragDelta += new System.Windows.Controls.Primitives.DragDeltaEventHandler(OnSplitterDragDelta); + splitter.DragCompleted += new System.Windows.Controls.Primitives.DragCompletedEventHandler(OnSplitterDragCompleted); + } + } + + void OnSplitterDragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) + { + var resizer = sender as LayoutGridResizerControl; + ShowResizerOverlayWindow(resizer); + } + + void OnSplitterDragDelta(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 (Orientation == System.Windows.Controls.Orientation.Horizontal) + { + 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 OnSplitterDragCompleted(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 (Orientation == System.Windows.Controls.Orientation.Horizontal) + delta = Canvas.GetLeft(_resizerGhost) - _initialStartPoint.X; + else + delta = Canvas.GetTop(_resizerGhost) - _initialStartPoint.Y; + + int indexOfResizer = InternalChildren.IndexOf(splitter); + + var prevChild = InternalChildren[indexOfResizer - 1] as FrameworkElement; + var nextChild = GetNextVisibleChild(indexOfResizer); + + var prevChildActualSize = prevChild.TransformActualSizeToAncestor(); + var nextChildActualSize = nextChild.TransformActualSizeToAncestor(); + + var prevChildModel = (ILayoutPositionableElement)(prevChild as ILayoutControl).Model; + var nextChildModel = (ILayoutPositionableElement)(nextChild as ILayoutControl).Model; + + if (Orientation == System.Windows.Controls.Orientation.Horizontal) + { + if (prevChildModel.DockWidth.IsStar) + { + prevChildModel.DockWidth = new GridLength(prevChildModel.DockWidth.Value * (prevChildActualSize.Width + delta) / prevChildActualSize.Width, GridUnitType.Star); + } + else + { + prevChildModel.DockWidth = new GridLength(prevChildModel.DockWidth.Value + delta, GridUnitType.Pixel); + } + + if (nextChildModel.DockWidth.IsStar) + { + nextChildModel.DockWidth = new GridLength(nextChildModel.DockWidth.Value * (nextChildActualSize.Width - delta) / nextChildActualSize.Width, GridUnitType.Star); + } + else + { + nextChildModel.DockWidth = new GridLength(nextChildModel.DockWidth.Value - delta, GridUnitType.Pixel); + } + } + else + { + if (prevChildModel.DockHeight.IsStar) + { + prevChildModel.DockHeight = new GridLength(prevChildModel.DockHeight.Value * (prevChildActualSize.Height + delta) / prevChildActualSize.Height, GridUnitType.Star); + } + else + { + prevChildModel.DockHeight = new GridLength(prevChildModel.DockHeight.Value + delta, GridUnitType.Pixel); + } + + if (nextChildModel.DockHeight.IsStar) + { + nextChildModel.DockHeight = new GridLength(nextChildModel.DockHeight.Value * (nextChildActualSize.Height - delta) / nextChildActualSize.Height, GridUnitType.Star); + } + else + { + nextChildModel.DockHeight = new GridLength(nextChildModel.DockHeight.Value - delta, GridUnitType.Pixel); + } + } + + HideResizerOverlayWindow(); + } + + Border _resizerGhost = null; + Window _resizerWindowHost = null; + Vector _initialStartPoint; + + FrameworkElement GetNextVisibleChild(int index) + { + for (int i = index + 1; i < InternalChildren.Count; i++) + { + if (InternalChildren[i] is LayoutGridResizerControl) + continue; + + if (Orientation == System.Windows.Controls.Orientation.Horizontal) + { + if (ColumnDefinitions[i].Width.IsStar || ColumnDefinitions[i].Width.Value > 0) + return InternalChildren[i] as FrameworkElement; + } + else + { + if (RowDefinitions[i].Height.IsStar || RowDefinitions[i].Height.Value > 0) + return InternalChildren[i] as FrameworkElement; + } + } + + return null; + } + + void ShowResizerOverlayWindow(LayoutGridResizerControl splitter) + { + _resizerGhost = new Border() + { + Background = splitter.BackgroundWhileDragging, + Opacity = splitter.OpacityWhileDragging + }; + + int indexOfResizer = InternalChildren.IndexOf(splitter); + + var prevChild = InternalChildren[indexOfResizer - 1] as FrameworkElement; + var nextChild = GetNextVisibleChild(indexOfResizer); + + var prevChildActualSize = prevChild.TransformActualSizeToAncestor(); + var nextChildActualSize = nextChild.TransformActualSizeToAncestor(); + + var prevChildModel = (ILayoutPositionableElement)(prevChild as ILayoutControl).Model; + var nextChildModel = (ILayoutPositionableElement)(nextChild as ILayoutControl).Model; + + Point ptTopLeftScreen = prevChild.PointToScreenDPIWithoutFlowDirection(new Point()); + + Size actualSize; + + if (Orientation == System.Windows.Controls.Orientation.Horizontal) + { + actualSize = new Size( + prevChildActualSize.Width - prevChildModel.DockMinWidth + splitter.ActualWidth + nextChildActualSize.Width - nextChildModel.DockMinWidth, + nextChildActualSize.Height); + + _resizerGhost.Width = splitter.ActualWidth; + _resizerGhost.Height = actualSize.Height; + ptTopLeftScreen.Offset(prevChildModel.DockMinWidth, 0.0); + } + else + { + actualSize = new Size( + prevChildActualSize.Width, + prevChildActualSize.Height - prevChildModel.DockMinHeight + splitter.ActualHeight + nextChildActualSize.Height - nextChildModel.DockMinHeight); + + _resizerGhost.Height = splitter.ActualHeight; + _resizerGhost.Width = actualSize.Width; + + ptTopLeftScreen.Offset(0.0, prevChildModel.DockMinHeight); + } + + _initialStartPoint = splitter.PointToScreenDPIWithoutFlowDirection(new Point()) - ptTopLeftScreen; + + if (Orientation == System.Windows.Controls.Orientation.Horizontal) + { + 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() + { + SizeToContent = System.Windows.SizeToContent.Manual, + ResizeMode = ResizeMode.NoResize, + WindowStyle = System.Windows.WindowStyle.None, + ShowInTaskbar = false, + AllowsTransparency = true, + Background = null, + Width = actualSize.Width, + Height = actualSize.Height, + Left = ptTopLeftScreen.X, + Top = ptTopLeftScreen.Y, + ShowActivated = false, + //Owner = Window.GetWindow(this), + Content = panelHostResizer + }; + _resizerWindowHost.Loaded += (s, e) => + { + _resizerWindowHost.SetParentToMainWindowOf(this); + }; + _resizerWindowHost.Show(); + } + + void HideResizerOverlayWindow() + { + if (_resizerWindowHost != null) + { + _resizerWindowHost.Close(); + _resizerWindowHost = null; + } + } + + #endregion + + + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutGridResizerControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutGridResizerControl.cs new file mode 100644 index 0000000..217faf8 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutGridResizerControl.cs @@ -0,0 +1,83 @@ +/************************************************************************************* + + 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.Controls.Primitives; +using System.Windows; +using System.Windows.Media; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutGridResizerControl : Thumb + { + static LayoutGridResizerControl() + { + //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class. + //This style is defined in themes\generic.xaml + DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutGridResizerControl), new FrameworkPropertyMetadata(typeof(LayoutGridResizerControl))); + HorizontalAlignmentProperty.OverrideMetadata(typeof(LayoutGridResizerControl), new FrameworkPropertyMetadata(HorizontalAlignment.Stretch, FrameworkPropertyMetadataOptions.AffectsParentMeasure)); + VerticalAlignmentProperty.OverrideMetadata(typeof(LayoutGridResizerControl), new FrameworkPropertyMetadata(VerticalAlignment.Stretch, FrameworkPropertyMetadataOptions.AffectsParentMeasure)); + BackgroundProperty.OverrideMetadata(typeof(LayoutGridResizerControl), new FrameworkPropertyMetadata(Brushes.Transparent)); + IsHitTestVisibleProperty.OverrideMetadata(typeof(LayoutGridResizerControl), new FrameworkPropertyMetadata(true, null)); + } + + + #region BackgroundWhileDragging + + /// + /// BackgroundWhileDragging Dependency Property + /// + public static readonly DependencyProperty BackgroundWhileDraggingProperty = + DependencyProperty.Register("BackgroundWhileDragging", typeof(Brush), typeof(LayoutGridResizerControl), + new FrameworkPropertyMetadata((Brush)Brushes.Black)); + + /// + /// Gets or sets the BackgroundWhileDragging property. This dependency property + /// indicates .... + /// + public Brush BackgroundWhileDragging + { + get { return (Brush)GetValue(BackgroundWhileDraggingProperty); } + set { SetValue(BackgroundWhileDraggingProperty, value); } + } + + #endregion + + #region OpacityWhileDragging + + /// + /// OpacityWhileDragging Dependency Property + /// + public static readonly DependencyProperty OpacityWhileDraggingProperty = + DependencyProperty.Register("OpacityWhileDragging", typeof(double), typeof(LayoutGridResizerControl), + new FrameworkPropertyMetadata((double)0.5)); + + /// + /// Gets or sets the OpacityWhileDragging property. This dependency property + /// indicates .... + /// + public double OpacityWhileDragging + { + get { return (double)GetValue(OpacityWhileDraggingProperty); } + set { SetValue(OpacityWhileDraggingProperty, value); } + } + + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutItem.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutItem.cs new file mode 100644 index 0000000..e6c5e1e --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutItem.cs @@ -0,0 +1,1168 @@ +/************************************************************************************* + + 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; +using Xceed.Wpf.AvalonDock.Layout; +using System.Windows.Input; +using Xceed.Wpf.AvalonDock.Commands; +using System.ComponentModel; +using System.Windows.Data; +using System.Windows.Media; +using System.Windows.Controls; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public abstract class LayoutItem : FrameworkElement + { + static LayoutItem() + { + ToolTipProperty.OverrideMetadata(typeof(LayoutItem), new FrameworkPropertyMetadata(null, (s, e) => OnToolTipChanged(s,e))); + VisibilityProperty.OverrideMetadata(typeof(LayoutItem), new FrameworkPropertyMetadata(Visibility.Visible, (s,e) => OnVisibilityChanged(s, e))); + } + + + internal LayoutItem() + { + + } + + internal virtual void Attach(LayoutContent model) + { + LayoutElement = model; + Model = model.Content; + + InitDefaultCommands(); + + LayoutElement.IsSelectedChanged+=new EventHandler(LayoutElement_IsSelectedChanged); + LayoutElement.IsActiveChanged+=new EventHandler(LayoutElement_IsActiveChanged); + + DataContext = this; + } + + + + void LayoutElement_IsActiveChanged(object sender, EventArgs e) + { + if (_isActiveReentrantFlag.CanEnter) + { + using (_isActiveReentrantFlag.Enter()) + { + var bnd = BindingOperations.GetBinding(this, IsActiveProperty); + IsActive = LayoutElement.IsActive; + var bnd2 = BindingOperations.GetBinding(this, IsActiveProperty); + } + } + } + + void LayoutElement_IsSelectedChanged(object sender, EventArgs e) + { + if (_isSelectedReentrantFlag.CanEnter) + { + using (_isSelectedReentrantFlag.Enter()) + { + IsSelected = LayoutElement.IsSelected; + } + } + } + + internal virtual void Detach() + { + LayoutElement.IsSelectedChanged -= new EventHandler(LayoutElement_IsSelectedChanged); + LayoutElement.IsActiveChanged -= new EventHandler(LayoutElement_IsActiveChanged); + LayoutElement = null; + Model = null; + } + + public LayoutContent LayoutElement + { + get; + private set; + } + + public object Model + { + get; + private set; + } + + ICommand _defaultCloseCommand; + ICommand _defaultFloatCommand; + ICommand _defaultDockAsDocumentCommand; + ICommand _defaultCloseAllButThisCommand; + ICommand _defaultCloseAllCommand; + ICommand _defaultActivateCommand; + ICommand _defaultNewVerticalTabGroupCommand; + ICommand _defaultNewHorizontalTabGroupCommand; + ICommand _defaultMoveToNextTabGroupCommand; + ICommand _defaultMoveToPreviousTabGroupCommand; + + protected virtual void InitDefaultCommands() + { + _defaultCloseCommand = new RelayCommand((p) => ExecuteCloseCommand(p), (p) => CanExecuteCloseCommand(p)); + _defaultFloatCommand = new RelayCommand((p) => ExecuteFloatCommand(p), (p) => CanExecuteFloatCommand(p)); + _defaultDockAsDocumentCommand = new RelayCommand((p) => ExecuteDockAsDocumentCommand(p), (p) => CanExecuteDockAsDocumentCommand(p)); + _defaultCloseAllButThisCommand = new RelayCommand((p) => ExecuteCloseAllButThisCommand(p), (p) => CanExecuteCloseAllButThisCommand(p)); + _defaultCloseAllCommand = new RelayCommand( ( p ) => ExecuteCloseAllCommand( p ), ( p ) => CanExecuteCloseAllCommand( p ) ); + _defaultActivateCommand = new RelayCommand( ( p ) => ExecuteActivateCommand( p ), ( p ) => CanExecuteActivateCommand( p ) ); + _defaultNewVerticalTabGroupCommand = new RelayCommand((p) => ExecuteNewVerticalTabGroupCommand(p), (p) => CanExecuteNewVerticalTabGroupCommand(p)); + _defaultNewHorizontalTabGroupCommand = new RelayCommand((p) => ExecuteNewHorizontalTabGroupCommand(p), (p) => CanExecuteNewHorizontalTabGroupCommand(p)); + _defaultMoveToNextTabGroupCommand = new RelayCommand((p) => ExecuteMoveToNextTabGroupCommand(p), (p) => CanExecuteMoveToNextTabGroupCommand(p)); + _defaultMoveToPreviousTabGroupCommand = new RelayCommand((p) => ExecuteMoveToPreviousTabGroupCommand(p), (p) => CanExecuteMoveToPreviousTabGroupCommand(p)); + } + + protected virtual void ClearDefaultBindings() + { + if (CloseCommand == _defaultCloseCommand) + BindingOperations.ClearBinding(this, CloseCommandProperty); + if (FloatCommand == _defaultFloatCommand) + BindingOperations.ClearBinding(this, FloatCommandProperty); + if (DockAsDocumentCommand == _defaultDockAsDocumentCommand) + BindingOperations.ClearBinding(this, DockAsDocumentCommandProperty); + if (CloseAllButThisCommand == _defaultCloseAllButThisCommand) + BindingOperations.ClearBinding(this, CloseAllButThisCommandProperty); + if( CloseAllCommand == _defaultCloseAllCommand ) + BindingOperations.ClearBinding( this, CloseAllCommandProperty ); + if (ActivateCommand == _defaultActivateCommand) + BindingOperations.ClearBinding(this, ActivateCommandProperty); + if (NewVerticalTabGroupCommand == _defaultNewVerticalTabGroupCommand) + BindingOperations.ClearBinding(this, NewVerticalTabGroupCommandProperty); + if (NewHorizontalTabGroupCommand == _defaultNewHorizontalTabGroupCommand) + BindingOperations.ClearBinding(this, NewHorizontalTabGroupCommandProperty); + if (MoveToNextTabGroupCommand == _defaultMoveToNextTabGroupCommand) + BindingOperations.ClearBinding(this, MoveToNextTabGroupCommandProperty); + if (MoveToPreviousTabGroupCommand == _defaultMoveToPreviousTabGroupCommand) + BindingOperations.ClearBinding(this, MoveToPreviousTabGroupCommandProperty); + } + + protected virtual void SetDefaultBindings() + { + if (CloseCommand == null) + CloseCommand = _defaultCloseCommand; + if (FloatCommand == null) + FloatCommand = _defaultFloatCommand; + if (DockAsDocumentCommand == null) + DockAsDocumentCommand = _defaultDockAsDocumentCommand; + if (CloseAllButThisCommand == null) + CloseAllButThisCommand = _defaultCloseAllButThisCommand; + if( CloseAllCommand == null ) + CloseAllCommand = _defaultCloseAllCommand; + if (ActivateCommand == null) + ActivateCommand = _defaultActivateCommand; + if (NewVerticalTabGroupCommand == null) + NewVerticalTabGroupCommand = _defaultNewVerticalTabGroupCommand; + if (NewHorizontalTabGroupCommand == null) + NewHorizontalTabGroupCommand = _defaultNewHorizontalTabGroupCommand; + if (MoveToNextTabGroupCommand == null) + MoveToNextTabGroupCommand = _defaultMoveToNextTabGroupCommand; + if (MoveToPreviousTabGroupCommand == null) + MoveToPreviousTabGroupCommand = _defaultMoveToPreviousTabGroupCommand; + + + IsSelected = LayoutElement.IsSelected; + IsActive = LayoutElement.IsActive; + } + + internal void _ClearDefaultBindings() + { + ClearDefaultBindings(); + } + + internal void _SetDefaultBindings() + { + SetDefaultBindings(); + } + + internal bool IsViewExists() + { + return (_view != null); + } + + ContentPresenter _view = null; + public ContentPresenter View + { + get + { + if (_view == null) + { + _view = new ContentPresenter(); + + _view.SetBinding(ContentPresenter.ContentProperty, new Binding("Content") { Source = LayoutElement }); + _view.SetBinding( ContentPresenter.ContentTemplateProperty, new Binding( "LayoutItemTemplate" ) { Source = LayoutElement.Root.Manager } ); + _view.SetBinding( ContentPresenter.ContentTemplateSelectorProperty, new Binding( "LayoutItemTemplateSelector" ) { Source = LayoutElement.Root.Manager } ); + LayoutElement.Root.Manager.InternalAddLogicalChild( _view ); + } + + return _view; + } + } + + + #region Title + + /// + /// Title Dependency Property + /// + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register("Title", typeof(string), typeof(LayoutItem), + new FrameworkPropertyMetadata((string)null, + new PropertyChangedCallback(OnTitleChanged))); + + /// + /// Gets or sets the Title property. This dependency property + /// indicates the title of the element. + /// + public string Title + { + get { return (string)GetValue(TitleProperty); } + set { SetValue(TitleProperty, value); } + } + + /// + /// Handles changes to the Title property. + /// + private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnTitleChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Title property. + /// + protected virtual void OnTitleChanged(DependencyPropertyChangedEventArgs e) + { + if (LayoutElement != null) + LayoutElement.Title = (string)e.NewValue; + } + + #endregion + + #region ToolTip + private static void OnToolTipChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)s).OnToolTipChanged(); + } + + private void OnToolTipChanged() + { + if (LayoutElement != null) + LayoutElement.ToolTip = ToolTip; + } + #endregion + + #region IconSource + + /// + /// IconSource Dependency Property + /// + public static readonly DependencyProperty IconSourceProperty = + DependencyProperty.Register("IconSource", typeof(ImageSource), typeof(LayoutItem), + new FrameworkPropertyMetadata((ImageSource)null, + new PropertyChangedCallback(OnIconSourceChanged))); + + /// + /// Gets or sets the IconSource property. This dependency property + /// indicates icon associated with the item. + /// + public ImageSource IconSource + { + get { return (ImageSource)GetValue(IconSourceProperty); } + set { SetValue(IconSourceProperty, value); } + } + + /// + /// Handles changes to the IconSource property. + /// + private static void OnIconSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnIconSourceChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the IconSource property. + /// + protected virtual void OnIconSourceChanged(DependencyPropertyChangedEventArgs e) + { + if (LayoutElement != null) + LayoutElement.IconSource = IconSource; + } + + #endregion + + #region Visibility + + private static void OnVisibilityChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)s).OnVisibilityChanged(); + } + + protected virtual void OnVisibilityChanged() + { + if (LayoutElement != null && + Visibility == System.Windows.Visibility.Collapsed) + LayoutElement.Close(); + } + + #endregion + + #region ContentId + + /// + /// ContentId Dependency Property + /// + public static readonly DependencyProperty ContentIdProperty = + DependencyProperty.Register("ContentId", typeof(string), typeof(LayoutItem), + new FrameworkPropertyMetadata((string)null, + new PropertyChangedCallback(OnContentIdChanged))); + + /// + /// Gets or sets the ContentId property. This dependency property + /// indicates the content id used to retrive content when deserializing layouts. + /// + public string ContentId + { + get { return (string)GetValue(ContentIdProperty); } + set { SetValue(ContentIdProperty, value); } + } + + /// + /// Handles changes to the ContentId property. + /// + private static void OnContentIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnContentIdChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the ContentId property. + /// + protected virtual void OnContentIdChanged(DependencyPropertyChangedEventArgs e) + { + if (LayoutElement != null) + LayoutElement.ContentId = (string)e.NewValue; + } + + #endregion + + #region IsSelected + + ReentrantFlag _isSelectedReentrantFlag = new ReentrantFlag(); + + /// + /// IsSelected Dependency Property + /// + public static readonly DependencyProperty IsSelectedProperty = + DependencyProperty.Register("IsSelected", typeof(bool), typeof(LayoutItem), + new FrameworkPropertyMetadata((bool)false, + new PropertyChangedCallback(OnIsSelectedChanged))); + + /// + /// Gets or sets the IsSelected property. This dependency property + /// indicates if the item is selected inside its container. + /// + public bool IsSelected + { + get { return (bool)GetValue(IsSelectedProperty); } + set { SetValue(IsSelectedProperty, value); } + } + + /// + /// Handles changes to the IsSelected property. + /// + private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnIsSelectedChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the IsSelected property. + /// + protected virtual void OnIsSelectedChanged(DependencyPropertyChangedEventArgs e) + { + if (_isSelectedReentrantFlag.CanEnter) + { + using (_isSelectedReentrantFlag.Enter()) + { + if (LayoutElement != null) + LayoutElement.IsSelected = (bool)e.NewValue; + } + } + } + + #endregion + + #region IsActive + + ReentrantFlag _isActiveReentrantFlag = new ReentrantFlag(); + + /// + /// IsActive Dependency Property + /// + public static readonly DependencyProperty IsActiveProperty = + DependencyProperty.Register("IsActive", typeof(bool), typeof(LayoutItem), + new FrameworkPropertyMetadata((bool)false, + new PropertyChangedCallback(OnIsActiveChanged))); + + /// + /// Gets or sets the IsActive property. This dependency property + /// indicates if the item is active in the UI. + /// + public bool IsActive + { + get { return (bool)GetValue(IsActiveProperty); } + set { SetValue(IsActiveProperty, value); } + } + + /// + /// Handles changes to the IsActive property. + /// + private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnIsActiveChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the IsActive property. + /// + protected virtual void OnIsActiveChanged(DependencyPropertyChangedEventArgs e) + { + if (_isActiveReentrantFlag.CanEnter) + { + using (_isActiveReentrantFlag.Enter()) + { + if (LayoutElement != null) + LayoutElement.IsActive = (bool)e.NewValue; + } + } + } + + #endregion + + #region CanClose + + /// + /// CanClose Dependency Property + /// + public static readonly DependencyProperty CanCloseProperty = + DependencyProperty.Register("CanClose", typeof(bool), typeof(LayoutItem), + new FrameworkPropertyMetadata((bool)true, + new PropertyChangedCallback(OnCanCloseChanged))); + + /// + /// Gets or sets the CanClose property. This dependency property + /// indicates if the item can be closed. + /// + public bool CanClose + { + get { return (bool)GetValue(CanCloseProperty); } + set { SetValue(CanCloseProperty, value); } + } + + /// + /// Handles changes to the CanClose property. + /// + private static void OnCanCloseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnCanCloseChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the CanClose property. + /// + protected virtual void OnCanCloseChanged(DependencyPropertyChangedEventArgs e) + { + if (LayoutElement != null) + LayoutElement.CanClose = (bool)e.NewValue; + } + + #endregion + + #region CanFloat + + /// + /// CanFloat Dependency Property + /// + public static readonly DependencyProperty CanFloatProperty = + DependencyProperty.Register("CanFloat", typeof(bool), typeof(LayoutItem), + new FrameworkPropertyMetadata((bool)true, + new PropertyChangedCallback(OnCanFloatChanged))); + + /// + /// Gets or sets the CanFloat property. This dependency property + /// indicates if user can move the layout element dragging it to another position. + /// + public bool CanFloat + { + get { return (bool)GetValue(CanFloatProperty); } + set { SetValue(CanFloatProperty, value); } + } + + /// + /// Handles changes to the CanFloat property. + /// + private static void OnCanFloatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnCanFloatChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the CanFloat property. + /// + protected virtual void OnCanFloatChanged(DependencyPropertyChangedEventArgs e) + { + if (LayoutElement != null) + LayoutElement.CanFloat = (bool)e.NewValue; + } + + #endregion + + #region CloseCommand + + /// + /// CloseCommand Dependency Property + /// + public static readonly DependencyProperty CloseCommandProperty = + DependencyProperty.Register("CloseCommand", typeof(ICommand), typeof(LayoutItem), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnCloseCommandChanged), + new CoerceValueCallback(CoerceCloseCommandValue))); + + /// + /// Gets or sets the CloseCommand property. This dependency property + /// indicates the command to execute when user click the document close button. + /// + public ICommand CloseCommand + { + get { return (ICommand)GetValue(CloseCommandProperty); } + set { SetValue(CloseCommandProperty, value); } + } + + /// + /// Handles changes to the CloseCommand property. + /// + private static void OnCloseCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnCloseCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the CloseCommand property. + /// + protected virtual void OnCloseCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the CloseCommand value. + /// + private static object CoerceCloseCommandValue(DependencyObject d, object value) + { + return value; + } + + private bool CanExecuteCloseCommand(object parameter) + { + return LayoutElement != null && LayoutElement.CanClose; + } + + private void ExecuteCloseCommand(object parameter) + { + Close(); + } + + protected abstract void Close(); + + + #endregion + + #region FloatCommand + /// + /// FloatCommand Dependency Property + /// + public static readonly DependencyProperty FloatCommandProperty = + DependencyProperty.Register("FloatCommand", typeof(ICommand), typeof(LayoutItem), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnFloatCommandChanged), + new CoerceValueCallback(CoerceFloatCommandValue))); + + /// + /// Gets or sets the FloatCommand property. This dependency property + /// indicates the command to execute when user click the float button. + /// + /// By default this command move the anchorable inside new floating window. + public ICommand FloatCommand + { + get { return (ICommand)GetValue(FloatCommandProperty); } + set { SetValue(FloatCommandProperty, value); } + } + + /// + /// Handles changes to the FloatCommand property. + /// + private static void OnFloatCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnFloatCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the FloatCommand property. + /// + protected virtual void OnFloatCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the FloatCommand value. + /// + private static object CoerceFloatCommandValue(DependencyObject d, object value) + { + return value; + } + + private bool CanExecuteFloatCommand(object anchorable) + { + return LayoutElement != null && LayoutElement.CanFloat && LayoutElement.FindParent() == null; + } + + private void ExecuteFloatCommand(object parameter) + { + LayoutElement.Root.Manager._ExecuteFloatCommand(LayoutElement); + } + + protected virtual void Float() + { + + } + + #endregion + + #region DockAsDocumentCommand + + /// + /// DockAsDocumentCommand Dependency Property + /// + public static readonly DependencyProperty DockAsDocumentCommandProperty = + DependencyProperty.Register("DockAsDocumentCommand", typeof(ICommand), typeof(LayoutItem), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnDockAsDocumentCommandChanged), + new CoerceValueCallback(CoerceDockAsDocumentCommandValue))); + + /// + /// Gets or sets the DockAsDocumentCommand property. This dependency property + /// indicates the command to execute when user click the DockAsDocument button. + /// + /// By default this command move the anchorable inside the last focused document pane. + public ICommand DockAsDocumentCommand + { + get { return (ICommand)GetValue(DockAsDocumentCommandProperty); } + set { SetValue(DockAsDocumentCommandProperty, value); } + } + + /// + /// Handles changes to the DockAsDocumentCommand property. + /// + private static void OnDockAsDocumentCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnDockAsDocumentCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DockAsDocumentCommand property. + /// + protected virtual void OnDockAsDocumentCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the DockAsDocumentCommand value. + /// + private static object CoerceDockAsDocumentCommandValue(DependencyObject d, object value) + { + return value; + } + + private bool CanExecuteDockAsDocumentCommand(object parameter) + { + return LayoutElement != null && LayoutElement.FindParent() == null; + } + + private void ExecuteDockAsDocumentCommand(object parameter) + { + LayoutElement.Root.Manager._ExecuteDockAsDocumentCommand(LayoutElement); + } + + #endregion + + #region CloseAllButThisCommand + + /// + /// CloseAllButThisCommand Dependency Property + /// + public static readonly DependencyProperty CloseAllButThisCommandProperty = + DependencyProperty.Register("CloseAllButThisCommand", typeof(ICommand), typeof(LayoutItem), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnCloseAllButThisCommandChanged), + new CoerceValueCallback(CoerceCloseAllButThisCommandValue))); + + /// + /// Gets or sets the CloseAllButThisCommand property. This dependency property + /// indicates the 'Close All But This' command. + /// + public ICommand CloseAllButThisCommand + { + get { return (ICommand)GetValue(CloseAllButThisCommandProperty); } + set { SetValue(CloseAllButThisCommandProperty, value); } + } + + /// + /// Handles changes to the CloseAllButThisCommand property. + /// + private static void OnCloseAllButThisCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnCloseAllButThisCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the CloseAllButThisCommand property. + /// + protected virtual void OnCloseAllButThisCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the CloseAllButThisCommand value. + /// + private static object CoerceCloseAllButThisCommandValue(DependencyObject d, object value) + { + return value; + } + + private bool CanExecuteCloseAllButThisCommand(object parameter) + { + if (LayoutElement == null) + return false; + var root = LayoutElement.Root; + if (root == null) + return false; + + return LayoutElement.Root.Manager.Layout. + Descendents().OfType().Where(d => d != LayoutElement && (d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow)).Any(); + } + + private void ExecuteCloseAllButThisCommand(object parameter) + { + LayoutElement.Root.Manager._ExecuteCloseAllButThisCommand(LayoutElement); + } + + #endregion + + #region CloseAllCommand + + /// + /// CloseAllCommand Dependency Property + /// + public static readonly DependencyProperty CloseAllCommandProperty = + DependencyProperty.Register( "CloseAllCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( null, + new PropertyChangedCallback( OnCloseAllCommandChanged ), + new CoerceValueCallback( CoerceCloseAllCommandValue ) ) ); + + /// + /// Gets or sets the CloseAllCommand property. This dependency property + /// indicates the 'Close All' command. + /// + public ICommand CloseAllCommand + { + get + { + return ( ICommand )GetValue( CloseAllCommandProperty ); + } + set + { + SetValue( CloseAllCommandProperty, value ); + } + } + + /// + /// Handles changes to the CloseAllCommand property. + /// + private static void OnCloseAllCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnCloseAllCommandChanged( e ); + } + + /// + /// Provides derived classes an opportunity to handle changes to the CloseAllCommand property. + /// + protected virtual void OnCloseAllCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } + + /// + /// Coerces the CloseAllCommand value. + /// + private static object CoerceCloseAllCommandValue( DependencyObject d, object value ) + { + return value; + } + + private bool CanExecuteCloseAllCommand( object parameter ) + { + if( LayoutElement == null ) + return false; + var root = LayoutElement.Root; + if( root == null ) + return false; + + return LayoutElement.Root.Manager.Layout. + Descendents().OfType().Where( d => ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).Any(); + } + + private void ExecuteCloseAllCommand( object parameter ) + { + LayoutElement.Root.Manager._ExecuteCloseAllCommand( LayoutElement ); + } + + #endregion + + #region ActivateCommand + + /// + /// ActivateCommand Dependency Property + /// + public static readonly DependencyProperty ActivateCommandProperty = + DependencyProperty.Register("ActivateCommand", typeof(ICommand), typeof(LayoutItem), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnActivateCommandChanged), + new CoerceValueCallback(CoerceActivateCommandValue))); + + /// + /// Gets or sets the ActivateCommand property. This dependency property + /// indicates the command to execute when user wants to activate a content (either a Document or an Anchorable). + /// + public ICommand ActivateCommand + { + get { return (ICommand)GetValue(ActivateCommandProperty); } + set { SetValue(ActivateCommandProperty, value); } + } + + /// + /// Handles changes to the ActivateCommand property. + /// + private static void OnActivateCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnActivateCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the ActivateCommand property. + /// + protected virtual void OnActivateCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the ActivateCommand value. + /// + private static object CoerceActivateCommandValue(DependencyObject d, object value) + { + return value; + } + + private bool CanExecuteActivateCommand(object parameter) + { + return LayoutElement != null; + } + + private void ExecuteActivateCommand(object parameter) + { + LayoutElement.Root.Manager._ExecuteContentActivateCommand(LayoutElement); + } + + #endregion + + #region NewVerticalTabGroupCommand + + /// + /// NewVerticalTabGroupCommand Dependency Property + /// + public static readonly DependencyProperty NewVerticalTabGroupCommandProperty = + DependencyProperty.Register("NewVerticalTabGroupCommand", typeof(ICommand), typeof(LayoutItem), + new FrameworkPropertyMetadata((ICommand)null, + new PropertyChangedCallback(OnNewVerticalTabGroupCommandChanged))); + + /// + /// Gets or sets the NewVerticalTabGroupCommand property. This dependency property + /// indicates the new vertical tab group command. + /// + public ICommand NewVerticalTabGroupCommand + { + get { return (ICommand)GetValue(NewVerticalTabGroupCommandProperty); } + set { SetValue(NewVerticalTabGroupCommandProperty, value); } + } + + /// + /// Handles changes to the NewVerticalTabGroupCommand property. + /// + private static void OnNewVerticalTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnNewVerticalTabGroupCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the NewVerticalTabGroupCommand property. + /// + protected virtual void OnNewVerticalTabGroupCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + private bool CanExecuteNewVerticalTabGroupCommand(object parameter) + { + if (LayoutElement == null) + return false; + var parentDocumentGroup = LayoutElement.FindParent(); + var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; + return ((parentDocumentGroup == null || + parentDocumentGroup.ChildrenCount == 1 || + parentDocumentGroup.Root.Manager.AllowMixedOrientation || + parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Horizontal) && + parentDocumentPane != null && + parentDocumentPane.ChildrenCount > 1); + } + + private void ExecuteNewVerticalTabGroupCommand(object parameter) + { + var layoutElement = LayoutElement; + var parentDocumentGroup = layoutElement.FindParent(); + var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + + if (parentDocumentGroup == null) + { + var grandParent = parentDocumentPane.Parent as ILayoutContainer; + parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; + grandParent.ReplaceChild(parentDocumentPane, parentDocumentGroup); + parentDocumentGroup.Children.Add(parentDocumentPane); + } + parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; + int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane); + parentDocumentGroup.InsertChildAt(indexOfParentPane + 1, new LayoutDocumentPane(layoutElement)); + layoutElement.IsActive = true; + layoutElement.Root.CollectGarbage(); + } + #endregion + + #region NewHorizontalTabGroupCommand + + /// + /// NewHorizontalTabGroupCommand Dependency Property + /// + public static readonly DependencyProperty NewHorizontalTabGroupCommandProperty = + DependencyProperty.Register("NewHorizontalTabGroupCommand", typeof(ICommand), typeof(LayoutItem), + new FrameworkPropertyMetadata((ICommand)null, + new PropertyChangedCallback(OnNewHorizontalTabGroupCommandChanged))); + + /// + /// Gets or sets the NewHorizontalTabGroupCommand property. This dependency property + /// indicates the new horizontal tab group command. + /// + public ICommand NewHorizontalTabGroupCommand + { + get { return (ICommand)GetValue(NewHorizontalTabGroupCommandProperty); } + set { SetValue(NewHorizontalTabGroupCommandProperty, value); } + } + + /// + /// Handles changes to the NewHorizontalTabGroupCommand property. + /// + private static void OnNewHorizontalTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnNewHorizontalTabGroupCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the NewHorizontalTabGroupCommand property. + /// + protected virtual void OnNewHorizontalTabGroupCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + + private bool CanExecuteNewHorizontalTabGroupCommand(object parameter) + { + if (LayoutElement == null) + return false; + var parentDocumentGroup = LayoutElement.FindParent(); + var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; + return ((parentDocumentGroup == null || + parentDocumentGroup.ChildrenCount == 1 || + parentDocumentGroup.Root.Manager.AllowMixedOrientation || + parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Vertical) && + parentDocumentPane != null && + parentDocumentPane.ChildrenCount > 1); + } + + private void ExecuteNewHorizontalTabGroupCommand(object parameter) + { + var layoutElement = LayoutElement; + var parentDocumentGroup = layoutElement.FindParent(); + var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + + if (parentDocumentGroup == null) + { + var grandParent = parentDocumentPane.Parent as ILayoutContainer; + parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; + grandParent.ReplaceChild(parentDocumentPane, parentDocumentGroup); + parentDocumentGroup.Children.Add(parentDocumentPane); + } + parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Vertical; + int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane); + parentDocumentGroup.InsertChildAt(indexOfParentPane + 1, new LayoutDocumentPane(layoutElement)); + layoutElement.IsActive = true; + layoutElement.Root.CollectGarbage(); + } + #endregion + + #region MoveToNextTabGroupCommand + + /// + /// MoveToNextTabGroupCommand Dependency Property + /// + public static readonly DependencyProperty MoveToNextTabGroupCommandProperty = + DependencyProperty.Register("MoveToNextTabGroupCommand", typeof(ICommand), typeof(LayoutItem), + new FrameworkPropertyMetadata((ICommand)null, + new PropertyChangedCallback(OnMoveToNextTabGroupCommandChanged))); + + /// + /// Gets or sets the MoveToNextTabGroupCommand property. This dependency property + /// indicates move to next tab group command. + /// + public ICommand MoveToNextTabGroupCommand + { + get { return (ICommand)GetValue(MoveToNextTabGroupCommandProperty); } + set { SetValue(MoveToNextTabGroupCommandProperty, value); } + } + + /// + /// Handles changes to the MoveToNextTabGroupCommand property. + /// + private static void OnMoveToNextTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnMoveToNextTabGroupCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the MoveToNextTabGroupCommand property. + /// + protected virtual void OnMoveToNextTabGroupCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + private bool CanExecuteMoveToNextTabGroupCommand(object parameter) + { + if (LayoutElement == null) + return false; + + var parentDocumentGroup = LayoutElement.FindParent(); + var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; + return (parentDocumentGroup != null && + parentDocumentPane != null && + parentDocumentGroup.ChildrenCount > 1 && + parentDocumentGroup.IndexOfChild(parentDocumentPane) < parentDocumentGroup.ChildrenCount - 1 && + parentDocumentGroup.Children[parentDocumentGroup.IndexOfChild(parentDocumentPane) + 1] is LayoutDocumentPane); + } + + private void ExecuteMoveToNextTabGroupCommand(object parameter) + { + var layoutElement = LayoutElement; + var parentDocumentGroup = layoutElement.FindParent(); + var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane); + var nextDocumentPane = parentDocumentGroup.Children[indexOfParentPane + 1] as LayoutDocumentPane; + nextDocumentPane.InsertChildAt(0, layoutElement); + layoutElement.IsActive = true; + layoutElement.Root.CollectGarbage(); + } + + #endregion + + #region MoveToPreviousTabGroupCommand + + /// + /// MoveToPreviousTabGroupCommand Dependency Property + /// + public static readonly DependencyProperty MoveToPreviousTabGroupCommandProperty = + DependencyProperty.Register("MoveToPreviousTabGroupCommand", typeof(ICommand), typeof(LayoutItem), + new FrameworkPropertyMetadata((ICommand)null, + new PropertyChangedCallback(OnMoveToPreviousTabGroupCommandChanged))); + + /// + /// Gets or sets the MoveToPreviousTabGroupCommand property. This dependency property + /// indicates move to rpevious tab group command. + /// + public ICommand MoveToPreviousTabGroupCommand + { + get { return (ICommand)GetValue(MoveToPreviousTabGroupCommandProperty); } + set { SetValue(MoveToPreviousTabGroupCommandProperty, value); } + } + + /// + /// Handles changes to the MoveToPreviousTabGroupCommand property. + /// + private static void OnMoveToPreviousTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((LayoutItem)d).OnMoveToPreviousTabGroupCommandChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the MoveToPreviousTabGroupCommand property. + /// + protected virtual void OnMoveToPreviousTabGroupCommandChanged(DependencyPropertyChangedEventArgs e) + { + } + + private bool CanExecuteMoveToPreviousTabGroupCommand(object parameter) + { + if (LayoutElement == null) + return false; + var parentDocumentGroup = LayoutElement.FindParent(); + var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; + return (parentDocumentGroup != null && + parentDocumentPane != null && + parentDocumentGroup.ChildrenCount > 1 && + parentDocumentGroup.IndexOfChild(parentDocumentPane) > 0 && + parentDocumentGroup.Children[parentDocumentGroup.IndexOfChild(parentDocumentPane) - 1] is LayoutDocumentPane); + } + + private void ExecuteMoveToPreviousTabGroupCommand(object parameter) + { + var layoutElement = LayoutElement; + var parentDocumentGroup = layoutElement.FindParent(); + var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane); + var nextDocumentPane = parentDocumentGroup.Children[indexOfParentPane - 1] as LayoutDocumentPane; + nextDocumentPane.InsertChildAt(0, layoutElement); + layoutElement.IsActive = true; + layoutElement.Root.CollectGarbage(); + } + #endregion + + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/LayoutPanelControl.cs b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutPanelControl.cs new file mode 100644 index 0000000..1a364b3 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/LayoutPanelControl.cs @@ -0,0 +1,131 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class LayoutPanelControl : LayoutGridControl, ILayoutControl + { + internal LayoutPanelControl(LayoutPanel model) + :base(model, model.Orientation) + { + _model = model; + + } + + LayoutPanel _model; + + protected override void OnFixChildrenDockLengths() + { + if (ActualWidth == 0.0 || + ActualHeight == 0.0) + return; + + var modelAsPositionableElement = _model as ILayoutPositionableElementWithActualSize; + #region Setup DockWidth/Height for children + if (_model.Orientation == Orientation.Horizontal) + { + if (_model.ContainsChildOfType()) + { + for (int i = 0; i < _model.Children.Count; i++) + { + var childContainerModel = _model.Children[i] as ILayoutContainer; + var childPositionableModel = _model.Children[i] as ILayoutPositionableElement; + + if (childContainerModel != null && + (childContainerModel.IsOfType() || + childContainerModel.ContainsChildOfType())) + { + childPositionableModel.DockWidth = new GridLength(1.0, GridUnitType.Star); + } + else if (childPositionableModel != null && childPositionableModel.DockWidth.IsStar) + { + var childPositionableModelWidthActualSize = childPositionableModel as ILayoutPositionableElementWithActualSize; + + var widthToSet = Math.Max(childPositionableModelWidthActualSize.ActualWidth, childPositionableModel.DockMinWidth); + + widthToSet = Math.Min(widthToSet, ActualWidth / 2.0); + widthToSet = Math.Max(widthToSet, childPositionableModel.DockMinWidth); + + childPositionableModel.DockWidth = new GridLength( + widthToSet, + GridUnitType.Pixel); + } + } + } + else + { + for (int i = 0; i < _model.Children.Count; i++) + { + var childPositionableModel = _model.Children[i] as ILayoutPositionableElement; + if (!childPositionableModel.DockWidth.IsStar) + { + childPositionableModel.DockWidth = new GridLength(1.0, GridUnitType.Star); + } + } + } + } + else + { + if (_model.ContainsChildOfType()) + { + for (int i = 0; i < _model.Children.Count; i++) + { + var childContainerModel = _model.Children[i] as ILayoutContainer; + var childPositionableModel = _model.Children[i] as ILayoutPositionableElement; + + if (childContainerModel != null && + (childContainerModel.IsOfType() || + childContainerModel.ContainsChildOfType())) + { + childPositionableModel.DockHeight = new GridLength(1.0, GridUnitType.Star); + } + else if (childPositionableModel != null && childPositionableModel.DockHeight.IsStar) + { + var childPositionableModelWidthActualSize = childPositionableModel as ILayoutPositionableElementWithActualSize; + + var heightToSet = Math.Max(childPositionableModelWidthActualSize.ActualHeight, childPositionableModel.DockMinHeight); + heightToSet = Math.Min(heightToSet, ActualHeight / 2.0); + heightToSet = Math.Max(heightToSet, childPositionableModel.DockMinHeight); + + childPositionableModel.DockHeight = new GridLength(heightToSet, GridUnitType.Pixel); + } + } + } + else + { + for (int i = 0; i < _model.Children.Count; i++) + { + var childPositionableModel = _model.Children[i] as ILayoutPositionableElement; + if (!childPositionableModel.DockHeight.IsStar) + { + childPositionableModel.DockHeight = new GridLength(1.0, GridUnitType.Star); + } + } + } + } + #endregion + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/MenuItemEx.cs b/Src/Xceed.Wpf.AvalonDock/Controls/MenuItemEx.cs new file mode 100644 index 0000000..7d55b68 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/MenuItemEx.cs @@ -0,0 +1,139 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class MenuItemEx : MenuItem + { + static MenuItemEx() + { + IconProperty.OverrideMetadata(typeof(MenuItemEx), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIconPropertyChanged))); + } + + + public MenuItemEx() + { + } + + #region IconTemplate + + /// + /// IconTemplate Dependency Property + /// + public static readonly DependencyProperty IconTemplateProperty = + DependencyProperty.Register("IconTemplate", typeof(DataTemplate), typeof(MenuItemEx), + new FrameworkPropertyMetadata((DataTemplate)null, + new PropertyChangedCallback(OnIconTemplateChanged))); + + /// + /// Gets or sets the IconTemplate property. This dependency property + /// indicates the data template for the icon. + /// + public DataTemplate IconTemplate + { + get { return (DataTemplate)GetValue(IconTemplateProperty); } + set { SetValue(IconTemplateProperty, value); } + } + + /// + /// Handles changes to the IconTemplate property. + /// + private static void OnIconTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((MenuItemEx)d).OnIconTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the IconTemplate property. + /// + protected virtual void OnIconTemplateChanged(DependencyPropertyChangedEventArgs e) + { + UpdateIcon(); + } + + #endregion + + #region IconTemplateSelector + + /// + /// IconTemplateSelector Dependency Property + /// + public static readonly DependencyProperty IconTemplateSelectorProperty = + DependencyProperty.Register("IconTemplateSelector", typeof(DataTemplateSelector), typeof(MenuItemEx), + new FrameworkPropertyMetadata((DataTemplateSelector)null, + new PropertyChangedCallback(OnIconTemplateSelectorChanged))); + + /// + /// Gets or sets the IconTemplateSelector property. This dependency property + /// indicates the DataTemplateSelector for the Icon. + /// + public DataTemplateSelector IconTemplateSelector + { + get { return (DataTemplateSelector)GetValue(IconTemplateSelectorProperty); } + set { SetValue(IconTemplateSelectorProperty, value); } + } + + /// + /// Handles changes to the IconTemplateSelector property. + /// + private static void OnIconTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((MenuItemEx)d).OnIconTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the IconTemplateSelector property. + /// + protected virtual void OnIconTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + UpdateIcon(); + } + + #endregion + + static void OnIconPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null) + { + ((MenuItemEx)sender).UpdateIcon(); + } + } + + bool _reentrantFlag = false; + void UpdateIcon() + { + if (_reentrantFlag) + return; + _reentrantFlag = true; + if (IconTemplateSelector != null) + { + var dataTemplateToUse = IconTemplateSelector.SelectTemplate(Icon, this); + if (dataTemplateToUse != null) + Icon = dataTemplateToUse.LoadContent(); + } + else if (IconTemplate != null) + Icon = IconTemplate.LoadContent(); + _reentrantFlag = false; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/NavigatorWindow.cs b/Src/Xceed.Wpf.AvalonDock/Controls/NavigatorWindow.cs new file mode 100644 index 0000000..2f86eab --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/NavigatorWindow.cs @@ -0,0 +1,364 @@ +/************************************************************************************* + + 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; +using Xceed.Wpf.AvalonDock.Layout; +using System.Windows.Interop; +using System.Windows.Threading; +using Xceed.Wpf.AvalonDock.Themes; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class NavigatorWindow : Window + { + private ResourceDictionary currentThemeResourceDictionary; // = null + + static NavigatorWindow() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigatorWindow), new FrameworkPropertyMetadata(typeof(NavigatorWindow))); + ShowActivatedProperty.OverrideMetadata(typeof(NavigatorWindow), new FrameworkPropertyMetadata(false)); + ShowInTaskbarProperty.OverrideMetadata(typeof(NavigatorWindow), new FrameworkPropertyMetadata(false)); + } + + DockingManager _manager; + internal NavigatorWindow(DockingManager manager) + { + _manager = manager; + + _internalSetSelectedDocument = true; + SetAnchorables(_manager.Layout.Descendents().OfType().Where(a => a.IsVisible).Select(d => (LayoutAnchorableItem)_manager.GetLayoutItemFromModel(d)).ToArray()); + SetDocuments(_manager.Layout.Descendents().OfType().OrderByDescending(d => d.LastActivationTimeStamp.GetValueOrDefault()).Select(d => (LayoutDocumentItem)_manager.GetLayoutItemFromModel(d)).ToArray()); + _internalSetSelectedDocument = false; + + if (Documents.Length > 1) + InternalSetSelectedDocument(Documents[1]); + + this.DataContext = this; + + this.Loaded += new RoutedEventHandler(OnLoaded); + this.Unloaded += new RoutedEventHandler(OnUnloaded); + + UpdateThemeResources(); + } + + + internal void UpdateThemeResources(Theme oldTheme = null) + { + if (oldTheme != null) + { + if( oldTheme is DictionaryTheme ) + { + if( currentThemeResourceDictionary != null ) + { + Resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); + currentThemeResourceDictionary = null; + } + } + else + { + var resourceDictionaryToRemove = + Resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); + if( resourceDictionaryToRemove != null ) + Resources.MergedDictionaries.Remove( + resourceDictionaryToRemove ); + } + } + + if (_manager.Theme != null) + { + if( _manager.Theme is DictionaryTheme ) + { + currentThemeResourceDictionary = ( ( DictionaryTheme )_manager.Theme ).ThemeResourceDictionary; + Resources.MergedDictionaries.Add( currentThemeResourceDictionary ); + } + else + { + Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = _manager.Theme.GetResourceUri() }); + } + } + } + + + void OnLoaded(object sender, RoutedEventArgs e) + { + this.Loaded -= new RoutedEventHandler(OnLoaded); + + this.Focus(); + + //this.SetParentToMainWindowOf(_manager); + WindowStartupLocation = WindowStartupLocation.CenterOwner; + } + + void OnUnloaded(object sender, RoutedEventArgs e) + { + this.Unloaded -= new RoutedEventHandler(OnUnloaded); + + //_hwndSrc.RemoveHook(_hwndSrcHook); + //_hwndSrc.Dispose(); + //_hwndSrc = null; + } + + //protected virtual IntPtr FilterMessage( + // IntPtr hwnd, + // int msg, + // IntPtr wParam, + // IntPtr lParam, + // ref bool handled + // ) + //{ + // handled = false; + + // switch (msg) + // { + // case Win32Helper.WM_ACTIVATE: + // if (((int)wParam & 0xFFFF) == Win32Helper.WA_INACTIVE) + // { + // if (lParam == new WindowInteropHelper(this.Owner).Handle) + // { + // Win32Helper.SetActiveWindow(_hwndSrc.Handle); + // handled = true; + // } + + // } + // break; + // } + + // return IntPtr.Zero; + //} + + + #region Documents + + /// + /// Documents Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey DocumentsPropertyKey + = DependencyProperty.RegisterReadOnly("Documents", typeof(IEnumerable), typeof(NavigatorWindow), + new FrameworkPropertyMetadata(null)); + + public static readonly DependencyProperty DocumentsProperty + = DocumentsPropertyKey.DependencyProperty; + + /// + /// Gets the Documents property. This dependency property + /// indicates the list of documents. + /// + public LayoutDocumentItem[] Documents + { + get { return (LayoutDocumentItem[])GetValue(DocumentsProperty); } + } + + /// + /// Provides a secure method for setting the Documents property. + /// This dependency property indicates the list of documents. + /// + /// The new value for the property. + protected void SetDocuments(LayoutDocumentItem[] value) + { + SetValue(DocumentsPropertyKey, value); + } + + #endregion + + #region Anchorables + + /// + /// Anchorables Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey AnchorablesPropertyKey + = DependencyProperty.RegisterReadOnly("Anchorables", typeof(IEnumerable), typeof(NavigatorWindow), + new FrameworkPropertyMetadata((IEnumerable)null)); + + public static readonly DependencyProperty AnchorablesProperty + = AnchorablesPropertyKey.DependencyProperty; + + /// + /// Gets the Anchorables property. This dependency property + /// indicates the list of anchorables. + /// + public IEnumerable Anchorables + { + get { return (IEnumerable)GetValue(AnchorablesProperty); } + } + + /// + /// Provides a secure method for setting the Anchorables property. + /// This dependency property indicates the list of anchorables. + /// + /// The new value for the property. + protected void SetAnchorables(IEnumerable value) + { + SetValue(AnchorablesPropertyKey, value); + } + + #endregion + + #region SelectedDocument + + /// + /// SelectedDocument Dependency Property + /// + public static readonly DependencyProperty SelectedDocumentProperty = + DependencyProperty.Register("SelectedDocument", typeof(LayoutDocumentItem), typeof(NavigatorWindow), + new FrameworkPropertyMetadata((LayoutDocumentItem)null, + new PropertyChangedCallback(OnSelectedDocumentChanged))); + + /// + /// Gets or sets the SelectedDocument property. This dependency property + /// indicates the selected document. + /// + public LayoutDocumentItem SelectedDocument + { + get { return (LayoutDocumentItem)GetValue(SelectedDocumentProperty); } + set { SetValue(SelectedDocumentProperty, value); } + } + + /// + /// Handles changes to the SelectedDocument property. + /// + private static void OnSelectedDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((NavigatorWindow)d).OnSelectedDocumentChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the SelectedDocument property. + /// + protected virtual void OnSelectedDocumentChanged(DependencyPropertyChangedEventArgs e) + { + if (_internalSetSelectedDocument) + return; + + if (SelectedDocument != null && + SelectedDocument.ActivateCommand.CanExecute(null)) + { + SelectedDocument.ActivateCommand.Execute(null); + Hide(); + } + + } + + bool _internalSetSelectedDocument = false; + void InternalSetSelectedDocument(LayoutDocumentItem documentToSelect) + { + _internalSetSelectedDocument = true; + SelectedDocument = documentToSelect; + _internalSetSelectedDocument = false; + } + + #endregion + + #region SelectedAnchorable + + /// + /// SelectedAnchorable Dependency Property + /// + public static readonly DependencyProperty SelectedAnchorableProperty = + DependencyProperty.Register("SelectedAnchorable", typeof(LayoutAnchorableItem), typeof(NavigatorWindow), + new FrameworkPropertyMetadata((LayoutAnchorableItem)null, + new PropertyChangedCallback(OnSelectedAnchorableChanged))); + + /// + /// Gets or sets the SelectedAnchorable property. This dependency property + /// indicates the selected anchorable. + /// + public LayoutAnchorableItem SelectedAnchorable + { + get { return (LayoutAnchorableItem)GetValue(SelectedAnchorableProperty); } + set { SetValue(SelectedAnchorableProperty, value); } + } + + /// + /// Handles changes to the SelectedAnchorable property. + /// + private static void OnSelectedAnchorableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((NavigatorWindow)d).OnSelectedAnchorableChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the SelectedAnchorable property. + /// + protected virtual void OnSelectedAnchorableChanged(DependencyPropertyChangedEventArgs e) + { + var selectedAnchorable = e.NewValue as LayoutAnchorableItem; + if (SelectedAnchorable != null && + SelectedAnchorable.ActivateCommand.CanExecute(null)) + { + SelectedAnchorable.ActivateCommand.Execute(null); + Close(); + } + } + + #endregion + + + internal void SelectNextDocument() + { + if (SelectedDocument != null) + { + int docIndex = Documents.IndexOf(SelectedDocument); + docIndex++; + if (docIndex == Documents.Length) + docIndex = 0; + InternalSetSelectedDocument(Documents[docIndex]); + } + + } + + protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e) + { + base.OnKeyDown(e); + } + + protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e) + { + if (e.Key == System.Windows.Input.Key.Tab) + { + SelectNextDocument(); + e.Handled = true; + } + + + base.OnPreviewKeyDown(e); + } + + protected override void OnPreviewKeyUp(System.Windows.Input.KeyEventArgs e) + { + if (e.Key != System.Windows.Input.Key.Tab) + { + if (SelectedAnchorable != null && + SelectedAnchorable.ActivateCommand.CanExecute(null)) + SelectedAnchorable.ActivateCommand.Execute(null); + + if (SelectedAnchorable == null && + SelectedDocument != null && + SelectedDocument.ActivateCommand.CanExecute(null)) + SelectedDocument.ActivateCommand.Execute(null); + Close(); + e.Handled = true; + } + + + base.OnPreviewKeyUp(e); + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/OverlayArea.cs b/Src/Xceed.Wpf.AvalonDock/Controls/OverlayArea.cs new file mode 100644 index 0000000..13e0db0 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/OverlayArea.cs @@ -0,0 +1,54 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public abstract class OverlayArea : IOverlayWindowArea + { + internal OverlayArea(IOverlayWindow overlayWindow) + { + _overlayWindow = overlayWindow; + } + + IOverlayWindow _overlayWindow; + + Rect? _screenDetectionArea; + Rect IOverlayWindowArea.ScreenDetectionArea + { + get + { + return _screenDetectionArea.Value; + } + } + + protected void SetScreenDetectionArea(Rect rect) + { + _screenDetectionArea = rect; + } + + + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/OverlayWindow.cs b/Src/Xceed.Wpf.AvalonDock/Controls/OverlayWindow.cs new file mode 100644 index 0000000..3e53569 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/OverlayWindow.cs @@ -0,0 +1,579 @@ +/************************************************************************************* + + 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; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Shapes; +using Xceed.Wpf.AvalonDock.Layout; +using System.Diagnostics; +using Xceed.Wpf.AvalonDock.Themes; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class OverlayWindow : Window, IOverlayWindow + { + private ResourceDictionary currentThemeResourceDictionary; // = null + + static OverlayWindow() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(OverlayWindow), new FrameworkPropertyMetadata(typeof(OverlayWindow))); + + OverlayWindow.AllowsTransparencyProperty.OverrideMetadata(typeof(OverlayWindow), new FrameworkPropertyMetadata(true)); + OverlayWindow.WindowStyleProperty.OverrideMetadata(typeof(OverlayWindow), new FrameworkPropertyMetadata(WindowStyle.None)); + OverlayWindow.ShowInTaskbarProperty.OverrideMetadata(typeof(OverlayWindow), new FrameworkPropertyMetadata(false)); + OverlayWindow.ShowActivatedProperty.OverrideMetadata(typeof(OverlayWindow), new FrameworkPropertyMetadata(false)); + OverlayWindow.VisibilityProperty.OverrideMetadata(typeof(OverlayWindow), new FrameworkPropertyMetadata(Visibility.Hidden)); + } + + + internal OverlayWindow(IOverlayWindowHost host) + { + _host = host; + UpdateThemeResources(); + } + + + internal void UpdateThemeResources(Theme oldTheme = null) + { + if (oldTheme != null) + { + if( oldTheme is DictionaryTheme ) + { + if( currentThemeResourceDictionary != null ) + { + Resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); + currentThemeResourceDictionary = null; + } + } + else + { + var resourceDictionaryToRemove = + Resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); + if( resourceDictionaryToRemove != null ) + Resources.MergedDictionaries.Remove( + resourceDictionaryToRemove ); + } + } + + if (_host.Manager.Theme != null) + { + if( _host.Manager.Theme is DictionaryTheme ) + { + currentThemeResourceDictionary = ( ( DictionaryTheme )_host.Manager.Theme ).ThemeResourceDictionary; + Resources.MergedDictionaries.Add( currentThemeResourceDictionary ); + } + else + { + Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = _host.Manager.Theme.GetResourceUri() }); + } + } + } + + + Canvas _mainCanvasPanel; + Grid _gridDockingManagerDropTargets; + Grid _gridAnchorablePaneDropTargets; + Grid _gridDocumentPaneDropTargets; + Grid _gridDocumentPaneFullDropTargets; + + FrameworkElement _dockingManagerDropTargetBottom; + FrameworkElement _dockingManagerDropTargetTop; + FrameworkElement _dockingManagerDropTargetLeft; + FrameworkElement _dockingManagerDropTargetRight; + + FrameworkElement _anchorablePaneDropTargetBottom; + FrameworkElement _anchorablePaneDropTargetTop; + FrameworkElement _anchorablePaneDropTargetLeft; + FrameworkElement _anchorablePaneDropTargetRight; + FrameworkElement _anchorablePaneDropTargetInto; + + FrameworkElement _documentPaneDropTargetBottom; + FrameworkElement _documentPaneDropTargetTop; + FrameworkElement _documentPaneDropTargetLeft; + FrameworkElement _documentPaneDropTargetRight; + FrameworkElement _documentPaneDropTargetInto; + + FrameworkElement _documentPaneDropTargetBottomAsAnchorablePane; + FrameworkElement _documentPaneDropTargetTopAsAnchorablePane; + FrameworkElement _documentPaneDropTargetLeftAsAnchorablePane; + FrameworkElement _documentPaneDropTargetRightAsAnchorablePane; + + FrameworkElement _documentPaneFullDropTargetBottom; + FrameworkElement _documentPaneFullDropTargetTop; + FrameworkElement _documentPaneFullDropTargetLeft; + FrameworkElement _documentPaneFullDropTargetRight; + FrameworkElement _documentPaneFullDropTargetInto; + + Path _previewBox; + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _mainCanvasPanel = GetTemplateChild("PART_DropTargetsContainer") as Canvas; + _gridDockingManagerDropTargets = GetTemplateChild("PART_DockingManagerDropTargets") as Grid; + _gridAnchorablePaneDropTargets = GetTemplateChild("PART_AnchorablePaneDropTargets") as Grid; + _gridDocumentPaneDropTargets = GetTemplateChild("PART_DocumentPaneDropTargets") as Grid; + _gridDocumentPaneFullDropTargets = GetTemplateChild("PART_DocumentPaneFullDropTargets") as Grid; + + _gridDockingManagerDropTargets.Visibility = System.Windows.Visibility.Hidden; + _gridAnchorablePaneDropTargets.Visibility = System.Windows.Visibility.Hidden; + _gridDocumentPaneDropTargets.Visibility = System.Windows.Visibility.Hidden; + if (_gridDocumentPaneFullDropTargets != null) + _gridDocumentPaneFullDropTargets.Visibility = System.Windows.Visibility.Hidden; + + _dockingManagerDropTargetBottom = GetTemplateChild("PART_DockingManagerDropTargetBottom") as FrameworkElement; + _dockingManagerDropTargetTop = GetTemplateChild("PART_DockingManagerDropTargetTop") as FrameworkElement; + _dockingManagerDropTargetLeft = GetTemplateChild("PART_DockingManagerDropTargetLeft") as FrameworkElement; + _dockingManagerDropTargetRight = GetTemplateChild("PART_DockingManagerDropTargetRight") as FrameworkElement; + + _anchorablePaneDropTargetBottom = GetTemplateChild("PART_AnchorablePaneDropTargetBottom") as FrameworkElement; + _anchorablePaneDropTargetTop = GetTemplateChild("PART_AnchorablePaneDropTargetTop") as FrameworkElement; + _anchorablePaneDropTargetLeft = GetTemplateChild("PART_AnchorablePaneDropTargetLeft") as FrameworkElement; + _anchorablePaneDropTargetRight = GetTemplateChild("PART_AnchorablePaneDropTargetRight") as FrameworkElement; + _anchorablePaneDropTargetInto = GetTemplateChild("PART_AnchorablePaneDropTargetInto") as FrameworkElement; + + _documentPaneDropTargetBottom = GetTemplateChild("PART_DocumentPaneDropTargetBottom") as FrameworkElement; + _documentPaneDropTargetTop = GetTemplateChild("PART_DocumentPaneDropTargetTop") as FrameworkElement; + _documentPaneDropTargetLeft = GetTemplateChild("PART_DocumentPaneDropTargetLeft") as FrameworkElement; + _documentPaneDropTargetRight = GetTemplateChild("PART_DocumentPaneDropTargetRight") as FrameworkElement; + _documentPaneDropTargetInto = GetTemplateChild("PART_DocumentPaneDropTargetInto") as FrameworkElement; + + _documentPaneDropTargetBottomAsAnchorablePane = GetTemplateChild("PART_DocumentPaneDropTargetBottomAsAnchorablePane") as FrameworkElement; + _documentPaneDropTargetTopAsAnchorablePane = GetTemplateChild("PART_DocumentPaneDropTargetTopAsAnchorablePane") as FrameworkElement; + _documentPaneDropTargetLeftAsAnchorablePane = GetTemplateChild("PART_DocumentPaneDropTargetLeftAsAnchorablePane") as FrameworkElement; + _documentPaneDropTargetRightAsAnchorablePane = GetTemplateChild("PART_DocumentPaneDropTargetRightAsAnchorablePane") as FrameworkElement; + + _documentPaneFullDropTargetBottom = GetTemplateChild("PART_DocumentPaneFullDropTargetBottom") as FrameworkElement; + _documentPaneFullDropTargetTop = GetTemplateChild("PART_DocumentPaneFullDropTargetTop") as FrameworkElement; + _documentPaneFullDropTargetLeft = GetTemplateChild("PART_DocumentPaneFullDropTargetLeft") as FrameworkElement; + _documentPaneFullDropTargetRight = GetTemplateChild("PART_DocumentPaneFullDropTargetRight") as FrameworkElement; + _documentPaneFullDropTargetInto = GetTemplateChild("PART_DocumentPaneFullDropTargetInto") as FrameworkElement; + + _previewBox = GetTemplateChild("PART_PreviewBox") as Path; + } + + + internal void EnableDropTargets() + { + if (_mainCanvasPanel != null) + _mainCanvasPanel.Visibility = System.Windows.Visibility.Visible; + } + + internal void HideDropTargets() + { + if (_mainCanvasPanel != null) + _mainCanvasPanel.Visibility = System.Windows.Visibility.Hidden; + + } + + IOverlayWindowHost _host; + + IEnumerable IOverlayWindow.GetTargets() + { + foreach (var visibleArea in _visibleAreas) + { + switch (visibleArea.Type) + { + case DropAreaType.DockingManager: + { + var dropAreaDockingManager = visibleArea as DropArea; + yield return new DockingManagerDropTarget(dropAreaDockingManager.AreaElement, _dockingManagerDropTargetLeft.GetScreenArea(), DropTargetType.DockingManagerDockLeft); + yield return new DockingManagerDropTarget(dropAreaDockingManager.AreaElement, _dockingManagerDropTargetTop.GetScreenArea(), DropTargetType.DockingManagerDockTop); + yield return new DockingManagerDropTarget(dropAreaDockingManager.AreaElement, _dockingManagerDropTargetBottom.GetScreenArea(), DropTargetType.DockingManagerDockBottom); + yield return new DockingManagerDropTarget(dropAreaDockingManager.AreaElement, _dockingManagerDropTargetRight.GetScreenArea(), DropTargetType.DockingManagerDockRight); + } + break; + case DropAreaType.AnchorablePane: + { + var dropAreaAnchorablePane = visibleArea as DropArea; + yield return new AnchorablePaneDropTarget(dropAreaAnchorablePane.AreaElement, _anchorablePaneDropTargetLeft.GetScreenArea(), DropTargetType.AnchorablePaneDockLeft); + yield return new AnchorablePaneDropTarget(dropAreaAnchorablePane.AreaElement, _anchorablePaneDropTargetTop.GetScreenArea(), DropTargetType.AnchorablePaneDockTop); + yield return new AnchorablePaneDropTarget(dropAreaAnchorablePane.AreaElement, _anchorablePaneDropTargetRight.GetScreenArea(), DropTargetType.AnchorablePaneDockRight); + yield return new AnchorablePaneDropTarget(dropAreaAnchorablePane.AreaElement, _anchorablePaneDropTargetBottom.GetScreenArea(), DropTargetType.AnchorablePaneDockBottom); + yield return new AnchorablePaneDropTarget(dropAreaAnchorablePane.AreaElement, _anchorablePaneDropTargetInto.GetScreenArea(), DropTargetType.AnchorablePaneDockInside); + + var parentPaneModel = dropAreaAnchorablePane.AreaElement.Model as LayoutAnchorablePane; + LayoutAnchorableTabItem lastAreaTabItem = null; + foreach (var dropAreaTabItem in dropAreaAnchorablePane.AreaElement.FindVisualChildren()) + { + var tabItemModel = dropAreaTabItem.Model as LayoutAnchorable; + lastAreaTabItem = lastAreaTabItem == null || lastAreaTabItem.GetScreenArea().Right < dropAreaTabItem.GetScreenArea().Right ? + dropAreaTabItem : lastAreaTabItem; + int tabIndex = parentPaneModel.Children.IndexOf(tabItemModel); + yield return new AnchorablePaneDropTarget(dropAreaAnchorablePane.AreaElement, dropAreaTabItem.GetScreenArea(), DropTargetType.AnchorablePaneDockInside, tabIndex); + } + + if (lastAreaTabItem != null) + { + var lastAreaTabItemScreenArea = lastAreaTabItem.GetScreenArea(); + var newAreaTabItemScreenArea = new Rect(lastAreaTabItemScreenArea.TopRight, new Point(lastAreaTabItemScreenArea.Right + lastAreaTabItemScreenArea.Width, lastAreaTabItemScreenArea.Bottom)); + if (newAreaTabItemScreenArea.Right < dropAreaAnchorablePane.AreaElement.GetScreenArea().Right) + yield return new AnchorablePaneDropTarget(dropAreaAnchorablePane.AreaElement, newAreaTabItemScreenArea, DropTargetType.AnchorablePaneDockInside, parentPaneModel.Children.Count); + } + + var dropAreaTitle = dropAreaAnchorablePane.AreaElement.FindVisualChildren().FirstOrDefault(); + if (dropAreaTitle != null) + yield return new AnchorablePaneDropTarget(dropAreaAnchorablePane.AreaElement, dropAreaTitle.GetScreenArea(), DropTargetType.AnchorablePaneDockInside); + } + break; + case DropAreaType.DocumentPane: + { + bool isDraggingAnchorables = _floatingWindow.Model is LayoutAnchorableFloatingWindow; + if (isDraggingAnchorables && _gridDocumentPaneFullDropTargets != null) + { + var dropAreaDocumentPane = visibleArea as DropArea; + if (_documentPaneFullDropTargetLeft.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneFullDropTargetLeft.GetScreenArea(), DropTargetType.DocumentPaneDockLeft); + if (_documentPaneFullDropTargetTop.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneFullDropTargetTop.GetScreenArea(), DropTargetType.DocumentPaneDockTop); + if (_documentPaneFullDropTargetRight.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneFullDropTargetRight.GetScreenArea(), DropTargetType.DocumentPaneDockRight); + if (_documentPaneFullDropTargetBottom.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneFullDropTargetBottom.GetScreenArea(), DropTargetType.DocumentPaneDockBottom); + if (_documentPaneFullDropTargetInto.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneFullDropTargetInto.GetScreenArea(), DropTargetType.DocumentPaneDockInside); + + var parentPaneModel = dropAreaDocumentPane.AreaElement.Model as LayoutDocumentPane; + LayoutDocumentTabItem lastAreaTabItem = null; + foreach (var dropAreaTabItem in dropAreaDocumentPane.AreaElement.FindVisualChildren()) + { + var tabItemModel = dropAreaTabItem.Model; + lastAreaTabItem = lastAreaTabItem == null || lastAreaTabItem.GetScreenArea().Right < dropAreaTabItem.GetScreenArea().Right ? + dropAreaTabItem : lastAreaTabItem; + int tabIndex = parentPaneModel.Children.IndexOf(tabItemModel); + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, dropAreaTabItem.GetScreenArea(), DropTargetType.DocumentPaneDockInside, tabIndex); + } + + if (lastAreaTabItem != null) + { + var lastAreaTabItemScreenArea = lastAreaTabItem.GetScreenArea(); + var newAreaTabItemScreenArea = new Rect(lastAreaTabItemScreenArea.TopRight, new Point(lastAreaTabItemScreenArea.Right + lastAreaTabItemScreenArea.Width, lastAreaTabItemScreenArea.Bottom)); + if (newAreaTabItemScreenArea.Right < dropAreaDocumentPane.AreaElement.GetScreenArea().Right) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, newAreaTabItemScreenArea, DropTargetType.DocumentPaneDockInside, parentPaneModel.Children.Count); + } + + if (_documentPaneDropTargetLeftAsAnchorablePane.IsVisible) + yield return new DocumentPaneDropAsAnchorableTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetLeftAsAnchorablePane.GetScreenArea(), DropTargetType.DocumentPaneDockAsAnchorableLeft); + if (_documentPaneDropTargetTopAsAnchorablePane.IsVisible) + yield return new DocumentPaneDropAsAnchorableTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetTopAsAnchorablePane.GetScreenArea(), DropTargetType.DocumentPaneDockAsAnchorableTop); + if (_documentPaneDropTargetRightAsAnchorablePane.IsVisible) + yield return new DocumentPaneDropAsAnchorableTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetRightAsAnchorablePane.GetScreenArea(), DropTargetType.DocumentPaneDockAsAnchorableRight); + if (_documentPaneDropTargetBottomAsAnchorablePane.IsVisible) + yield return new DocumentPaneDropAsAnchorableTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetBottomAsAnchorablePane.GetScreenArea(), DropTargetType.DocumentPaneDockAsAnchorableBottom); + } + else + { + + var dropAreaDocumentPane = visibleArea as DropArea; + if (_documentPaneDropTargetLeft.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetLeft.GetScreenArea(), DropTargetType.DocumentPaneDockLeft); + if (_documentPaneDropTargetTop.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetTop.GetScreenArea(), DropTargetType.DocumentPaneDockTop); + if (_documentPaneDropTargetRight.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetRight.GetScreenArea(), DropTargetType.DocumentPaneDockRight); + if (_documentPaneDropTargetBottom.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetBottom.GetScreenArea(), DropTargetType.DocumentPaneDockBottom); + if (_documentPaneDropTargetInto.IsVisible) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetInto.GetScreenArea(), DropTargetType.DocumentPaneDockInside); + + var parentPaneModel = dropAreaDocumentPane.AreaElement.Model as LayoutDocumentPane; + LayoutDocumentTabItem lastAreaTabItem = null; + foreach (var dropAreaTabItem in dropAreaDocumentPane.AreaElement.FindVisualChildren()) + { + var tabItemModel = dropAreaTabItem.Model; + lastAreaTabItem = lastAreaTabItem == null || lastAreaTabItem.GetScreenArea().Right < dropAreaTabItem.GetScreenArea().Right ? + dropAreaTabItem : lastAreaTabItem; + int tabIndex = parentPaneModel.Children.IndexOf(tabItemModel); + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, dropAreaTabItem.GetScreenArea(), DropTargetType.DocumentPaneDockInside, tabIndex); + } + + if (lastAreaTabItem != null) + { + var lastAreaTabItemScreenArea = lastAreaTabItem.GetScreenArea(); + var newAreaTabItemScreenArea = new Rect(lastAreaTabItemScreenArea.TopRight, new Point(lastAreaTabItemScreenArea.Right + lastAreaTabItemScreenArea.Width, lastAreaTabItemScreenArea.Bottom)); + if (newAreaTabItemScreenArea.Right < dropAreaDocumentPane.AreaElement.GetScreenArea().Right) + yield return new DocumentPaneDropTarget(dropAreaDocumentPane.AreaElement, newAreaTabItemScreenArea, DropTargetType.DocumentPaneDockInside, parentPaneModel.Children.Count); + } + } + } + break; + case DropAreaType.DocumentPaneGroup: + { + var dropAreaDocumentPane = visibleArea as DropArea; + if (_documentPaneDropTargetInto.IsVisible) + yield return new DocumentPaneGroupDropTarget(dropAreaDocumentPane.AreaElement, _documentPaneDropTargetInto.GetScreenArea(), DropTargetType.DocumentPaneGroupDockInside); + } + break; + } + + } + yield break; + } + + LayoutFloatingWindowControl _floatingWindow = null; + void IOverlayWindow.DragEnter(LayoutFloatingWindowControl floatingWindow) + { + _floatingWindow = floatingWindow; + EnableDropTargets(); + } + + void IOverlayWindow.DragLeave(LayoutFloatingWindowControl floatingWindow) + { + Visibility = System.Windows.Visibility.Hidden; + _floatingWindow = null; + } + + protected override void OnClosing(System.ComponentModel.CancelEventArgs e) + { + base.OnClosing(e); + } + + + List _visibleAreas = new List(); + void IOverlayWindow.DragEnter(IDropArea area) + { + _visibleAreas.Add(area); + + FrameworkElement areaElement; + switch (area.Type) + { + case DropAreaType.DockingManager: + areaElement = _gridDockingManagerDropTargets; + break; + case DropAreaType.AnchorablePane: + areaElement = _gridAnchorablePaneDropTargets; + break; + case DropAreaType.DocumentPaneGroup: + { + areaElement = _gridDocumentPaneDropTargets; + var dropAreaDocumentPaneGroup = area as DropArea; + var layoutDocumentPane = (dropAreaDocumentPaneGroup.AreaElement.Model as LayoutDocumentPaneGroup).Children.First() as LayoutDocumentPane; + var parentDocumentPaneGroup = layoutDocumentPane.Parent as LayoutDocumentPaneGroup; + + _documentPaneDropTargetLeft.Visibility = Visibility.Hidden; + _documentPaneDropTargetRight.Visibility = Visibility.Hidden; + _documentPaneDropTargetTop.Visibility = Visibility.Hidden; + _documentPaneDropTargetBottom.Visibility = Visibility.Hidden; + } + break; + case DropAreaType.DocumentPane: + default: + { + bool isDraggingAnchorables = _floatingWindow.Model is LayoutAnchorableFloatingWindow; + if (isDraggingAnchorables && _gridDocumentPaneFullDropTargets != null) + { + areaElement = _gridDocumentPaneFullDropTargets; + var dropAreaDocumentPaneGroup = area as DropArea; + var layoutDocumentPane = dropAreaDocumentPaneGroup.AreaElement.Model as LayoutDocumentPane; + var parentDocumentPaneGroup = layoutDocumentPane.Parent as LayoutDocumentPaneGroup; + + if (parentDocumentPaneGroup != null && + parentDocumentPaneGroup.Children.Where(c => c.IsVisible).Count() > 1) + { + var manager = parentDocumentPaneGroup.Root.Manager; + if (!manager.AllowMixedOrientation) + { + _documentPaneFullDropTargetLeft.Visibility = parentDocumentPaneGroup.Orientation == Orientation.Horizontal ? Visibility.Visible : Visibility.Hidden; + _documentPaneFullDropTargetRight.Visibility = parentDocumentPaneGroup.Orientation == Orientation.Horizontal ? Visibility.Visible : Visibility.Hidden; + _documentPaneFullDropTargetTop.Visibility = parentDocumentPaneGroup.Orientation == Orientation.Vertical ? Visibility.Visible : Visibility.Hidden; + _documentPaneFullDropTargetBottom.Visibility = parentDocumentPaneGroup.Orientation == Orientation.Vertical ? Visibility.Visible : Visibility.Hidden; + } + else + { + _documentPaneFullDropTargetLeft.Visibility = Visibility.Visible; + _documentPaneFullDropTargetRight.Visibility = Visibility.Visible; + _documentPaneFullDropTargetTop.Visibility = Visibility.Visible; + _documentPaneFullDropTargetBottom.Visibility = Visibility.Visible; + } + } + else if (parentDocumentPaneGroup == null && + layoutDocumentPane != null && + layoutDocumentPane.ChildrenCount == 0) + { + _documentPaneFullDropTargetLeft.Visibility = Visibility.Hidden; + _documentPaneFullDropTargetRight.Visibility = Visibility.Hidden; + _documentPaneFullDropTargetTop.Visibility = Visibility.Hidden; + _documentPaneFullDropTargetBottom.Visibility = Visibility.Hidden; + } + else + { + _documentPaneFullDropTargetLeft.Visibility = Visibility.Visible; + _documentPaneFullDropTargetRight.Visibility = Visibility.Visible; + _documentPaneFullDropTargetTop.Visibility = Visibility.Visible; + _documentPaneFullDropTargetBottom.Visibility = Visibility.Visible; + } + + if (parentDocumentPaneGroup != null && + parentDocumentPaneGroup.Children.Where(c => c.IsVisible).Count() > 1) + { + int indexOfDocumentPane = parentDocumentPaneGroup.Children.Where(ch => ch.IsVisible).ToList().IndexOf(layoutDocumentPane); + bool isFirstChild = indexOfDocumentPane == 0; + bool isLastChild = indexOfDocumentPane == parentDocumentPaneGroup.ChildrenCount - 1; + + var manager = parentDocumentPaneGroup.Root.Manager; + if (!manager.AllowMixedOrientation) + { + _documentPaneDropTargetBottomAsAnchorablePane.Visibility = + parentDocumentPaneGroup.Orientation == Orientation.Vertical ? + (isLastChild ? System.Windows.Visibility.Visible : System.Windows.Visibility.Hidden) : + System.Windows.Visibility.Hidden; + _documentPaneDropTargetTopAsAnchorablePane.Visibility = + parentDocumentPaneGroup.Orientation == Orientation.Vertical ? + (isFirstChild ? System.Windows.Visibility.Visible : System.Windows.Visibility.Hidden) : + System.Windows.Visibility.Hidden; + + _documentPaneDropTargetLeftAsAnchorablePane.Visibility = + parentDocumentPaneGroup.Orientation == Orientation.Horizontal ? + (isFirstChild ? System.Windows.Visibility.Visible : System.Windows.Visibility.Hidden) : + System.Windows.Visibility.Hidden; + + + _documentPaneDropTargetRightAsAnchorablePane.Visibility = + parentDocumentPaneGroup.Orientation == Orientation.Horizontal ? + (isLastChild ? System.Windows.Visibility.Visible : System.Windows.Visibility.Hidden) : + System.Windows.Visibility.Hidden; + } + else + { + _documentPaneDropTargetBottomAsAnchorablePane.Visibility = System.Windows.Visibility.Visible; + _documentPaneDropTargetLeftAsAnchorablePane.Visibility = System.Windows.Visibility.Visible; + _documentPaneDropTargetRightAsAnchorablePane.Visibility = System.Windows.Visibility.Visible; + _documentPaneDropTargetTopAsAnchorablePane.Visibility = System.Windows.Visibility.Visible; + } + } + else + { + _documentPaneDropTargetBottomAsAnchorablePane.Visibility = System.Windows.Visibility.Visible; + _documentPaneDropTargetLeftAsAnchorablePane.Visibility = System.Windows.Visibility.Visible; + _documentPaneDropTargetRightAsAnchorablePane.Visibility = System.Windows.Visibility.Visible; + _documentPaneDropTargetTopAsAnchorablePane.Visibility = System.Windows.Visibility.Visible; + } + } + else + { + areaElement = _gridDocumentPaneDropTargets; + var dropAreaDocumentPaneGroup = area as DropArea; + var layoutDocumentPane = dropAreaDocumentPaneGroup.AreaElement.Model as LayoutDocumentPane; + var parentDocumentPaneGroup = layoutDocumentPane.Parent as LayoutDocumentPaneGroup; + + if (parentDocumentPaneGroup != null && + parentDocumentPaneGroup.Children.Where(c => c.IsVisible).Count() > 1) + { + var manager = parentDocumentPaneGroup.Root.Manager; + if (!manager.AllowMixedOrientation) + { + _documentPaneDropTargetLeft.Visibility = parentDocumentPaneGroup.Orientation == Orientation.Horizontal ? Visibility.Visible : Visibility.Hidden; + _documentPaneDropTargetRight.Visibility = parentDocumentPaneGroup.Orientation == Orientation.Horizontal ? Visibility.Visible : Visibility.Hidden; + _documentPaneDropTargetTop.Visibility = parentDocumentPaneGroup.Orientation == Orientation.Vertical ? Visibility.Visible : Visibility.Hidden; + _documentPaneDropTargetBottom.Visibility = parentDocumentPaneGroup.Orientation == Orientation.Vertical ? Visibility.Visible : Visibility.Hidden; + } + else + { + _documentPaneDropTargetLeft.Visibility = Visibility.Visible; + _documentPaneDropTargetRight.Visibility = Visibility.Visible; + _documentPaneDropTargetTop.Visibility = Visibility.Visible; + _documentPaneDropTargetBottom.Visibility = Visibility.Visible; + } + + } + else if (parentDocumentPaneGroup == null && + layoutDocumentPane != null && + layoutDocumentPane.ChildrenCount == 0) + { + _documentPaneDropTargetLeft.Visibility = Visibility.Hidden; + _documentPaneDropTargetRight.Visibility = Visibility.Hidden; + _documentPaneDropTargetTop.Visibility = Visibility.Hidden; + _documentPaneDropTargetBottom.Visibility = Visibility.Hidden; + } + else + { + _documentPaneDropTargetLeft.Visibility = Visibility.Visible; + _documentPaneDropTargetRight.Visibility = Visibility.Visible; + _documentPaneDropTargetTop.Visibility = Visibility.Visible; + _documentPaneDropTargetBottom.Visibility = Visibility.Visible; + } + } + } + break; + } + + Canvas.SetLeft(areaElement, area.DetectionRect.Left - Left); + Canvas.SetTop(areaElement, area.DetectionRect.Top - Top); + areaElement.Width = area.DetectionRect.Width; + areaElement.Height = area.DetectionRect.Height; + areaElement.Visibility = System.Windows.Visibility.Visible; + } + + void IOverlayWindow.DragLeave(IDropArea area) + { + _visibleAreas.Remove(area); + + FrameworkElement areaElement; + switch (area.Type) + { + case DropAreaType.DockingManager: + areaElement = _gridDockingManagerDropTargets; + break; + case DropAreaType.AnchorablePane: + areaElement = _gridAnchorablePaneDropTargets; + break; + case DropAreaType.DocumentPaneGroup: + areaElement = _gridDocumentPaneDropTargets; + break; + case DropAreaType.DocumentPane: + default: + { + bool isDraggingAnchorables = _floatingWindow.Model is LayoutAnchorableFloatingWindow; + if (isDraggingAnchorables && _gridDocumentPaneFullDropTargets != null) + areaElement = _gridDocumentPaneFullDropTargets; + else + areaElement = _gridDocumentPaneDropTargets; + } + break; + } + + areaElement.Visibility = System.Windows.Visibility.Hidden; + } + + void IOverlayWindow.DragEnter(IDropTarget target) + { + var previewBoxPath = target.GetPreviewPath(this, _floatingWindow.Model as LayoutFloatingWindow); + if (previewBoxPath != null) + { + _previewBox.Data = previewBoxPath; + _previewBox.Visibility = System.Windows.Visibility.Visible; + } + } + + void IOverlayWindow.DragLeave(IDropTarget target) + { + _previewBox.Visibility = System.Windows.Visibility.Hidden; + } + + void IOverlayWindow.DragDrop(IDropTarget target) + { + target.Drop(_floatingWindow.Model as LayoutFloatingWindow); + } + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/OverlayWindowDropTarget.cs b/Src/Xceed.Wpf.AvalonDock/Controls/OverlayWindowDropTarget.cs new file mode 100644 index 0000000..11ca072 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/OverlayWindowDropTarget.cs @@ -0,0 +1,55 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public class OverlayWindowDropTarget : IOverlayWindowDropTarget + { + internal OverlayWindowDropTarget(IOverlayWindowArea overlayArea, OverlayWindowDropTargetType targetType, FrameworkElement element) + { + _overlayArea = overlayArea; + _type = targetType; + _screenDetectionArea = new Rect(element.TransformToDeviceDPI(new Point()), element.TransformActualSizeToAncestor()); + } + + IOverlayWindowArea _overlayArea; + + Rect _screenDetectionArea; + Rect IOverlayWindowDropTarget.ScreenDetectionArea + { + get + { + return _screenDetectionArea; + } + + } + + OverlayWindowDropTargetType _type; + OverlayWindowDropTargetType IOverlayWindowDropTarget.Type + { + get { return _type; } + } + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/OverlayWindowDropTargetType.cs b/Src/Xceed.Wpf.AvalonDock/Controls/OverlayWindowDropTargetType.cs new file mode 100644 index 0000000..581d46c --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/OverlayWindowDropTargetType.cs @@ -0,0 +1,44 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + public enum OverlayWindowDropTargetType + { + DockingManagerDockLeft, + DockingManagerDockTop, + DockingManagerDockRight, + DockingManagerDockBottom, + + DocumentPaneDockLeft, + DocumentPaneDockTop, + DocumentPaneDockRight, + DocumentPaneDockBottom, + DocumentPaneDockInside, + + AnchorablePaneDockLeft, + AnchorablePaneDockTop, + AnchorablePaneDockRight, + AnchorablePaneDockBottom, + AnchorablePaneDockInside, + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/ReentrantFlag.cs b/Src/Xceed.Wpf.AvalonDock/Controls/ReentrantFlag.cs new file mode 100644 index 0000000..2395cef --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/ReentrantFlag.cs @@ -0,0 +1,56 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + class ReentrantFlag + { + public class _ReentrantFlagHandler : IDisposable + { + ReentrantFlag _owner; + public _ReentrantFlagHandler(ReentrantFlag owner) + { + _owner = owner; + _owner._flag = true; + } + + public void Dispose() + { + _owner._flag = false; + } + } + + bool _flag = false; + + public _ReentrantFlagHandler Enter() + { + if (_flag) + throw new InvalidOperationException(); + return new _ReentrantFlagHandler(this); + } + + public bool CanEnter + { + get { return !_flag; } + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/ComGuids.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/ComGuids.cs new file mode 100644 index 0000000..d591008 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/ComGuids.cs @@ -0,0 +1,111 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + internal static partial class IID + { + /// IID_IEnumIDList + public const string EnumIdList = "000214F2-0000-0000-C000-000000000046"; + /// IID_IEnumObjects + public const string EnumObjects = "2c1c7e2e-2d0e-4059-831e-1e6f82335c2e"; + /// IID_IHTMLDocument2 + public const string HtmlDocument2 = "332C4425-26CB-11D0-B483-00C04FD90119"; + /// IID_IModalWindow + public const string ModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802"; + /// IID_IObjectArray + public const string ObjectArray = "92CA9DCD-5622-4bba-A805-5E9F541BD8C9"; + /// IID_IObjectCollection + public const string ObjectCollection = "5632b1a4-e38a-400a-928a-d4cd63230295"; + /// IID_IPropertyNotifySink + public const string PropertyNotifySink = "9BFBBC02-EFF1-101A-84ED-00AA00341D07"; + /// IID_IPropertyStore + public const string PropertyStore = "886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"; + /// IID_IServiceProvider + public const string ServiceProvider = "6d5140c1-7436-11ce-8034-00aa006009fa"; + /// IID_IShellFolder + public const string ShellFolder = "000214E6-0000-0000-C000-000000000046"; + /// IID_IShellLink + public const string ShellLink = "000214F9-0000-0000-C000-000000000046"; + /// IID_IShellItem + public const string ShellItem = "43826d1e-e718-42ee-bc55-a1e261c37bfe"; + /// IID_IShellItem2 + public const string ShellItem2 = "7e9fb0d3-919f-4307-ab2e-9b1860310c93"; + /// IID_IShellItemArray + public const string ShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B"; + /// IID_ITaskbarList + public const string TaskbarList = "56FDF342-FD6D-11d0-958A-006097C9A090"; + /// IID_ITaskbarList2 + public const string TaskbarList2 = "602D4995-B13A-429b-A66E-1935E44F4317"; + /// IID_IUnknown + public const string Unknown = "00000000-0000-0000-C000-000000000046"; + + #region Win7 IIDs + + /// IID_IApplicationDestinations + public const string ApplicationDestinations = "12337d35-94c6-48a0-bce7-6a9c69d4d600"; + /// IID_IApplicationDocumentLists + public const string ApplicationDocumentLists = "3c594f9f-9f30-47a1-979a-c9e83d3d0a06"; + /// IID_ICustomDestinationList + public const string CustomDestinationList = "6332debf-87b5-4670-90c0-5e57b408a49e"; + /// IID_IObjectWithAppUserModelID + public const string ObjectWithAppUserModelId = "36db0196-9665-46d1-9ba7-d3709eecf9ed"; + /// IID_IObjectWithProgID + public const string ObjectWithProgId = "71e806fb-8dee-46fc-bf8c-7748a8a1ae13"; + /// IID_ITaskbarList3 + public const string TaskbarList3 = "ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf"; + /// IID_ITaskbarList4 + public const string TaskbarList4 = "c43dc798-95d1-4bea-9030-bb99e2983a1a"; + + #endregion + } + + internal static partial class CLSID + { + public static T CoCreateInstance(string clsid) + { + return (T)System.Activator.CreateInstance(System.Type.GetTypeFromCLSID(new System.Guid(clsid))); + } + + /// CLSID_TaskbarList + /// IID_ITaskbarList + public const string TaskbarList = "56FDF344-FD6D-11d0-958A-006097C9A090"; + /// CLSID_EnumerableObjectCollection + /// IID_IEnumObjects. + public const string EnumerableObjectCollection = "2d3468c1-36a7-43b6-ac24-d3f02fd9607a"; + /// CLSID_ShellLink + /// IID_IShellLink + public const string ShellLink = "00021401-0000-0000-C000-000000000046"; + + #region Win7 CLSIDs + + /// CLSID_DestinationList + /// IID_ICustomDestinationList + public const string DestinationList = "77f10cf0-3db5-4966-b520-b7c54fd35ed6"; + /// CLSID_ApplicationDestinations + /// IID_IApplicationDestinations + public const string ApplicationDestinations = "86c14003-4d6b-4ef3-a7b4-0506663b2e68"; + /// CLSID_ApplicationDocumentLists + /// IID_IApplicationDocumentLists + public const string ApplicationDocumentLists = "86bec222-30f2-47e0-9f25-60d11cd75c28"; + + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/Debug.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/Debug.cs new file mode 100644 index 0000000..aa3cf71 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/Debug.cs @@ -0,0 +1,389 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +// Conditional to use more aggressive fail-fast behaviors when debugging. +#define DEV_DEBUG + +// This file contains general utilities to aid in development. +// It is distinct from unit test Assert classes. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Threading; + + /// A static class for verifying assumptions. + internal static class Assert + { + private static void _Break() + { +#if DEV_DEBUG + Debugger.Break(); +#else + Debug.Assert(false); +#endif + } + + /// A function signature for Assert.Evaluate. + public delegate void EvaluateFunction(); + + /// A function signature for Assert.Implies. + /// Returns the truth of a predicate. + public delegate bool ImplicationFunction(); + + /// + /// Executes the specified argument. + /// + /// The function to execute. + [Conditional("DEBUG")] + public static void Evaluate(EvaluateFunction argument) + { + IsNotNull(argument); + argument(); + } + + /// Obsolete: Use Standard.Assert.AreEqual instead of Assert.Equals + /// The generic type to compare for equality. + /// The first generic type data to compare. This is is the expected value. + /// The second generic type data to compare. This is the actual value. + [ + Obsolete("Use Assert.AreEqual instead of Assert.Equals", false), + Conditional("DEBUG") + ] + public static void Equals(T expected, T actual) + { + AreEqual(expected, actual); + } + + /// + /// Verifies that two generic type data are equal. The assertion fails if they are not. + /// + /// The generic type to compare for equality. + /// The first generic type data to compare. This is is the expected value. + /// The second generic type data to compare. This is the actual value. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void AreEqual(T expected, T actual) + { + if (null == expected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null != actual && !actual.Equals(expected)) + { + _Break(); + } + } + else if (!expected.Equals(actual)) + { + _Break(); + } + } + + /// + /// Verifies that two generic type data are not equal. The assertion fails if they are. + /// + /// The generic type to compare for inequality. + /// The first generic type data to compare. This is is the value that's not expected. + /// The second generic type data to compare. This is the actual value. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void AreNotEqual(T notExpected, T actual) + { + if (null == notExpected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null == actual || actual.Equals(notExpected)) + { + _Break(); + } + } + else if (notExpected.Equals(actual)) + { + _Break(); + } + } + + /// + /// Verifies that if the specified condition is true, then so is the result. + /// The assertion fails if the condition is true but the result is false. + /// + /// if set to true [condition]. + /// + /// A second Boolean statement. If the first was true then so must this be. + /// If the first statement was false then the value of this is ignored. + /// + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void Implies(bool condition, bool result) + { + if (condition && !result) + { + _Break(); + } + } + + /// + /// Lazy evaluation overload. Verifies that if a condition is true, then so is a secondary value. + /// + /// The conditional value. + /// A function to be evaluated for truth if the condition argument is true. + /// + /// This overload only evaluates the result if the first condition is true. + /// + [Conditional("DEBUG")] + public static void Implies(bool condition, ImplicationFunction result) + { + if (condition && !result()) + { + _Break(); + } + } + + /// + /// Verifies that a string has content. I.e. it is not null and it is not empty. + /// + /// The string to verify. + [Conditional("DEBUG")] + public static void IsNeitherNullNorEmpty(string value) + { + IsFalse(string.IsNullOrEmpty(value)); + } + + /// + /// Verifies that a string has content. I.e. it is not null and it is not purely whitespace. + /// + /// The string to verify. + [Conditional("DEBUG")] + public static void IsNeitherNullNorWhitespace(string value) + { + if (string.IsNullOrEmpty(value)) + { + _Break(); + } + + if (value.Trim().Length == 0) + { + _Break(); + } + } + + /// + /// Verifies the specified value is not null. The assertion fails if it is. + /// + /// The generic reference type. + /// The value to check for nullness. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsNotNull(T value) where T : class + { + if (null == value) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void IsDefault(T value) where T : struct + { + if (!value.Equals(default(T))) + { + Assert.Fail(); + } + } + + [Conditional("DEBUG")] + public static void IsNotDefault(T value) where T : struct + { + if (value.Equals(default(T))) + { + Assert.Fail(); + } + } + + /// + /// Verifies that the specified condition is false. The assertion fails if it is true. + /// + /// The expression that should be false. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsFalse(bool condition) + { + if (condition) + { + _Break(); + } + } + + /// + /// Verifies that the specified condition is false. The assertion fails if it is true. + /// + /// The expression that should be false. + /// The message to display if the condition is true. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsFalse(bool condition, string message) + { + if (condition) + { + _Break(); + } + } + + /// + /// Verifies that the specified condition is true. The assertion fails if it is not. + /// + /// A condition that is expected to be true. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsTrue(bool condition) + { + if (!condition) + { + _Break(); + } + } + + /// + /// Verifies that the specified condition is true. The assertion fails if it is not. + /// + /// A condition that is expected to be true. + /// The message to write in case the condition is false. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsTrue(bool condition, string message) + { + if (!condition) + { + _Break(); + } + } + + /// + /// This line should never be executed. The assertion always fails. + /// + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void Fail() + { + _Break(); + } + + /// + /// This line should never be executed. The assertion always fails. + /// + /// The message to display if this function is executed. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void Fail(string message) + { + _Break(); + } + + /// + /// Verifies that the specified object is null. The assertion fails if it is not. + /// + /// The item to verify is null. + [Conditional("DEBUG")] + public static void IsNull(T item) where T : class + { + if (null != item) + { + _Break(); + } + } + + /// + /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. + /// + /// The lower bound inclusive value. + /// The value to verify. + /// The upper bound inclusive value. + [Conditional("DEBUG")] + public static void BoundedDoubleInc(double lowerBoundInclusive, double value, double upperBoundInclusive) + { + if (value < lowerBoundInclusive || value > upperBoundInclusive) + { + _Break(); + } + } + + /// + /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. + /// + /// The lower bound inclusive value. + /// The value to verify. + /// The upper bound exclusive value. + [Conditional("DEBUG")] + public static void BoundedInteger(int lowerBoundInclusive, int value, int upperBoundExclusive) + { + if (value < lowerBoundInclusive || value >= upperBoundExclusive) + { + _Break(); + } + } + + /// + /// Verify the current thread's apartment state is what's expected. The assertion fails if it isn't + /// + /// + /// The expected apartment state for the current thread. + /// + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsApartmentState(ApartmentState expectedState) + { + if (Thread.CurrentThread.GetApartmentState() != expectedState) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void NullableIsNotNull(T? value) where T : struct + { + if (null == value) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void NullableIsNull(T? value) where T : struct + { + if (null != value) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void IsNotOnMainThread() + { + if (System.Windows.Application.Current.Dispatcher.CheckAccess()) + { + _Break(); + } + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/DoubleUtil.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/DoubleUtil.cs new file mode 100644 index 0000000..e3ba2c2 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/DoubleUtil.cs @@ -0,0 +1,148 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + + /// + /// DoubleUtil uses fixed eps to provide fuzzy comparison functionality for doubles. + /// Note that FP noise is a big problem and using any of these compare + /// methods is not a complete solution, but rather the way to reduce + /// the probability of repeating unnecessary work. + /// + internal static class DoubleUtilities + { + /// + /// Epsilon - more or less random, more or less small number. + /// + private const double Epsilon = 0.00000153; + + /// + /// AreClose returns whether or not two doubles are "close". That is, whether or + /// not they are within epsilon of each other. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the AreClose comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool AreClose(double value1, double value2) + { + if (value1 == value2) + { + return true; + } + + double delta = value1 - value2; + return (delta < Epsilon) && (delta > -Epsilon); + } + + /// + /// LessThan returns whether or not the first double is less than the second double. + /// That is, whether or not the first is strictly less than *and* not within epsilon of + /// the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the LessThan comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool LessThan(double value1, double value2) + { + return (value1 < value2) && !AreClose(value1, value2); + } + + /// + /// GreaterThan returns whether or not the first double is greater than the second double. + /// That is, whether or not the first is strictly greater than *and* not within epsilon of + /// the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the GreaterThan comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool GreaterThan(double value1, double value2) + { + return (value1 > value2) && !AreClose(value1, value2); + } + + /// + /// LessThanOrClose returns whether or not the first double is less than or close to + /// the second double. That is, whether or not the first is strictly less than or within + /// epsilon of the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the LessThanOrClose comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool LessThanOrClose(double value1, double value2) + { + return (value1 < value2) || AreClose(value1, value2); + } + + /// + /// GreaterThanOrClose returns whether or not the first double is greater than or close to + /// the second double. That is, whether or not the first is strictly greater than or within + /// epsilon of the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the GreaterThanOrClose comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool GreaterThanOrClose(double value1, double value2) + { + return (value1 > value2) || AreClose(value1, value2); + } + + /// + /// Test to see if a double is a finite number (is not NaN or Infinity). + /// + /// The value to test. + /// Whether or not the value is a finite number. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFinite(double value) + { + return !double.IsNaN(value) && !double.IsInfinity(value); + } + + /// + /// Test to see if a double a valid size value (is finite and > 0). + /// + /// The value to test. + /// Whether or not the value is a valid size value. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsValidSize(double value) + { + return IsFinite(value) && GreaterThanOrClose(value, 0); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/DpiHelper.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/DpiHelper.cs new file mode 100644 index 0000000..116808e --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/DpiHelper.cs @@ -0,0 +1,102 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Media; + + internal static class DpiHelper + { + private static Matrix _transformToDevice; + private static Matrix _transformToDip; + + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + static DpiHelper() + { + using (SafeDC desktop = SafeDC.GetDesktop()) + { + // Can get these in the static constructor. They shouldn't vary window to window, + // and changing the system DPI requires a restart. + int pixelsPerInchX = NativeMethods.GetDeviceCaps(desktop, DeviceCap.LOGPIXELSX); + int pixelsPerInchY = NativeMethods.GetDeviceCaps(desktop, DeviceCap.LOGPIXELSY); + + _transformToDip = Matrix.Identity; + _transformToDip.Scale(96d / (double)pixelsPerInchX, 96d / (double)pixelsPerInchY); + _transformToDevice = Matrix.Identity; + _transformToDevice.Scale((double)pixelsPerInchX / 96d, (double)pixelsPerInchY / 96d); + } + } + + /// + /// Convert a point in device independent pixels (1/96") to a point in the system coordinates. + /// + /// A point in the logical coordinate system. + /// Returns the parameter converted to the system's coordinates. + public static Point LogicalPixelsToDevice(Point logicalPoint) + { + return _transformToDevice.Transform(logicalPoint); + } + + /// + /// Convert a point in system coordinates to a point in device independent pixels (1/96"). + /// + /// A point in the physical coordinate system. + /// Returns the parameter converted to the device independent coordinate system. + public static Point DevicePixelsToLogical(Point devicePoint) + { + return _transformToDip.Transform(devicePoint); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Rect LogicalRectToDevice(Rect logicalRectangle) + { + Point topLeft = LogicalPixelsToDevice(new Point(logicalRectangle.Left, logicalRectangle.Top)); + Point bottomRight = LogicalPixelsToDevice(new Point(logicalRectangle.Right, logicalRectangle.Bottom)); + + return new Rect(topLeft, bottomRight); + } + + public static Rect DeviceRectToLogical(Rect deviceRectangle) + { + Point topLeft = DevicePixelsToLogical(new Point(deviceRectangle.Left, deviceRectangle.Top)); + Point bottomRight = DevicePixelsToLogical(new Point(deviceRectangle.Right, deviceRectangle.Bottom)); + + return new Rect(topLeft, bottomRight); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Size LogicalSizeToDevice(Size logicalSize) + { + Point pt = LogicalPixelsToDevice(new Point(logicalSize.Width, logicalSize.Height)); + + return new Size { Width = pt.X, Height = pt.Y }; + } + + public static Size DeviceSizeToLogical(Size deviceSize) + { + Point pt = DevicePixelsToLogical(new Point(deviceSize.Width, deviceSize.Height)); + + return new Size(pt.X, pt.Y); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/ErrorCodes.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/ErrorCodes.cs new file mode 100644 index 0000000..a928dd0 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/ErrorCodes.cs @@ -0,0 +1,524 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.Reflection; + using System.Runtime.InteropServices; + + /// + /// Wrapper for common Win32 status codes. + /// + [StructLayout(LayoutKind.Explicit)] + internal struct Win32Error + { + [FieldOffset(0)] + private readonly int _value; + + // NOTE: These public static field declarations are automatically + // picked up by (HRESULT's) ToString through reflection. + + /// The operation completed successfully. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_SUCCESS = new Win32Error(0); + /// Incorrect function. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_FUNCTION = new Win32Error(1); + /// The system cannot find the file specified. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_FILE_NOT_FOUND = new Win32Error(2); + /// The system cannot find the path specified. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_PATH_NOT_FOUND = new Win32Error(3); + /// The system cannot open the file. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_TOO_MANY_OPEN_FILES = new Win32Error(4); + /// Access is denied. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_ACCESS_DENIED = new Win32Error(5); + /// The handle is invalid. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_HANDLE = new Win32Error(6); + /// Not enough storage is available to complete this operation. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_OUTOFMEMORY = new Win32Error(14); + /// There are no more files. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NO_MORE_FILES = new Win32Error(18); + /// The process cannot access the file because it is being used by another process. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_SHARING_VIOLATION = new Win32Error(32); + /// The parameter is incorrect. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_PARAMETER = new Win32Error(87); + /// The data area passed to a system call is too small. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INSUFFICIENT_BUFFER = new Win32Error(122); + /// Cannot nest calls to LoadModule. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NESTING_NOT_ALLOWED = new Win32Error(215); + /// Illegal operation attempted on a registry key that has been marked for deletion. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_KEY_DELETED = new Win32Error(1018); + /// Element not found. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NOT_FOUND = new Win32Error(1168); + /// There was no match for the specified key in the index. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NO_MATCH = new Win32Error(1169); + /// An invalid device was specified. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_BAD_DEVICE = new Win32Error(1200); + /// The operation was canceled by the user. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_CANCELLED = new Win32Error(1223); + /// The window class was already registered. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_CLASS_ALREADY_EXISTS = new Win32Error(1410); + /// The specified datatype is invalid. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_DATATYPE = new Win32Error(1804); + + /// + /// Create a new Win32 error. + /// + /// The integer value of the error. + public Win32Error(int i) + { + _value = i; + } + + /// Performs HRESULT_FROM_WIN32 conversion. + /// The Win32 error being converted to an HRESULT. + /// The equivilent HRESULT value. + public static explicit operator HRESULT(Win32Error error) + { + // #define __HRESULT_FROM_WIN32(x) + // ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) + if (error._value <= 0) + { + return new HRESULT((uint)error._value); + } + return HRESULT.Make(true, Facility.Win32, error._value & 0x0000FFFF); + } + + // Method version of the cast operation + /// Performs HRESULT_FROM_WIN32 conversion. + /// The Win32 error being converted to an HRESULT. + /// The equivilent HRESULT value. + public HRESULT ToHRESULT() + { + return (HRESULT)this; + } + + /// Performs the equivalent of Win32's GetLastError() + /// A Win32Error instance with the result of the native GetLastError + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static Win32Error GetLastError() + { + return new Win32Error(Marshal.GetLastWin32Error()); + } + + public override bool Equals(object obj) + { + try + { + return ((Win32Error)obj)._value == _value; + } + catch (InvalidCastException) + { + return false; + } + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + /// + /// Compare two Win32 error codes for equality. + /// + /// The first error code to compare. + /// The second error code to compare. + /// Whether the two error codes are the same. + public static bool operator ==(Win32Error errLeft, Win32Error errRight) + { + return errLeft._value == errRight._value; + } + + /// + /// Compare two Win32 error codes for inequality. + /// + /// The first error code to compare. + /// The second error code to compare. + /// Whether the two error codes are not the same. + public static bool operator !=(Win32Error errLeft, Win32Error errRight) + { + return !(errLeft == errRight); + } + } + + internal enum Facility + { + /// FACILITY_NULL + Null = 0, + /// FACILITY_RPC + Rpc = 1, + /// FACILITY_DISPATCH + Dispatch = 2, + /// FACILITY_STORAGE + Storage = 3, + /// FACILITY_ITF + Itf = 4, + /// FACILITY_WIN32 + Win32 = 7, + /// FACILITY_WINDOWS + Windows = 8, + /// FACILITY_CONTROL + Control = 10, + /// MSDN doced facility code for ESE errors. + Ese = 0xE5E, + /// FACILITY_WINCODEC (WIC) + WinCodec = 0x898, + } + + /// Wrapper for HRESULT status codes. + [StructLayout(LayoutKind.Explicit)] + internal struct HRESULT + { + [FieldOffset(0)] + private readonly uint _value; + + // NOTE: These public static field declarations are automatically + // picked up by ToString through reflection. + /// S_OK + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT S_OK = new HRESULT(0x00000000); + /// S_FALSE + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT S_FALSE = new HRESULT(0x00000001); + /// E_PENDING + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_PENDING = new HRESULT(0x8000000A); + /// E_NOTIMPL + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_NOTIMPL = new HRESULT(0x80004001); + /// E_NOINTERFACE + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_NOINTERFACE = new HRESULT(0x80004002); + /// E_POINTER + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_POINTER = new HRESULT(0x80004003); + /// E_ABORT + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_ABORT = new HRESULT(0x80004004); + /// E_FAIL + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_FAIL = new HRESULT(0x80004005); + /// E_UNEXPECTED + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_UNEXPECTED = new HRESULT(0x8000FFFF); + /// STG_E_INVALIDFUNCTION + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT STG_E_INVALIDFUNCTION = new HRESULT(0x80030001); + /// REGDB_E_CLASSNOTREG + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT REGDB_E_CLASSNOTREG = new HRESULT(0x80040154); + + /// DESTS_E_NO_MATCHING_ASSOC_HANDLER. Win7 internal error code for Jump Lists. + /// There is no Assoc Handler for the given item registered by the specified application. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DESTS_E_NO_MATCHING_ASSOC_HANDLER = new HRESULT(0x80040F03); + /// DESTS_E_NORECDOCS. Win7 internal error code for Jump Lists. + /// The given item is excluded from the recent docs folder by the NoRecDocs bit on its registration. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DESTS_E_NORECDOCS = new HRESULT(0x80040F04); + /// DESTS_E_NOTALLCLEARED. Win7 internal error code for Jump Lists. + /// Not all of the items were successfully cleared + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DESTS_E_NOTALLCLEARED = new HRESULT(0x80040F05); + + /// E_ACCESSDENIED + /// Win32Error ERROR_ACCESS_DENIED. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_ACCESSDENIED = new HRESULT(0x80070005); + /// E_OUTOFMEMORY + /// Win32Error ERROR_OUTOFMEMORY. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_OUTOFMEMORY = new HRESULT(0x8007000E); + /// E_INVALIDARG + /// Win32Error ERROR_INVALID_PARAMETER. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_INVALIDARG = new HRESULT(0x80070057); + /// INTSAFE_E_ARITHMETIC_OVERFLOW + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT INTSAFE_E_ARITHMETIC_OVERFLOW = new HRESULT(0x80070216); + /// COR_E_OBJECTDISPOSED + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT COR_E_OBJECTDISPOSED = new HRESULT(0x80131622); + /// WC_E_GREATERTHAN + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WC_E_GREATERTHAN = new HRESULT(0xC00CEE23); + /// WC_E_SYNTAX + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WC_E_SYNTAX = new HRESULT(0xC00CEE2D); + + /// + /// Create an HRESULT from an integer value. + /// + /// + public HRESULT(uint i) + { + _value = i; + } + + public static HRESULT Make(bool severe, Facility facility, int code) + { + // #define MAKE_HRESULT(sev,fac,code) \ + // ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) + + // Severity has 1 bit reserved. + // bitness is enforced by the boolean parameter. + + // Facility has 11 bits reserved (different than SCODES, which have 4 bits reserved) + // MSDN documentation incorrectly uses 12 bits for the ESE facility (e5e), so go ahead and let that one slide. + // And WIC also ignores it the documented size... + Assert.Implies((int)facility != (int)((int)facility & 0x1FF), facility == Facility.Ese || facility == Facility.WinCodec); + // Code has 4 bits reserved. + Assert.AreEqual(code, code & 0xFFFF); + + return new HRESULT((uint)((severe ? (1 << 31) : 0) | ((int)facility << 16) | code)); + } + + /// + /// retrieve HRESULT_FACILITY + /// + public Facility Facility + { + get + { + return GetFacility((int)_value); + } + } + + public static Facility GetFacility(int errorCode) + { + // #define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) + return (Facility)((errorCode >> 16) & 0x1fff); + } + + /// + /// retrieve HRESULT_CODE + /// + public int Code + { + get + { + return GetCode((int)_value); + } + } + + public static int GetCode(int error) + { + // #define HRESULT_CODE(hr) ((hr) & 0xFFFF) + return (int)(error & 0xFFFF); + } + + #region Object class override members + + /// + /// Get a string representation of this HRESULT. + /// + /// + public override string ToString() + { + // Use reflection to try to name this HRESULT. + // This is expensive, but if someone's ever printing HRESULT strings then + // I think it's a fair guess that they're not in a performance critical area + // (e.g. printing exception strings). + // This is less error prone than trying to keep the list in the function. + // To properly add an HRESULT's name to the ToString table, just add the HRESULT + // like all the others above. + // + // CONSIDER: This data is static. It could be cached + // after first usage for fast lookup since the keys are unique. + // + foreach (FieldInfo publicStaticField in typeof(HRESULT).GetFields(BindingFlags.Static | BindingFlags.Public)) + { + if (publicStaticField.FieldType == typeof(HRESULT)) + { + var hr = (HRESULT)publicStaticField.GetValue(null); + if (hr == this) + { + return publicStaticField.Name; + } + } + } + + // Try Win32 error codes also + if (Facility == Facility.Win32) + { + foreach (FieldInfo publicStaticField in typeof(Win32Error).GetFields(BindingFlags.Static | BindingFlags.Public)) + { + if (publicStaticField.FieldType == typeof(Win32Error)) + { + var error = (Win32Error)publicStaticField.GetValue(null); + if ((HRESULT)error == this) + { + return "HRESULT_FROM_WIN32(" + publicStaticField.Name + ")"; + } + } + } + } + + // If there's no good name for this HRESULT, + // return the string as readable hex (0x########) format. + return string.Format(CultureInfo.InvariantCulture, "0x{0:X8}", _value); + } + + public override bool Equals(object obj) + { + try + { + return ((HRESULT)obj)._value == _value; + } + catch (InvalidCastException) + { + return false; + } + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + #endregion + + public static bool operator ==(HRESULT hrLeft, HRESULT hrRight) + { + return hrLeft._value == hrRight._value; + } + + public static bool operator !=(HRESULT hrLeft, HRESULT hrRight) + { + return !(hrLeft == hrRight); + } + + public bool Succeeded + { + get { return (int)_value >= 0; } + } + + public bool Failed + { + get { return (int)_value < 0; } + } + + public void ThrowIfFailed() + { + ThrowIfFailed(null); + } + + [ + SuppressMessage( + "Microsoft.Usage", + "CA2201:DoNotRaiseReservedExceptionTypes", + Justification="Only recreating Exceptions that were already raised."), + SuppressMessage( + "Microsoft.Security", + "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands") + ] + public void ThrowIfFailed(string message) + { + if (Failed) + { + if (string.IsNullOrEmpty(message)) + { + message = ToString(); + } +#if DEBUG + else + { + message += " (" + ToString() + ")"; + } +#endif + // Wow. Reflection in a throw call. Later on this may turn out to have been a bad idea. + // If you're throwing an exception I assume it's OK for me to take some time to give it back. + // I want to convert the HRESULT to a more appropriate exception type than COMException. + // Marshal.ThrowExceptionForHR does this for me, but the general call uses GetErrorInfo + // if it's set, and then ignores the HRESULT that I've provided. This makes it so this + // call works the first time but you get burned on the second. To avoid this, I use + // the overload that explicitly ignores the IErrorInfo. + // In addition, the function doesn't allow me to set the Message unless I go through + // the process of implementing an IErrorInfo and then use that. There's no stock + // implementations of IErrorInfo available and I don't think it's worth the maintenance + // overhead of doing it, nor would it have significant value over this approach. + Exception e = Marshal.GetExceptionForHR((int)_value, new IntPtr(-1)); + Assert.IsNotNull(e); + // ArgumentNullException doesn't have the right constructor parameters, + // (nor does Win32Exception...) + // but E_POINTER gets mapped to NullReferenceException, + // so I don't think it will ever matter. + Assert.IsFalse(e is ArgumentNullException); + + // If we're not getting anything better than a COMException from Marshal, + // then at least check the facility and attempt to do better ourselves. + if (e.GetType() == typeof(COMException)) + { + switch (Facility) + { + case Facility.Win32: + e = new Win32Exception(Code, message); + break; + default: + e = new COMException(message, (int)_value); + break; + } + } + else + { + ConstructorInfo cons = e.GetType().GetConstructor(new[] { typeof(string) }); + if (null != cons) + { + e = cons.Invoke(new object[] { message }) as Exception; + Assert.IsNotNull(e); + } + } + throw e; + } + } + + /// + /// Convert the result of Win32 GetLastError() into a raised exception. + /// + public static void ThrowLastError() + { + ((HRESULT)Win32Error.GetLastError()).ThrowIfFailed(); + // Only expecting to call this when we're expecting a failed GetLastError() + Assert.Fail(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/MessageWindow.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/MessageWindow.cs new file mode 100644 index 0000000..7167d8a --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/MessageWindow.cs @@ -0,0 +1,185 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.Runtime.InteropServices; + using System.Windows; + using System.Windows.Threading; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + + internal sealed class MessageWindow : DispatcherObject, IDisposable + { + // Alias this to a static so the wrapper doesn't get GC'd + private static readonly WndProc s_WndProc = new WndProc(_WndProc); + private static readonly Dictionary s_windowLookup = new Dictionary(); + + private WndProc _wndProcCallback; + private string _className; + private bool _isDisposed; + + public IntPtr Handle { get; private set; } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public MessageWindow(CS classStyle, WS style, WS_EX exStyle, Rect location, string name, WndProc callback) + { + // A null callback means just use DefWindowProc. + _wndProcCallback = callback; + _className = "MessageWindowClass+" + Guid.NewGuid().ToString(); + + var wc = new WNDCLASSEX + { + cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)), + style = classStyle, + lpfnWndProc = s_WndProc, + hInstance = NativeMethods.GetModuleHandle(null), + hbrBackground = NativeMethods.GetStockObject(StockObject.NULL_BRUSH), + lpszMenuName = "", + lpszClassName = _className, + }; + + NativeMethods.RegisterClassEx(ref wc); + + GCHandle gcHandle = default(GCHandle); + try + { + gcHandle = GCHandle.Alloc(this); + IntPtr pinnedThisPtr = (IntPtr)gcHandle; + + Handle = NativeMethods.CreateWindowEx( + exStyle, + _className, + name, + style, + (int)location.X, + (int)location.Y, + (int)location.Width, + (int)location.Height, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero, + pinnedThisPtr); + } + finally + { + gcHandle.Free(); + } + } + + ~MessageWindow() + { + _Dispose(false, false); + } + + public void Dispose() + { + _Dispose(true, false); + GC.SuppressFinalize(this); + } + + // This isn't right if the Dispatcher has already started shutting down. + // It will wind up leaking the class ATOM... + [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] + private void _Dispose(bool disposing, bool isHwndBeingDestroyed) + { + if (_isDisposed) + { + // Block against reentrancy. + return; + } + + _isDisposed = true; + + IntPtr hwnd = Handle; + string className = _className; + + if (isHwndBeingDestroyed) + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(IntPtr.Zero, className))); + } + else if (Handle != IntPtr.Zero) + { + if (CheckAccess()) + { + _DestroyWindow(hwnd, className); + } + else + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(hwnd, className))); + } + } + + s_windowLookup.Remove(hwnd); + + _className = null; + Handle = IntPtr.Zero; + } + + [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly")] + private static IntPtr _WndProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam) + { + IntPtr ret = IntPtr.Zero; + MessageWindow hwndWrapper = null; + + if (msg == WM.CREATE) + { + var createStruct = (CREATESTRUCT)Marshal.PtrToStructure(lParam, typeof(CREATESTRUCT)); + GCHandle gcHandle = GCHandle.FromIntPtr(createStruct.lpCreateParams); + hwndWrapper = (MessageWindow)gcHandle.Target; + s_windowLookup.Add(hwnd, hwndWrapper); + } + else + { + if (!s_windowLookup.TryGetValue(hwnd, out hwndWrapper)) + { + return NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); + } + } + Assert.IsNotNull(hwndWrapper); + + WndProc callback = hwndWrapper._wndProcCallback; + if (callback != null) + { + ret = callback(hwnd, msg, wParam, lParam); + } + else + { + ret = NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); + } + + if (msg == WM.NCDESTROY) + { + hwndWrapper._Dispose(true, true); + GC.SuppressFinalize(hwndWrapper); + } + + return ret; + } + + private static object _DestroyWindow(IntPtr hwnd, string className) + { + Utility.SafeDestroyWindow(ref hwnd); + NativeMethods.UnregisterClass(className, NativeMethods.GetModuleHandle(null)); + return null; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/NativeMethods.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/NativeMethods.cs new file mode 100644 index 0000000..5334198 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/NativeMethods.cs @@ -0,0 +1,3474 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Runtime.ConstrainedExecution; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Security.Permissions; + using System.Text; + using Microsoft.Win32.SafeHandles; + + // Some COM interfaces and Win32 structures are already declared in the framework. + // Interesting ones to remember in System.Runtime.InteropServices.ComTypes are: + using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; + using IPersistFile = System.Runtime.InteropServices.ComTypes.IPersistFile; + using IStream = System.Runtime.InteropServices.ComTypes.IStream; + + #region Native Values + + internal static class Win32Value + { + public const uint MAX_PATH = 260; + public const uint INFOTIPSIZE = 1024; + public const uint TRUE = 1; + public const uint FALSE = 0; + public const uint sizeof_WCHAR = 2; + public const uint sizeof_CHAR = 1; + public const uint sizeof_BOOL = 4; + } + + /// + /// HIGHCONTRAST flags + /// + [Flags] + internal enum HCF + { + HIGHCONTRASTON = 0x00000001, + AVAILABLE = 0x00000002, + HOTKEYACTIVE = 0x00000004, + CONFIRMHOTKEY = 0x00000008, + HOTKEYSOUND = 0x00000010, + INDICATOR = 0x00000020, + HOTKEYAVAILABLE = 0x00000040, + } + + /// + /// BITMAPINFOHEADER Compression type. BI_*. + /// + internal enum BI + { + RGB = 0, + } + + /// + /// CombingRgn flags. RGN_* + /// + internal enum RGN + { + /// + /// Creates the intersection of the two combined regions. + /// + AND = 1, + /// + /// Creates the union of two combined regions. + /// + OR = 2, + /// + /// Creates the union of two combined regions except for any overlapping areas. + /// + XOR = 3, + /// + /// Combines the parts of hrgnSrc1 that are not part of hrgnSrc2. + /// + DIFF = 4, + /// + /// Creates a copy of the region identified by hrgnSrc1. + /// + COPY = 5, + } + + internal enum CombineRgnResult + { + ERROR = 0, + NULLREGION = 1, + SIMPLEREGION = 2, + COMPLEXREGION = 3, + } + + /// + /// For IWebBrowser2. OLECMDEXECOPT_* + /// + internal enum OLECMDEXECOPT + { + DODEFAULT = 0, + PROMPTUSER = 1, + DONTPROMPTUSER = 2, + SHOWHELP = 3 + } + + /// + /// For IWebBrowser2. OLECMDF_* + /// + internal enum OLECMDF + { + SUPPORTED = 1, + ENABLED = 2, + LATCHED = 4, + NINCHED = 8, + INVISIBLE = 16, + DEFHIDEONCTXTMENU = 32 + } + + /// + /// For IWebBrowser2. OLECMDID_* + /// + internal enum OLECMDID + { + OPEN = 1, + NEW = 2, + SAVE = 3, + SAVEAS = 4, + SAVECOPYAS = 5, + PRINT = 6, + PRINTPREVIEW = 7, + PAGESETUP = 8, + SPELL = 9, + PROPERTIES = 10, + CUT = 11, + COPY = 12, + PASTE = 13, + PASTESPECIAL = 14, + UNDO = 15, + REDO = 16, + SELECTALL = 17, + CLEARSELECTION = 18, + ZOOM = 19, + GETZOOMRANGE = 20, + UPDATECOMMANDS = 21, + REFRESH = 22, + STOP = 23, + HIDETOOLBARS = 24, + SETPROGRESSMAX = 25, + SETPROGRESSPOS = 26, + SETPROGRESSTEXT = 27, + SETTITLE = 28, + SETDOWNLOADSTATE = 29, + STOPDOWNLOAD = 30, + ONTOOLBARACTIVATED = 31, + FIND = 32, + DELETE = 33, + HTTPEQUIV = 34, + HTTPEQUIV_DONE = 35, + ENABLE_INTERACTION = 36, + ONUNLOAD = 37, + PROPERTYBAG2 = 38, + PREREFRESH = 39, + SHOWSCRIPTERROR = 40, + SHOWMESSAGE = 41, + SHOWFIND = 42, + SHOWPAGESETUP = 43, + SHOWPRINT = 44, + CLOSE = 45, + ALLOWUILESSSAVEAS = 46, + DONTDOWNLOADCSS = 47, + UPDATEPAGESTATUS = 48, + PRINT2 = 49, + PRINTPREVIEW2 = 50, + SETPRINTTEMPLATE = 51, + GETPRINTTEMPLATE = 52, + PAGEACTIONBLOCKED = 55, + PAGEACTIONUIQUERY = 56, + FOCUSVIEWCONTROLS = 57, + FOCUSVIEWCONTROLSQUERY = 58, + SHOWPAGEACTIONMENU = 59 + } + + /// + /// For IWebBrowser2. READYSTATE_* + /// + enum READYSTATE + { + UNINITIALIZED = 0, + LOADING = 1, + LOADED = 2, + INTERACTIVE = 3, + COMPLETE = 4 + } + + /// + /// DATAOBJ_GET_ITEM_FLAGS. DOGIF_*. + /// + internal enum DOGIF + { + DEFAULT = 0x0000, + TRAVERSE_LINK = 0x0001, // if the item is a link get the target + NO_HDROP = 0x0002, // don't fallback and use CF_HDROP clipboard format + NO_URL = 0x0004, // don't fallback and use URL clipboard format + ONLY_IF_ONE = 0x0008, // only return the item if there is one item in the array + } + + internal enum DWM_SIT + { + None, + DISPLAYFRAME = 1, + } + + [Flags] + internal enum ErrorModes + { + /// Use the system default, which is to display all error dialog boxes. + Default = 0x0, + /// + /// The system does not display the critical-error-handler message box. + /// Instead, the system sends the error to the calling process. + /// + FailCriticalErrors = 0x1, + /// + /// 64-bit Windows: The system automatically fixes memory alignment faults and makes them + /// invisible to the application. It does this for the calling process and any descendant processes. + /// After this value is set for a process, subsequent attempts to clear the value are ignored. + /// + NoGpFaultErrorBox = 0x2, + /// + /// The system does not display the general-protection-fault message box. + /// This flag should only be set by debugging applications that handle general + /// protection (GP) faults themselves with an exception handler. + /// + NoAlignmentFaultExcept = 0x4, + /// + /// The system does not display a message box when it fails to find a file. + /// Instead, the error is returned to the calling process. + /// + NoOpenFileErrorBox = 0x8000 + } + + /// + /// Non-client hit test values, HT* + /// + internal enum HT + { + ERROR = -2, + TRANSPARENT = -1, + NOWHERE = 0, + CLIENT = 1, + CAPTION = 2, + SYSMENU = 3, + GROWBOX = 4, + SIZE = GROWBOX, + MENU = 5, + HSCROLL = 6, + VSCROLL = 7, + MINBUTTON = 8, + MAXBUTTON = 9, + LEFT = 10, + RIGHT = 11, + TOP = 12, + TOPLEFT = 13, + TOPRIGHT = 14, + BOTTOM = 15, + BOTTOMLEFT = 16, + BOTTOMRIGHT = 17, + BORDER = 18, + REDUCE = MINBUTTON, + ZOOM = MAXBUTTON, + SIZEFIRST = LEFT, + SIZELAST = BOTTOMRIGHT, + OBJECT = 19, + CLOSE = 20, + HELP = 21 + } + + /// + /// GetClassLongPtr values, GCLP_* + /// + internal enum GCLP + { + HBRBACKGROUND = -10, + } + + /// + /// GetWindowLongPtr values, GWL_* + /// + internal enum GWL + { + WNDPROC = (-4), + HINSTANCE = (-6), + HWNDPARENT = (-8), + STYLE = (-16), + EXSTYLE = (-20), + USERDATA = (-21), + ID = (-12) + } + + /// + /// SystemMetrics. SM_* + /// + internal enum SM + { + CXSCREEN = 0, + CYSCREEN = 1, + CXVSCROLL = 2, + CYHSCROLL = 3, + CYCAPTION = 4, + CXBORDER = 5, + CYBORDER = 6, + CXFIXEDFRAME = 7, + CYFIXEDFRAME = 8, + CYVTHUMB = 9, + CXHTHUMB = 10, + CXICON = 11, + CYICON = 12, + CXCURSOR = 13, + CYCURSOR = 14, + CYMENU = 15, + CXFULLSCREEN = 16, + CYFULLSCREEN = 17, + CYKANJIWINDOW = 18, + MOUSEPRESENT = 19, + CYVSCROLL = 20, + CXHSCROLL = 21, + DEBUG = 22, + SWAPBUTTON = 23, + CXMIN = 28, + CYMIN = 29, + CXSIZE = 30, + CYSIZE = 31, + CXFRAME = 32, + CXSIZEFRAME = CXFRAME, + CYFRAME = 33, + CYSIZEFRAME = CYFRAME, + CXMINTRACK = 34, + CYMINTRACK = 35, + CXDOUBLECLK = 36, + CYDOUBLECLK = 37, + CXICONSPACING = 38, + CYICONSPACING = 39, + MENUDROPALIGNMENT = 40, + PENWINDOWS = 41, + DBCSENABLED = 42, + CMOUSEBUTTONS = 43, + SECURE = 44, + CXEDGE = 45, + CYEDGE = 46, + CXMINSPACING = 47, + CYMINSPACING = 48, + CXSMICON = 49, + CYSMICON = 50, + CYSMCAPTION = 51, + CXSMSIZE = 52, + CYSMSIZE = 53, + CXMENUSIZE = 54, + CYMENUSIZE = 55, + ARRANGE = 56, + CXMINIMIZED = 57, + CYMINIMIZED = 58, + CXMAXTRACK = 59, + CYMAXTRACK = 60, + CXMAXIMIZED = 61, + CYMAXIMIZED = 62, + NETWORK = 63, + CLEANBOOT = 67, + CXDRAG = 68, + CYDRAG = 69, + SHOWSOUNDS = 70, + CXMENUCHECK = 71, + CYMENUCHECK = 72, + SLOWMACHINE = 73, + MIDEASTENABLED = 74, + MOUSEWHEELPRESENT = 75, + XVIRTUALSCREEN = 76, + YVIRTUALSCREEN = 77, + CXVIRTUALSCREEN = 78, + CYVIRTUALSCREEN = 79, + CMONITORS = 80, + SAMEDISPLAYFORMAT = 81, + IMMENABLED = 82, + CXFOCUSBORDER = 83, + CYFOCUSBORDER = 84, + TABLETPC = 86, + MEDIACENTER = 87, + REMOTESESSION = 0x1000, + REMOTECONTROL = 0x2001, + } + + /// + /// SystemParameterInfo values, SPI_* + /// + internal enum SPI + { + GETBEEP = 0x0001, + SETBEEP = 0x0002, + GETMOUSE = 0x0003, + SETMOUSE = 0x0004, + GETBORDER = 0x0005, + SETBORDER = 0x0006, + GETKEYBOARDSPEED = 0x000A, + SETKEYBOARDSPEED = 0x000B, + LANGDRIVER = 0x000C, + ICONHORIZONTALSPACING = 0x000D, + GETSCREENSAVETIMEOUT = 0x000E, + SETSCREENSAVETIMEOUT = 0x000F, + GETSCREENSAVEACTIVE = 0x0010, + SETSCREENSAVEACTIVE = 0x0011, + GETGRIDGRANULARITY = 0x0012, + SETGRIDGRANULARITY = 0x0013, + SETDESKWALLPAPER = 0x0014, + SETDESKPATTERN = 0x0015, + GETKEYBOARDDELAY = 0x0016, + SETKEYBOARDDELAY = 0x0017, + ICONVERTICALSPACING = 0x0018, + GETICONTITLEWRAP = 0x0019, + SETICONTITLEWRAP = 0x001A, + GETMENUDROPALIGNMENT = 0x001B, + SETMENUDROPALIGNMENT = 0x001C, + SETDOUBLECLKWIDTH = 0x001D, + SETDOUBLECLKHEIGHT = 0x001E, + GETICONTITLELOGFONT = 0x001F, + SETDOUBLECLICKTIME = 0x0020, + SETMOUSEBUTTONSWAP = 0x0021, + SETICONTITLELOGFONT = 0x0022, + GETFASTTASKSWITCH = 0x0023, + SETFASTTASKSWITCH = 0x0024, + + SETDRAGFULLWINDOWS = 0x0025, + GETDRAGFULLWINDOWS = 0x0026, + GETNONCLIENTMETRICS = 0x0029, + SETNONCLIENTMETRICS = 0x002A, + GETMINIMIZEDMETRICS = 0x002B, + SETMINIMIZEDMETRICS = 0x002C, + GETICONMETRICS = 0x002D, + SETICONMETRICS = 0x002E, + SETWORKAREA = 0x002F, + GETWORKAREA = 0x0030, + SETPENWINDOWS = 0x0031, + GETHIGHCONTRAST = 0x0042, + SETHIGHCONTRAST = 0x0043, + GETKEYBOARDPREF = 0x0044, + SETKEYBOARDPREF = 0x0045, + GETSCREENREADER = 0x0046, + SETSCREENREADER = 0x0047, + GETANIMATION = 0x0048, + SETANIMATION = 0x0049, + GETFONTSMOOTHING = 0x004A, + SETFONTSMOOTHING = 0x004B, + SETDRAGWIDTH = 0x004C, + SETDRAGHEIGHT = 0x004D, + SETHANDHELD = 0x004E, + GETLOWPOWERTIMEOUT = 0x004F, + GETPOWEROFFTIMEOUT = 0x0050, + SETLOWPOWERTIMEOUT = 0x0051, + SETPOWEROFFTIMEOUT = 0x0052, + GETLOWPOWERACTIVE = 0x0053, + GETPOWEROFFACTIVE = 0x0054, + SETLOWPOWERACTIVE = 0x0055, + SETPOWEROFFACTIVE = 0x0056, + SETCURSORS = 0x0057, + SETICONS = 0x0058, + GETDEFAULTINPUTLANG = 0x0059, + SETDEFAULTINPUTLANG = 0x005A, + SETLANGTOGGLE = 0x005B, + GETWINDOWSEXTENSION = 0x005C, + SETMOUSETRAILS = 0x005D, + GETMOUSETRAILS = 0x005E, + SETSCREENSAVERRUNNING = 0x0061, + SCREENSAVERRUNNING = SETSCREENSAVERRUNNING, + GETFILTERKEYS = 0x0032, + SETFILTERKEYS = 0x0033, + GETTOGGLEKEYS = 0x0034, + SETTOGGLEKEYS = 0x0035, + GETMOUSEKEYS = 0x0036, + SETMOUSEKEYS = 0x0037, + GETSHOWSOUNDS = 0x0038, + SETSHOWSOUNDS = 0x0039, + GETSTICKYKEYS = 0x003A, + SETSTICKYKEYS = 0x003B, + GETACCESSTIMEOUT = 0x003C, + SETACCESSTIMEOUT = 0x003D, + + GETSERIALKEYS = 0x003E, + SETSERIALKEYS = 0x003F, + GETSOUNDSENTRY = 0x0040, + SETSOUNDSENTRY = 0x0041, + GETSNAPTODEFBUTTON = 0x005F, + SETSNAPTODEFBUTTON = 0x0060, + GETMOUSEHOVERWIDTH = 0x0062, + SETMOUSEHOVERWIDTH = 0x0063, + GETMOUSEHOVERHEIGHT = 0x0064, + SETMOUSEHOVERHEIGHT = 0x0065, + GETMOUSEHOVERTIME = 0x0066, + SETMOUSEHOVERTIME = 0x0067, + GETWHEELSCROLLLINES = 0x0068, + SETWHEELSCROLLLINES = 0x0069, + GETMENUSHOWDELAY = 0x006A, + SETMENUSHOWDELAY = 0x006B, + + GETWHEELSCROLLCHARS = 0x006C, + SETWHEELSCROLLCHARS = 0x006D, + + GETSHOWIMEUI = 0x006E, + SETSHOWIMEUI = 0x006F, + + GETMOUSESPEED = 0x0070, + SETMOUSESPEED = 0x0071, + GETSCREENSAVERRUNNING = 0x0072, + GETDESKWALLPAPER = 0x0073, + + GETAUDIODESCRIPTION = 0x0074, + SETAUDIODESCRIPTION = 0x0075, + + GETSCREENSAVESECURE = 0x0076, + SETSCREENSAVESECURE = 0x0077, + + GETHUNGAPPTIMEOUT = 0x0078, + SETHUNGAPPTIMEOUT = 0x0079, + GETWAITTOKILLTIMEOUT = 0x007A, + SETWAITTOKILLTIMEOUT = 0x007B, + GETWAITTOKILLSERVICETIMEOUT = 0x007C, + SETWAITTOKILLSERVICETIMEOUT = 0x007D, + GETMOUSEDOCKTHRESHOLD = 0x007E, + SETMOUSEDOCKTHRESHOLD = 0x007F, + GETPENDOCKTHRESHOLD = 0x0080, + SETPENDOCKTHRESHOLD = 0x0081, + GETWINARRANGING = 0x0082, + SETWINARRANGING = 0x0083, + GETMOUSEDRAGOUTTHRESHOLD = 0x0084, + SETMOUSEDRAGOUTTHRESHOLD = 0x0085, + GETPENDRAGOUTTHRESHOLD = 0x0086, + SETPENDRAGOUTTHRESHOLD = 0x0087, + GETMOUSESIDEMOVETHRESHOLD = 0x0088, + SETMOUSESIDEMOVETHRESHOLD = 0x0089, + GETPENSIDEMOVETHRESHOLD = 0x008A, + SETPENSIDEMOVETHRESHOLD = 0x008B, + GETDRAGFROMMAXIMIZE = 0x008C, + SETDRAGFROMMAXIMIZE = 0x008D, + GETSNAPSIZING = 0x008E, + SETSNAPSIZING = 0x008F, + GETDOCKMOVING = 0x0090, + SETDOCKMOVING = 0x0091, + + GETACTIVEWINDOWTRACKING = 0x1000, + SETACTIVEWINDOWTRACKING = 0x1001, + GETMENUANIMATION = 0x1002, + SETMENUANIMATION = 0x1003, + GETCOMBOBOXANIMATION = 0x1004, + SETCOMBOBOXANIMATION = 0x1005, + GETLISTBOXSMOOTHSCROLLING = 0x1006, + SETLISTBOXSMOOTHSCROLLING = 0x1007, + GETGRADIENTCAPTIONS = 0x1008, + SETGRADIENTCAPTIONS = 0x1009, + GETKEYBOARDCUES = 0x100A, + SETKEYBOARDCUES = 0x100B, + GETMENUUNDERLINES = GETKEYBOARDCUES, + SETMENUUNDERLINES = SETKEYBOARDCUES, + GETACTIVEWNDTRKZORDER = 0x100C, + SETACTIVEWNDTRKZORDER = 0x100D, + GETHOTTRACKING = 0x100E, + SETHOTTRACKING = 0x100F, + GETMENUFADE = 0x1012, + SETMENUFADE = 0x1013, + GETSELECTIONFADE = 0x1014, + SETSELECTIONFADE = 0x1015, + GETTOOLTIPANIMATION = 0x1016, + SETTOOLTIPANIMATION = 0x1017, + GETTOOLTIPFADE = 0x1018, + SETTOOLTIPFADE = 0x1019, + GETCURSORSHADOW = 0x101A, + SETCURSORSHADOW = 0x101B, + GETMOUSESONAR = 0x101C, + SETMOUSESONAR = 0x101D, + GETMOUSECLICKLOCK = 0x101E, + SETMOUSECLICKLOCK = 0x101F, + GETMOUSEVANISH = 0x1020, + SETMOUSEVANISH = 0x1021, + GETFLATMENU = 0x1022, + SETFLATMENU = 0x1023, + GETDROPSHADOW = 0x1024, + SETDROPSHADOW = 0x1025, + GETBLOCKSENDINPUTRESETS = 0x1026, + SETBLOCKSENDINPUTRESETS = 0x1027, + + GETUIEFFECTS = 0x103E, + SETUIEFFECTS = 0x103F, + + GETDISABLEOVERLAPPEDCONTENT = 0x1040, + SETDISABLEOVERLAPPEDCONTENT = 0x1041, + GETCLIENTAREAANIMATION = 0x1042, + SETCLIENTAREAANIMATION = 0x1043, + GETCLEARTYPE = 0x1048, + SETCLEARTYPE = 0x1049, + GETSPEECHRECOGNITION = 0x104A, + SETSPEECHRECOGNITION = 0x104B, + + GETFOREGROUNDLOCKTIMEOUT = 0x2000, + SETFOREGROUNDLOCKTIMEOUT = 0x2001, + GETACTIVEWNDTRKTIMEOUT = 0x2002, + SETACTIVEWNDTRKTIMEOUT = 0x2003, + GETFOREGROUNDFLASHCOUNT = 0x2004, + SETFOREGROUNDFLASHCOUNT = 0x2005, + GETCARETWIDTH = 0x2006, + SETCARETWIDTH = 0x2007, + + GETMOUSECLICKLOCKTIME = 0x2008, + SETMOUSECLICKLOCKTIME = 0x2009, + GETFONTSMOOTHINGTYPE = 0x200A, + SETFONTSMOOTHINGTYPE = 0x200B, + + GETFONTSMOOTHINGCONTRAST = 0x200C, + SETFONTSMOOTHINGCONTRAST = 0x200D, + + GETFOCUSBORDERWIDTH = 0x200E, + SETFOCUSBORDERWIDTH = 0x200F, + GETFOCUSBORDERHEIGHT = 0x2010, + SETFOCUSBORDERHEIGHT = 0x2011, + + GETFONTSMOOTHINGORIENTATION = 0x2012, + SETFONTSMOOTHINGORIENTATION = 0x2013, + + GETMINIMUMHITRADIUS = 0x2014, + SETMINIMUMHITRADIUS = 0x2015, + GETMESSAGEDURATION = 0x2016, + SETMESSAGEDURATION = 0x2017, + } + + /// + /// SystemParameterInfo flag values, SPIF_* + /// + [Flags] + internal enum SPIF + { + None = 0, + UPDATEINIFILE = 0x01, + SENDCHANGE = 0x02, + SENDWININICHANGE = SENDCHANGE, + } + + [Flags] + internal enum STATE_SYSTEM + { + UNAVAILABLE = 0x00000001, // Disabled + SELECTED = 0x00000002, + FOCUSED = 0x00000004, + PRESSED = 0x00000008, + CHECKED = 0x00000010, + MIXED = 0x00000020, // 3-state checkbox or toolbar button + INDETERMINATE = MIXED, + READONLY = 0x00000040, + HOTTRACKED = 0x00000080, + DEFAULT = 0x00000100, + EXPANDED = 0x00000200, + COLLAPSED = 0x00000400, + BUSY = 0x00000800, + FLOATING = 0x00001000, // Children "owned" not "contained" by parent + MARQUEED = 0x00002000, + ANIMATED = 0x00004000, + INVISIBLE = 0x00008000, + OFFSCREEN = 0x00010000, + SIZEABLE = 0x00020000, + MOVEABLE = 0x00040000, + SELFVOICING = 0x00080000, + FOCUSABLE = 0x00100000, + SELECTABLE = 0x00200000, + LINKED = 0x00400000, + TRAVERSED = 0x00800000, + MULTISELECTABLE = 0x01000000, // Supports multiple selection + EXTSELECTABLE = 0x02000000, // Supports extended selection + ALERT_LOW = 0x04000000, // This information is of low priority + ALERT_MEDIUM = 0x08000000, // This information is of medium priority + ALERT_HIGH = 0x10000000, // This information is of high priority + PROTECTED = 0x20000000, // access to this is restricted + VALID = 0x3FFFFFFF, + } + + internal enum StockObject : int + { + WHITE_BRUSH = 0, + LTGRAY_BRUSH = 1, + GRAY_BRUSH = 2, + DKGRAY_BRUSH = 3, + BLACK_BRUSH = 4, + NULL_BRUSH = 5, + HOLLOW_BRUSH = NULL_BRUSH, + WHITE_PEN = 6, + BLACK_PEN = 7, + NULL_PEN = 8, + SYSTEM_FONT = 13, + DEFAULT_PALETTE = 15, + } + + /// + /// CS_* + /// + [Flags] + internal enum CS : uint + { + VREDRAW = 0x0001, + HREDRAW = 0x0002, + DBLCLKS = 0x0008, + OWNDC = 0x0020, + CLASSDC = 0x0040, + PARENTDC = 0x0080, + NOCLOSE = 0x0200, + SAVEBITS = 0x0800, + BYTEALIGNCLIENT = 0x1000, + BYTEALIGNWINDOW = 0x2000, + GLOBALCLASS = 0x4000, + IME = 0x00010000, + DROPSHADOW = 0x00020000 + } + + /// + /// WindowStyle values, WS_* + /// + [Flags] + internal enum WS : uint + { + OVERLAPPED = 0x00000000, + POPUP = 0x80000000, + CHILD = 0x40000000, + MINIMIZE = 0x20000000, + VISIBLE = 0x10000000, + DISABLED = 0x08000000, + CLIPSIBLINGS = 0x04000000, + CLIPCHILDREN = 0x02000000, + MAXIMIZE = 0x01000000, + BORDER = 0x00800000, + DLGFRAME = 0x00400000, + VSCROLL = 0x00200000, + HSCROLL = 0x00100000, + SYSMENU = 0x00080000, + THICKFRAME = 0x00040000, + GROUP = 0x00020000, + TABSTOP = 0x00010000, + + MINIMIZEBOX = 0x00020000, + MAXIMIZEBOX = 0x00010000, + + CAPTION = BORDER | DLGFRAME, + TILED = OVERLAPPED, + ICONIC = MINIMIZE, + SIZEBOX = THICKFRAME, + TILEDWINDOW = OVERLAPPEDWINDOW, + + OVERLAPPEDWINDOW = OVERLAPPED | CAPTION | SYSMENU | THICKFRAME | MINIMIZEBOX | MAXIMIZEBOX, + POPUPWINDOW = POPUP | BORDER | SYSMENU, + CHILDWINDOW = CHILD, + } + + /// + /// Window message values, WM_* + /// + internal enum WM + { + NULL = 0x0000, + CREATE = 0x0001, + DESTROY = 0x0002, + MOVE = 0x0003, + SIZE = 0x0005, + ACTIVATE = 0x0006, + SETFOCUS = 0x0007, + KILLFOCUS = 0x0008, + ENABLE = 0x000A, + SETREDRAW = 0x000B, + SETTEXT = 0x000C, + GETTEXT = 0x000D, + GETTEXTLENGTH = 0x000E, + PAINT = 0x000F, + CLOSE = 0x0010, + QUERYENDSESSION = 0x0011, + QUIT = 0x0012, + QUERYOPEN = 0x0013, + ERASEBKGND = 0x0014, + SYSCOLORCHANGE = 0x0015, + SHOWWINDOW = 0x0018, + CTLCOLOR = 0x0019, + WININICHANGE = 0x001A, + SETTINGCHANGE = 0x001A, + ACTIVATEAPP = 0x001C, + SETCURSOR = 0x0020, + MOUSEACTIVATE = 0x0021, + CHILDACTIVATE = 0x0022, + QUEUESYNC = 0x0023, + GETMINMAXINFO = 0x0024, + + WINDOWPOSCHANGING = 0x0046, + WINDOWPOSCHANGED = 0x0047, + + CONTEXTMENU = 0x007B, + STYLECHANGING = 0x007C, + STYLECHANGED = 0x007D, + DISPLAYCHANGE = 0x007E, + GETICON = 0x007F, + SETICON = 0x0080, + NCCREATE = 0x0081, + NCDESTROY = 0x0082, + NCCALCSIZE = 0x0083, + NCHITTEST = 0x0084, + NCPAINT = 0x0085, + NCACTIVATE = 0x0086, + GETDLGCODE = 0x0087, + SYNCPAINT = 0x0088, + NCMOUSEMOVE = 0x00A0, + NCLBUTTONDOWN = 0x00A1, + NCLBUTTONUP = 0x00A2, + NCLBUTTONDBLCLK = 0x00A3, + NCRBUTTONDOWN = 0x00A4, + NCRBUTTONUP = 0x00A5, + NCRBUTTONDBLCLK = 0x00A6, + NCMBUTTONDOWN = 0x00A7, + NCMBUTTONUP = 0x00A8, + NCMBUTTONDBLCLK = 0x00A9, + + SYSKEYDOWN = 0x0104, + SYSKEYUP = 0x0105, + SYSCHAR = 0x0106, + SYSDEADCHAR = 0x0107, + COMMAND = 0x0111, + SYSCOMMAND = 0x0112, + + MOUSEMOVE = 0x0200, + LBUTTONDOWN = 0x0201, + LBUTTONUP = 0x0202, + LBUTTONDBLCLK = 0x0203, + RBUTTONDOWN = 0x0204, + RBUTTONUP = 0x0205, + RBUTTONDBLCLK = 0x0206, + MBUTTONDOWN = 0x0207, + MBUTTONUP = 0x0208, + MBUTTONDBLCLK = 0x0209, + MOUSEWHEEL = 0x020A, + XBUTTONDOWN = 0x020B, + XBUTTONUP = 0x020C, + XBUTTONDBLCLK = 0x020D, + MOUSEHWHEEL = 0x020E, + PARENTNOTIFY = 0x0210, + + CAPTURECHANGED = 0x0215, + POWERBROADCAST = 0x0218, + DEVICECHANGE = 0x0219, + + ENTERSIZEMOVE = 0x0231, + EXITSIZEMOVE = 0x0232, + + IME_SETCONTEXT = 0x0281, + IME_NOTIFY = 0x0282, + IME_CONTROL = 0x0283, + IME_COMPOSITIONFULL = 0x0284, + IME_SELECT = 0x0285, + IME_CHAR = 0x0286, + IME_REQUEST = 0x0288, + IME_KEYDOWN = 0x0290, + IME_KEYUP = 0x0291, + + NCMOUSELEAVE = 0x02A2, + + TABLET_DEFBASE = 0x02C0, + //WM_TABLET_MAXOFFSET = 0x20, + + TABLET_ADDED = TABLET_DEFBASE + 8, + TABLET_DELETED = TABLET_DEFBASE + 9, + TABLET_FLICK = TABLET_DEFBASE + 11, + TABLET_QUERYSYSTEMGESTURESTATUS = TABLET_DEFBASE + 12, + + CUT = 0x0300, + COPY = 0x0301, + PASTE = 0x0302, + CLEAR = 0x0303, + UNDO = 0x0304, + RENDERFORMAT = 0x0305, + RENDERALLFORMATS = 0x0306, + DESTROYCLIPBOARD = 0x0307, + DRAWCLIPBOARD = 0x0308, + PAINTCLIPBOARD = 0x0309, + VSCROLLCLIPBOARD = 0x030A, + SIZECLIPBOARD = 0x030B, + ASKCBFORMATNAME = 0x030C, + CHANGECBCHAIN = 0x030D, + HSCROLLCLIPBOARD = 0x030E, + QUERYNEWPALETTE = 0x030F, + PALETTEISCHANGING = 0x0310, + PALETTECHANGED = 0x0311, + HOTKEY = 0x0312, + PRINT = 0x0317, + PRINTCLIENT = 0x0318, + APPCOMMAND = 0x0319, + THEMECHANGED = 0x031A, + + DWMCOMPOSITIONCHANGED = 0x031E, + DWMNCRENDERINGCHANGED = 0x031F, + DWMCOLORIZATIONCOLORCHANGED = 0x0320, + DWMWINDOWMAXIMIZEDCHANGE = 0x0321, + + GETTITLEBARINFOEX = 0x033F, + #region Windows 7 + DWMSENDICONICTHUMBNAIL = 0x0323, + DWMSENDICONICLIVEPREVIEWBITMAP = 0x0326, + #endregion + + USER = 0x0400, + + // This is the hard-coded message value used by WinForms for Shell_NotifyIcon. + // It's relatively safe to reuse. + TRAYMOUSEMESSAGE = 0x800, //WM_USER + 1024 + APP = 0x8000, + } + + /// + /// Window style extended values, WS_EX_* + /// + [Flags] + internal enum WS_EX : uint + { + None = 0, + DLGMODALFRAME = 0x00000001, + NOPARENTNOTIFY = 0x00000004, + TOPMOST = 0x00000008, + ACCEPTFILES = 0x00000010, + TRANSPARENT = 0x00000020, + MDICHILD = 0x00000040, + TOOLWINDOW = 0x00000080, + WINDOWEDGE = 0x00000100, + CLIENTEDGE = 0x00000200, + CONTEXTHELP = 0x00000400, + RIGHT = 0x00001000, + LEFT = 0x00000000, + RTLREADING = 0x00002000, + LTRREADING = 0x00000000, + LEFTSCROLLBAR = 0x00004000, + RIGHTSCROLLBAR = 0x00000000, + CONTROLPARENT = 0x00010000, + STATICEDGE = 0x00020000, + APPWINDOW = 0x00040000, + LAYERED = 0x00080000, + NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children + LAYOUTRTL = 0x00400000, // Right to left mirroring + COMPOSITED = 0x02000000, + NOACTIVATE = 0x08000000, + OVERLAPPEDWINDOW = (WINDOWEDGE | CLIENTEDGE), + PALETTEWINDOW = (WINDOWEDGE | TOOLWINDOW | TOPMOST), + } + + /// + /// GetDeviceCaps nIndex values. + /// + internal enum DeviceCap + { + /// Number of bits per pixel + /// + BITSPIXEL = 12, + /// + /// Number of planes + /// + PLANES = 14, + /// + /// Logical pixels inch in X + /// + LOGPIXELSX = 88, + /// + /// Logical pixels inch in Y + /// + LOGPIXELSY = 90, + } + + internal enum FO : int + { + MOVE = 0x0001, + COPY = 0x0002, + DELETE = 0x0003, + RENAME = 0x0004, + } + + /// + /// "FILEOP_FLAGS", FOF_*. + /// + internal enum FOF : ushort + { + MULTIDESTFILES = 0x0001, + CONFIRMMOUSE = 0x0002, + SILENT = 0x0004, + RENAMEONCOLLISION = 0x0008, + NOCONFIRMATION = 0x0010, + WANTMAPPINGHANDLE = 0x0020, + ALLOWUNDO = 0x0040, + FILESONLY = 0x0080, + SIMPLEPROGRESS = 0x0100, + NOCONFIRMMKDIR = 0x0200, + NOERRORUI = 0x0400, + NOCOPYSECURITYATTRIBS = 0x0800, + NORECURSION = 0x1000, + NO_CONNECTED_ELEMENTS = 0x2000, + WANTNUKEWARNING = 0x4000, + NORECURSEREPARSE = 0x8000, + } + + /// + /// EnableMenuItem uEnable values, MF_* + /// + [Flags] + internal enum MF : uint + { + /// + /// Possible return value for EnableMenuItem + /// + DOES_NOT_EXIST = unchecked((uint)-1), + ENABLED = 0, + BYCOMMAND = 0, + GRAYED = 1, + DISABLED = 2, + } + + /// Specifies the type of visual style attribute to set on a window. + internal enum WINDOWTHEMEATTRIBUTETYPE : uint + { + /// Non-client area window attributes will be set. + WTA_NONCLIENT = 1, + } + + /// + /// DWMFLIP3DWINDOWPOLICY. DWMFLIP3D_* + /// + internal enum DWMFLIP3D + { + DEFAULT, + EXCLUDEBELOW, + EXCLUDEABOVE, + //LAST + } + + /// + /// DWMNCRENDERINGPOLICY. DWMNCRP_* + /// + internal enum DWMNCRP + { + USEWINDOWSTYLE, + DISABLED, + ENABLED, + //LAST + } + + /// + /// DWMWINDOWATTRIBUTE. DWMWA_* + /// + internal enum DWMWA + { + NCRENDERING_ENABLED = 1, + NCRENDERING_POLICY, + TRANSITIONS_FORCEDISABLED, + ALLOW_NCPAINT, + CAPTION_BUTTON_BOUNDS, + NONCLIENT_RTL_LAYOUT, + FORCE_ICONIC_REPRESENTATION, + FLIP3D_POLICY, + EXTENDED_FRAME_BOUNDS, + + // New to Windows 7: + + HAS_ICONIC_BITMAP, + DISALLOW_PEEK, + EXCLUDED_FROM_PEEK, + + // LAST + } + + /// + /// WindowThemeNonClientAttributes + /// + [Flags] + internal enum WTNCA : uint + { + /// Prevents the window caption from being drawn. + NODRAWCAPTION = 0x00000001, + /// Prevents the system icon from being drawn. + NODRAWICON = 0x00000002, + /// Prevents the system icon menu from appearing. + NOSYSMENU = 0x00000004, + /// Prevents mirroring of the question mark, even in right-to-left (RTL) layout. + NOMIRRORHELP = 0x00000008, + /// A mask that contains all the valid bits. + VALIDBITS = NODRAWCAPTION | NODRAWICON | NOMIRRORHELP | NOSYSMENU, + } + + /// + /// SetWindowPos options + /// + [Flags] + internal enum SWP + { + ASYNCWINDOWPOS = 0x4000, + DEFERERASE = 0x2000, + DRAWFRAME = 0x0020, + FRAMECHANGED = 0x0020, + HIDEWINDOW = 0x0080, + NOACTIVATE = 0x0010, + NOCOPYBITS = 0x0100, + NOMOVE = 0x0002, + NOOWNERZORDER = 0x0200, + NOREDRAW = 0x0008, + NOREPOSITION = 0x0200, + NOSENDCHANGING = 0x0400, + NOSIZE = 0x0001, + NOZORDER = 0x0004, + SHOWWINDOW = 0x0040, + } + + /// + /// ShowWindow options + /// + internal enum SW + { + HIDE = 0, + SHOWNORMAL = 1, + NORMAL = 1, + SHOWMINIMIZED = 2, + SHOWMAXIMIZED = 3, + MAXIMIZE = 3, + SHOWNOACTIVATE = 4, + SHOW = 5, + MINIMIZE = 6, + SHOWMINNOACTIVE = 7, + SHOWNA = 8, + RESTORE = 9, + SHOWDEFAULT = 10, + FORCEMINIMIZE = 11, + } + + internal enum SC + { + SIZE = 0xF000, + MOVE = 0xF010, + MINIMIZE = 0xF020, + MAXIMIZE = 0xF030, + NEXTWINDOW = 0xF040, + PREVWINDOW = 0xF050, + CLOSE = 0xF060, + VSCROLL = 0xF070, + HSCROLL = 0xF080, + MOUSEMENU = 0xF090, + KEYMENU = 0xF100, + ARRANGE = 0xF110, + RESTORE = 0xF120, + TASKLIST = 0xF130, + SCREENSAVE = 0xF140, + HOTKEY = 0xF150, + DEFAULT = 0xF160, + MONITORPOWER = 0xF170, + CONTEXTHELP = 0xF180, + SEPARATOR = 0xF00F, + /// + /// SCF_ISSECURE + /// + F_ISSECURE = 0x00000001, + ICON = MINIMIZE, + ZOOM = MAXIMIZE, + } + + /// + /// GDI+ Status codes + /// + internal enum Status + { + Ok = 0, + GenericError = 1, + InvalidParameter = 2, + OutOfMemory = 3, + ObjectBusy = 4, + InsufficientBuffer = 5, + NotImplemented = 6, + Win32Error = 7, + WrongState = 8, + Aborted = 9, + FileNotFound = 10, + ValueOverflow = 11, + AccessDenied = 12, + UnknownImageFormat = 13, + FontFamilyNotFound = 14, + FontStyleNotFound = 15, + NotTrueTypeFont = 16, + UnsupportedGdiplusVersion = 17, + GdiplusNotInitialized = 18, + PropertyNotFound = 19, + PropertyNotSupported = 20, + ProfileNotFound = 21, + } + + internal enum MOUSEEVENTF : int + { + //mouse event constants + LEFTDOWN = 2, + LEFTUP = 4 + } + + /// + /// MSGFLT_*. New in Vista. Realiased in Windows 7. + /// + internal enum MSGFLT + { + // Win7 versions of this enum: + RESET = 0, + ALLOW = 1, + DISALLOW = 2, + + // Vista versions of this enum: + // ADD = 1, + // REMOVE = 2, + } + + internal enum MSGFLTINFO + { + NONE = 0, + ALREADYALLOWED_FORWND = 1, + ALREADYDISALLOWED_FORWND = 2, + ALLOWED_HIGHER = 3, + } + + internal enum INPUT_TYPE : uint + { + MOUSE = 0, + } + + /// + /// Shell_NotifyIcon messages. NIM_* + /// + internal enum NIM : uint + { + ADD = 0, + MODIFY = 1, + DELETE = 2, + SETFOCUS = 3, + SETVERSION = 4, + } + + /// + /// SHAddToRecentDocuments flags. SHARD_* + /// + internal enum SHARD + { + PIDL = 0x00000001, + PATHA = 0x00000002, + PATHW = 0x00000003, + APPIDINFO = 0x00000004, // indicates the data type is a pointer to a SHARDAPPIDINFO structure + APPIDINFOIDLIST = 0x00000005, // indicates the data type is a pointer to a SHARDAPPIDINFOIDLIST structure + LINK = 0x00000006, // indicates the data type is a pointer to an IShellLink instance + APPIDINFOLINK = 0x00000007, // indicates the data type is a pointer to a SHARDAPPIDINFOLINK structure + } + + [Flags] + enum SLGP + { + SHORTPATH = 0x1, + UNCPRIORITY = 0x2, + RAWPATH = 0x4 + } + + /// + /// Shell_NotifyIcon flags. NIF_* + /// + [Flags] + internal enum NIF : uint + { + MESSAGE = 0x0001, + ICON = 0x0002, + TIP = 0x0004, + STATE = 0x0008, + INFO = 0x0010, + GUID = 0x0020, + + /// + /// Vista only. + /// + REALTIME = 0x0040, + /// + /// Vista only. + /// + SHOWTIP = 0x0080, + + XP_MASK = MESSAGE | ICON | STATE | INFO | GUID, + VISTA_MASK = XP_MASK | REALTIME | SHOWTIP, + } + + /// + /// Shell_NotifyIcon info flags. NIIF_* + /// + internal enum NIIF + { + NONE = 0x00000000, + INFO = 0x00000001, + WARNING = 0x00000002, + ERROR = 0x00000003, + /// XP SP2 and later. + USER = 0x00000004, + /// XP and later. + NOSOUND = 0x00000010, + /// Vista and later. + LARGE_ICON = 0x00000020, + /// Windows 7 and later + NIIF_RESPECT_QUIET_TIME = 0x00000080, + /// XP and later. Native version called NIIF_ICON_MASK. + XP_ICON_MASK = 0x0000000F, + } + + /// + /// AC_* + /// + internal enum AC : byte + { + SRC_OVER = 0, + SRC_ALPHA = 1, + } + + internal enum ULW + { + ALPHA = 2, + COLORKEY = 1, + OPAQUE = 4, + } + + internal enum WVR + { + ALIGNTOP = 0x0010, + ALIGNLEFT = 0x0020, + ALIGNBOTTOM = 0x0040, + ALIGNRIGHT = 0x0080, + HREDRAW = 0x0100, + VREDRAW = 0x0200, + VALIDRECTS = 0x0400, + REDRAW = HREDRAW | VREDRAW, + } + + #endregion + + #region SafeHandles + + internal sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + private SafeFindHandle() : base(true) { } + + protected override bool ReleaseHandle() + { + return NativeMethods.FindClose(handle); + } + } + + internal sealed class SafeDC : SafeHandleZeroOrMinusOneIsInvalid + { + private static class NativeMethods + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern SafeDC GetDC(IntPtr hwnd); + + // Weird legacy function, documentation is unclear about how to use it... + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", CharSet = CharSet.Unicode)] + public static extern SafeDC CreateDC([MarshalAs(UnmanagedType.LPWStr)] string lpszDriver, [MarshalAs(UnmanagedType.LPWStr)] string lpszDevice, IntPtr lpszOutput, IntPtr lpInitData); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern SafeDC CreateCompatibleDC(IntPtr hdc); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteDC(IntPtr hdc); + } + + private IntPtr? _hwnd; + private bool _created; + + public IntPtr Hwnd + { + set + { + Assert.NullableIsNull(_hwnd); + _hwnd = value; + } + } + + private SafeDC() : base(true) { } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + if (_created) + { + return NativeMethods.DeleteDC(handle); + } + + if (!_hwnd.HasValue || _hwnd.Value == IntPtr.Zero) + { + return true; + } + + return NativeMethods.ReleaseDC(_hwnd.Value, handle) == 1; + } + + [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes"), SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC CreateDC(string deviceName) + { + SafeDC dc = null; + try + { + // Should this really be on the driver parameter? + dc = NativeMethods.CreateDC(deviceName, null, IntPtr.Zero, IntPtr.Zero); + } + finally + { + if (dc != null) + { + dc._created = true; + } + } + + if (dc.IsInvalid) + { + dc.Dispose(); + throw new SystemException("Unable to create a device context from the specified device information."); + } + + return dc; + } + + [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes"), SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC CreateCompatibleDC(SafeDC hdc) + { + SafeDC dc = null; + try + { + IntPtr hPtr = IntPtr.Zero; + if (hdc != null) + { + hPtr = hdc.handle; + } + dc = NativeMethods.CreateCompatibleDC(hPtr); + if (dc == null) + { + HRESULT.ThrowLastError(); + } + } + finally + { + if (dc != null) + { + dc._created = true; + } + } + + if (dc.IsInvalid) + { + dc.Dispose(); + throw new SystemException("Unable to create a device context from the specified device information."); + } + + return dc; + } + + public static SafeDC GetDC(IntPtr hwnd) + { + SafeDC dc = null; + try + { + dc = NativeMethods.GetDC(hwnd); + } + finally + { + if (dc != null) + { + dc.Hwnd = hwnd; + } + } + + if (dc.IsInvalid) + { + // GetDC does not set the last error... + HRESULT.E_FAIL.ThrowIfFailed(); + } + + return dc; + } + + public static SafeDC GetDesktop() + { + return GetDC(IntPtr.Zero); + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC WrapDC(IntPtr hdc) + { + // This won't actually get released by the class, but it allows an IntPtr to be converted for signatures. + return new SafeDC + { + handle = hdc, + _created = false, + _hwnd = IntPtr.Zero, + }; + } + } + + internal sealed class SafeHBITMAP : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeHBITMAP() : base(true) { } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + return NativeMethods.DeleteObject(handle); + } + } + + internal sealed class SafeGdiplusStartupToken : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeGdiplusStartupToken() : base(true) { } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + Status s = NativeMethods.GdiplusShutdown(this.handle); + return s == Status.Ok; + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] + public static SafeGdiplusStartupToken Startup() + { + SafeGdiplusStartupToken safeHandle = new SafeGdiplusStartupToken(); + IntPtr unsafeHandle; + StartupOutput output; + Status s = NativeMethods.GdiplusStartup(out unsafeHandle, new StartupInput(), out output); + if (s == Status.Ok) + { + safeHandle.handle = unsafeHandle; + return safeHandle; + } + safeHandle.Dispose(); + throw new Exception("Unable to initialize GDI+"); + } + } + + internal sealed class SafeConnectionPointCookie : SafeHandleZeroOrMinusOneIsInvalid + { + private IConnectionPoint _cp; + // handle holds the cookie value. + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IConnectionPoint")] + public SafeConnectionPointCookie(IConnectionPointContainer target, object sink, Guid eventId) + : base(true) + { + Verify.IsNotNull(target, "target"); + Verify.IsNotNull(sink, "sink"); + Verify.IsNotDefault(eventId, "eventId"); + + handle = IntPtr.Zero; + + IConnectionPoint cp = null; + try + { + int dwCookie; + target.FindConnectionPoint(ref eventId, out cp); + cp.Advise(sink, out dwCookie); + if (dwCookie == 0) + { + throw new InvalidOperationException("IConnectionPoint::Advise returned an invalid cookie."); + } + handle = new IntPtr(dwCookie); + _cp = cp; + cp = null; + } + finally + { + Utility.SafeRelease(ref cp); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void Disconnect() + { + ReleaseHandle(); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + try + { + if (!this.IsInvalid) + { + int dwCookie = handle.ToInt32(); + handle = IntPtr.Zero; + + Assert.IsNotNull(_cp); + try + { + _cp.Unadvise(dwCookie); + } + finally + { + Utility.SafeRelease(ref _cp); + } + } + return true; + } + catch + { + return false; + } + } + } + + #endregion + + #region Native Types + + [StructLayout(LayoutKind.Sequential)] + internal struct BLENDFUNCTION + { + // Must be AC_SRC_OVER + public AC BlendOp; + // Must be 0. + public byte BlendFlags; + // Alpha transparency between 0 (transparent) - 255 (opaque) + public byte SourceConstantAlpha; + // Must be AC_SRC_ALPHA + public AC AlphaFormat; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HIGHCONTRAST + { + public int cbSize; + public HCF dwFlags; + //[MarshalAs(UnmanagedType.LPWStr, SizeConst=80)] + //public String lpszDefaultScheme; + public IntPtr lpszDefaultScheme; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct RGBQUAD + { + public byte rgbBlue; + public byte rgbGreen; + public byte rgbRed; + public byte rgbReserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + internal struct BITMAPINFOHEADER + { + public int biSize; + public int biWidth; + public int biHeight; + public short biPlanes; + public short biBitCount; + public BI biCompression; + public int biSizeImage; + public int biXPelsPerMeter; + public int biYPelsPerMeter; + public int biClrUsed; + public int biClrImportant; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct BITMAPINFO + { + public BITMAPINFOHEADER bmiHeader; + public RGBQUAD bmiColors; + } + + // Win7 only. + [StructLayout(LayoutKind.Sequential)] + internal struct CHANGEFILTERSTRUCT + { + public uint cbSize; + public MSGFLTINFO ExtStatus; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct CREATESTRUCT + { + public IntPtr lpCreateParams; + public IntPtr hInstance; + public IntPtr hMenu; + public IntPtr hwndParent; + public int cy; + public int cx; + public int y; + public int x; + public WS style; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszName; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszClass; + public WS_EX dwExStyle; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] + internal struct SHFILEOPSTRUCT + { + public IntPtr hwnd; + [MarshalAs(UnmanagedType.U4)] + public FO wFunc; + // double-null terminated arrays of LPWSTRS + public string pFrom; + public string pTo; + [MarshalAs(UnmanagedType.U2)] + public FOF fFlags; + [MarshalAs(UnmanagedType.Bool)] + public int fAnyOperationsAborted; + public IntPtr hNameMappings; + public string lpszProgressTitle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TITLEBARINFO + { + public int cbSize; + public RECT rcTitleBar; + public STATE_SYSTEM rgstate_TitleBar; + public STATE_SYSTEM rgstate_Reserved; + public STATE_SYSTEM rgstate_MinimizeButton; + public STATE_SYSTEM rgstate_MaximizeButton; + public STATE_SYSTEM rgstate_HelpButton; + public STATE_SYSTEM rgstate_CloseButton; + } + + // New to Vista. + [StructLayout(LayoutKind.Sequential)] + internal struct TITLEBARINFOEX + { + public int cbSize; + public RECT rcTitleBar; + public STATE_SYSTEM rgstate_TitleBar; + public STATE_SYSTEM rgstate_Reserved; + public STATE_SYSTEM rgstate_MinimizeButton; + public STATE_SYSTEM rgstate_MaximizeButton; + public STATE_SYSTEM rgstate_HelpButton; + public STATE_SYSTEM rgstate_CloseButton; + public RECT rgrect_TitleBar; + public RECT rgrect_Reserved; + public RECT rgrect_MinimizeButton; + public RECT rgrect_MaximizeButton; + public RECT rgrect_HelpButton; + public RECT rgrect_CloseButton; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential)] + internal class NOTIFYICONDATA + { + public int cbSize; + public IntPtr hWnd; + public int uID; + public NIF uFlags; + public int uCallbackMessage; + public IntPtr hIcon; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public char[] szTip = new char[128]; + /// + /// The state of the icon. There are two flags that can be set independently. + /// NIS_HIDDEN = 1. The icon is hidden. + /// NIS_SHAREDICON = 2. The icon is shared. + /// + public uint dwState; + public uint dwStateMask; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public char[] szInfo = new char[256]; + // Prior to Vista this was a union of uTimeout and uVersion. As of Vista, uTimeout has been deprecated. + public uint uVersion; // Used with Shell_NotifyIcon flag NIM_SETVERSION. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public char[] szInfoTitle = new char[64]; + public uint dwInfoFlags; + public Guid guidItem; + // Vista only + IntPtr hBalloonIcon; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Explicit)] + internal class PROPVARIANT : IDisposable + { + private static class NativeMethods + { + [DllImport("ole32.dll")] + internal static extern HRESULT PropVariantClear(PROPVARIANT pvar); + } + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(0)] + private ushort vt; + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private IntPtr pointerVal; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private byte byteVal; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private long longVal; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private short boolVal; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public VarEnum VarType + { + get { return (VarEnum)vt; } + } + + // Right now only using this for strings. + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public string GetValue() + { + if (vt == (ushort)VarEnum.VT_LPWSTR) + { + return Marshal.PtrToStringUni(pointerVal); + } + + return null; + } + + public void SetValue(bool f) + { + Clear(); + vt = (ushort)VarEnum.VT_BOOL; + boolVal = (short)(f ? -1 : 0); + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void SetValue(string val) + { + Clear(); + vt = (ushort)VarEnum.VT_LPWSTR; + pointerVal = Marshal.StringToCoTaskMemUni(val); + } + + public void Clear() + { + HRESULT hr = NativeMethods.PropVariantClear(this); + Assert.IsTrue(hr.Succeeded); + } + + #region IDisposable Pattern + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~PROPVARIANT() + { + Dispose(false); + } + + [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] + private void Dispose(bool disposing) + { + Clear(); + } + + #endregion + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal class SHARDAPPIDINFO + { + [MarshalAs(UnmanagedType.Interface)] + object psi; // The namespace location of the the item that should be added to the recent docs folder. + [MarshalAs(UnmanagedType.LPWStr)] + string pszAppID; // The id of the application that should be associated with this recent doc. + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal class SHARDAPPIDINFOIDLIST + { + /// The idlist for the shell item that should be added to the recent docs folder. + IntPtr pidl; + /// The id of the application that should be associated with this recent doc. + [MarshalAs(UnmanagedType.LPWStr)] + string pszAppID; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal class SHARDAPPIDINFOLINK + { + IntPtr psl; // An IShellLink instance that when launched opens a recently used item in the specified + // application. This link is not added to the recent docs folder, but will be added to the + // specified application's destination list. + [MarshalAs(UnmanagedType.LPWStr)] + string pszAppID; // The id of the application that should be associated with this recent doc. + } + + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct LOGFONT + { + public int lfHeight; + public int lfWidth; + public int lfEscapement; + public int lfOrientation; + public int lfWeight; + public byte lfItalic; + public byte lfUnderline; + public byte lfStrikeOut; + public byte lfCharSet; + public byte lfOutPrecision; + public byte lfClipPrecision; + public byte lfQuality; + public byte lfPitchAndFamily; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string lfFaceName; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MINMAXINFO + { + public POINT ptReserved; + public POINT ptMaxSize; + public POINT ptMaxPosition; + public POINT ptMinTrackSize; + public POINT ptMaxTrackSize; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NONCLIENTMETRICS + { + public int cbSize; + public int iBorderWidth; + public int iScrollWidth; + public int iScrollHeight; + public int iCaptionWidth; + public int iCaptionHeight; + public LOGFONT lfCaptionFont; + public int iSmCaptionWidth; + public int iSmCaptionHeight; + public LOGFONT lfSmCaptionFont; + public int iMenuWidth; + public int iMenuHeight; + public LOGFONT lfMenuFont; + public LOGFONT lfStatusFont; + public LOGFONT lfMessageFont; + // Vista only + public int iPaddedBorderWidth; + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static NONCLIENTMETRICS VistaMetricsStruct + { + get + { + var ncm = new NONCLIENTMETRICS(); + ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS)); + return ncm; + } + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static NONCLIENTMETRICS XPMetricsStruct + { + get + { + var ncm = new NONCLIENTMETRICS(); + // Account for the missing iPaddedBorderWidth + ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS)) - sizeof(int); + return ncm; + } + } + } + + /// Defines options that are used to set window visual style attributes. + [StructLayout(LayoutKind.Explicit)] + internal struct WTA_OPTIONS + { + // public static readonly uint Size = (uint)Marshal.SizeOf(typeof(WTA_OPTIONS)); + public const uint Size = 8; + + /// + /// A combination of flags that modify window visual style attributes. + /// Can be a combination of the WTNCA constants. + /// + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used by native code.")] + [FieldOffset(0)] + public WTNCA dwFlags; + + /// + /// A bitmask that describes how the values specified in dwFlags should be applied. + /// If the bit corresponding to a value in dwFlags is 0, that flag will be removed. + /// If the bit is 1, the flag will be added. + /// + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used by native code.")] + [FieldOffset(4)] + public WTNCA dwMask; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MARGINS + { + /// Width of left border that retains its size. + public int cxLeftWidth; + /// Width of right border that retains its size. + public int cxRightWidth; + /// Height of top border that retains its size. + public int cyTopHeight; + /// Height of bottom border that retains its size. + public int cyBottomHeight; + }; + + [StructLayout(LayoutKind.Sequential)] + internal class MONITORINFO + { + public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); + public RECT rcMonitor; + public RECT rcWork; + public int dwFlags; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct POINT + { + public int x; + public int y; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential)] + internal class RefPOINT + { + public int x; + public int y; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct RECT + { + private int _left; + private int _top; + private int _right; + private int _bottom; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void Offset(int dx, int dy) + { + _left += dx; + _top += dy; + _right += dx; + _bottom += dy; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Left + { + get { return _left; } + set { _left = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Right + { + get { return _right; } + set { _right = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Top + { + get { return _top; } + set { _top = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Bottom + { + get { return _bottom; } + set { _bottom = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Width + { + get { return _right - _left; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Height + { + get { return _bottom - _top; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public POINT Position + { + get { return new POINT { x = _left, y = _top }; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public SIZE Size + { + get { return new SIZE { cx = Width, cy = Height }; } + } + + public static RECT Union(RECT rect1, RECT rect2) + { + return new RECT + { + Left = Math.Min(rect1.Left, rect2.Left), + Top = Math.Min(rect1.Top, rect2.Top), + Right = Math.Max(rect1.Right, rect2.Right), + Bottom = Math.Max(rect1.Bottom, rect2.Bottom), + }; + } + + public override bool Equals(object obj) + { + try + { + var rc = (RECT)obj; + return rc._bottom == _bottom + && rc._left == _left + && rc._right == _right + && rc._top == _top; + } + catch (InvalidCastException) + { + return false; + } + } + + public override int GetHashCode() + { + return (_left << 16 | Utility.LOWORD(_right)) ^ (_top << 16 | Utility.LOWORD(_bottom)); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential)] + internal class RefRECT + { + private int _left; + private int _top; + private int _right; + private int _bottom; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public RefRECT(int left, int top, int right, int bottom) + { + _left = left; + _top = top; + _right = right; + _bottom = bottom; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Width + { + get { return _right - _left; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Height + { + get { return _bottom - _top; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Left + { + get { return _left; } + set { _left = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Right + { + get { return _right; } + set { _right = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Top + { + get { return _top; } + set { _top = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Bottom + { + get { return _bottom; } + set { _bottom = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void Offset(int dx, int dy) + { + _left += dx; + _top += dy; + _right += dx; + _bottom += dy; + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SIZE + { + public int cx; + public int cy; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct StartupOutput + { + public IntPtr hook; + public IntPtr unhook; + } + + [StructLayout(LayoutKind.Sequential)] + internal class StartupInput + { + public int GdiplusVersion = 1; + public IntPtr DebugEventCallback; + public bool SuppressBackgroundThread; + public bool SuppressExternalCodecs; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [BestFitMapping(false)] + internal class WIN32_FIND_DATAW + { + public FileAttributes dwFileAttributes; + public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; + public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; + public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; + public int nFileSizeHigh; + public int nFileSizeLow; + public int dwReserved0; + public int dwReserved1; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string cFileName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] + public string cAlternateFileName; + } + + [StructLayout(LayoutKind.Sequential)] + internal class WINDOWPLACEMENT + { + public int length = Marshal.SizeOf(typeof(WINDOWPLACEMENT)); + public int flags; + public SW showCmd; + public POINT ptMinPosition; + public POINT ptMaxPosition; + public RECT rcNormalPosition; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct WINDOWPOS + { + public IntPtr hwnd; + public IntPtr hwndInsertAfter; + public int x; + public int y; + public int cx; + public int cy; + public int flags; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct WNDCLASSEX + { + public int cbSize; + public CS style; + public WndProc lpfnWndProc; + public int cbClsExtra; + public int cbWndExtra; + public IntPtr hInstance; + public IntPtr hIcon; + public IntPtr hCursor; + public IntPtr hbrBackground; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszMenuName; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszClassName; + public IntPtr hIconSm; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MOUSEINPUT + { + public int dx; + public int dy; + public int mouseData; + public int dwFlags; + public int time; + public IntPtr dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct INPUT + { + public uint type; + public MOUSEINPUT mi; + }; + + [StructLayout(LayoutKind.Sequential)] + internal struct UNSIGNED_RATIO + { + public uint uiNumerator; + public uint uiDenominator; + } + + [StructLayout(LayoutKind.Sequential, Pack=1)] + internal struct DWM_TIMING_INFO + { + public int cbSize; + public UNSIGNED_RATIO rateRefresh; + public ulong qpcRefreshPeriod; + public UNSIGNED_RATIO rateCompose; + public ulong qpcVBlank; + public ulong cRefresh; + public uint cDXRefresh; + public ulong qpcCompose; + public ulong cFrame; + public uint cDXPresent; + public ulong cRefreshFrame; + public ulong cFrameSubmitted; + public uint cDXPresentSubmitted; + public ulong cFrameConfirmed; + public uint cDXPresentConfirmed; + public ulong cRefreshConfirmed; + public uint cDXRefreshConfirmed; + public ulong cFramesLate; + public uint cFramesOutstanding; + public ulong cFrameDisplayed; + public ulong qpcFrameDisplayed; + public ulong cRefreshFrameDisplayed; + public ulong cFrameComplete; + public ulong qpcFrameComplete; + public ulong cFramePending; + public ulong qpcFramePending; + public ulong cFramesDisplayed; + public ulong cFramesComplete; + public ulong cFramesPending; + public ulong cFramesAvailable; + public ulong cFramesDropped; + public ulong cFramesMissed; + public ulong cRefreshNextDisplayed; + public ulong cRefreshNextPresented; + public ulong cRefreshesDisplayed; + public ulong cRefreshesPresented; + public ulong cRefreshStarted; + public ulong cPixelsReceived; + public ulong cPixelsDrawn; + public ulong cBuffersEmpty; + } + + #endregion + + /// Delegate declaration that matches native WndProc signatures. + internal delegate IntPtr WndProc(IntPtr hwnd, WM uMsg, IntPtr wParam, IntPtr lParam); + + /// Delegate declaration that matches native WndProc signatures. + internal delegate IntPtr WndProcHook(IntPtr hwnd, WM uMsg, IntPtr wParam, IntPtr lParam, ref bool handled); + + /// Delegate declaration that matches managed WndProc signatures. + internal delegate IntPtr MessageHandler(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled); + + // Some native methods are shimmed through public versions that handle converting failures into thrown exceptions. + internal static class NativeMethods + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "AdjustWindowRectEx", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _AdjustWindowRectEx(ref RECT lpRect, WS dwStyle, [MarshalAs(UnmanagedType.Bool)] bool bMenu, WS_EX dwExStyle); + + public static RECT AdjustWindowRectEx(RECT lpRect, WS dwStyle, bool bMenu, WS_EX dwExStyle) + { + // Native version modifies the parameter in place. + if (!_AdjustWindowRectEx(ref lpRect, dwStyle, bMenu, dwExStyle)) + { + HRESULT.ThrowLastError(); + } + + return lpRect; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "ChangeWindowMessageFilter", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _ChangeWindowMessageFilter(WM message, MSGFLT dwFlag); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "ChangeWindowMessageFilterEx", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFLT action, [In, Out, Optional] ref CHANGEFILTERSTRUCT pChangeFilterStruct); + + // Note that processes at or below SECURITY_MANDATORY_LOW_RID are not allowed to change the message filter. + // If those processes call this function, it will fail and generate the extended error code, ERROR_ACCESS_DENIED. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static HRESULT ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFLT action, out MSGFLTINFO filterInfo) + { + filterInfo = MSGFLTINFO.NONE; + + bool ret; + + // This origins of this API were added for Vista. The Ex version was added for Windows 7. + // If we're not on either, then this message filter isolation doesn't exist. + if (!Utility.IsOSVistaOrNewer) + { + return HRESULT.S_FALSE; + } + + // If we're on Vista rather than Win7 then we can't use the Ex version of this function. + // The Ex version is preferred if possible because this results in process-wide modifications of the filter + // and is deprecated as of Win7. + if (!Utility.IsOSWindows7OrNewer) + { + // Note that the Win7 MSGFLT_ALLOW/DISALLOW enum values map to the Vista MSGFLT_ADD/REMOVE + ret = _ChangeWindowMessageFilter(message, action); + if (!ret) + { + return (HRESULT)Win32Error.GetLastError(); + } + return HRESULT.S_OK; + } + + var filterstruct = new CHANGEFILTERSTRUCT { cbSize = (uint)Marshal.SizeOf(typeof(CHANGEFILTERSTRUCT)) }; + ret = _ChangeWindowMessageFilterEx(hwnd, message, action, ref filterstruct); + if (!ret) + { + return (HRESULT)Win32Error.GetLastError(); + } + + filterInfo = filterstruct.ExtStatus; + return HRESULT.S_OK; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + public static extern CombineRgnResult CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2, RGN fnCombineMode); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", EntryPoint = "CommandLineToArgvW", CharSet = CharSet.Unicode)] + private static extern IntPtr _CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string cmdLine, out int numArgs); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string[] CommandLineToArgvW(string cmdLine) + { + IntPtr argv = IntPtr.Zero; + try + { + int numArgs = 0; + + argv = _CommandLineToArgvW(cmdLine, out numArgs); + if (argv == IntPtr.Zero) + { + throw new Win32Exception(); + } + var result = new string[numArgs]; + + for (int i = 0; i < numArgs; i++) + { + IntPtr currArg = Marshal.ReadIntPtr(argv, i * Marshal.SizeOf(typeof(IntPtr))); + result[i] = Marshal.PtrToStringUni(currArg); + } + + return result; + } + finally + { + + IntPtr p = _LocalFree(argv); + // Otherwise LocalFree failed. + Assert.AreEqual(IntPtr.Zero, p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateDIBSection", SetLastError = true)] + private static extern SafeHBITMAP _CreateDIBSection(SafeDC hdc, [In] ref BITMAPINFO bitmapInfo, int iUsage, [Out] out IntPtr ppvBits, IntPtr hSection, int dwOffset); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateDIBSection", SetLastError = true)] + private static extern SafeHBITMAP _CreateDIBSectionIntPtr(IntPtr hdc, [In] ref BITMAPINFO bitmapInfo, int iUsage, [Out] out IntPtr ppvBits, IntPtr hSection, int dwOffset); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeHBITMAP CreateDIBSection(SafeDC hdc, ref BITMAPINFO bitmapInfo, out IntPtr ppvBits, IntPtr hSection, int dwOffset) + { + const int DIB_RGB_COLORS = 0; + SafeHBITMAP hBitmap = null; + if (hdc == null) + { + hBitmap = _CreateDIBSectionIntPtr(IntPtr.Zero, ref bitmapInfo, DIB_RGB_COLORS, out ppvBits, hSection, dwOffset); + } + else + { + hBitmap = _CreateDIBSection(hdc, ref bitmapInfo, DIB_RGB_COLORS, out ppvBits, hSection, dwOffset); + } + + if (hBitmap.IsInvalid) + { + HRESULT.ThrowLastError(); + } + + return hBitmap; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateRoundRectRgn", SetLastError = true)] + private static extern IntPtr _CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse) + { + IntPtr ret = _CreateRoundRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, nWidthEllipse, nHeightEllipse); + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateRectRgn", SetLastError = true)] + private static extern IntPtr _CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect) + { + IntPtr ret = _CreateRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect); + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateRectRgnIndirect", SetLastError = true)] + private static extern IntPtr _CreateRectRgnIndirect([In] ref RECT lprc); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateRectRgnIndirect(RECT lprc) + { + IntPtr ret = _CreateRectRgnIndirect(ref lprc); + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + public static extern IntPtr CreateSolidBrush(int crColor); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CreateWindowExW")] + private static extern IntPtr _CreateWindowEx( + WS_EX dwExStyle, + [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, + [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, + WS dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateWindowEx( + WS_EX dwExStyle, + string lpClassName, + string lpWindowName, + WS dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam) + { + IntPtr ret = _CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + if (IntPtr.Zero == ret) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "DefWindowProcW")] + public static extern IntPtr DefWindowProc(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteObject(IntPtr hObject); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DestroyIcon(IntPtr handle); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DestroyWindow(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindow(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS pMarInset); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmIsCompositionEnabled", PreserveSig = false)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _DwmIsCompositionEnabled(); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmGetColorizationColor", PreserveSig = true)] + private static extern HRESULT _DwmGetColorizationColor(out uint pcrColorization, [Out, MarshalAs(UnmanagedType.Bool)] out bool pfOpaqueBlend); + + public static bool DwmGetColorizationColor(out uint pcrColorization, out bool pfOpaqueBlend) + { + // Make this call safe to make on downlevel OSes... + if (Utility.IsOSVistaOrNewer && IsThemeActive()) + { + HRESULT hr = _DwmGetColorizationColor(out pcrColorization, out pfOpaqueBlend); + if (hr.Succeeded) + { + return true; + } + } + + // Default values. If for some reason the native DWM API fails it's never enough of a reason + // to bring down the app. Empirically it still sometimes returns errors even when the theme service is on. + // We'll still use the boolean return value to allow the caller to respond if they care. + pcrColorization = 0xFF000000; + pfOpaqueBlend = true; + + return false; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool DwmIsCompositionEnabled() + { + // Make this call safe to make on downlevel OSes... + if (!Utility.IsOSVistaOrNewer) + { + return false; + } + return _DwmIsCompositionEnabled(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DwmDefWindowProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam, out IntPtr plResult); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmSetWindowAttribute")] + private static extern void _DwmSetWindowAttribute(IntPtr hwnd, DWMWA dwAttribute, ref int pvAttribute, int cbAttribute); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void DwmSetWindowAttributeFlip3DPolicy(IntPtr hwnd, DWMFLIP3D flip3dPolicy) + { + Assert.IsTrue(Utility.IsOSVistaOrNewer); + var dwPolicy = (int)flip3dPolicy; + _DwmSetWindowAttribute(hwnd, DWMWA.FLIP3D_POLICY, ref dwPolicy, sizeof(int)); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void DwmSetWindowAttributeDisallowPeek(IntPtr hwnd, bool disallowPeek) + { + Assert.IsTrue(Utility.IsOSWindows7OrNewer); + int dwDisallow = (int)(disallowPeek ? Win32Value.TRUE : Win32Value.FALSE); + _DwmSetWindowAttribute(hwnd, DWMWA.DISALLOW_PEEK, ref dwDisallow, sizeof(int)); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "EnableMenuItem")] + private static extern int _EnableMenuItem(IntPtr hMenu, SC uIDEnableItem, MF uEnable); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static MF EnableMenuItem(IntPtr hMenu, SC uIDEnableItem, MF uEnable) + { + // Returns the previous state of the menu item, or -1 if the menu item does not exist. + int iRet = _EnableMenuItem(hMenu, uIDEnableItem, uEnable); + return (MF)iRet; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "RemoveMenu", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void RemoveMenu(IntPtr hMenu, SC uPosition, MF uFlags) + { + if (!_RemoveMenu(hMenu, (uint)uPosition, (uint)uFlags)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "DrawMenuBar", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _DrawMenuBar(IntPtr hWnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void DrawMenuBar(IntPtr hWnd) + { + if (!_DrawMenuBar(hWnd)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll")] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FindClose(IntPtr handle); + + // Not shimming this SetLastError=true function because callers want to evaluate the reason for failure. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern SafeFindHandle FindFirstFileW(string lpFileName, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATAW lpFindFileData); + + // Not shimming this SetLastError=true function because callers want to evaluate the reason for failure. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FindNextFileW(SafeFindHandle hndFindFile, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATAW lpFindFileData); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetClientRect", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetClientRect(IntPtr hwnd, [Out] out RECT lpRect); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static RECT GetClientRect(IntPtr hwnd) + { + RECT rc; + if (!_GetClientRect(hwnd, out rc)) + { + HRESULT.ThrowLastError(); + } + return rc; + } + + [DllImport("uxtheme.dll", EntryPoint="GetCurrentThemeName", CharSet = CharSet.Unicode)] + private static extern HRESULT _GetCurrentThemeName( + StringBuilder pszThemeFileName, + int dwMaxNameChars, + StringBuilder pszColorBuff, + int cchMaxColorChars, + StringBuilder pszSizeBuff, + int cchMaxSizeChars); + + public static void GetCurrentThemeName(out string themeFileName, out string color, out string size) + { + // Not expecting strings longer than MAX_PATH. We will return the error + var fileNameBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + var colorBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + var sizeBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + + // This will throw if the theme service is not active (e.g. not UxTheme!IsThemeActive). + _GetCurrentThemeName(fileNameBuilder, fileNameBuilder.Capacity, + colorBuilder, colorBuilder.Capacity, + sizeBuilder, sizeBuilder.Capacity) + .ThrowIfFailed(); + + themeFileName = fileNameBuilder.ToString(); + color = colorBuilder.ToString(); + size = sizeBuilder.ToString(); + } + + [DllImport("uxtheme.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsThemeActive(); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [Obsolete("Use SafeDC.GetDC instead.", true)] + public static void GetDC() { } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + public static extern int GetDeviceCaps(SafeDC hdc, DeviceCap nIndex); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", EntryPoint = "GetModuleFileName", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern int _GetModuleFileName(IntPtr hModule, StringBuilder lpFilename, int nSize); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string GetModuleFileName(IntPtr hModule) + { + var buffer = new StringBuilder((int)Win32Value.MAX_PATH); + while (true) + { + int size = _GetModuleFileName(hModule, buffer, buffer.Capacity); + if (size == 0) + { + HRESULT.ThrowLastError(); + } + + // GetModuleFileName returns nSize when it's truncated but does NOT set the last error. + // MSDN documentation says this has changed in Windows 2000+. + if (size == buffer.Capacity) + { + // Enlarge the buffer and try again. + buffer.EnsureCapacity(buffer.Capacity * 2); + continue; + } + + return buffer.ToString(); + } + } + + [DllImport("kernel32.dll", EntryPoint = "GetModuleHandleW", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern IntPtr _GetModuleHandle([MarshalAs(UnmanagedType.LPWStr)] string lpModuleName); + + public static IntPtr GetModuleHandle(string lpModuleName) + { + IntPtr retPtr = _GetModuleHandle(lpModuleName); + if (retPtr == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + return retPtr; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetMonitorInfo", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetMonitorInfo(IntPtr hMonitor, [In, Out] MONITORINFO lpmi); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static MONITORINFO GetMonitorInfo(IntPtr hMonitor) + { + var mi = new MONITORINFO(); + if (!_GetMonitorInfo(hMonitor, mi)) + { + throw new Win32Exception(); + } + return mi; + } + + [DllImport("gdi32.dll", EntryPoint = "GetStockObject", SetLastError = true)] + private static extern IntPtr _GetStockObject(StockObject fnObject); + + public static IntPtr GetStockObject(StockObject fnObject) + { + IntPtr retPtr = _GetStockObject(fnObject); + if (retPtr == null) + { + HRESULT.ThrowLastError(); + } + return retPtr; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern IntPtr GetSystemMenu(IntPtr hWnd, [MarshalAs(UnmanagedType.Bool)] bool bRevert); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern int GetSystemMetrics(SM nIndex); + + // This is aliased as a macro in 32bit Windows. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr GetWindowLongPtr(IntPtr hwnd, GWL nIndex) + { + IntPtr ret = IntPtr.Zero; + if (8 == IntPtr.Size) + { + ret = GetWindowLongPtr64(hwnd, nIndex); + } + else + { + ret = new IntPtr(GetWindowLongPtr32(hwnd, nIndex)); + } + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + /// + /// Sets attributes to control how visual styles are applied to a specified window. + /// + /// + /// Handle to a window to apply changes to. + /// + /// + /// Value of type WINDOWTHEMEATTRIBUTETYPE that specifies the type of attribute to set. + /// The value of this parameter determines the type of data that should be passed in the pvAttribute parameter. + /// Can be the following value: + /// WTA_NONCLIENT (Specifies non-client related attributes). + /// pvAttribute must be a pointer of type WTA_OPTIONS. + /// + /// + /// A pointer that specifies attributes to set. Type is determined by the value of the eAttribute value. + /// + /// + /// Specifies the size, in bytes, of the data pointed to by pvAttribute. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("uxtheme.dll", PreserveSig = false)] + public static extern void SetWindowThemeAttribute([In] IntPtr hwnd, [In] WINDOWTHEMEATTRIBUTETYPE eAttribute, [In] ref WTA_OPTIONS pvAttribute, [In] uint cbAttribute); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetWindowLong", SetLastError = true)] + private static extern int GetWindowLongPtr32(IntPtr hWnd, GWL nIndex); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = true)] + private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, GWL nIndex); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetWindowPlacement(IntPtr hwnd, WINDOWPLACEMENT lpwndpl); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static WINDOWPLACEMENT GetWindowPlacement(IntPtr hwnd) + { + WINDOWPLACEMENT wndpl = new WINDOWPLACEMENT(); + if (GetWindowPlacement(hwnd, wndpl)) + { + return wndpl; + } + throw new Win32Exception(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetWindowRect", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetWindowRect(IntPtr hWnd, out RECT lpRect); + + public static RECT GetWindowRect(IntPtr hwnd) + { + RECT rc; + if (!_GetWindowRect(hwnd, out rc)) + { + HRESULT.ThrowLastError(); + } + return rc; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipCreateBitmapFromStream(IStream stream, out IntPtr bitmap); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipCreateHBITMAPFromBitmap(IntPtr bitmap, out IntPtr hbmReturn, Int32 background); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipCreateHICONFromBitmap(IntPtr bitmap, out IntPtr hbmReturn); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipDisposeImage(IntPtr image); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipImageForceValidation(IntPtr image); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdiplusStartup(out IntPtr token, StartupInput input, out StartupOutput output); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdiplusShutdown(IntPtr token); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindowVisible(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", EntryPoint = "LocalFree", SetLastError = true)] + private static extern IntPtr _LocalFree(IntPtr hMem); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "PostMessage", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _PostMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void PostMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam) + { + if (!_PostMessage(hWnd, Msg, wParam, lParam)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")] + private static extern short _RegisterClassEx([In] ref WNDCLASSEX lpwcx); + + // Note that this will throw HRESULT_FROM_WIN32(ERROR_CLASS_ALREADY_EXISTS) on duplicate registration. + // If needed, consider adding a Try* version of this function that returns the error code since that + // may be ignorable. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static short RegisterClassEx(ref WNDCLASSEX lpwcx) + { + short ret = _RegisterClassEx(ref lpwcx); + if (ret == 0) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "RegisterWindowMessage", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern uint _RegisterWindowMessage([MarshalAs(UnmanagedType.LPWStr)] string lpString); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static WM RegisterWindowMessage(string lpString) + { + uint iRet = _RegisterWindowMessage(lpString); + if (iRet == 0) + { + HRESULT.ThrowLastError(); + } + return (WM)iRet; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetActiveWindow", SetLastError = true)] + private static extern IntPtr _SetActiveWindow(IntPtr hWnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SetActiveWindow(IntPtr hwnd) + { + Verify.IsNotDefault(hwnd, "hwnd"); + IntPtr ret = _SetActiveWindow(hwnd); + if (ret == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + // This is aliased as a macro in 32bit Windows. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SetClassLongPtr(IntPtr hwnd, GCLP nIndex, IntPtr dwNewLong) + { + if (8 == IntPtr.Size) + { + return SetClassLongPtr64(hwnd, nIndex, dwNewLong); + } + return new IntPtr(SetClassLongPtr32(hwnd, nIndex, dwNewLong.ToInt32())); + } + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetClassLong", SetLastError = true)] + private static extern int SetClassLongPtr32(IntPtr hWnd, GCLP nIndex, int dwNewLong); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetClassLongPtr", SetLastError = true)] + private static extern IntPtr SetClassLongPtr64(IntPtr hWnd, GCLP nIndex, IntPtr dwNewLong); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", SetLastError = true)] + public static extern ErrorModes SetErrorMode(ErrorModes newMode); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "SetProcessWorkingSetSize")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SetProcessWorkingSetSize(IntPtr hProcess, IntPtr dwMinimiumWorkingSetSize, IntPtr dwMaximumWorkingSetSize); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SetProcessWorkingSetSize(IntPtr hProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize) + { + if (!_SetProcessWorkingSetSize(hProcess, new IntPtr(dwMinimumWorkingSetSize), new IntPtr(dwMaximumWorkingSetSize))) + { + throw new Win32Exception(); + } + } + + // This is aliased as a macro in 32bit Windows. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SetWindowLongPtr(IntPtr hwnd, GWL nIndex, IntPtr dwNewLong) + { + if (8 == IntPtr.Size) + { + return SetWindowLongPtr64(hwnd, nIndex, dwNewLong); + } + return new IntPtr(SetWindowLongPtr32(hwnd, nIndex, dwNewLong.ToInt32())); + } + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] + private static extern int SetWindowLongPtr32(IntPtr hWnd, GWL nIndex, int dwNewLong); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] + private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, GWL nIndex, IntPtr dwNewLong); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowRgn", SetLastError = true)] + private static extern int _SetWindowRgn(IntPtr hWnd, IntPtr hRgn, [MarshalAs(UnmanagedType.Bool)] bool bRedraw); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw) + { + int err = _SetWindowRgn(hWnd, hRgn, bRedraw); + if (0 == err) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags) + { + if (!_SetWindowPos(hWnd, hWndInsertAfter, x, y, cx, cy, uFlags)) + { + // If this fails it's never worth taking down the process. Let the caller deal with the error if they want. + return false; + } + + return true; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", SetLastError = false)] + public static extern Win32Error SHFileOperation(ref SHFILEOPSTRUCT lpFileOp); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ShowWindow(IntPtr hwnd, SW nCmdShow); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SystemParametersInfo_String(SPI uiAction, int uiParam, [MarshalAs(UnmanagedType.LPWStr)] string pvParam, SPIF fWinIni); + + /// Overload of SystemParametersInfo for getting and setting NONCLIENTMETRICS. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SystemParametersInfo_NONCLIENTMETRICS(SPI uiAction, int uiParam, [In, Out] ref NONCLIENTMETRICS pvParam, SPIF fWinIni); + + /// Overload of SystemParametersInfo for getting and setting HIGHCONTRAST. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SystemParametersInfo_HIGHCONTRAST(SPI uiAction, int uiParam, [In, Out] ref HIGHCONTRAST pvParam, SPIF fWinIni); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SystemParametersInfo(SPI uiAction, int uiParam, string pvParam, SPIF fWinIni) + { + if (!_SystemParametersInfo_String(uiAction, uiParam, pvParam, fWinIni)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static NONCLIENTMETRICS SystemParameterInfo_GetNONCLIENTMETRICS() + { + var metrics = Utility.IsOSVistaOrNewer + ? NONCLIENTMETRICS.VistaMetricsStruct + : NONCLIENTMETRICS.XPMetricsStruct; + + if (!_SystemParametersInfo_NONCLIENTMETRICS(SPI.GETNONCLIENTMETRICS, metrics.cbSize, ref metrics, SPIF.None)) + { + HRESULT.ThrowLastError(); + } + + return metrics; + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static HIGHCONTRAST SystemParameterInfo_GetHIGHCONTRAST() + { + var hc = new HIGHCONTRAST { cbSize = Marshal.SizeOf(typeof(HIGHCONTRAST)) }; + + if (!_SystemParametersInfo_HIGHCONTRAST(SPI.GETHIGHCONTRAST, hc.cbSize, ref hc, SPIF.None)) + { + HRESULT.ThrowLastError(); + } + + return hc; + } + + // This function is strange in that it returns a BOOL if TPM_RETURNCMD isn't specified, but otherwise the command Id. + // Currently it's only used with TPM_RETURNCMD, so making the signature match that. + [DllImport("user32.dll")] + public static extern uint TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "SelectObject", SetLastError = true)] + private static extern IntPtr _SelectObject(SafeDC hdc, IntPtr hgdiobj); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SelectObject(SafeDC hdc, IntPtr hgdiobj) + { + IntPtr ret = _SelectObject(hdc, hgdiobj); + if (ret == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "SelectObject", SetLastError = true)] + private static extern IntPtr _SelectObjectSafeHBITMAP(SafeDC hdc, SafeHBITMAP hgdiobj); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SelectObject(SafeDC hdc, SafeHBITMAP hgdiobj) + { + IntPtr ret = _SelectObjectSafeHBITMAP(hdc, hgdiobj); + if (ret == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + public static extern int SendInput(int nInputs, ref INPUT pInputs, int cbSize); + + // Depending on the message, callers may want to call GetLastError based on the return value. + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr SendMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "UnregisterClass", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UnregisterClassAtom(IntPtr lpClassName, IntPtr hInstance); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "UnregisterClass", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UnregisterClassName(string lpClassName, IntPtr hInstance); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UnregisterClass(short atom, IntPtr hinstance) + { + if (!_UnregisterClassAtom(new IntPtr(atom), hinstance)) + { + HRESULT.ThrowLastError(); + } + } + + public static void UnregisterClass(string lpClassName, IntPtr hInstance) + { + if (!_UnregisterClassName(lpClassName, hInstance)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "UpdateLayeredWindow")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UpdateLayeredWindow( + IntPtr hwnd, + SafeDC hdcDst, + [In] ref POINT pptDst, + [In] ref SIZE psize, + SafeDC hdcSrc, + [In] ref POINT pptSrc, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "UpdateLayeredWindow")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UpdateLayeredWindowIntPtr( + IntPtr hwnd, + IntPtr hdcDst, + IntPtr pptDst, + IntPtr psize, + IntPtr hdcSrc, + IntPtr pptSrc, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UpdateLayeredWindow( + IntPtr hwnd, + SafeDC hdcDst, + ref POINT pptDst, + ref SIZE psize, + SafeDC hdcSrc, + ref POINT pptSrc, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags) + { + if (!_UpdateLayeredWindow(hwnd, hdcDst, ref pptDst, ref psize, hdcSrc, ref pptSrc, crKey, ref pblend, dwFlags)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UpdateLayeredWindow( + IntPtr hwnd, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags) + { + if (!_UpdateLayeredWindowIntPtr(hwnd, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, crKey, ref pblend, dwFlags)) + { + HRESULT.ThrowLastError(); + } + } + + #region Win7 declarations + + [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocs_String(SHARD uFlags, [MarshalAs(UnmanagedType.LPWStr)] string pv); + + // This overload is required. There's a cast in the Shell code that causes the wrong vtbl to be used + // if we let the marshaller convert the parameter to an IUnknown. + [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocs_ShellLink(SHARD uFlags, IShellLinkW pv); + + public static void SHAddToRecentDocs(string path) + { + _SHAddToRecentDocs_String(SHARD.PATHW, path); + } + + // Win7 only. + public static void SHAddToRecentDocs(IShellLinkW shellLink) + { + _SHAddToRecentDocs_ShellLink(SHARD.LINK, shellLink); + } + + + // #define DWM_SIT_DISPLAYFRAME 0x00000001 // Display a window frame around the provided bitmap + + [DllImport("dwmapi.dll", EntryPoint="DwmGetCompositionTimingInfo")] + private static extern HRESULT _DwmGetCompositionTimingInfo(IntPtr hwnd, ref DWM_TIMING_INFO pTimingInfo); + + public static DWM_TIMING_INFO? DwmGetCompositionTimingInfo(IntPtr hwnd) + { + if (!Utility.IsOSVistaOrNewer) + { + // API was new to Vista. + return null; + } + + var dti = new DWM_TIMING_INFO { cbSize = Marshal.SizeOf(typeof(DWM_TIMING_INFO)) }; + HRESULT hr = _DwmGetCompositionTimingInfo( Utility.IsOSWindows8OrNewer ? IntPtr.Zero : hwnd, ref dti ); + if (hr == HRESULT.E_PENDING) + { + // The system isn't yet ready to respond. Return null rather than throw. + return null; + } + hr.ThrowIfFailed(); + + return dti; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmInvalidateIconicBitmaps(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmSetIconicThumbnail(IntPtr hwnd, IntPtr hbmp, DWM_SIT dwSITFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmSetIconicLivePreviewBitmap(IntPtr hwnd, IntPtr hbmp, RefPOINT pptClient, DWM_SIT dwSITFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false)] + public static extern void SHGetItemFromDataObject(IDataObject pdtobj, DOGIF dwFlags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false)] + public static extern HRESULT SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool Shell_NotifyIcon(NIM dwMessage, [In] NOTIFYICONDATA lpdata); + + /// + /// Sets the User Model AppID for the current process, enabling Windows to retrieve this ID + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false)] + public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID); + + /// + /// Retrieves the User Model AppID that has been explicitly set for the current process via SetCurrentProcessExplicitAppUserModelID + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll")] + public static extern HRESULT GetCurrentProcessExplicitAppUserModelID([Out, MarshalAs(UnmanagedType.LPWStr)] out string AppID); + + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/ShellProvider.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/ShellProvider.cs new file mode 100644 index 0000000..a367ddf --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/ShellProvider.cs @@ -0,0 +1,983 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Text; + + using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; + + #region Enums and Static Property Classes + + /// ShellItem attribute flags. SIATTRIBFLAGS_* + internal enum SIATTRIBFLAGS + { + AND = 0x00000001, + OR = 0x00000002, + APPCOMPAT = 0x00000003, + } + + internal enum APPDOCLISTTYPE + { + ADLT_RECENT = 0, // The recently used documents list + ADLT_FREQUENT, // The frequently used documents list + } + + /// + /// Flags for SetTabProperties. STPF_* + /// + /// The native enum was called STPFLAG. + [Flags] + internal enum STPF + { + NONE = 0x00000000, + USEAPPTHUMBNAILALWAYS = 0x00000001, + USEAPPTHUMBNAILWHENACTIVE = 0x00000002, + USEAPPPEEKALWAYS = 0x00000004, + USEAPPPEEKWHENACTIVE = 0x00000008, + } + + /// + /// Flags for Setting Taskbar Progress state. TBPF_* + /// + /// + /// The native enum was called TBPFLAG. + /// + internal enum TBPF + { + NOPROGRESS = 0x00000000, + INDETERMINATE = 0x00000001, + NORMAL = 0x00000002, + ERROR = 0x00000004, + PAUSED = 0x00000008, + } + + /// + /// THUMBBUTTON mask. THB_* + /// + [Flags] + internal enum THB : uint + { + BITMAP = 0x0001, + ICON = 0x0002, + TOOLTIP = 0x0004, + FLAGS = 0x0008, + } + + /// + /// THUMBBUTTON flags. THBF_* + /// + [Flags] + internal enum THBF : uint + { + ENABLED = 0x0000, + DISABLED = 0x0001, + DISMISSONCLICK = 0x0002, + NOBACKGROUND = 0x0004, + HIDDEN = 0x0008, + // Added post-beta + NONINTERACTIVE = 0x0010, + } + + /// + /// GetPropertyStoreFlags. GPS_*. + /// + /// + /// These are new for Vista, but are used in downlevel components + /// + internal enum GPS + { + // If no flags are specified (GPS_DEFAULT), a read-only property store is returned that includes properties for the file or item. + // In the case that the shell item is a file, the property store contains: + // 1. properties about the file from the file system + // 2. properties from the file itself provided by the file's property handler, unless that file is offline, + // see GPS_OPENSLOWITEM + // 3. if requested by the file's property handler and supported by the file system, properties stored in the + // alternate property store. + // + // Non-file shell items should return a similar read-only store + // + // Specifying other GPS_ flags modifies the store that is returned + DEFAULT = 0x00000000, + HANDLERPROPERTIESONLY = 0x00000001, // only include properties directly from the file's property handler + READWRITE = 0x00000002, // Writable stores will only include handler properties + TEMPORARY = 0x00000004, // A read/write store that only holds properties for the lifetime of the IShellItem object + FASTPROPERTIESONLY = 0x00000008, // do not include any properties from the file's property handler (because the file's property handler will hit the disk) + OPENSLOWITEM = 0x00000010, // include properties from a file's property handler, even if it means retrieving the file from offline storage. + DELAYCREATION = 0x00000020, // delay the creation of the file's property handler until those properties are read, written, or enumerated + BESTEFFORT = 0x00000040, // For readonly stores, succeed and return all available properties, even if one or more sources of properties fails. Not valid with GPS_READWRITE. + NO_OPLOCK = 0x00000080, // some data sources protect the read property store with an oplock, this disables that + MASK_VALID = 0x000000FF, + } + + /// + /// KNOWNDESTCATEGORY. KDC_* + /// + internal enum KDC + { + FREQUENT = 1, + RECENT, + } + + // IShellFolder::GetAttributesOf flags + [Flags] + internal enum SFGAO : uint + { + /// Objects can be copied + /// DROPEFFECT_COPY + CANCOPY = 0x1, + /// Objects can be moved + /// DROPEFFECT_MOVE + CANMOVE = 0x2, + /// Objects can be linked + /// + /// DROPEFFECT_LINK. + /// + /// If this bit is set on an item in the shell folder, a + /// 'Create Shortcut' menu item will be added to the File + /// menu and context menus for the item. If the user selects + /// that command, your IContextMenu::InvokeCommand() will be called + /// with 'link'. + /// That flag will also be used to determine if 'Create Shortcut' + /// should be added when the item in your folder is dragged to another + /// folder. + /// + CANLINK = 0x4, + /// supports BindToObject(IID_IStorage) + STORAGE = 0x00000008, + /// Objects can be renamed + CANRENAME = 0x00000010, + /// Objects can be deleted + CANDELETE = 0x00000020, + /// Objects have property sheets + HASPROPSHEET = 0x00000040, + + // unused = 0x00000080, + + /// Objects are drop target + DROPTARGET = 0x00000100, + CAPABILITYMASK = 0x00000177, + // unused = 0x00000200, + // unused = 0x00000400, + // unused = 0x00000800, + // unused = 0x00001000, + /// Object is encrypted (use alt color) + ENCRYPTED = 0x00002000, + /// 'Slow' object + ISSLOW = 0x00004000, + /// Ghosted icon + GHOSTED = 0x00008000, + /// Shortcut (link) + LINK = 0x00010000, + /// Shared + SHARE = 0x00020000, + /// Read-only + READONLY = 0x00040000, + /// Hidden object + HIDDEN = 0x00080000, + DISPLAYATTRMASK = 0x000FC000, + /// May contain children with SFGAO_FILESYSTEM + FILESYSANCESTOR = 0x10000000, + /// Support BindToObject(IID_IShellFolder) + FOLDER = 0x20000000, + /// Is a win32 file system object (file/folder/root) + FILESYSTEM = 0x40000000, + /// May contain children with SFGAO_FOLDER (may be slow) + HASSUBFOLDER = 0x80000000, + CONTENTSMASK = 0x80000000, + /// Invalidate cached information (may be slow) + VALIDATE = 0x01000000, + /// Is this removeable media? + REMOVABLE = 0x02000000, + /// Object is compressed (use alt color) + COMPRESSED = 0x04000000, + /// Supports IShellFolder, but only implements CreateViewObject() (non-folder view) + BROWSABLE = 0x08000000, + /// Is a non-enumerated object (should be hidden) + NONENUMERATED = 0x00100000, + /// Should show bold in explorer tree + NEWCONTENT = 0x00200000, + /// Obsolete + CANMONIKER = 0x00400000, + /// Obsolete + HASSTORAGE = 0x00400000, + /// Supports BindToObject(IID_IStream) + STREAM = 0x00400000, + /// May contain children with SFGAO_STORAGE or SFGAO_STREAM + STORAGEANCESTOR = 0x00800000, + /// For determining storage capabilities, ie for open/save semantics + STORAGECAPMASK = 0x70C50008, + /// + /// Attributes that are masked out for PKEY_SFGAOFlags because they are considered + /// to cause slow calculations or lack context + /// (SFGAO_VALIDATE | SFGAO_ISSLOW | SFGAO_HASSUBFOLDER and others) + /// + PKEYSFGAOMASK = 0x81044000, + } + + /// + /// IShellFolder::EnumObjects grfFlags bits. Also called SHCONT + /// + internal enum SHCONTF + { + CHECKING_FOR_CHILDREN = 0x0010, // hint that client is checking if (what) child items the folder contains - not all details (e.g. short file name) are needed + FOLDERS = 0x0020, // only want folders enumerated (SFGAO_FOLDER) + NONFOLDERS = 0x0040, // include non folders (items without SFGAO_FOLDER) + INCLUDEHIDDEN = 0x0080, // show items normally hidden (items with SFGAO_HIDDEN) + INIT_ON_FIRST_NEXT = 0x0100, // DEFUNCT - this is always assumed + NETPRINTERSRCH = 0x0200, // hint that client is looking for printers + SHAREABLE = 0x0400, // hint that client is looking sharable resources (local drives or hidden root shares) + STORAGE = 0x0800, // include all items with accessible storage and their ancestors + NAVIGATION_ENUM = 0x1000, // mark child folders to indicate that they should provide a "navigation" enumeration by default + FASTITEMS = 0x2000, // hint that client is only interested in items that can be enumerated quickly + FLATLIST = 0x4000, // enumerate items as flat list even if folder is stacked + ENABLE_ASYNC = 0x8000, // inform enumerator that client is listening for change notifications so enumerator does not need to be complete, items can be reported via change notifications + } + + /// + /// IShellFolder::GetDisplayNameOf/SetNameOf uFlags. Also called SHGDNF. + /// + /// + /// For compatibility with SIGDN, these bits must all sit in the LOW word. + /// + [Flags] + internal enum SHGDN + { + SHGDN_NORMAL = 0x0000, // default (display purpose) + SHGDN_INFOLDER = 0x0001, // displayed under a folder (relative) + SHGDN_FOREDITING = 0x1000, // for in-place editing + SHGDN_FORADDRESSBAR = 0x4000, // UI friendly parsing name (remove ugly stuff) + SHGDN_FORPARSING = 0x8000, // parsing name for ParseDisplayName() + } + + /// + /// SHELLITEMCOMPAREHINTF. SICHINT_*. + /// + internal enum SICHINT : uint + { + /// iOrder based on display in a folder view + DISPLAY = 0x00000000, + /// exact instance compare + ALLFIELDS = 0x80000000, + /// iOrder based on canonical name (better performance) + CANONICAL = 0x10000000, + TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000, + }; + + /// + /// ShellItem enum. SIGDN_*. + /// + internal enum SIGDN : uint + { // lower word (& with 0xFFFF) + NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL + PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING + DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING + PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING + DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + FILESYSPATH = 0x80058000, // SHGDN_FORPARSING + URL = 0x80068000, // SHGDN_FORPARSING + PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + PARENTRELATIVE = 0x80080001, // SHGDN_INFOLDER + } + + /// + /// STR_GPS_* + /// + /// + /// When requesting a property store through IShellFolder, you can specify the equivalent of + /// GPS_DEFAULT by passing in a null IBindCtx parameter. + /// + /// You can specify the equivalent of GPS_READWRITE by passing a mode of STGM_READWRITE | STGM_EXCLUSIVE + /// in the bind context + /// + /// Here are the string versions of GPS_ flags, passed to IShellFolder::BindToObject() via IBindCtx::RegisterObjectParam() + /// These flags are valid when requesting an IPropertySetStorage or IPropertyStore handler + /// + /// The meaning of these flags are described above. + /// + /// There is no STR_ equivalent for GPS_TEMPORARY because temporary property stores + /// are provided by IShellItem2 only -- not by the underlying IShellFolder. + /// + internal static class STR_GPS + { + public const string HANDLERPROPERTIESONLY = "GPS_HANDLERPROPERTIESONLY"; + public const string FASTPROPERTIESONLY = "GPS_FASTPROPERTIESONLY"; + public const string OPENSLOWITEM = "GPS_OPENSLOWITEM"; + public const string DELAYCREATION = "GPS_DELAYCREATION"; + public const string BESTEFFORT = "GPS_BESTEFFORT"; + public const string NO_OPLOCK = "GPS_NO_OPLOCK"; + } + + #endregion + + #region Structs + + [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)] + internal struct THUMBBUTTON + { + /// + /// WPARAM value for a THUMBBUTTON being clicked. + /// + public const int THBN_CLICKED = 0x1800; + + public THB dwMask; + public uint iId; + public uint iBitmap; + public IntPtr hIcon; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szTip; + public THBF dwFlags; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct PKEY + { + /// fmtid + private readonly Guid _fmtid; + /// pid + private readonly uint _pid; + + public PKEY(Guid fmtid, uint pid) + { + _fmtid = fmtid; + _pid = pid; + } + + /// PKEY_Title + public static readonly PKEY Title = new PKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2); + /// PKEY_AppUserModel_ID + public static readonly PKEY AppUserModel_ID = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5); + /// PKEY_AppUserModel_IsDestListSeparator + public static readonly PKEY AppUserModel_IsDestListSeparator = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 6); + /// PKEY_AppUserModel_RelaunchCommand + public static readonly PKEY AppUserModel_RelaunchCommand = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 2); + /// PKEY_AppUserModel_RelaunchDisplayNameResource + public static readonly PKEY AppUserModel_RelaunchDisplayNameResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 4); + /// PKEY_AppUserModel_RelaunchIconResource + public static readonly PKEY AppUserModel_RelaunchIconResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 3); + } + + #endregion + + #region Interfaces + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.EnumIdList), + ] + internal interface IEnumIDList + { + [PreserveSig()] + HRESULT Next(uint celt, out IntPtr rgelt, out int pceltFetched); + [PreserveSig()] + HRESULT Skip(uint celt); + void Reset(); + void Clone([Out, MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.EnumObjects), + ] + internal interface IEnumObjects + { + //[local] + // This signature might not work... Hopefully don't need this interface though. + void Next(uint celt, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.IUnknown, IidParameterIndex = 1, SizeParamIndex = 0)] object[] rgelt, [Out] out uint pceltFetched); + + /* + [call_as(Next)] HRESULT RemoteNext( + [in] ULONG celt, + [in] REFIID riid, + [out, size_is(celt), length_is(*pceltFetched), iid_is(riid)] void **rgelt, + [out] ULONG *pceltFetched); + */ + + void Skip(uint celt); + + void Reset(); + + IEnumObjects Clone(); + } + + /// Unknown Object Array + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectArray), + ] + internal interface IObjectArray + { + uint GetCount(); + [return: MarshalAs(UnmanagedType.IUnknown)] + object GetAt([In] uint uiIndex, [In] ref Guid riid); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectArray), + ] + interface IObjectCollection : IObjectArray + { + #region IObjectArray redeclarations + new uint GetCount(); + [return: MarshalAs(UnmanagedType.IUnknown)] + new object GetAt([In] uint uiIndex, [In] ref Guid riid); + #endregion + + void AddObject([MarshalAs(UnmanagedType.IUnknown)] object punk); + void AddFromArray(IObjectArray poaSource); + void RemoveObjectAt(uint uiIndex); + void Clear(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.PropertyStore) + ] + internal interface IPropertyStore + { + uint GetCount(); + PKEY GetAt(uint iProp); + void GetValue([In] ref PKEY pkey, [In, Out] PROPVARIANT pv); + void SetValue([In] ref PKEY pkey, PROPVARIANT pv); + void Commit(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellFolder), + ] + internal interface IShellFolder + { + void ParseDisplayName( + [In] IntPtr hwnd, + [In] IBindCtx pbc, + [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, + [In, Out] ref int pchEaten, + [Out] out IntPtr ppidl, + [In, Out] ref uint pdwAttributes); + + IEnumIDList EnumObjects( + [In] IntPtr hwnd, + [In] SHCONTF grfFlags); + + // returns an instance of a sub-folder which is specified by the IDList (pidl). + // IShellFolder or derived interfaces + [return: MarshalAs(UnmanagedType.Interface)] + object BindToObject( + [In] IntPtr pidl, + [In] IBindCtx pbc, + [In] ref Guid riid); + + // produces the same result as BindToObject() + [return: MarshalAs(UnmanagedType.Interface)] + object BindToStorage([In] IntPtr pidl, [In] IBindCtx pbc, [In] ref Guid riid); + + // compares two IDLists and returns the result. The shell + // explorer always passes 0 as lParam, which indicates 'sort by name'. + // It should return 0 (as CODE of the scode), if two id indicates the + // same object; negative value if pidl1 should be placed before pidl2; + // positive value if pidl2 should be placed before pidl1. + // use the macro ResultFromShort() to extract the result comparison + // it deals with the casting and type conversion issues for you + [PreserveSig] + HRESULT CompareIDs([In] IntPtr lParam, [In] IntPtr pidl1, [In] IntPtr pidl2); + + // creates a view object of the folder itself. The view + // object is a difference instance from the shell folder object. + // 'hwndOwner' can be used as the owner window of its dialog box or + // menu during the lifetime of the view object. + // This member function should always create a new + // instance which has only one reference count. The explorer may create + // more than one instances of view object from one shell folder object + // and treat them as separate instances. + // returns IShellView derived interface + [return: MarshalAs(UnmanagedType.Interface)] + object CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid); + + // returns the attributes of specified objects in that + // folder. 'cidl' and 'apidl' specifies objects. 'apidl' contains only + // simple IDLists. The explorer initializes *prgfInOut with a set of + // flags to be evaluated. The shell folder may optimize the operation + // by not returning unspecified flags. + void GetAttributesOf( + [In] uint cidl, + [In] IntPtr apidl, + [In, Out] ref SFGAO rgfInOut); + + // creates a UI object to be used for specified objects. + // The shell explorer passes either IID_IDataObject (for transfer operation) + // or IID_IContextMenu (for context menu operation) as riid + // and many other interfaces + [return: MarshalAs(UnmanagedType.Interface)] + object GetUIObjectOf( + [In] IntPtr hwndOwner, + [In] uint cidl, + [In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 2)] IntPtr apidl, + [In] ref Guid riid, + [In, Out] ref uint rgfReserved); + + // returns the display name of the specified object. + // If the ID contains the display name (in the locale character set), + // it returns the offset to the name. Otherwise, it returns a pointer + // to the display name string (UNICODE), which is allocated by the + // task allocator, or fills in a buffer. + // use the helper APIS StrRetToStr() or StrRetToBuf() to deal with the different + // forms of the STRRET structure + void GetDisplayNameOf([In] IntPtr pidl, [In] SHGDN uFlags, [Out] out IntPtr pName); + + // sets the display name of the specified object. + // If it changes the ID as well, it returns the new ID which is + // alocated by the task allocator. + void SetNameOf([In] IntPtr hwnd, + [In] IntPtr pidl, + [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, + [In] SHGDN uFlags, + [Out] out IntPtr ppidlOut); + } + + /// + /// Shell Namespace helper + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellItem), + ] + internal interface IShellItem + { + [return: MarshalAs(UnmanagedType.Interface)] + object BindToHandler(IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid); + + IShellItem GetParent(); + + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetDisplayName(SIGDN sigdnName); + + SFGAO GetAttributes(SFGAO sfgaoMask); + + int Compare(IShellItem psi, SICHINT hint); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellItemArray), + ] + internal interface IShellItemArray + { + [return: MarshalAs(UnmanagedType.Interface)] + object BindToHandler(IBindCtx pbc, [In] ref Guid rbhid, [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStore(int flags, [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyDescriptionList([In] ref PKEY keyType, [In] ref Guid riid); + + uint GetAttributes(SIATTRIBFLAGS dwAttribFlags, uint sfgaoMask); + + uint GetCount(); + + IShellItem GetItemAt(uint dwIndex); + + [return: MarshalAs(UnmanagedType.Interface)] + object EnumItems(); + } + + /// + /// Shell Namespace helper 2 + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellItem2), + ] + interface IShellItem2 : IShellItem + { + #region IShellItem redeclarations + [return: MarshalAs(UnmanagedType.Interface)] + new object BindToHandler([In] IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid); + new IShellItem GetParent(); + [return: MarshalAs(UnmanagedType.LPWStr)] + new string GetDisplayName(SIGDN sigdnName); + new SFGAO GetAttributes(SFGAO sfgaoMask); + new int Compare(IShellItem psi, SICHINT hint); + #endregion + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStore( + GPS flags, + [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStoreWithCreateObject( + GPS flags, + [MarshalAs(UnmanagedType.IUnknown)] object punkCreateObject, // factory for low-rights creation of type ICreateObject + [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStoreForKeys( + IntPtr rgKeys, + uint cKeys, + GPS flags, + [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyDescriptionList( + IntPtr keyType, + [In] ref Guid riid); + + // Ensures any cached information in this item is up to date, or returns __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) if the item does not exist. + void Update(IBindCtx pbc); + + PROPVARIANT GetProperty(IntPtr key); + + Guid GetCLSID(IntPtr key); + + FILETIME GetFileTime(IntPtr key); + + int GetInt32(IntPtr key); + + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetString(IntPtr key); + + uint GetUInt32(IntPtr key); + + ulong GetUInt64(IntPtr key); + + [return: MarshalAs(UnmanagedType.Bool)] + void GetBool(IntPtr key); + } + + [ + ComImport, + InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellLink), + ] + internal interface IShellLinkW + { + void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, [In, Out] WIN32_FIND_DATAW pfd, SLGP fFlags); + void GetIDList(out IntPtr ppidl); + void SetIDList(IntPtr pidl); + void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxName); + void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); + void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); + void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); + void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); + void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + short GetHotKey(); + void SetHotKey(short wHotKey); + uint GetShowCmd(); + void SetShowCmd(uint iShowCmd); + void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon); + void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); + void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved); + void Resolve(IntPtr hwnd, uint fFlags); + void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList), + ] + internal interface ITaskbarList + { + /// + /// This function must be called first to validate use of other members. + /// + void HrInit(); + + /// + /// This function adds a tab for hwnd to the taskbar. + /// + /// The HWND for which to add the tab. + void AddTab(IntPtr hwnd); + + /// + /// This function deletes a tab for hwnd from the taskbar. + /// + /// The HWND for which the tab is to be deleted. + void DeleteTab(IntPtr hwnd); + + /// + /// This function activates the tab associated with hwnd on the taskbar. + /// + /// The HWND for which the tab is to be actuvated. + void ActivateTab(IntPtr hwnd); + + /// + /// This function marks hwnd in the taskbar as the active tab. + /// + /// The HWND to activate. + void SetActiveAlt(IntPtr hwnd); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList2), + ] + internal interface ITaskbarList2 : ITaskbarList + { + #region ITaskbarList redeclaration + new void HrInit(); + new void AddTab(IntPtr hwnd); + new void DeleteTab(IntPtr hwnd); + new void ActivateTab(IntPtr hwnd); + new void SetActiveAlt(IntPtr hwnd); + #endregion + + /// + /// Marks a window as full-screen. + /// + /// The handle of the window to be marked. + /// A Boolean value marking the desired full-screen status of the window. + /// + /// Setting the value of fFullscreen to true, the Shell treats this window as a full-screen window, and the taskbar + /// is moved to the bottom of the z-order when this window is active. Setting the value of fFullscreen to false + /// removes the full-screen marking, but does not cause the Shell to treat the window as though it were + /// definitely not full-screen. With a false fFullscreen value, the Shell depends on its automatic detection facility + /// to specify how the window should be treated, possibly still flagging the window as full-screen. + /// + void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + } + + // Used to remove items from the automatic destination lists created when apps or the system call SHAddToRecentDocs to report usage of a document. + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ApplicationDestinations) + ] + internal interface IApplicationDestinations + { + // Set the App User Model ID for the application removing destinations from its list. If an AppID is not provided + // via this method, the system will use a heuristically determined ID. This method must be called before + // RemoveDestination or RemoveAllDestinations. + void SetAppID([In, MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + + // Remove an IShellItem or an IShellLink from the automatic destination list + void RemoveDestination([MarshalAs(UnmanagedType.IUnknown)] object punk); + + // Clear the frequent and recent destination lists for this application. + void RemoveAllDestinations(); + } + + /// + /// Allows an application to retrieve the most recent and frequent documents opened in that app, as reported via SHAddToRecentDocs + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ApplicationDocumentLists) + ] + internal interface IApplicationDocumentLists + { + /// + /// Set the App User Model ID for the application retrieving this list. If an AppID is not provided via this method, + /// the system will use a heuristically determined ID. This method must be called before GetList. + /// + /// App Id. + void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + + /// + /// Retrieve an IEnumObjects or IObjectArray for IShellItems and/or IShellLinks. + /// Items may appear in both the frequent and recent lists. + /// + /// + /// + [return: MarshalAs(UnmanagedType.IUnknown)] + object GetList([In] APPDOCLISTTYPE listtype, [In] uint cItemsDesired, [In] ref Guid riid); + } + + // Custom Destination List + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.CustomDestinationList) + ] + internal interface ICustomDestinationList + { + void SetAppID([In, MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + + // Retrieve IObjectArray of IShellItems or IShellLinks that represent removed destinations + [return: MarshalAs(UnmanagedType.Interface)] + object BeginList(out uint pcMaxSlots, [In] ref Guid riid); + + // PreserveSig because this will return custom errors when attempting to add unregistered ShellItems. + // Can't readily detect that case without just trying to append it. + [PreserveSig] + HRESULT AppendCategory([MarshalAs(UnmanagedType.LPWStr)] string pszCategory, IObjectArray poa); + void AppendKnownCategory(KDC category); + [PreserveSig] + HRESULT AddUserTasks(IObjectArray poa); + void CommitList(); + + // Retrieve IObjectCollection of IShellItems + [return: MarshalAs(UnmanagedType.Interface)] + object GetRemovedDestinations([In] ref Guid riid); + void DeleteList([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + void AbortList(); + } + + /// + /// Provides access to the App User Model ID on objects supporting this value. + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectWithAppUserModelId) + ] + internal interface IObjectWithAppUserModelId + { + void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetAppID(); + }; + + /// + /// Provides access to the ProgID associated with an object + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectWithProgId) + ] + internal interface IObjectWithProgId + { + void SetProgID([MarshalAs(UnmanagedType.LPWStr)] string pszProgID); + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetProgID(); + }; + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList3), + ] + internal interface ITaskbarList3 : ITaskbarList2 + { + #region ITaskbarList2 redeclaration + + #region ITaskbarList redeclaration + new void HrInit(); + new void AddTab(IntPtr hwnd); + new void DeleteTab(IntPtr hwnd); + new void ActivateTab(IntPtr hwnd); + new void SetActiveAlt(IntPtr hwnd); + #endregion + + new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + + #endregion + + [PreserveSig] + HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal); + + [PreserveSig] + HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags); + + [PreserveSig] + HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI); + + [PreserveSig] + HRESULT UnregisterTab(IntPtr hwndTab); + + [PreserveSig] + HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore); + + [PreserveSig] + HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved); + + [PreserveSig] + HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + + [PreserveSig] + HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + + [PreserveSig] + HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl); + + [PreserveSig] + HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription); + + [PreserveSig] + HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip); + + // Using RefRECT to making passing NULL possible. Removes clipping from the HWND. + [PreserveSig] + HRESULT SetThumbnailClip(IntPtr hwnd, RefRECT prcClip); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList3), + ] + internal interface ITaskbarList4 : ITaskbarList3 + { + #region ITaskbarList3 redeclaration + + #region ITaskbarList2 redeclaration + + #region ITaskbarList redeclaration + new void HrInit(); + new void AddTab(IntPtr hwnd); + new void DeleteTab(IntPtr hwnd); + new void ActivateTab(IntPtr hwnd); + new void SetActiveAlt(IntPtr hwnd); + #endregion + + new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + + #endregion + + [PreserveSig] new HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal); + [PreserveSig] new HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags); + [PreserveSig] new HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI); + [PreserveSig] new HRESULT UnregisterTab(IntPtr hwndTab); + [PreserveSig] new HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore); + [PreserveSig] new HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved); + [PreserveSig] new HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + [PreserveSig] new HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + [PreserveSig] new HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl); + [PreserveSig] new HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription); + [PreserveSig] new HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip); + // Using RefRECT to making passing NULL possible. Removes clipping from the HWND. + [PreserveSig] new HRESULT SetThumbnailClip(IntPtr hwnd, RefRECT prcClip); + + #endregion + + void SetTabProperties(IntPtr hwndTab, STPF stpFlags); + } + + #endregion +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/StreamHelper.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/StreamHelper.cs new file mode 100644 index 0000000..8bdbc20 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/StreamHelper.cs @@ -0,0 +1,357 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + + // disambiguate with System.Runtime.InteropServices.STATSTG + using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG; + + // All these methods return void. Does the standard marshaller convert them to HRESULTs? + /// + /// Wraps a managed stream instance into an interface pointer consumable by COM. + /// + internal sealed class ManagedIStream : IStream, IDisposable + { + private const int STGTY_STREAM = 2; + private const int STGM_READWRITE = 2; + private const int LOCK_EXCLUSIVE = 2; + + private Stream _source; + + /// + /// Initializes a new instance of the ManagedIStream class with the specified managed Stream object. + /// + /// + /// The stream that this IStream reference is wrapping. + /// + public ManagedIStream(Stream source) + { + Verify.IsNotNull(source, "source"); + _source = source; + } + + private void _Validate() + { + if (null == _source) + { + throw new ObjectDisposedException("this"); + } + } + + // Comments are taken from MSDN IStream documentation. + #region IStream Members + + /// + /// Creates a new stream object with its own seek pointer that + /// references the same bytes as the original stream. + /// + /// + /// When this method returns, contains the new stream object. This parameter is passed uninitialized. + /// + /// + /// For more information, see the existing documentation for IStream::Clone in the MSDN library. + /// This class doesn't implement Clone. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")] + [Obsolete("The method is not implemented", true)] + public void Clone(out IStream ppstm) + { + ppstm = null; + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Ensures that any changes made to a stream object that is open in transacted + /// mode are reflected in the parent storage. + /// + /// + /// A value that controls how the changes for the stream object are committed. + /// + /// + /// For more information, see the existing documentation for IStream::Commit in the MSDN library. + /// + public void Commit(int grfCommitFlags) + { + _Validate(); + _source.Flush(); + } + + /// + /// Copies a specified number of bytes from the current seek pointer in the + /// stream to the current seek pointer in another stream. + /// + /// + /// A reference to the destination stream. + /// + /// + /// The number of bytes to copy from the source stream. + /// + /// + /// On successful return, contains the actual number of bytes read from the source. + /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written + /// to this parameter on success.) + /// + /// + /// On successful return, contains the actual number of bytes written to the destination. + /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written + /// to this parameter on success.) + /// + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) + { + Verify.IsNotNull(pstm, "pstm"); + + _Validate(); + + // Reasonbly sized buffer, don't try to copy large streams in bulk. + var buffer = new byte[4096]; + long cbWritten = 0; + + while (cbWritten < cb) + { + int cbRead = _source.Read(buffer, 0, buffer.Length); + if (0 == cbRead) + { + break; + } + + // COM documentation is a bit vague here whether NULL is valid for the third parameter. + // Going to assume it is, as most implementations I've seen treat it as optional. + // It's possible this will break on some IStream implementations. + pstm.Write(buffer, cbRead, IntPtr.Zero); + cbWritten += cbRead; + } + + if (IntPtr.Zero != pcbRead) + { + Marshal.WriteInt64(pcbRead, cbWritten); + } + + if (IntPtr.Zero != pcbWritten) + { + Marshal.WriteInt64(pcbWritten, cbWritten); + } + } + + /// + /// Restricts access to a specified range of bytes in the stream. + /// + /// + /// The byte offset for the beginning of the range. + /// + /// + /// The length of the range, in bytes, to restrict. + /// + /// + /// The requested restrictions on accessing the range. + /// + /// + /// For more information, see the existing documentation for IStream::LockRegion in the MSDN library. + /// This class doesn't implement LockRegion. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)] + public void LockRegion(long libOffset, long cb, int dwLockType) + { + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Reads a specified number of bytes from the stream object into memory starting at the current seek pointer. + /// + /// + /// When this method returns, contains the data read from the stream. This parameter is passed uninitialized. + /// + /// + /// The number of bytes to read from the stream object. + /// + /// + /// A pointer to a ULONG variable that receives the actual number of bytes read from the stream object. + /// + /// + /// For more information, see the existing documentation for ISequentialStream::Read in the MSDN library. + /// + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void Read(byte[] pv, int cb, IntPtr pcbRead) + { + _Validate(); + + int cbRead = _source.Read(pv, 0, cb); + + if (IntPtr.Zero != pcbRead) + { + Marshal.WriteInt32(pcbRead, cbRead); + } + } + + + /// + /// Discards all changes that have been made to a transacted stream since the last Commit call. + /// + /// + /// This class doesn't implement Revert. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)] + public void Revert() + { + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Changes the seek pointer to a new location relative to the beginning of the + /// stream, to the end of the stream, or to the current seek pointer. + /// + /// + /// The displacement to add to dwOrigin. + /// + /// + /// The origin of the seek. The origin can be the beginning of the file, the current seek pointer, or the end of the file. + /// + /// + /// On successful return, contains the offset of the seek pointer from the beginning of the stream. + /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written + /// to this parameter on success.) + /// + /// + /// For more information, see the existing documentation for IStream::Seek in the MSDN library. + /// + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) + { + _Validate(); + + long position = _source.Seek(dlibMove, (SeekOrigin)dwOrigin); + + if (IntPtr.Zero != plibNewPosition) + { + Marshal.WriteInt64(plibNewPosition, position); + } + } + + /// + /// Changes the size of the stream object. + /// + /// + /// The new size of the stream as a number of bytes. + /// + /// + /// For more information, see the existing documentation for IStream::SetSize in the MSDN library. + /// + public void SetSize(long libNewSize) + { + _Validate(); + _source.SetLength(libNewSize); + } + + /// + /// Retrieves the STATSTG structure for this stream. + /// + /// + /// When this method returns, contains a STATSTG structure that describes this stream object. + /// This parameter is passed uninitialized. + /// + /// + /// Members in the STATSTG structure that this method does not return, thus saving some memory allocation operations. + /// + public void Stat(out STATSTG pstatstg, int grfStatFlag) + { + pstatstg = default(STATSTG); + _Validate(); + + pstatstg.type = STGTY_STREAM; + pstatstg.cbSize = _source.Length; + pstatstg.grfMode = STGM_READWRITE; + pstatstg.grfLocksSupported = LOCK_EXCLUSIVE; + } + + /// + /// Removes the access restriction on a range of bytes previously restricted with the LockRegion method. + /// + /// The byte offset for the beginning of the range. + /// + /// + /// The length, in bytes, of the range to restrict. + /// + /// + /// The access restrictions previously placed on the range. + /// + /// + /// For more information, see the existing documentation for IStream::UnlockRegion in the MSDN library. + /// This class doesn't implement UnlockRegion. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")] + [Obsolete("The method is not implemented", true)] + public void UnlockRegion(long libOffset, long cb, int dwLockType) + { + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Writes a specified number of bytes into the stream object starting at the current seek pointer. + /// + /// + /// The buffer to write this stream to. + /// + /// + /// The number of bytes to write to the stream. + /// + /// + /// On successful return, contains the actual number of bytes written to the stream object. + /// If the caller sets this pointer to null, this method does not provide the actual number + /// of bytes written. + /// + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void Write(byte[] pv, int cb, IntPtr pcbWritten) + { + _Validate(); + + _source.Write(pv, 0, cb); + + if (IntPtr.Zero != pcbWritten) + { + Marshal.WriteInt32(pcbWritten, cb); + } + } + + #endregion + + #region IDisposable Members + + /// + /// Releases resources controlled by this object. + /// + /// + /// Dispose can be called multiple times, but trying to use the object + /// after it has been disposed will generally throw ObjectDisposedExceptions. + /// + public void Dispose() + { + _source = null; + } + + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/Utilities.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/Utilities.cs new file mode 100644 index 0000000..ca99f5b --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/Utilities.cs @@ -0,0 +1,1062 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +// This file contains general utilities to aid in development. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Security.Cryptography; + using System.Text; + using System.Windows; + using System.Windows.Media; + using System.Windows.Media.Imaging; + + internal static partial class Utility + { + private static readonly Version _osVersion = Environment.OSVersion.Version; + private static readonly Version _presentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _MemCmp(IntPtr left, IntPtr right, long cb) + { + int offset = 0; + + for (; offset < (cb - sizeof(Int64)); offset += sizeof(Int64)) + { + Int64 left64 = Marshal.ReadInt64(left, offset); + Int64 right64 = Marshal.ReadInt64(right, offset); + + if (left64 != right64) + { + return false; + } + } + + for (; offset < cb; offset += sizeof(byte)) + { + byte left8 = Marshal.ReadByte(left, offset); + byte right8 = Marshal.ReadByte(right, offset); + + if (left8 != right8) + { + return false; + } + } + + return true; + } + + /// The native RGB macro. + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int RGB(Color c) + { + return c.R | (c.G << 8) | (c.B << 16); + } + + /// Convert a native integer that represent a color with an alpha channel into a Color struct. + /// The integer that represents the color. Its bits are of the format 0xAARRGGBB. + /// A Color representation of the parameter. + public static Color ColorFromArgbDword(uint color) + { + return Color.FromArgb( + (byte)((color & 0xFF000000) >> 24), + (byte)((color & 0x00FF0000) >> 16), + (byte)((color & 0x0000FF00) >> 8), + (byte)((color & 0x000000FF) >> 0)); + } + + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int GET_X_LPARAM(IntPtr lParam) + { + return LOWORD(lParam.ToInt32()); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int GET_Y_LPARAM(IntPtr lParam) + { + return HIWORD(lParam.ToInt32()); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int HIWORD(int i) + { + return (short)(i >> 16); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int LOWORD(int i) + { + return (short)(i & 0xFFFF); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static bool AreStreamsEqual(Stream left, Stream right) + { + if (null == left) + { + return right == null; + } + if (null == right) + { + return false; + } + + if (!left.CanRead || !right.CanRead) + { + throw new NotSupportedException("The streams can't be read for comparison"); + } + + if (left.Length != right.Length) + { + return false; + } + + var length = (int)left.Length; + + // seek to beginning + left.Position = 0; + right.Position = 0; + + // total bytes read + int totalReadLeft = 0; + int totalReadRight = 0; + + // bytes read on this iteration + int cbReadLeft = 0; + int cbReadRight = 0; + + // where to store the read data + var leftBuffer = new byte[512]; + var rightBuffer = new byte[512]; + + // pin the left buffer + GCHandle handleLeft = GCHandle.Alloc(leftBuffer, GCHandleType.Pinned); + IntPtr ptrLeft = handleLeft.AddrOfPinnedObject(); + + // pin the right buffer + GCHandle handleRight = GCHandle.Alloc(rightBuffer, GCHandleType.Pinned); + IntPtr ptrRight = handleRight.AddrOfPinnedObject(); + + try + { + while (totalReadLeft < length) + { + Assert.AreEqual(totalReadLeft, totalReadRight); + + cbReadLeft = left.Read(leftBuffer, 0, leftBuffer.Length); + cbReadRight = right.Read(rightBuffer, 0, rightBuffer.Length); + + // verify the contents are an exact match + if (cbReadLeft != cbReadRight) + { + return false; + } + + if (!_MemCmp(ptrLeft, ptrRight, cbReadLeft)) + { + return false; + } + + totalReadLeft += cbReadLeft; + totalReadRight += cbReadRight; + } + + Assert.AreEqual(cbReadLeft, cbReadRight); + Assert.AreEqual(totalReadLeft, totalReadRight); + Assert.AreEqual(length, totalReadLeft); + + return true; + } + finally + { + handleLeft.Free(); + handleRight.Free(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool GuidTryParse(string guidString, out Guid guid) + { + Verify.IsNeitherNullNorEmpty(guidString, "guidString"); + + try + { + guid = new Guid(guidString); + return true; + } + catch (FormatException) + { + } + catch (OverflowException) + { + } + // Doesn't seem to be a valid guid. + guid = default(Guid); + return false; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(int value, int mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(uint value, uint mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(long value, long mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(ulong value, ulong mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsOSVistaOrNewer + { + get { return _osVersion >= new Version(6, 0); } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsOSWindows7OrNewer + { + get { return _osVersion >= new Version(6, 1); } + } + + [SuppressMessage( "Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode" )] + public static bool IsOSWindows8OrNewer + { + get + { + return _osVersion >= new Version( 6, 2 ); + } + } + + /// + /// Is this using WPF4? + /// + /// + /// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds + /// when handling WM_NCCALCSIZE on the HWND. + /// + public static bool IsPresentationFrameworkVersionLessThan4 + { + get { return _presentationFrameworkVersion < new Version(4, 0); } + } + + // Caller is responsible for destroying the HICON + // Caller is responsible to ensure that GDI+ has been initialized. + [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr GenerateHICON(ImageSource image, Size dimensions) + { + if (image == null) + { + return IntPtr.Zero; + } + + // If we're getting this from a ".ico" resource, then it comes through as a BitmapFrame. + // We can use leverage this as a shortcut to get the right 16x16 representation + // because DrawImage doesn't do that for us. + var bf = image as BitmapFrame; + if (bf != null) + { + bf = GetBestMatch(bf.Decoder.Frames, (int)dimensions.Width, (int)dimensions.Height); + } + else + { + // Constrain the dimensions based on the aspect ratio. + var drawingDimensions = new Rect(0, 0, dimensions.Width, dimensions.Height); + + // There's no reason to assume that the requested image dimensions are square. + double renderRatio = dimensions.Width / dimensions.Height; + double aspectRatio = image.Width / image.Height; + + // If it's smaller than the requested size, then place it in the middle and pad the image. + if (image.Width <= dimensions.Width && image.Height <= dimensions.Height) + { + drawingDimensions = new Rect((dimensions.Width - image.Width) / 2, (dimensions.Height - image.Height) / 2, image.Width, image.Height); + } + else if (renderRatio > aspectRatio) + { + double scaledRenderWidth = (image.Width / image.Height) * dimensions.Width; + drawingDimensions = new Rect((dimensions.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, dimensions.Height); + } + else if (renderRatio < aspectRatio) + { + double scaledRenderHeight = (image.Height / image.Width) * dimensions.Height; + drawingDimensions = new Rect(0, (dimensions.Height - scaledRenderHeight) / 2, dimensions.Width, scaledRenderHeight); + } + + var dv = new DrawingVisual(); + DrawingContext dc = dv.RenderOpen(); + dc.DrawImage(image, drawingDimensions); + dc.Close(); + + var bmp = new RenderTargetBitmap((int)dimensions.Width, (int)dimensions.Height, 96, 96, PixelFormats.Pbgra32); + bmp.Render(dv); + bf = BitmapFrame.Create(bmp); + } + + // Using GDI+ to convert to an HICON. + // I'd rather not duplicate their code. + using (MemoryStream memstm = new MemoryStream()) + { + BitmapEncoder enc = new PngBitmapEncoder(); + enc.Frames.Add(bf); + enc.Save(memstm); + + using (var istm = new ManagedIStream(memstm)) + { + // We are not bubbling out GDI+ errors when creating the native image fails. + IntPtr bitmap = IntPtr.Zero; + try + { + Status gpStatus = NativeMethods.GdipCreateBitmapFromStream(istm, out bitmap); + if (Status.Ok != gpStatus) + { + return IntPtr.Zero; + } + + IntPtr hicon; + gpStatus = NativeMethods.GdipCreateHICONFromBitmap(bitmap, out hicon); + if (Status.Ok != gpStatus) + { + return IntPtr.Zero; + } + + // Caller is responsible for freeing this. + return hicon; + } + finally + { + Utility.SafeDisposeImage(ref bitmap); + } + } + } + } + + public static BitmapFrame GetBestMatch(IList frames, int width, int height) + { + return _GetBestMatch(frames, _GetBitDepth(), width, height); + } + + private static int _MatchImage(BitmapFrame frame, int bitDepth, int width, int height, int bpp) + { + int score = 2 * _WeightedAbs(bpp, bitDepth, false) + + _WeightedAbs(frame.PixelWidth, width, true) + + _WeightedAbs(frame.PixelHeight, height, true); + + return score; + } + + private static int _WeightedAbs(int valueHave, int valueWant, bool fPunish) + { + int diff = (valueHave - valueWant); + + if (diff < 0) + { + diff = (fPunish ? -2 : -1) * diff; + } + + return diff; + } + + /// From a list of BitmapFrames find the one that best matches the requested dimensions. + /// The methods used here are copied from Win32 sources. We want to be consistent with + /// system behaviors. + private static BitmapFrame _GetBestMatch(IList frames, int bitDepth, int width, int height) + { + int bestScore = int.MaxValue; + int bestBpp = 0; + int bestIndex = 0; + + bool isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder; + + for (int i = 0; i < frames.Count && bestScore != 0; ++i) + { + int currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel; + + if (currentIconBitDepth == 0) + { + currentIconBitDepth = 8; + } + + int score = _MatchImage(frames[i], bitDepth, width, height, currentIconBitDepth); + if (score < bestScore) + { + bestIndex = i; + bestBpp = currentIconBitDepth; + bestScore = score; + } + else if (score == bestScore) + { + // Tie breaker: choose the higher color depth. If that fails, choose first one. + if (bestBpp < currentIconBitDepth) + { + bestIndex = i; + bestBpp = currentIconBitDepth; + } + } + } + + return frames[bestIndex]; + } + + // This can be cached. It's not going to change under reasonable circumstances. + private static int s_bitDepth; // = 0; + private static int _GetBitDepth() + { + if (s_bitDepth == 0) + { + using (SafeDC dc = SafeDC.GetDesktop()) + { + s_bitDepth = NativeMethods.GetDeviceCaps(dc, DeviceCap.BITSPIXEL) * NativeMethods.GetDeviceCaps(dc, DeviceCap.PLANES); + } + } + return s_bitDepth; + } + + /// + /// Simple guard against the exceptions that File.Delete throws on null and empty strings. + /// + /// The path to delete. Unlike File.Delete, this can be null or empty. + /// + /// Note that File.Delete, and by extension SafeDeleteFile, does not throw an exception + /// if the file does not exist. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDeleteFile(string path) + { + if (!string.IsNullOrEmpty(path)) + { + + File.Delete(path); + } + } + + /// GDI's DeleteObject + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDeleteObject(ref IntPtr gdiObject) + { + IntPtr p = gdiObject; + gdiObject = IntPtr.Zero; + if (IntPtr.Zero != p) + { + NativeMethods.DeleteObject(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDestroyIcon(ref IntPtr hicon) + { + IntPtr p = hicon; + hicon = IntPtr.Zero; + if (IntPtr.Zero != p) + { + NativeMethods.DestroyIcon(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDestroyWindow(ref IntPtr hwnd) + { + IntPtr p = hwnd; + hwnd = IntPtr.Zero; + if (NativeMethods.IsWindow(p)) + { + NativeMethods.DestroyWindow(p); + } + } + + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDispose(ref T disposable) where T : IDisposable + { + // Dispose can safely be called on an object multiple times. + IDisposable t = disposable; + disposable = default(T); + if (null != t) + { + t.Dispose(); + } + } + + /// GDI+'s DisposeImage + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDisposeImage(ref IntPtr gdipImage) + { + IntPtr p = gdipImage; + gdipImage = IntPtr.Zero; + if (IntPtr.Zero != p) + { + NativeMethods.GdipDisposeImage(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static void SafeCoTaskMemFree(ref IntPtr ptr) + { + IntPtr p = ptr; + ptr = IntPtr.Zero; + if (IntPtr.Zero != p) + { + Marshal.FreeCoTaskMem(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static void SafeFreeHGlobal(ref IntPtr hglobal) + { + IntPtr p = hglobal; + hglobal = IntPtr.Zero; + if (IntPtr.Zero != p) + { + Marshal.FreeHGlobal(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static void SafeRelease(ref T comObject) where T : class + { + T t = comObject; + comObject = default(T); + if (null != t) + { + Assert.IsTrue(Marshal.IsComObject(t)); + Marshal.ReleaseComObject(t); + } + } + + /// + /// Utility to help classes catenate their properties for implementing ToString(). + /// + /// The StringBuilder to catenate the results into. + /// The name of the property to be catenated. + /// The value of the property to be catenated. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void GeneratePropertyString(StringBuilder source, string propertyName, string value) + { + Assert.IsNotNull(source); + Assert.IsFalse(string.IsNullOrEmpty(propertyName)); + + if (0 != source.Length) + { + source.Append(' '); + } + + source.Append(propertyName); + source.Append(": "); + if (string.IsNullOrEmpty(value)) + { + source.Append(""); + } + else + { + source.Append('\"'); + source.Append(value); + source.Append('\"'); + } + } + + /// + /// Generates ToString functionality for a struct. This is an expensive way to do it, + /// it exists for the sake of debugging while classes are in flux. + /// Eventually this should just be removed and the classes should + /// do this without reflection. + /// + /// + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [Obsolete] + public static string GenerateToString(T @object) where T : struct + { + var sbRet = new StringBuilder(); + foreach (PropertyInfo property in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if (0 != sbRet.Length) + { + sbRet.Append(", "); + } + Assert.AreEqual(0, property.GetIndexParameters().Length); + object value = property.GetValue(@object, null); + string format = null == value ? "{0}: " : "{0}: \"{1}\""; + sbRet.AppendFormat(format, property.Name, value); + } + return sbRet.ToString(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void CopyStream(Stream destination, Stream source) + { + Assert.IsNotNull(source); + Assert.IsNotNull(destination); + + destination.Position = 0; + + // If we're copying from, say, a web stream, don't fail because of this. + if (source.CanSeek) + { + source.Position = 0; + + // Consider that this could throw because + // the source stream doesn't know it's size... + destination.SetLength(source.Length); + } + + var buffer = new byte[4096]; + int cbRead; + + do + { + cbRead = source.Read(buffer, 0, buffer.Length); + if (0 != cbRead) + { + destination.Write(buffer, 0, cbRead); + } + } + while (buffer.Length == cbRead); + + // Reset the Seek pointer before returning. + destination.Position = 0; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string HashStreamMD5(Stream stm) + { + stm.Position = 0; + var hashBuilder = new StringBuilder(); + using (MD5 md5 = MD5.Create()) + { + foreach (byte b in md5.ComputeHash(stm)) + { + hashBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture)); + } + } + + return hashBuilder.ToString(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void EnsureDirectory(string path) + { + if (!Directory.Exists(Path.GetDirectoryName(path))) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool MemCmp(byte[] left, byte[] right, int cb) + { + Assert.IsNotNull(left); + Assert.IsNotNull(right); + + Assert.IsTrue(cb <= Math.Min(left.Length, right.Length)); + + // pin this buffer + GCHandle handleLeft = GCHandle.Alloc(left, GCHandleType.Pinned); + IntPtr ptrLeft = handleLeft.AddrOfPinnedObject(); + + // pin the other buffer + GCHandle handleRight = GCHandle.Alloc(right, GCHandleType.Pinned); + IntPtr ptrRight = handleRight.AddrOfPinnedObject(); + + bool fRet = _MemCmp(ptrLeft, ptrRight, cb); + + handleLeft.Free(); + handleRight.Free(); + + return fRet; + } + + private class _UrlDecoder + { + private readonly Encoding _encoding; + private readonly char[] _charBuffer; + private readonly byte[] _byteBuffer; + private int _byteCount; + private int _charCount; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public _UrlDecoder(int size, Encoding encoding) + { + _encoding = encoding; + _charBuffer = new char[size]; + _byteBuffer = new byte[size]; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void AddByte(byte b) + { + _byteBuffer[_byteCount++] = b; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void AddChar(char ch) + { + _FlushBytes(); + _charBuffer[_charCount++] = ch; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private void _FlushBytes() + { + if (_byteCount > 0) + { + _charCount += _encoding.GetChars(_byteBuffer, 0, _byteCount, _charBuffer, _charCount); + _byteCount = 0; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public string GetString() + { + _FlushBytes(); + if (_charCount > 0) + { + return new string(_charBuffer, 0, _charCount); + } + return ""; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string UrlDecode(string url) + { + if (url == null) + { + return null; + } + + var decoder = new _UrlDecoder(url.Length, Encoding.UTF8); + int length = url.Length; + for (int i = 0; i < length; ++i) + { + char ch = url[i]; + + if (ch == '+') + { + decoder.AddByte((byte)' '); + continue; + } + + if (ch == '%' && i < length - 2) + { + // decode %uXXXX into a Unicode character. + if (url[i + 1] == 'u' && i < length - 5) + { + int a = _HexToInt(url[i + 2]); + int b = _HexToInt(url[i + 3]); + int c = _HexToInt(url[i + 4]); + int d = _HexToInt(url[i + 5]); + if (a >= 0 && b >= 0 && c >= 0 && d >= 0) + { + decoder.AddChar((char)((a << 12) | (b << 8) | (c << 4) | d)); + i += 5; + + continue; + } + } + else + { + // decode %XX into a Unicode character. + int a = _HexToInt(url[i + 1]); + int b = _HexToInt(url[i + 2]); + + if (a >= 0 && b >= 0) + { + decoder.AddByte((byte)((a << 4) | b)); + i += 2; + + continue; + } + } + } + + // Add any 7bit character as a byte. + if ((ch & 0xFF80) == 0) + { + decoder.AddByte((byte)ch); + } + else + { + decoder.AddChar(ch); + } + } + + return decoder.GetString(); + } + + /// + /// Encodes a URL string. Duplicated functionality from System.Web.HttpUtility.UrlEncode. + /// + /// + /// + /// + /// Duplicated from System.Web.HttpUtility because System.Web isn't part of the client profile. + /// URL Encoding replaces ' ' with '+' and unsafe ASCII characters with '%XX'. + /// Safe characters are defined in RFC2396 (http://www.ietf.org/rfc/rfc2396.txt). + /// They are the 7-bit ASCII alphanumerics and the mark characters "-_.!~*'()". + /// This implementation does not treat '~' as a safe character to be consistent with the System.Web version. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string UrlEncode(string url) + { + if (url == null) + { + return null; + } + + byte[] bytes = Encoding.UTF8.GetBytes(url); + + bool needsEncoding = false; + int unsafeCharCount = 0; + foreach (byte b in bytes) + { + if (b == ' ') + { + needsEncoding = true; + } + else if (!_UrlEncodeIsSafe(b)) + { + ++unsafeCharCount; + needsEncoding = true; + } + } + + if (needsEncoding) + { + var buffer = new byte[bytes.Length + (unsafeCharCount * 2)]; + int writeIndex = 0; + foreach (byte b in bytes) + { + if (_UrlEncodeIsSafe(b)) + { + buffer[writeIndex++] = b; + } + else if (b == ' ') + { + buffer[writeIndex++] = (byte)'+'; + } + else + { + buffer[writeIndex++] = (byte)'%'; + buffer[writeIndex++] = _IntToHex((b >> 4) & 0xF); + buffer[writeIndex++] = _IntToHex(b & 0xF); + } + } + bytes = buffer; + Assert.AreEqual(buffer.Length, writeIndex); + } + + return Encoding.ASCII.GetString(bytes); + } + + // HttpUtility's UrlEncode is slightly different from the RFC. + // RFC2396 describes unreserved characters as alphanumeric or + // the list "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" + // The System.Web version unnecessarily escapes '~', which should be okay... + // Keeping that same pattern here just to be consistent. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _UrlEncodeIsSafe(byte b) + { + if (_IsAsciiAlphaNumeric(b)) + { + return true; + } + + switch ((char)b) + { + case '-': + case '_': + case '.': + case '!': + //case '~': + case '*': + case '\'': + case '(': + case ')': + return true; + } + + return false; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _IsAsciiAlphaNumeric(byte b) + { + return (b >= 'a' && b <= 'z') + || (b >= 'A' && b <= 'Z') + || (b >= '0' && b <= '9'); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static byte _IntToHex(int n) + { + Assert.BoundedInteger(0, n, 16); + if (n <= 9) + { + return (byte)(n + '0'); + } + return (byte)(n - 10 + 'A'); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static int _HexToInt(char h) + { + if (h >= '0' && h <= '9') + { + return h - '0'; + } + + if (h >= 'a' && h <= 'f') + { + return h - 'a' + 10; + } + + if (h >= 'A' && h <= 'F') + { + return h - 'A' + 10; + } + + Assert.Fail("Invalid hex character " + h); + return -1; + } + + public static void AddDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) + { + if (component == null) + { + return; + } + Assert.IsNotNull(property); + Assert.IsNotNull(listener); + + DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); + dpd.AddValueChanged(component, listener); + } + + public static void RemoveDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) + { + if (component == null) + { + return; + } + Assert.IsNotNull(property); + Assert.IsNotNull(listener); + + DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); + dpd.RemoveValueChanged(component, listener); + } + + #region Extension Methods + + public static bool IsThicknessNonNegative(Thickness thickness) + { + if (!IsDoubleFiniteAndNonNegative(thickness.Top)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(thickness.Left)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(thickness.Bottom)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(thickness.Right)) + { + return false; + } + + return true; + } + + public static bool IsCornerRadiusValid(CornerRadius cornerRadius) + { + if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopLeft)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopRight)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomLeft)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomRight)) + { + return false; + } + + return true; + } + + public static bool IsDoubleFiniteAndNonNegative(double d) + { + if (double.IsNaN(d) || double.IsInfinity(d) || d < 0) + { + return false; + } + + return true; + } + + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/Verify.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/Verify.cs new file mode 100644 index 0000000..0156e6a --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/Standard/Verify.cs @@ -0,0 +1,328 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +// This file contains general utilities to aid in development. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Threading; + + /// + /// A static class for retail validated assertions. + /// Instead of breaking into the debugger an exception is thrown. + /// + internal static class Verify + { + /// + /// Ensure that the current thread's apartment state is what's expected. + /// + /// + /// The required apartment state for the current thread. + /// + /// + /// The message string for the exception to be thrown if the state is invalid. + /// + /// + /// Thrown if the calling thread's apartment state is not the same as the requiredState. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsApartmentState(ApartmentState requiredState, string message) + { + if (Thread.CurrentThread.GetApartmentState() != requiredState) + { + throw new InvalidOperationException(message); + } + } + + /// + /// Ensure that an argument is neither null nor empty. + /// + /// The string to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")] + [DebuggerStepThrough] + public static void IsNeitherNullNorEmpty(string value, string name) + { + // catch caller errors, mixing up the parameters. Name should never be empty. + Assert.IsNeitherNullNorEmpty(name); + + // Notice that ArgumentNullException and ArgumentException take the parameters in opposite order :P + const string errorMessage = "The parameter can not be either null or empty."; + if (null == value) + { + throw new ArgumentNullException(name, errorMessage); + } + if ("" == value) + { + throw new ArgumentException(errorMessage, name); + } + } + + /// + /// Ensure that an argument is neither null nor does it consist only of whitespace. + /// + /// The string to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")] + [DebuggerStepThrough] + public static void IsNeitherNullNorWhitespace(string value, string name) + { + // catch caller errors, mixing up the parameters. Name should never be empty. + Assert.IsNeitherNullNorEmpty(name); + + // Notice that ArgumentNullException and ArgumentException take the parameters in opposite order :P + const string errorMessage = "The parameter can not be either null or empty or consist only of white space characters."; + if (null == value) + { + throw new ArgumentNullException(name, errorMessage); + } + if ("" == value.Trim()) + { + throw new ArgumentException(errorMessage, name); + } + } + + /// Verifies that an argument is not null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNotDefault(T obj, string name) where T : struct + { + if (default(T).Equals(obj)) + { + throw new ArgumentException("The parameter must not be the default value.", name); + } + } + + /// Verifies that an argument is not null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNotNull(T obj, string name) where T : class + { + if (null == obj) + { + throw new ArgumentNullException(name); + } + } + + /// Verifies that an argument is null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNull(T obj, string name) where T : class + { + if (null != obj) + { + throw new ArgumentException("The parameter must be null.", name); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void PropertyIsNotNull(T obj, string name) where T : class + { + if (null == obj) + { + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} cannot be null at this time.", name)); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void PropertyIsNull(T obj, string name) where T : class + { + if (null != obj) + { + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} must be null at this time.", name)); + } + } + + /// + /// Verifies the specified statement is true. Throws an ArgumentException if it's not. + /// + /// The statement to be verified as true. + /// Name of the parameter to include in the ArgumentException. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsTrue(bool statement, string name) + { + if (!statement) + { + throw new ArgumentException("", name); + } + } + + /// + /// Verifies the specified statement is true. Throws an ArgumentException if it's not. + /// + /// The statement to be verified as true. + /// Name of the parameter to include in the ArgumentException. + /// The message to include in the ArgumentException. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsTrue(bool statement, string name, string message) + { + if (!statement) + { + throw new ArgumentException(message, name); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void AreEqual(T expected, T actual, string parameterName, string message) + { + if (null == expected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null != actual && !actual.Equals(expected)) + { + throw new ArgumentException(message, parameterName); + } + } + else if (!expected.Equals(actual)) + { + throw new ArgumentException(message, parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void AreNotEqual(T notExpected, T actual, string parameterName, string message) + { + if (null == notExpected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null == actual || actual.Equals(notExpected)) + { + throw new ArgumentException(message, parameterName); + } + } + else if (notExpected.Equals(actual)) + { + throw new ArgumentException(message, parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void UriIsAbsolute(Uri uri, string parameterName) + { + Verify.IsNotNull(uri, parameterName); + if (!uri.IsAbsoluteUri) + { + throw new ArgumentException("The URI must be absolute.", parameterName); + } + } + + /// + /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. + /// + /// The lower bound inclusive value. + /// The value to verify. + /// The upper bound exclusive value. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void BoundedInteger(int lowerBoundInclusive, int value, int upperBoundExclusive, string parameterName) + { + if (value < lowerBoundInclusive || value >= upperBoundExclusive) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The integer value must be bounded with [{0}, {1})", lowerBoundInclusive, upperBoundExclusive), parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void BoundedDoubleInc(double lowerBoundInclusive, double value, double upperBoundInclusive, string message, string parameter) + { + if (value < lowerBoundInclusive || value > upperBoundInclusive) + { + throw new ArgumentException(message, parameter); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void TypeSupportsInterface(Type type, Type interfaceType, string parameterName) + { + Assert.IsNeitherNullNorEmpty(parameterName); + Verify.IsNotNull(type, "type"); + Verify.IsNotNull(interfaceType, "interfaceType"); + + if (type.GetInterface(interfaceType.Name) == null) + { + throw new ArgumentException("The type of this parameter does not support a required interface", parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void FileExists(string filePath, string parameterName) + { + Verify.IsNeitherNullNorEmpty(filePath, parameterName); + if (!File.Exists(filePath)) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "No file exists at \"{0}\"", filePath), parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + internal static void ImplementsInterface(object parameter, Type interfaceType, string parameterName) + { + Assert.IsNotNull(parameter); + Assert.IsNotNull(interfaceType); + Assert.IsTrue(interfaceType.IsInterface); + + bool isImplemented = false; + foreach (var ifaceType in parameter.GetType().GetInterfaces()) + { + if (ifaceType == interfaceType) + { + isImplemented = true; + break; + } + } + + if (!isImplemented) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The parameter must implement interface {0}.", interfaceType.ToString()), parameterName); + } + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/SystemCommands.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/SystemCommands.cs new file mode 100644 index 0000000..45c009a --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/SystemCommands.cs @@ -0,0 +1,107 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Windows; + using System.Windows.Input; + using System.Windows.Interop; + using Standard; + + public static class SystemCommands + { + public static RoutedCommand CloseWindowCommand { get; private set; } + public static RoutedCommand MaximizeWindowCommand { get; private set; } + public static RoutedCommand MinimizeWindowCommand { get; private set; } + public static RoutedCommand RestoreWindowCommand { get; private set; } + public static RoutedCommand ShowSystemMenuCommand { get; private set; } + + static SystemCommands() + { + CloseWindowCommand = new RoutedCommand("CloseWindow", typeof(SystemCommands)); + MaximizeWindowCommand = new RoutedCommand("MaximizeWindow", typeof(SystemCommands)); + MinimizeWindowCommand = new RoutedCommand("MinimizeWindow", typeof(SystemCommands)); + RestoreWindowCommand = new RoutedCommand("RestoreWindow", typeof(SystemCommands)); + ShowSystemMenuCommand = new RoutedCommand("ShowSystemMenu", typeof(SystemCommands)); + } + + private static void _PostSystemCommand(Window window, SC command) + { + IntPtr hwnd = new WindowInteropHelper(window).Handle; + if (hwnd == IntPtr.Zero || !NativeMethods.IsWindow(hwnd)) + { + return; + } + + NativeMethods.PostMessage(hwnd, WM.SYSCOMMAND, new IntPtr((int)command), IntPtr.Zero); + } + + public static void CloseWindow(Window window) + { + Verify.IsNotNull(window, "window"); + _PostSystemCommand(window, SC.CLOSE); + } + + public static void MaximizeWindow(Window window) + { + Verify.IsNotNull(window, "window"); + _PostSystemCommand(window, SC.MAXIMIZE); + } + + public static void MinimizeWindow(Window window) + { + Verify.IsNotNull(window, "window"); + _PostSystemCommand(window, SC.MINIMIZE); + } + + public static void RestoreWindow(Window window) + { + Verify.IsNotNull(window, "window"); + _PostSystemCommand(window, SC.RESTORE); + } + + /// Display the system menu at a specified location. + /// The location to display the system menu, in logical screen coordinates. + public static void ShowSystemMenu(Window window, Point screenLocation) + { + Verify.IsNotNull(window, "window"); + ShowSystemMenuPhysicalCoordinates(window, DpiHelper.LogicalPixelsToDevice(screenLocation)); + } + + internal static void ShowSystemMenuPhysicalCoordinates(Window window, Point physicalScreenLocation) + { + const uint TPM_RETURNCMD = 0x0100; + const uint TPM_LEFTBUTTON = 0x0; + + Verify.IsNotNull(window, "window"); + IntPtr hwnd = new WindowInteropHelper(window).Handle; + if (hwnd == IntPtr.Zero || !NativeMethods.IsWindow(hwnd)) + { + return; + } + + IntPtr hmenu = NativeMethods.GetSystemMenu(hwnd, false); + + uint cmd = NativeMethods.TrackPopupMenuEx(hmenu, TPM_LEFTBUTTON | TPM_RETURNCMD, (int)physicalScreenLocation.X, (int)physicalScreenLocation.Y, hwnd, IntPtr.Zero); + if (0 != cmd) + { + NativeMethods.PostMessage(hwnd, WM.SYSCOMMAND, new IntPtr(cmd), IntPtr.Zero); + } + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/SystemParameters2.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/SystemParameters2.cs new file mode 100644 index 0000000..d2ce2ad --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/SystemParameters2.cs @@ -0,0 +1,573 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; + using System.Windows; + using System.Windows.Media; + using Standard; + + [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")] + public class SystemParameters2 : INotifyPropertyChanged + { + private delegate void _SystemMetricUpdate(IntPtr wParam, IntPtr lParam); + + [ThreadStatic] + private static SystemParameters2 _threadLocalSingleton; + + private MessageWindow _messageHwnd; + + private bool _isGlassEnabled; + private Color _glassColor; + private SolidColorBrush _glassColorBrush; + private Thickness _windowResizeBorderThickness; + private Thickness _windowNonClientFrameThickness; + private double _captionHeight; + private Size _smallIconSize; + private string _uxThemeName; + private string _uxThemeColor; + private bool _isHighContrast; + private CornerRadius _windowCornerRadius; + private Rect _captionButtonLocation; + + private readonly Dictionary> _UpdateTable; + + #region Initialization and Update Methods + + // Most properties exposed here have a way of being queried directly + // and a way of being notified of updates via a window message. + // This region is a grouping of both, for each of the exposed properties. + + private void _InitializeIsGlassEnabled() + { + IsGlassEnabled = NativeMethods.DwmIsCompositionEnabled(); + } + + private void _UpdateIsGlassEnabled(IntPtr wParam, IntPtr lParam) + { + // Neither the wParam or lParam are used in this case. + _InitializeIsGlassEnabled(); + } + + private void _InitializeGlassColor() + { + bool isOpaque; + uint color; + NativeMethods.DwmGetColorizationColor(out color, out isOpaque); + color |= isOpaque ? 0xFF000000 : 0; + + WindowGlassColor = Utility.ColorFromArgbDword(color); + + var glassBrush = new SolidColorBrush(WindowGlassColor); + glassBrush.Freeze(); + + WindowGlassBrush = glassBrush; + } + + private void _UpdateGlassColor(IntPtr wParam, IntPtr lParam) + { + bool isOpaque = lParam != IntPtr.Zero; + uint color = unchecked((uint)(int)wParam.ToInt64()); + color |= isOpaque ? 0xFF000000 : 0; + WindowGlassColor = Utility.ColorFromArgbDword(color); + var glassBrush = new SolidColorBrush(WindowGlassColor); + glassBrush.Freeze(); + WindowGlassBrush = glassBrush; + } + + private void _InitializeCaptionHeight() + { + Point ptCaption = new Point(0, NativeMethods.GetSystemMetrics(SM.CYCAPTION)); + WindowCaptionHeight = DpiHelper.DevicePixelsToLogical(ptCaption).Y; + } + + private void _UpdateCaptionHeight(IntPtr wParam, IntPtr lParam) + { + _InitializeCaptionHeight(); + } + + private void _InitializeWindowResizeBorderThickness() + { + Size frameSize = new Size( + NativeMethods.GetSystemMetrics(SM.CXSIZEFRAME), + NativeMethods.GetSystemMetrics(SM.CYSIZEFRAME)); + Size frameSizeInDips = DpiHelper.DeviceSizeToLogical(frameSize); + WindowResizeBorderThickness = new Thickness(frameSizeInDips.Width, frameSizeInDips.Height, frameSizeInDips.Width, frameSizeInDips.Height); + } + + private void _UpdateWindowResizeBorderThickness(IntPtr wParam, IntPtr lParam) + { + _InitializeWindowResizeBorderThickness(); + } + + private void _InitializeWindowNonClientFrameThickness() + { + Size frameSize = new Size( + NativeMethods.GetSystemMetrics(SM.CXSIZEFRAME), + NativeMethods.GetSystemMetrics(SM.CYSIZEFRAME)); + Size frameSizeInDips = DpiHelper.DeviceSizeToLogical(frameSize); + int captionHeight = NativeMethods.GetSystemMetrics(SM.CYCAPTION); + double captionHeightInDips = DpiHelper.DevicePixelsToLogical(new Point(0, captionHeight)).Y; + WindowNonClientFrameThickness = new Thickness(frameSizeInDips.Width, frameSizeInDips.Height + captionHeightInDips, frameSizeInDips.Width, frameSizeInDips.Height); + } + + private void _UpdateWindowNonClientFrameThickness(IntPtr wParam, IntPtr lParam) + { + _InitializeWindowNonClientFrameThickness(); + } + + private void _InitializeSmallIconSize() + { + SmallIconSize = new Size( + NativeMethods.GetSystemMetrics(SM.CXSMICON), + NativeMethods.GetSystemMetrics(SM.CYSMICON)); + } + + private void _UpdateSmallIconSize(IntPtr wParam, IntPtr lParam) + { + _InitializeSmallIconSize(); + } + + private void _LegacyInitializeCaptionButtonLocation() + { + // This calculation isn't quite right, but it's pretty close. + // I expect this is good enough for the scenarios where this is expected to be used. + int captionX = NativeMethods.GetSystemMetrics(SM.CXSIZE); + int captionY = NativeMethods.GetSystemMetrics(SM.CYSIZE); + + int frameX = NativeMethods.GetSystemMetrics(SM.CXSIZEFRAME) + NativeMethods.GetSystemMetrics(SM.CXEDGE); + int frameY = NativeMethods.GetSystemMetrics(SM.CYSIZEFRAME) + NativeMethods.GetSystemMetrics(SM.CYEDGE); + + Rect captionRect = new Rect(0, 0, captionX * 3, captionY); + captionRect.Offset(-frameX - captionRect.Width, frameY); + + WindowCaptionButtonsLocation = captionRect; + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + private void _InitializeCaptionButtonLocation() + { + // There is a completely different way to do this on XP. + if (!Utility.IsOSVistaOrNewer || !NativeMethods.IsThemeActive()) + { + _LegacyInitializeCaptionButtonLocation(); + return; + } + + var tbix = new TITLEBARINFOEX { cbSize = Marshal.SizeOf(typeof(TITLEBARINFOEX)) }; + IntPtr lParam = Marshal.AllocHGlobal(tbix.cbSize); + try + { + Marshal.StructureToPtr(tbix, lParam, false); + // This might flash a window in the taskbar while being calculated. + // WM_GETTITLEBARINFOEX doesn't work correctly unless the window is visible while processing. + NativeMethods.ShowWindow(_messageHwnd.Handle, SW.SHOW); + NativeMethods.SendMessage(_messageHwnd.Handle, WM.GETTITLEBARINFOEX, IntPtr.Zero, lParam); + tbix = (TITLEBARINFOEX)Marshal.PtrToStructure(lParam, typeof(TITLEBARINFOEX)); + } + finally + { + NativeMethods.ShowWindow(_messageHwnd.Handle, SW.HIDE); + Utility.SafeFreeHGlobal(ref lParam); + } + + // TITLEBARINFOEX has information relative to the screen. We need to convert the containing rect + // to instead be relative to the top-right corner of the window. + RECT rcAllCaptionButtons = RECT.Union(tbix.rgrect_CloseButton, tbix.rgrect_MinimizeButton); + // For all known themes, the RECT for the maximize box shouldn't add anything to the union of the minimize and close boxes. + Assert.AreEqual(rcAllCaptionButtons, RECT.Union(rcAllCaptionButtons, tbix.rgrect_MaximizeButton)); + + RECT rcWindow = NativeMethods.GetWindowRect(_messageHwnd.Handle); + + // Reorient the Top/Right to be relative to the top right edge of the Window. + var deviceCaptionLocation = new Rect( + rcAllCaptionButtons.Left - rcWindow.Width - rcWindow.Left, + rcAllCaptionButtons.Top - rcWindow.Top, + rcAllCaptionButtons.Width, + rcAllCaptionButtons.Height); + + Rect logicalCaptionLocation = DpiHelper.DeviceRectToLogical(deviceCaptionLocation); + + WindowCaptionButtonsLocation = logicalCaptionLocation; + } + + private void _UpdateCaptionButtonLocation(IntPtr wParam, IntPtr lParam) + { + _InitializeCaptionButtonLocation(); + } + + private void _InitializeHighContrast() + { + HIGHCONTRAST hc = NativeMethods.SystemParameterInfo_GetHIGHCONTRAST(); + HighContrast = (hc.dwFlags & HCF.HIGHCONTRASTON) != 0; + } + + private void _UpdateHighContrast(IntPtr wParam, IntPtr lParam) + { + _InitializeHighContrast(); + } + + private void _InitializeThemeInfo() + { + if (!NativeMethods.IsThemeActive()) + { + UxThemeName = "Classic"; + UxThemeColor = ""; + return; + } + + string name; + string color; + string size; + NativeMethods.GetCurrentThemeName(out name, out color, out size); + + // Consider whether this is the most useful way to expose this... + UxThemeName = System.IO.Path.GetFileNameWithoutExtension(name); + UxThemeColor = color; + } + + private void _UpdateThemeInfo(IntPtr wParam, IntPtr lParam) + { + _InitializeThemeInfo(); + } + + private void _InitializeWindowCornerRadius() + { + // The radius of window corners isn't exposed as a true system parameter. + // It instead is a logical size that we're approximating based on the current theme. + // There aren't any known variations based on theme color. + Assert.IsNeitherNullNorEmpty(UxThemeName); + + // These radii are approximate. The way WPF does rounding is different than how + // rounded-rectangle HRGNs are created, which is also different than the actual + // round corners on themed Windows. For now we're not exposing anything to + // mitigate the differences. + var cornerRadius = default(CornerRadius); + + // This list is known to be incomplete and very much not future-proof. + // On XP there are at least a couple of shipped themes that this won't catch, + // "Zune" and "Royale", but WPF doesn't know about these either. + // If a new theme was to replace Aero, then this will fall back on "classic" behaviors. + // This isn't ideal, but it's not the end of the world. WPF will generally have problems anyways. + switch (UxThemeName.ToUpperInvariant()) + { + case "LUNA": + cornerRadius = new CornerRadius(6, 6, 0, 0); + break; + case "AERO": + // Aero has two cases. One with glass and one without... + if (NativeMethods.DwmIsCompositionEnabled()) + { + cornerRadius = new CornerRadius(8); + } + else + { + cornerRadius = new CornerRadius(6, 6, 0, 0); + } + break; + case "CLASSIC": + case "ZUNE": + case "ROYALE": + default: + cornerRadius = new CornerRadius(0); + break; + } + + WindowCornerRadius = cornerRadius; + } + + private void _UpdateWindowCornerRadius(IntPtr wParam, IntPtr lParam) + { + // Neither the wParam or lParam are used in this case. + _InitializeWindowCornerRadius(); + } + + + #endregion + + /// + /// Private constructor. The public way to access this class is through the static Current property. + /// + private SystemParameters2() + { + // This window gets used for calculations about standard caption button locations + // so it has WS_OVERLAPPEDWINDOW as a style to give it normal caption buttons. + // This window may be shown during calculations of caption bar information, so create it at a location that's likely offscreen. + _messageHwnd = new MessageWindow((CS)0, WS.OVERLAPPEDWINDOW | WS.DISABLED, (WS_EX)0, new Rect(-16000, -16000, 100, 100), "", _WndProc); + _messageHwnd.Dispatcher.ShutdownStarted += (sender, e) => Utility.SafeDispose(ref _messageHwnd); + + // Fixup the default values of the DPs. + _InitializeIsGlassEnabled(); + _InitializeGlassColor(); + _InitializeCaptionHeight(); + _InitializeWindowNonClientFrameThickness(); + _InitializeWindowResizeBorderThickness(); + _InitializeCaptionButtonLocation(); + _InitializeSmallIconSize(); + _InitializeHighContrast(); + _InitializeThemeInfo(); + // WindowCornerRadius isn't exposed by true system parameters, so it requires the theme to be initialized first. + _InitializeWindowCornerRadius(); + + _UpdateTable = new Dictionary> + { + { WM.THEMECHANGED, + new List<_SystemMetricUpdate> + { + _UpdateThemeInfo, + _UpdateHighContrast, + _UpdateWindowCornerRadius, + _UpdateCaptionButtonLocation, } }, + { WM.SETTINGCHANGE, + new List<_SystemMetricUpdate> + { + _UpdateCaptionHeight, + _UpdateWindowResizeBorderThickness, + _UpdateSmallIconSize, + _UpdateHighContrast, + _UpdateWindowNonClientFrameThickness, + _UpdateCaptionButtonLocation, } }, + { WM.DWMNCRENDERINGCHANGED, new List<_SystemMetricUpdate> { _UpdateIsGlassEnabled } }, + { WM.DWMCOMPOSITIONCHANGED, new List<_SystemMetricUpdate> { _UpdateIsGlassEnabled } }, + { WM.DWMCOLORIZATIONCOLORCHANGED, new List<_SystemMetricUpdate> { _UpdateGlassColor } }, + }; + } + + public static SystemParameters2 Current + { + get + { + if (_threadLocalSingleton == null) + { + _threadLocalSingleton = new SystemParameters2(); + } + return _threadLocalSingleton; + } + } + + private IntPtr _WndProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam) + { + // Don't do this if called within the SystemParameters2 constructor + if (_UpdateTable != null) + { + List<_SystemMetricUpdate> handlers; + if (_UpdateTable.TryGetValue(msg, out handlers)) + { + Assert.IsNotNull(handlers); + foreach (var handler in handlers) + { + handler(wParam, lParam); + } + } + } + + return NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); + } + + public bool IsGlassEnabled + { + get + { + // return _isGlassEnabled; + // It turns out there may be some lag between someone asking this + // and the window getting updated. It's not too expensive, just always do the check. + return NativeMethods.DwmIsCompositionEnabled(); + } + private set + { + if (value != _isGlassEnabled) + { + _isGlassEnabled = value; + _NotifyPropertyChanged("IsGlassEnabled"); + } + } + } + + public Color WindowGlassColor + { + get { return _glassColor; } + private set + { + if (value != _glassColor) + { + _glassColor = value; + _NotifyPropertyChanged("WindowGlassColor"); + } + } + } + + public SolidColorBrush WindowGlassBrush + { + get { return _glassColorBrush; } + private set + { + Assert.IsNotNull(value); + Assert.IsTrue(value.IsFrozen); + if (_glassColorBrush == null || value.Color != _glassColorBrush.Color) + { + _glassColorBrush = value; + _NotifyPropertyChanged("WindowGlassBrush"); + } + } + } + + public Thickness WindowResizeBorderThickness + { + get { return _windowResizeBorderThickness; } + private set + { + if (value != _windowResizeBorderThickness) + { + _windowResizeBorderThickness = value; + _NotifyPropertyChanged("WindowResizeBorderThickness"); + } + } + } + + public Thickness WindowNonClientFrameThickness + { + get { return _windowNonClientFrameThickness; } + private set + { + if (value != _windowNonClientFrameThickness) + { + _windowNonClientFrameThickness = value; + _NotifyPropertyChanged("WindowNonClientFrameThickness"); + } + } + } + + public double WindowCaptionHeight + { + get { return _captionHeight; } + private set + { + if (value != _captionHeight) + { + _captionHeight = value; + _NotifyPropertyChanged("WindowCaptionHeight"); + } + } + } + + public Size SmallIconSize + { + get { return new Size(_smallIconSize.Width, _smallIconSize.Height); } + private set + { + if (value != _smallIconSize) + { + _smallIconSize = value; + _NotifyPropertyChanged("SmallIconSize"); + } + } + } + + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ux")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ux")] + public string UxThemeName + { + get { return _uxThemeName; } + private set + { + if (value != _uxThemeName) + { + _uxThemeName = value; + _NotifyPropertyChanged("UxThemeName"); + } + } + } + + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ux")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ux")] + public string UxThemeColor + { + get { return _uxThemeColor; } + private set + { + if (value != _uxThemeColor) + { + _uxThemeColor = value; + _NotifyPropertyChanged("UxThemeColor"); + } + } + } + + public bool HighContrast + { + get { return _isHighContrast; } + private set + { + if (value != _isHighContrast) + { + _isHighContrast = value; + _NotifyPropertyChanged("HighContrast"); + } + } + } + + public CornerRadius WindowCornerRadius + { + get { return _windowCornerRadius; } + private set + { + if (value != _windowCornerRadius) + { + _windowCornerRadius = value; + _NotifyPropertyChanged("WindowCornerRadius"); + } + } + } + + public Rect WindowCaptionButtonsLocation + { + get { return _captionButtonLocation; } + private set + { + if (value != _captionButtonLocation) + { + _captionButtonLocation = value; + _NotifyPropertyChanged("WindowCaptionButtonsLocation"); + } + } + } + + #region INotifyPropertyChanged Members + + private void _NotifyPropertyChanged(string propertyName) + { + Assert.IsNeitherNullNorEmpty(propertyName); + var handler = PropertyChanged; + if (handler != null) + { + handler(this, new PropertyChangedEventArgs(propertyName)); + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/WindowChrome.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/WindowChrome.cs new file mode 100644 index 0000000..69767c9 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/WindowChrome.cs @@ -0,0 +1,267 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Data; + using Standard; + + public class WindowChrome : Freezable + { + private struct _SystemParameterBoundProperty + { + public string SystemParameterPropertyName { get; set; } + public DependencyProperty DependencyProperty { get; set; } + } + + // Named property available for fully extending the glass frame. + public static Thickness GlassFrameCompleteThickness { get { return new Thickness(-1); } } + + #region Attached Properties + + public static readonly DependencyProperty WindowChromeProperty = DependencyProperty.RegisterAttached( + "WindowChrome", + typeof(WindowChrome), + typeof(WindowChrome), + new PropertyMetadata(null, _OnChromeChanged)); + + private static void _OnChromeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + // The different design tools handle drawing outside their custom window objects differently. + // Rather than try to support this concept in the design surface let the designer draw its own + // chrome anyways. + // There's certainly room for improvement here. + if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(d)) + { + return; + } + + var window = (Window)d; + var newChrome = (WindowChrome)e.NewValue; + + Assert.IsNotNull(window); + + // Update the ChromeWorker with this new object. + + // If there isn't currently a worker associated with the Window then assign a new one. + // There can be a many:1 relationship of to Window to WindowChrome objects, but a 1:1 for a Window and a WindowChromeWorker. + WindowChromeWorker chromeWorker = WindowChromeWorker.GetWindowChromeWorker(window); + if (chromeWorker == null) + { + chromeWorker = new WindowChromeWorker(); + WindowChromeWorker.SetWindowChromeWorker(window, chromeWorker); + } + + chromeWorker.SetWindowChrome(newChrome); + } + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static WindowChrome GetWindowChrome(Window window) + { + Verify.IsNotNull(window, "window"); + return (WindowChrome)window.GetValue(WindowChromeProperty); + } + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static void SetWindowChrome(Window window, WindowChrome chrome) + { + Verify.IsNotNull(window, "window"); + window.SetValue(WindowChromeProperty, chrome); + } + + public static readonly DependencyProperty IsHitTestVisibleInChromeProperty = DependencyProperty.RegisterAttached( + "IsHitTestVisibleInChrome", + typeof(bool), + typeof(WindowChrome), + new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits)); + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static bool GetIsHitTestVisibleInChrome(IInputElement inputElement) + { + Verify.IsNotNull(inputElement, "inputElement"); + var dobj = inputElement as DependencyObject; + if (dobj == null) + { + throw new ArgumentException("The element must be a DependencyObject", "inputElement"); + } + return (bool)dobj.GetValue(IsHitTestVisibleInChromeProperty); + } + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static void SetIsHitTestVisibleInChrome(IInputElement inputElement, bool hitTestVisible) + { + Verify.IsNotNull(inputElement, "inputElement"); + var dobj = inputElement as DependencyObject; + if (dobj == null) + { + throw new ArgumentException("The element must be a DependencyObject", "inputElement"); + } + dobj.SetValue(IsHitTestVisibleInChromeProperty, hitTestVisible); + } + + #endregion + + #region Dependency Properties + + public static readonly DependencyProperty CaptionHeightProperty = DependencyProperty.Register( + "CaptionHeight", + typeof(double), + typeof(WindowChrome), + new PropertyMetadata( + 0d, + (d, e) => ((WindowChrome)d)._OnPropertyChangedThatRequiresRepaint()), + value => (double)value >= 0d); + + /// The extent of the top of the window to treat as the caption. + public double CaptionHeight + { + get { return (double)GetValue(CaptionHeightProperty); } + set { SetValue(CaptionHeightProperty, value); } + } + + public static readonly DependencyProperty ResizeBorderThicknessProperty = DependencyProperty.Register( + "ResizeBorderThickness", + typeof(Thickness), + typeof(WindowChrome), + new PropertyMetadata(default(Thickness)), + (value) => Utility.IsThicknessNonNegative((Thickness)value)); + + public Thickness ResizeBorderThickness + { + get { return (Thickness)GetValue(ResizeBorderThicknessProperty); } + set { SetValue(ResizeBorderThicknessProperty, value); } + } + + public static readonly DependencyProperty GlassFrameThicknessProperty = DependencyProperty.Register( + "GlassFrameThickness", + typeof(Thickness), + typeof(WindowChrome), + new PropertyMetadata( + default(Thickness), + (d, e) => ((WindowChrome)d)._OnPropertyChangedThatRequiresRepaint(), + (d, o) => _CoerceGlassFrameThickness((Thickness)o))); + + private static object _CoerceGlassFrameThickness(Thickness thickness) + { + // If it's explicitly set, but set to a thickness with at least one negative side then + // coerce the value to the stock GlassFrameCompleteThickness. + if (!Utility.IsThicknessNonNegative(thickness)) + { + return GlassFrameCompleteThickness; + } + + return thickness; + } + public Thickness GlassFrameThickness + { + get { return (Thickness)GetValue(GlassFrameThicknessProperty); } + set { SetValue(GlassFrameThicknessProperty, value); } + } + + public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( + "CornerRadius", + typeof(CornerRadius), + typeof(WindowChrome), + new PropertyMetadata( + default(CornerRadius), + (d, e) => ((WindowChrome)d)._OnPropertyChangedThatRequiresRepaint()), + (value) => Utility.IsCornerRadiusValid((CornerRadius)value)); + + public CornerRadius CornerRadius + { + get { return (CornerRadius)GetValue(CornerRadiusProperty); } + set { SetValue(CornerRadiusProperty, value); } + } + + #region ShowSystemMenu + + /// + /// Gets or sets the ShowSystemMenu property. This dependency property + /// indicates if the system menu should be shown at right click on the caption. + /// + public bool ShowSystemMenu + { + get; + set; + } + + #endregion + + + + #endregion + + protected override Freezable CreateInstanceCore() + { + return new WindowChrome(); + } + + private static readonly List<_SystemParameterBoundProperty> _BoundProperties = new List<_SystemParameterBoundProperty> + { + new _SystemParameterBoundProperty { DependencyProperty = CornerRadiusProperty, SystemParameterPropertyName = "WindowCornerRadius" }, + new _SystemParameterBoundProperty { DependencyProperty = CaptionHeightProperty, SystemParameterPropertyName = "WindowCaptionHeight" }, + new _SystemParameterBoundProperty { DependencyProperty = ResizeBorderThicknessProperty, SystemParameterPropertyName = "WindowResizeBorderThickness" }, + new _SystemParameterBoundProperty { DependencyProperty = GlassFrameThicknessProperty, SystemParameterPropertyName = "WindowNonClientFrameThickness" }, + }; + + public WindowChrome() + { + // Effective default values for some of these properties are set to be bindings + // that set them to system defaults. + // A more correct way to do this would be to Coerce the value iff the source of the DP was the default value. + // Unfortunately with the current property system we can't detect whether the value being applied at the time + // of the coersion is the default. + foreach (var bp in _BoundProperties) + { + // This list must be declared after the DP's are assigned. + Assert.IsNotNull(bp.DependencyProperty); + BindingOperations.SetBinding( + this, + bp.DependencyProperty, + new Binding + { + Source = SystemParameters2.Current, + Path = new PropertyPath(bp.SystemParameterPropertyName), + Mode = BindingMode.OneWay, + UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, + }); + } + } + + private void _OnPropertyChangedThatRequiresRepaint() + { + var handler = PropertyChangedThatRequiresRepaint; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + internal event EventHandler PropertyChangedThatRequiresRepaint; + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/Shell/WindowChromeWorker.cs b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/WindowChromeWorker.cs new file mode 100644 index 0000000..4796580 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/Shell/WindowChromeWorker.cs @@ -0,0 +1,1227 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; + using System.Threading; + using System.Windows; + using System.Windows.Interop; + using System.Windows.Media; + using System.Windows.Threading; + using Standard; + + using HANDLE_MESSAGE = System.Collections.Generic.KeyValuePair; + using System.Windows.Controls.Primitives; + + internal class WindowChromeWorker : DependencyObject + { + // Delegate signature used for Dispatcher.BeginInvoke. + private delegate void _Action(); + + #region Fields + + private const SWP _SwpFlags = SWP.FRAMECHANGED | SWP.NOSIZE | SWP.NOMOVE | SWP.NOZORDER | SWP.NOOWNERZORDER | SWP.NOACTIVATE; + + private readonly List _messageTable; + + /// The Window that's chrome is being modified. + private Window _window; + /// Underlying HWND for the _window. + private IntPtr _hwnd; + private HwndSource _hwndSource = null; + private bool _isHooked = false; + + // These fields are for tracking workarounds for WPF 3.5SP1 behaviors. + private bool _isFixedUp = false; + private bool _isUserResizing = false; + private bool _hasUserMovedWindow = false; + private Point _windowPosAtStartOfUserMove = default(Point); + + // Field to track attempts to force off Device Bitmaps on Win7. + private int _blackGlassFixupAttemptCount; + + /// Object that describes the current modifications being made to the chrome. + private WindowChrome _chromeInfo; + + // Keep track of this so we can detect when we need to apply changes. Tracking these separately + // as I've seen using just one cause things to get enough out of sync that occasionally the caption will redraw. + private WindowState _lastRoundingState; + private WindowState _lastMenuState; + private bool _isGlassEnabled; + + #endregion + + public WindowChromeWorker() + { + _messageTable = new List + { + new HANDLE_MESSAGE(WM.SETTEXT, _HandleSetTextOrIcon), + new HANDLE_MESSAGE(WM.SETICON, _HandleSetTextOrIcon), + new HANDLE_MESSAGE(WM.NCACTIVATE, _HandleNCActivate), + new HANDLE_MESSAGE(WM.NCCALCSIZE, _HandleNCCalcSize), + new HANDLE_MESSAGE(WM.NCHITTEST, _HandleNCHitTest), + new HANDLE_MESSAGE(WM.NCRBUTTONUP, _HandleNCRButtonUp), + new HANDLE_MESSAGE(WM.SIZE, _HandleSize), + new HANDLE_MESSAGE(WM.WINDOWPOSCHANGED, _HandleWindowPosChanged), + new HANDLE_MESSAGE(WM.DWMCOMPOSITIONCHANGED, _HandleDwmCompositionChanged), + }; + + if (Utility.IsPresentationFrameworkVersionLessThan4) + { + _messageTable.AddRange(new[] + { + new HANDLE_MESSAGE(WM.SETTINGCHANGE, _HandleSettingChange), + new HANDLE_MESSAGE(WM.ENTERSIZEMOVE, _HandleEnterSizeMove), + new HANDLE_MESSAGE(WM.EXITSIZEMOVE, _HandleExitSizeMove), + new HANDLE_MESSAGE(WM.MOVE, _HandleMove), + }); + } + } + + public void SetWindowChrome(WindowChrome newChrome) + { + VerifyAccess(); + Assert.IsNotNull(_window); + + if (newChrome == _chromeInfo) + { + // Nothing's changed. + return; + } + + if (_chromeInfo != null) + { + _chromeInfo.PropertyChangedThatRequiresRepaint -= _OnChromePropertyChangedThatRequiresRepaint; + } + + _chromeInfo = newChrome; + if (_chromeInfo != null) + { + _chromeInfo.PropertyChangedThatRequiresRepaint += _OnChromePropertyChangedThatRequiresRepaint; + } + + _ApplyNewCustomChrome(); + } + + private void _OnChromePropertyChangedThatRequiresRepaint(object sender, EventArgs e) + { + _UpdateFrameState(true); + } + + public static readonly DependencyProperty WindowChromeWorkerProperty = DependencyProperty.RegisterAttached( + "WindowChromeWorker", + typeof(WindowChromeWorker), + typeof(WindowChromeWorker), + new PropertyMetadata(null, _OnChromeWorkerChanged)); + + private static void _OnChromeWorkerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var w = (Window)d; + var cw = (WindowChromeWorker)e.NewValue; + + // The WindowChromeWorker object should only be set on the window once, and never to null. + Assert.IsNotNull(w); + Assert.IsNotNull(cw); + Assert.IsNull(cw._window); + + cw._SetWindow(w); + } + + private void _SetWindow(Window window) + { + Assert.IsNull(_window); + Assert.IsNotNull(window); + + _window = window; + + // There are potentially a couple funny states here. + // The window may have been shown and closed, in which case it's no longer usable. + // We shouldn't add any hooks in that case, just exit early. + // If the window hasn't yet been shown, then we need to make sure to remove hooks after it's closed. + _hwnd = new WindowInteropHelper(_window).Handle; + + if (Utility.IsPresentationFrameworkVersionLessThan4) + { + // On older versions of the framework the client size of the window is incorrectly calculated. + // We need to modify the template to fix this on behalf of the user. + Utility.AddDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + Utility.AddDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + } + + _window.Closed += _UnsetWindow; + + // Use whether we can get an HWND to determine if the Window has been loaded. + if (IntPtr.Zero != _hwnd) + { + // We've seen that the HwndSource can't always be retrieved from the HWND, so cache it early. + // Specifically it seems to sometimes disappear when the OS theme is changing. + _hwndSource = HwndSource.FromHwnd(_hwnd); + Assert.IsNotNull(_hwndSource); + _window.ApplyTemplate(); + + if (_chromeInfo != null) + { + _ApplyNewCustomChrome(); + } + } + else + { + _window.SourceInitialized += (sender, e) => + { + _hwnd = new WindowInteropHelper(_window).Handle; + Assert.IsNotDefault(_hwnd); + _hwndSource = HwndSource.FromHwnd(_hwnd); + Assert.IsNotNull(_hwndSource); + + if (_chromeInfo != null) + { + _ApplyNewCustomChrome(); + } + }; + } + } + + private void _UnsetWindow(object sender, EventArgs e) + { + if (Utility.IsPresentationFrameworkVersionLessThan4) + { + Utility.RemoveDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + Utility.RemoveDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + } + + if (_chromeInfo != null) + { + _chromeInfo.PropertyChangedThatRequiresRepaint -= _OnChromePropertyChangedThatRequiresRepaint; + } + + _RestoreStandardChromeState(true); + } + + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static WindowChromeWorker GetWindowChromeWorker(Window window) + { + Verify.IsNotNull(window, "window"); + return (WindowChromeWorker)window.GetValue(WindowChromeWorkerProperty); + } + + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static void SetWindowChromeWorker(Window window, WindowChromeWorker chrome) + { + Verify.IsNotNull(window, "window"); + window.SetValue(WindowChromeWorkerProperty, chrome); + } + + private void _OnWindowPropertyChangedThatRequiresTemplateFixup(object sender, EventArgs e) + { + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + if (_chromeInfo != null && _hwnd != IntPtr.Zero) + { + // Assume that when the template changes it's going to be applied. + // We don't have a good way to externally hook into the template + // actually being applied, so we asynchronously post the fixup operation + // at Loaded priority, so it's expected that the visual tree will be + // updated before _FixupFrameworkIssues is called. + _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupFrameworkIssues); + } + } + + private void _ApplyNewCustomChrome() + { + if (_hwnd == IntPtr.Zero) + { + // Not yet hooked. + return; + } + + if (_chromeInfo == null) + { + _RestoreStandardChromeState(false); + return; + } + + if (!_isHooked) + { + _hwndSource.AddHook(_WndProc); + _isHooked = true; + } + + _FixupFrameworkIssues(); + + // Force this the first time. + _UpdateSystemMenu(_window.WindowState); + _UpdateFrameState(true); + + NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); + } + + private void _FixupFrameworkIssues() + { + Assert.IsNotNull(_chromeInfo); + Assert.IsNotNull(_window); + + // This margin is only necessary if the client rect is going to be calculated incorrectly by WPF. + // This bug was fixed in V4 of the framework. + if (!Utility.IsPresentationFrameworkVersionLessThan4) + { + return; + } + + if (_window.Template == null) + { + // Nothing to fixup yet. This will get called again when a template does get set. + return; + } + + // Guard against the visual tree being empty. + if (VisualTreeHelper.GetChildrenCount(_window) == 0) + { + // The template isn't null, but we don't have a visual tree. + // Hope that ApplyTemplate is in the queue and repost this, because there's not much we can do right now. + _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupFrameworkIssues); + return; + } + + var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0); + + RECT rcWindow = NativeMethods.GetWindowRect(_hwnd); + RECT rcAdjustedClient = _GetAdjustedWindowRect(rcWindow); + + Rect rcLogicalWindow = DpiHelper.DeviceRectToLogical(new Rect(rcWindow.Left, rcWindow.Top, rcWindow.Width, rcWindow.Height)); + Rect rcLogicalClient = DpiHelper.DeviceRectToLogical(new Rect(rcAdjustedClient.Left, rcAdjustedClient.Top, rcAdjustedClient.Width, rcAdjustedClient.Height)); + + Thickness nonClientThickness = new Thickness( + rcLogicalWindow.Left - rcLogicalClient.Left, + rcLogicalWindow.Top - rcLogicalClient.Top, + rcLogicalClient.Right - rcLogicalWindow.Right, + rcLogicalClient.Bottom - rcLogicalWindow.Bottom); + + if( rootElement != null ) + { + rootElement.Margin = new Thickness( + 0, + 0, + -(nonClientThickness.Left + nonClientThickness.Right), + -(nonClientThickness.Top + nonClientThickness.Bottom) ); + } + + // The negative thickness on the margin doesn't properly get applied in RTL layouts. + // The width is right, but there is a black bar on the right. + // To fix this we just add an additional RenderTransform to the root element. + // This works fine, but if the window is dynamically changing its FlowDirection then this can have really bizarre side effects. + // This will mostly work if the FlowDirection is dynamically changed, but there aren't many real scenarios that would call for + // that so I'm not addressing the rest of the quirkiness. + if( rootElement != null ) + { + if (_window.FlowDirection == FlowDirection.RightToLeft) + { + rootElement.RenderTransform = new MatrixTransform(1, 0, 0, 1, -(nonClientThickness.Left + nonClientThickness.Right), 0); + } + else + { + rootElement.RenderTransform = null; + } + } + + if (!_isFixedUp) + { + _hasUserMovedWindow = false; + _window.StateChanged += _FixupRestoreBounds; + + _isFixedUp = true; + } + } + + // There was a regression in DWM in Windows 7 with regard to handling WM_NCCALCSIZE to effect custom chrome. + // When windows with glass are maximized on a multimonitor setup the glass frame tends to turn black. + // Also when windows are resized they tend to flicker black, sometimes staying that way until resized again. + // + // This appears to be a bug in DWM related to device bitmap optimizations. At least on RTM Win7 we can + // evoke a legacy code path that bypasses the bug by calling an esoteric DWM function. This doesn't affect + // the system, just the application. + // WPF also tends to call this function anyways during animations, so we're just forcing the issue + // consistently and a bit earlier. + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private void _FixupWindows7Issues() + { + if (_blackGlassFixupAttemptCount > 5) + { + // Don't keep trying if there's an endemic problem with this. + return; + } + + if (Utility.IsOSWindows7OrNewer && NativeMethods.DwmIsCompositionEnabled()) + { + ++_blackGlassFixupAttemptCount; + + bool success = false; + try + { + DWM_TIMING_INFO? dti = NativeMethods.DwmGetCompositionTimingInfo(_hwnd); + success = dti != null; + } + catch (Exception) + { + // We aren't sure of all the reasons this could fail. + // If we find new ones we should consider making the NativeMethod swallow them as well. + // Since we have a limited number of retries and this method isn't actually critical, just repost. + + // Disabling this for the published code to reduce debug noise. This will get compiled away for retail binaries anyways. + //Assert.Fail(e.Message); + } + + // NativeMethods.DwmGetCompositionTimingInfo swallows E_PENDING. + // If the call wasn't successful, try again later. + if (!success) + { + Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupWindows7Issues); + } + else + { + // Reset this. We will want to force this again if DWM composition changes. + _blackGlassFixupAttemptCount = 0; + } + } + } + + private void _FixupRestoreBounds(object sender, EventArgs e) + { + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + if (_window.WindowState == WindowState.Maximized || _window.WindowState == WindowState.Minimized) + { + // Old versions of WPF sometimes force their incorrect idea of the Window's location + // on the Win32 restore bounds. If we have reason to think this is the case, then + // try to undo what WPF did after it has done its thing. + if (_hasUserMovedWindow) + { + _hasUserMovedWindow = false; + WINDOWPLACEMENT wp = NativeMethods.GetWindowPlacement(_hwnd); + + RECT adjustedDeviceRc = _GetAdjustedWindowRect(new RECT { Bottom = 100, Right = 100 }); + Point adjustedTopLeft = DpiHelper.DevicePixelsToLogical( + new Point( + wp.rcNormalPosition.Left - adjustedDeviceRc.Left, + wp.rcNormalPosition.Top - adjustedDeviceRc.Top)); + + _window.Top = adjustedTopLeft.Y; + _window.Left = adjustedTopLeft.X; + } + } + } + + private RECT _GetAdjustedWindowRect(RECT rcWindow) + { + // This should only be used to work around issues in the Framework that were fixed in 4.0 + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + var style = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE); + var exstyle = (WS_EX)NativeMethods.GetWindowLongPtr(_hwnd, GWL.EXSTYLE); + + return NativeMethods.AdjustWindowRectEx(rcWindow, style, false, exstyle); + } + + // Windows tries hard to hide this state from applications. + // Generally you can tell that the window is in a docked position because the restore bounds from GetWindowPlacement + // don't match the current window location and it's not in a maximized or minimized state. + // Because this isn't doced or supported, it's also not incredibly consistent. Sometimes some things get updated in + // different orders, so this isn't absolutely reliable. + private bool _IsWindowDocked + { + get + { + // We're only detecting this state to work around .Net 3.5 issues. + // This logic won't work correctly when those issues are fixed. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + if (_window.WindowState != WindowState.Normal) + { + return false; + } + + RECT adjustedOffset = _GetAdjustedWindowRect(new RECT { Bottom = 100, Right = 100 }); + Point windowTopLeft = new Point(_window.Left, _window.Top); + windowTopLeft -= (Vector)DpiHelper.DevicePixelsToLogical(new Point(adjustedOffset.Left, adjustedOffset.Top)); + + return _window.RestoreBounds.Location != windowTopLeft; + } + } + + #region WindowProc and Message Handlers + + private IntPtr _WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + // Only expecting messages for our cached HWND. + Assert.AreEqual(hwnd, _hwnd); + + var message = (WM)msg; + foreach (var handlePair in _messageTable) + { + if (handlePair.Key == message) + { + return handlePair.Value(message, wParam, lParam, out handled); + } + } + return IntPtr.Zero; + } + + private IntPtr _HandleSetTextOrIcon(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + bool modified = _ModifyStyle(WS.VISIBLE, 0); + + // Setting the caption text and icon cause Windows to redraw the caption. + // Letting the default WndProc handle the message without the WS_VISIBLE + // style applied bypasses the redraw. + IntPtr lRet = NativeMethods.DefWindowProc(_hwnd, uMsg, wParam, lParam); + + // Put back the style we removed. + if (modified) + { + _ModifyStyle(0, WS.VISIBLE); + } + handled = true; + return lRet; + } + + private IntPtr _HandleNCActivate(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // Despite MSDN's documentation of lParam not being used, + // calling DefWindowProc with lParam set to -1 causes Windows not to draw over the caption. + + // Directly call DefWindowProc with a custom parameter + // which bypasses any other handling of the message. + IntPtr lRet = NativeMethods.DefWindowProc(_hwnd, WM.NCACTIVATE, wParam, new IntPtr(-1)); + handled = true; + return lRet; + } + + private IntPtr _HandleNCCalcSize(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // lParam is an [in, out] that can be either a RECT* (wParam == FALSE) or an NCCALCSIZE_PARAMS*. + // Since the first field of NCCALCSIZE_PARAMS is a RECT and is the only field we care about + // we can unconditionally treat it as a RECT. + + // Since we always want the client size to equal the window size, we can unconditionally handle it + // without having to modify the parameters. + + handled = true; + return new IntPtr((int)WVR.REDRAW); + } + + private IntPtr _HandleNCHitTest(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + IntPtr lRet = IntPtr.Zero; + handled = false; + + // Give DWM a chance at this first. + if (Utility.IsOSVistaOrNewer && _chromeInfo.GlassFrameThickness != default(Thickness) && _isGlassEnabled) + { + // If we're on Vista, give the DWM a chance to handle the message first. + handled = NativeMethods.DwmDefWindowProc(_hwnd, uMsg, wParam, lParam, out lRet); + } + + // Handle letting the system know if we consider the mouse to be in our effective non-client area. + // If DWM already handled this by way of DwmDefWindowProc, then respect their call. + if (IntPtr.Zero == lRet) + { + var mousePosScreen = new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam)); + Rect windowPosition = _GetWindowRect(); + + HT ht = _HitTestNca( + DpiHelper.DeviceRectToLogical(windowPosition), + DpiHelper.DevicePixelsToLogical(mousePosScreen)); + + // Don't blindly respect HTCAPTION. + // We want UIElements in the caption area to be actionable so run through a hittest first. + if (ht != HT.CLIENT) + { + Point mousePosWindow = mousePosScreen; + mousePosWindow.Offset(-windowPosition.X, -windowPosition.Y); + mousePosWindow = DpiHelper.DevicePixelsToLogical(mousePosWindow); + IInputElement inputElement = _window.InputHitTest(mousePosWindow); + if (inputElement != null && WindowChrome.GetIsHitTestVisibleInChrome(inputElement)) + { + ht = HT.CLIENT; + } + } + handled = true; + lRet = new IntPtr((int)ht); + } + return lRet; + } + + private IntPtr _HandleNCRButtonUp(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // Emulate the system behavior of clicking the right mouse button over the caption area + // to bring up the system menu. + if (HT.CAPTION == (HT)wParam.ToInt32()) + { + if (_window.ContextMenu != null) + { + _window.ContextMenu.Placement = PlacementMode.MousePoint; + _window.ContextMenu.IsOpen = true; + } + else if (WindowChrome.GetWindowChrome(_window).ShowSystemMenu) + SystemCommands.ShowSystemMenuPhysicalCoordinates(_window, new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam))); + } + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleSize(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + const int SIZE_MAXIMIZED = 2; + + // Force when maximized. + // We can tell what's happening right now, but the Window doesn't yet know it's + // maximized. Not forcing this update will eventually cause the + // default caption to be drawn. + WindowState? state = null; + if (wParam.ToInt32() == SIZE_MAXIMIZED) + { + state = WindowState.Maximized; + } + _UpdateSystemMenu(state); + + // Still let the default WndProc handle this. + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleWindowPosChanged(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx + // The WM_WINDOWPOSCHANGED message is sent at the end of the window + // state change process. It sort of combines the other state change + // notifications, WM_MOVE, WM_SIZE, and WM_SHOWWINDOW. But it doesn't + // suffer from the same limitations as WM_SHOWWINDOW, so you can + // reliably use it to react to the window being shown or hidden. + + _UpdateSystemMenu(null); + + if (!_isGlassEnabled) + { + Assert.IsNotDefault(lParam); + var wp = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS)); + _SetRoundingRegion(wp); + } + + // Still want to pass this to DefWndProc + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleDwmCompositionChanged(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + _UpdateFrameState(false); + + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleSettingChange(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // There are several settings that can cause fixups for the template to become invalid when changed. + // These shouldn't be required on the v4 framework. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + _FixupFrameworkIssues(); + + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleEnterSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // This is only intercepted to deal with bugs in Window in .Net 3.5 and below. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + _isUserResizing = true; + + // On Win7 if the user is dragging the window out of the maximized state then we don't want to use that location + // as a restore point. + Assert.Implies(_window.WindowState == WindowState.Maximized, Utility.IsOSWindows7OrNewer); + if (_window.WindowState != WindowState.Maximized) + { + // Check for the docked window case. The window can still be restored when it's in this position so + // try to account for that and not update the start position. + if (!_IsWindowDocked) + { + _windowPosAtStartOfUserMove = new Point(_window.Left, _window.Top); + } + // Realistically we also don't want to update the start position when moving from one docked state to another (or to and from maximized), + // but it's tricky to detect and this is already a workaround for a bug that's fixed in newer versions of the framework. + // Not going to try to handle all cases. + } + + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleExitSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // This is only intercepted to deal with bugs in Window in .Net 3.5 and below. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + _isUserResizing = false; + + // On Win7 the user can change the Window's state by dragging the window to the top of the monitor. + // If they did that, then we need to try to update the restore bounds or else WPF will put the window at the maximized location (e.g. (-8,-8)). + if (_window.WindowState == WindowState.Maximized) + { + Assert.IsTrue(Utility.IsOSWindows7OrNewer); + _window.Top = _windowPosAtStartOfUserMove.Y; + _window.Left = _windowPosAtStartOfUserMove.X; + } + + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // This is only intercepted to deal with bugs in Window in .Net 3.5 and below. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + if (_isUserResizing) + { + _hasUserMovedWindow = true; + } + + handled = false; + return IntPtr.Zero; + } + + #endregion + + /// Add and remove a native WindowStyle from the HWND. + /// The styles to be removed. These can be bitwise combined. + /// The styles to be added. These can be bitwise combined. + /// Whether the styles of the HWND were modified as a result of this call. + private bool _ModifyStyle(WS removeStyle, WS addStyle) + { + Assert.IsNotDefault(_hwnd); + var dwStyle = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE).ToInt32(); + var dwNewStyle = (dwStyle & ~removeStyle) | addStyle; + if (dwStyle == dwNewStyle) + { + return false; + } + + NativeMethods.SetWindowLongPtr(_hwnd, GWL.STYLE, new IntPtr((int)dwNewStyle)); + return true; + } + + /// + /// Get the WindowState as the native HWND knows it to be. This isn't necessarily the same as what Window thinks. + /// + private WindowState _GetHwndState() + { + var wpl = NativeMethods.GetWindowPlacement(_hwnd); + switch (wpl.showCmd) + { + case SW.SHOWMINIMIZED: return WindowState.Minimized; + case SW.SHOWMAXIMIZED: return WindowState.Maximized; + } + return WindowState.Normal; + } + + /// + /// Get the bounding rectangle for the window in physical coordinates. + /// + /// The bounding rectangle for the window. + private Rect _GetWindowRect() + { + // Get the window rectangle. + RECT windowPosition = NativeMethods.GetWindowRect(_hwnd); + return new Rect(windowPosition.Left, windowPosition.Top, windowPosition.Width, windowPosition.Height); + } + + /// + /// Update the items in the system menu based on the current, or assumed, WindowState. + /// + /// + /// The state to assume that the Window is in. This can be null to query the Window's state. + /// + /// + /// We want to update the menu while we have some control over whether the caption will be repainted. + /// + private void _UpdateSystemMenu(WindowState? assumeState) + { + const MF mfEnabled = MF.ENABLED | MF.BYCOMMAND; + const MF mfDisabled = MF.GRAYED | MF.DISABLED | MF.BYCOMMAND; + + WindowState state = assumeState ?? _GetHwndState(); + + if (null != assumeState || _lastMenuState != state) + { + _lastMenuState = state; + + bool modified = _ModifyStyle(WS.VISIBLE, 0); + IntPtr hmenu = NativeMethods.GetSystemMenu(_hwnd, false); + if (IntPtr.Zero != hmenu) + { + var dwStyle = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE).ToInt32(); + + bool canMinimize = Utility.IsFlagSet((int)dwStyle, (int)WS.MINIMIZEBOX); + bool canMaximize = Utility.IsFlagSet((int)dwStyle, (int)WS.MAXIMIZEBOX); + bool canSize = Utility.IsFlagSet((int)dwStyle, (int)WS.THICKFRAME); + + switch (state) + { + case WindowState.Maximized: + NativeMethods.EnableMenuItem(hmenu, SC.RESTORE, mfEnabled); + NativeMethods.EnableMenuItem(hmenu, SC.MOVE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.SIZE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MINIMIZE, canMinimize ? mfEnabled : mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MAXIMIZE, mfDisabled); + break; + case WindowState.Minimized: + NativeMethods.EnableMenuItem(hmenu, SC.RESTORE, mfEnabled); + NativeMethods.EnableMenuItem(hmenu, SC.MOVE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.SIZE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MINIMIZE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MAXIMIZE, canMaximize ? mfEnabled : mfDisabled); + break; + default: + NativeMethods.EnableMenuItem(hmenu, SC.RESTORE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MOVE, mfEnabled); + NativeMethods.EnableMenuItem(hmenu, SC.SIZE, canSize ? mfEnabled : mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MINIMIZE, canMinimize ? mfEnabled : mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MAXIMIZE, canMaximize ? mfEnabled : mfDisabled); + break; + } + } + + if (modified) + { + _ModifyStyle(0, WS.VISIBLE); + } + } + } + + private void _UpdateFrameState(bool force) + { + if (IntPtr.Zero == _hwnd) + { + return; + } + + // Don't rely on SystemParameters2 for this, just make the check ourselves. + bool frameState = NativeMethods.DwmIsCompositionEnabled(); + + if (force || frameState != _isGlassEnabled) + { + _isGlassEnabled = frameState && _chromeInfo.GlassFrameThickness != default(Thickness); + + if (!_isGlassEnabled) + { + _SetRoundingRegion(null); + } + else + { + _ClearRoundingRegion(); + _ExtendGlassFrame(); + + _FixupWindows7Issues(); + } + + NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); + } + } + + private void _ClearRoundingRegion() + { + NativeMethods.SetWindowRgn(_hwnd, IntPtr.Zero, NativeMethods.IsWindowVisible(_hwnd)); + } + + private void _SetRoundingRegion(WINDOWPOS? wp) + { + const int MONITOR_DEFAULTTONEAREST = 0x00000002; + + // We're early - WPF hasn't necessarily updated the state of the window. + // Need to query it ourselves. + WINDOWPLACEMENT wpl = NativeMethods.GetWindowPlacement(_hwnd); + + if (wpl.showCmd == SW.SHOWMAXIMIZED) + { + int left; + int top; + + if (wp.HasValue) + { + left = wp.Value.x; + top = wp.Value.y; + } + else + { + Rect r = _GetWindowRect(); + left = (int)r.Left; + top = (int)r.Top; + } + + IntPtr hMon = NativeMethods.MonitorFromWindow(_hwnd, MONITOR_DEFAULTTONEAREST); + + MONITORINFO mi = NativeMethods.GetMonitorInfo(hMon); + RECT rcMax = mi.rcWork; + // The location of maximized window takes into account the border that Windows was + // going to remove, so we also need to consider it. + rcMax.Offset(-left, -top); + + IntPtr hrgn = IntPtr.Zero; + try + { + hrgn = NativeMethods.CreateRectRgnIndirect(rcMax); + NativeMethods.SetWindowRgn(_hwnd, hrgn, NativeMethods.IsWindowVisible(_hwnd)); + hrgn = IntPtr.Zero; + } + finally + { + Utility.SafeDeleteObject(ref hrgn); + } + } + else + { + Size windowSize; + + // Use the size if it's specified. + if (null != wp && !Utility.IsFlagSet(wp.Value.flags, (int)SWP.NOSIZE)) + { + windowSize = new Size((double)wp.Value.cx, (double)wp.Value.cy); + } + else if (null != wp && (_lastRoundingState == _window.WindowState)) + { + return; + } + else + { + windowSize = _GetWindowRect().Size; + } + + _lastRoundingState = _window.WindowState; + + IntPtr hrgn = IntPtr.Zero; + try + { + double shortestDimension = Math.Min(windowSize.Width, windowSize.Height); + + double topLeftRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.TopLeft, 0)).X; + topLeftRadius = Math.Min(topLeftRadius, shortestDimension / 2); + + if (_IsUniform(_chromeInfo.CornerRadius)) + { + // RoundedRect HRGNs require an additional pixel of padding. + hrgn = _CreateRoundRectRgn(new Rect(windowSize), topLeftRadius); + } + else + { + // We need to combine HRGNs for each of the corners. + // Create one for each quadrant, but let it overlap into the two adjacent ones + // by the radius amount to ensure that there aren't corners etched into the middle + // of the window. + hrgn = _CreateRoundRectRgn(new Rect(0, 0, windowSize.Width / 2 + topLeftRadius, windowSize.Height / 2 + topLeftRadius), topLeftRadius); + + double topRightRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.TopRight, 0)).X; + topRightRadius = Math.Min(topRightRadius, shortestDimension / 2); + Rect topRightRegionRect = new Rect(0, 0, windowSize.Width / 2 + topRightRadius, windowSize.Height / 2 + topRightRadius); + topRightRegionRect.Offset(windowSize.Width / 2 - topRightRadius, 0); + Assert.AreEqual(topRightRegionRect.Right, windowSize.Width); + + _CreateAndCombineRoundRectRgn(hrgn, topRightRegionRect, topRightRadius); + + double bottomLeftRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.BottomLeft, 0)).X; + bottomLeftRadius = Math.Min(bottomLeftRadius, shortestDimension / 2); + Rect bottomLeftRegionRect = new Rect(0, 0, windowSize.Width / 2 + bottomLeftRadius, windowSize.Height / 2 + bottomLeftRadius); + bottomLeftRegionRect.Offset(0, windowSize.Height / 2 - bottomLeftRadius); + Assert.AreEqual(bottomLeftRegionRect.Bottom, windowSize.Height); + + _CreateAndCombineRoundRectRgn(hrgn, bottomLeftRegionRect, bottomLeftRadius); + + double bottomRightRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.BottomRight, 0)).X; + bottomRightRadius = Math.Min(bottomRightRadius, shortestDimension / 2); + Rect bottomRightRegionRect = new Rect(0, 0, windowSize.Width / 2 + bottomRightRadius, windowSize.Height / 2 + bottomRightRadius); + bottomRightRegionRect.Offset(windowSize.Width / 2 - bottomRightRadius, windowSize.Height / 2 - bottomRightRadius); + Assert.AreEqual(bottomRightRegionRect.Right, windowSize.Width); + Assert.AreEqual(bottomRightRegionRect.Bottom, windowSize.Height); + + _CreateAndCombineRoundRectRgn(hrgn, bottomRightRegionRect, bottomRightRadius); + } + + NativeMethods.SetWindowRgn(_hwnd, hrgn, NativeMethods.IsWindowVisible(_hwnd)); + hrgn = IntPtr.Zero; + } + finally + { + // Free the memory associated with the HRGN if it wasn't assigned to the HWND. + Utility.SafeDeleteObject(ref hrgn); + } + } + } + + private static IntPtr _CreateRoundRectRgn(Rect region, double radius) + { + // Round outwards. + + if (DoubleUtilities.AreClose(0, radius)) + { + return NativeMethods.CreateRectRgn( + (int)Math.Floor(region.Left), + (int)Math.Floor(region.Top), + (int)Math.Ceiling(region.Right), + (int)Math.Ceiling(region.Bottom)); + } + + // RoundedRect HRGNs require an additional pixel of padding on the bottom right to look correct. + return NativeMethods.CreateRoundRectRgn( + (int)Math.Floor(region.Left), + (int)Math.Floor(region.Top), + (int)Math.Ceiling(region.Right) + 1, + (int)Math.Ceiling(region.Bottom) + 1, + (int)Math.Ceiling(radius), + (int)Math.Ceiling(radius)); + } + + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "HRGNs")] + private static void _CreateAndCombineRoundRectRgn(IntPtr hrgnSource, Rect region, double radius) + { + IntPtr hrgn = IntPtr.Zero; + try + { + hrgn = _CreateRoundRectRgn(region, radius); + CombineRgnResult result = NativeMethods.CombineRgn(hrgnSource, hrgnSource, hrgn, RGN.OR); + if (result == CombineRgnResult.ERROR) + { + throw new InvalidOperationException("Unable to combine two HRGNs."); + } + } + catch + { + Utility.SafeDeleteObject(ref hrgn); + throw; + } + } + + private static bool _IsUniform(CornerRadius cornerRadius) + { + if (!DoubleUtilities.AreClose(cornerRadius.BottomLeft, cornerRadius.BottomRight)) + { + return false; + } + + if (!DoubleUtilities.AreClose(cornerRadius.TopLeft, cornerRadius.TopRight)) + { + return false; + } + + if (!DoubleUtilities.AreClose(cornerRadius.BottomLeft, cornerRadius.TopRight)) + { + return false; + } + + return true; + } + + private void _ExtendGlassFrame() + { + Assert.IsNotNull(_window); + + // Expect that this might be called on OSes other than Vista. + if (!Utility.IsOSVistaOrNewer) + { + // Not an error. Just not on Vista so we're not going to get glass. + return; + } + + if (IntPtr.Zero == _hwnd) + { + // Can't do anything with this call until the Window has been shown. + return; + } + + // Ensure standard HWND background painting when DWM isn't enabled. + if (!NativeMethods.DwmIsCompositionEnabled()) + { + _hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor; + } + else + { + // This makes the glass visible at a Win32 level so long as nothing else is covering it. + // The Window's Background needs to be changed independent of this. + + // Apply the transparent background to the HWND + _hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent; + + // Thickness is going to be DIPs, need to convert to system coordinates. + Point deviceTopLeft = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Left, _chromeInfo.GlassFrameThickness.Top)); + Point deviceBottomRight = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Right, _chromeInfo.GlassFrameThickness.Bottom)); + + var dwmMargin = new MARGINS + { + // err on the side of pushing in glass an extra pixel. + cxLeftWidth = (int)Math.Ceiling(deviceTopLeft.X), + cxRightWidth = (int)Math.Ceiling(deviceBottomRight.X), + cyTopHeight = (int)Math.Ceiling(deviceTopLeft.Y), + cyBottomHeight = (int)Math.Ceiling(deviceBottomRight.Y), + }; + + NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref dwmMargin); + } + } + + /// + /// Matrix of the HT values to return when responding to NC window messages. + /// + [SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")] + private static readonly HT[,] _HitTestBorders = new[,] + { + { HT.TOPLEFT, HT.TOP, HT.TOPRIGHT }, + { HT.LEFT, HT.CLIENT, HT.RIGHT }, + { HT.BOTTOMLEFT, HT.BOTTOM, HT.BOTTOMRIGHT }, + }; + + private HT _HitTestNca(Rect windowPosition, Point mousePosition) + { + // Determine if hit test is for resizing, default middle (1,1). + int uRow = 1; + int uCol = 1; + bool onResizeBorder = false; + + // Determine if the point is at the top or bottom of the window. + if (mousePosition.Y >= windowPosition.Top && mousePosition.Y < windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top + _chromeInfo.CaptionHeight) + { + onResizeBorder = (mousePosition.Y < (windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top)); + uRow = 0; // top (caption or resize border) + } + else if (mousePosition.Y < windowPosition.Bottom && mousePosition.Y >= windowPosition.Bottom - (int)_chromeInfo.ResizeBorderThickness.Bottom) + { + uRow = 2; // bottom + } + + // Determine if the point is at the left or right of the window. + if (mousePosition.X >= windowPosition.Left && mousePosition.X < windowPosition.Left + (int)_chromeInfo.ResizeBorderThickness.Left) + { + uCol = 0; // left side + } + else if (mousePosition.X < windowPosition.Right && mousePosition.X >= windowPosition.Right - _chromeInfo.ResizeBorderThickness.Right) + { + uCol = 2; // right side + } + + // If the cursor is in one of the top edges by the caption bar, but below the top resize border, + // then resize left-right rather than diagonally. + if (uRow == 0 && uCol != 1 && !onResizeBorder) + { + uRow = 1; + } + + HT ht = _HitTestBorders[uRow, uCol]; + + if (ht == HT.TOP && !onResizeBorder) + { + ht = HT.CAPTION; + } + + return ht; + } + + #region Remove Custom Chrome Methods + + private void _RestoreStandardChromeState(bool isClosing) + { + VerifyAccess(); + + _UnhookCustomChrome(); + + if (!isClosing) + { + _RestoreFrameworkIssueFixups(); + _RestoreGlassFrame(); + _RestoreHrgn(); + + _window.InvalidateMeasure(); + } + } + + private void _UnhookCustomChrome() + { + Assert.IsNotDefault(_hwnd); + Assert.IsNotNull(_window); + + if (_isHooked) + { + _hwndSource.RemoveHook(_WndProc); + _isHooked = false; + } + } + + private void _RestoreFrameworkIssueFixups() + { + // This margin is only necessary if the client rect is going to be calculated incorrectly by WPF. + // This bug was fixed in V4 of the framework. + if (Utility.IsPresentationFrameworkVersionLessThan4) + { + Assert.IsTrue(_isFixedUp); + + var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0); + if( rootElement != null ) + { + // Undo anything that was done before. + rootElement.Margin = new Thickness(); + } + + _window.StateChanged -= _FixupRestoreBounds; + _isFixedUp = false; + } + } + + private void _RestoreGlassFrame() + { + Assert.IsNull(_chromeInfo); + Assert.IsNotNull(_window); + + // Expect that this might be called on OSes other than Vista + // and if the window hasn't yet been shown, then we don't need to undo anything. + if (!Utility.IsOSVistaOrNewer || _hwnd == IntPtr.Zero) + { + return; + } + + _hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor; + + if (NativeMethods.DwmIsCompositionEnabled()) + { + // If glass is enabled, push it back to the normal bounds. + var dwmMargin = new MARGINS(); + NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref dwmMargin); + } + } + + private void _RestoreHrgn() + { + _ClearRoundingRegion(); + NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); + } + + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/TransformExtentions.cs b/Src/Xceed.Wpf.AvalonDock/Controls/TransformExtentions.cs new file mode 100644 index 0000000..e6b4e04 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/TransformExtentions.cs @@ -0,0 +1,126 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + internal static class TransformExtensions + { + public static Point PointToScreenDPI(this Visual visual, Point pt) + { + Point resultPt = visual.PointToScreen(pt); + return TransformToDeviceDPI(visual, resultPt); + } + + public static Point PointToScreenDPIWithoutFlowDirection(this FrameworkElement element, Point point) + { + if (FrameworkElement.GetFlowDirection(element) == FlowDirection.RightToLeft) + { + var actualSize = element.TransformActualSizeToAncestor(); + Point leftToRightPoint = new Point( + actualSize.Width - point.X, + point.Y); + return element.PointToScreenDPI(leftToRightPoint); + } + + return element.PointToScreenDPI(point); + } + + + + public static Rect GetScreenArea(this FrameworkElement element) + { + // return new Rect(element.PointToScreenDPI(new Point()), + // element.TransformActualSizeToAncestor()); + //} + + //public static Rect GetScreenAreaWithoutFlowDirection(this FrameworkElement element) + //{ + var point = element.PointToScreenDPI(new Point()); + if (FrameworkElement.GetFlowDirection(element) == FlowDirection.RightToLeft) + { + var actualSize = element.TransformActualSizeToAncestor(); + Point leftToRightPoint = new Point( + actualSize.Width - point.X, + point.Y); + return new Rect(leftToRightPoint, + actualSize); + } + + return new Rect(point, + element.TransformActualSizeToAncestor()); + } + + public static Point TransformToDeviceDPI(this Visual visual, Point pt) + { + Matrix m = PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice; + return new Point(pt.X / m.M11, pt.Y / m.M22); + } + + public static Size TransformFromDeviceDPI(this Visual visual, Size size) + { + Matrix m = PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice; + return new Size(size.Width * m.M11, size.Height * m.M22); + } + + public static Point TransformFromDeviceDPI(this Visual visual, Point pt) + { + Matrix m = PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice; + return new Point(pt.X * m.M11, pt.Y * m.M22); + } + + public static bool CanTransform(this Visual visual) + { + return PresentationSource.FromVisual(visual) != null; + } + + public static Size TransformActualSizeToAncestor(this FrameworkElement element) + { + if (PresentationSource.FromVisual(element) == null) + return new Size(element.ActualWidth, element.ActualHeight); + + var parentWindow = PresentationSource.FromVisual(element).RootVisual; + var transformToWindow = element.TransformToAncestor(parentWindow); + return transformToWindow.TransformBounds(new Rect(0, 0, element.ActualWidth, element.ActualHeight)).Size; + } + + public static Size TransformSizeToAncestor(this FrameworkElement element, Size sizeToTransform) + { + if (PresentationSource.FromVisual(element) == null) + return sizeToTransform; + + var parentWindow = PresentationSource.FromVisual(element).RootVisual; + var transformToWindow = element.TransformToAncestor(parentWindow); + return transformToWindow.TransformBounds(new Rect(0, 0, sizeToTransform.Width, sizeToTransform.Height)).Size; + } + + public static GeneralTransform TansformToAncestor(this FrameworkElement element) + { + if (PresentationSource.FromVisual(element) == null) + return new MatrixTransform(Matrix.Identity); + + var parentWindow = PresentationSource.FromVisual(element).RootVisual; + return element.TransformToAncestor(parentWindow); + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/WeakDictionary.cs b/Src/Xceed.Wpf.AvalonDock/Controls/WeakDictionary.cs new file mode 100644 index 0000000..c23b535 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/WeakDictionary.cs @@ -0,0 +1,94 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + class WeakDictionary where K : class + { + public WeakDictionary() + {} + + List _keys = new List(); + List _values = new List(); + + public V this[K key] + { + get + { + V valueToReturn; + if (!GetValue(key, out valueToReturn)) + throw new ArgumentException(); + return valueToReturn; + } + set + { + SetValue(key, value); + } + } + + public bool ContainsKey(K key) + { + CollectGarbage(); + return -1 != _keys.FindIndex(k => k.GetValueOrDefault() == key); + } + + public void SetValue(K key, V value) + { + CollectGarbage(); + int vIndex = _keys.FindIndex(k => k.GetValueOrDefault() == key); + if (vIndex > -1) + _values[vIndex] = value; + else + { + _values.Add(value); + _keys.Add(new WeakReference(key)); + } + } + + public bool GetValue(K key, out V value) + { + CollectGarbage(); + int vIndex = _keys.FindIndex(k => k.GetValueOrDefault() == key); + value = default(V); + if (vIndex == -1) + return false; + value = _values[vIndex]; + return true; + } + + + void CollectGarbage() + { + int vIndex = 0; + + do + { + vIndex = _keys.FindIndex(vIndex, k => !k.IsAlive); + if (vIndex >= 0) + { + _keys.RemoveAt(vIndex); + _values.RemoveAt(vIndex); + } + } + while (vIndex >= 0); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/WindowActivateEventArgs.cs b/Src/Xceed.Wpf.AvalonDock/Controls/WindowActivateEventArgs.cs new file mode 100644 index 0000000..de8376c --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/WindowActivateEventArgs.cs @@ -0,0 +1,37 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + class WindowActivateEventArgs : EventArgs + { + public WindowActivateEventArgs(IntPtr hwndActivating) + { + HwndActivating = hwndActivating; + } + + public IntPtr HwndActivating + { + get; + private set; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Controls/WindowHookHandler.cs b/Src/Xceed.Wpf.AvalonDock/Controls/WindowHookHandler.cs new file mode 100644 index 0000000..b97374a --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Controls/WindowHookHandler.cs @@ -0,0 +1,99 @@ +/************************************************************************************* + + 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.Threading; + +namespace Xceed.Wpf.AvalonDock.Controls +{ + class FocusChangeEventArgs : EventArgs + { + public FocusChangeEventArgs(IntPtr gotFocusWinHandle, IntPtr lostFocusWinHandle) + { + GotFocusWinHandle = gotFocusWinHandle; + LostFocusWinHandle = lostFocusWinHandle; + } + + public IntPtr GotFocusWinHandle + { + get; + private set; + } + public IntPtr LostFocusWinHandle + { + get; + private set; + } + } + + class WindowHookHandler + { + public WindowHookHandler() + { + + } + + IntPtr _windowHook; + Win32Helper.HookProc _hookProc; + public void Attach() + { + _hookProc = new Win32Helper.HookProc(this.HookProc); + _windowHook = Win32Helper.SetWindowsHookEx( + Win32Helper.HookType.WH_CBT, + _hookProc, + IntPtr.Zero, + (int)Win32Helper.GetCurrentThreadId()); + } + + + public void Detach() + { + Win32Helper.UnhookWindowsHookEx(_windowHook); + } + + public int HookProc(int code, IntPtr wParam, IntPtr lParam) + { + if (code == Win32Helper.HCBT_SETFOCUS) + { + if (FocusChanged != null) + FocusChanged(this, new FocusChangeEventArgs(wParam, lParam)); + } + else if (code == Win32Helper.HCBT_ACTIVATE) + { + if (_insideActivateEvent.CanEnter) + { + using (_insideActivateEvent.Enter()) + { + //if (Activate != null) + // Activate(this, new WindowActivateEventArgs(wParam)); + } + } + } + + + return Win32Helper.CallNextHookEx(_windowHook, code, wParam, lParam); + } + + public event EventHandler FocusChanged; + + //public event EventHandler Activate; + + ReentrantFlag _insideActivateEvent = new ReentrantFlag(); + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/ActivateCommandLayoutItemFromLayoutModelConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/ActivateCommandLayoutItemFromLayoutModelConverter.cs new file mode 100644 index 0000000..ac80701 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/ActivateCommandLayoutItemFromLayoutModelConverter.cs @@ -0,0 +1,51 @@ +/************************************************************************************* + + 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.Data; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + public class ActivateCommandLayoutItemFromLayoutModelConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + //when this converter is called layout could be constructing so many properties here are potentially not valid + var layoutModel = value as LayoutContent; + if (layoutModel == null) + return null; + if (layoutModel.Root == null) + return null; + if (layoutModel.Root.Manager == null) + return null; + + var layoutItemModel = layoutModel.Root.Manager.GetLayoutItemFromModel(layoutModel); + if (layoutItemModel == null) + return Binding.DoNothing; + + return layoutItemModel.ActivateCommand; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/AnchorSideToAngleConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/AnchorSideToAngleConverter.cs new file mode 100644 index 0000000..57f36f6 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/AnchorSideToAngleConverter.cs @@ -0,0 +1,44 @@ +/************************************************************************************* + + 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.Data; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + [ValueConversion(typeof(AnchorSide), typeof(double))] + public class AnchorSideToAngleConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + AnchorSide side = (AnchorSide)value; + if (side == AnchorSide.Left || + side == AnchorSide.Right) + return 90.0; + + return Binding.DoNothing; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/AnchorSideToOrientationConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/AnchorSideToOrientationConverter.cs new file mode 100644 index 0000000..ba27830 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/AnchorSideToOrientationConverter.cs @@ -0,0 +1,45 @@ +/************************************************************************************* + + 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.Data; +using System.Windows.Controls; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + [ValueConversion(typeof(AnchorSide), typeof(Orientation))] + public class AnchorSideToOrientationConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + AnchorSide side = (AnchorSide)value; + if (side == AnchorSide.Left || + side == AnchorSide.Right) + return Orientation.Vertical; + + return Orientation.Horizontal; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/AutoHideCommandLayoutItemFromLayoutModelConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/AutoHideCommandLayoutItemFromLayoutModelConverter.cs new file mode 100644 index 0000000..dbce7be --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/AutoHideCommandLayoutItemFromLayoutModelConverter.cs @@ -0,0 +1,52 @@ +/************************************************************************************* + + 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.Data; +using Xceed.Wpf.AvalonDock.Layout; +using Xceed.Wpf.AvalonDock.Controls; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + public class AutoHideCommandLayoutItemFromLayoutModelConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + //when this converter is called layout could be constructing so many properties here are potentially not valid + var layoutModel = value as LayoutContent; + if (layoutModel == null) + return null; + if (layoutModel.Root == null) + return null; + if (layoutModel.Root.Manager == null) + return null; + + var layoutItemModel = layoutModel.Root.Manager.GetLayoutItemFromModel(layoutModel) as LayoutAnchorableItem; + if (layoutItemModel == null) + return Binding.DoNothing; + + return layoutItemModel.AutoHideCommand; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/BoolToVisibilityConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/BoolToVisibilityConverter.cs new file mode 100644 index 0000000..97c270e --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/BoolToVisibilityConverter.cs @@ -0,0 +1,92 @@ +/************************************************************************************* + + 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.Data; +using System.Windows; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + [ValueConversion(typeof(bool), typeof(Visibility))] + public class BoolToVisibilityConverter : IValueConverter + { + + #region IValueConverter Members + /// + /// Converts a value. + /// + /// The value produced by the binding source. + /// The type of the binding target property. + /// The converter parameter to use. + /// The culture to use in the converter. + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (value is bool && targetType == typeof(Visibility)) + { + bool val = (bool)value; + if (val) + return Visibility.Visible; + else + if (parameter != null && parameter is Visibility) + return parameter; + else + return Visibility.Collapsed; + } + if (value == null) + { + if (parameter != null && parameter is Visibility) + return parameter; + else + return Visibility.Collapsed; + } + + return Visibility.Visible; + ///throw new ArgumentException("Invalid argument/return type. Expected argument: bool and return type: Visibility"); + } + + /// + /// Converts a value. + /// + /// The value that is produced by the binding target. + /// The type to convert to. + /// The converter parameter to use. + /// The culture to use in the converter. + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (value is Visibility && targetType == typeof(bool)) + { + Visibility val = (Visibility)value; + if (val == Visibility.Visible) + return true; + else + return false; + } + throw new ArgumentException("Invalid argument/return type. Expected argument: Visibility and return type: bool"); + } + #endregion + } + + +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/HideCommandLayoutItemFromLayoutModelConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/HideCommandLayoutItemFromLayoutModelConverter.cs new file mode 100644 index 0000000..3e23fe2 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/HideCommandLayoutItemFromLayoutModelConverter.cs @@ -0,0 +1,52 @@ +/************************************************************************************* + + 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.Data; +using Xceed.Wpf.AvalonDock.Layout; +using Xceed.Wpf.AvalonDock.Controls; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + public class HideCommandLayoutItemFromLayoutModelConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + //when this converter is called layout could be constructing so many properties here are potentially not valid + var layoutModel = value as LayoutContent; + if (layoutModel == null) + return null; + if (layoutModel.Root == null) + return null; + if (layoutModel.Root.Manager == null) + return null; + + var layoutItemModel = layoutModel.Root.Manager.GetLayoutItemFromModel(layoutModel) as LayoutAnchorableItem; + if (layoutItemModel == null) + return Binding.DoNothing; + + return layoutItemModel.HideCommand; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/InverseBoolToVisibilityConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/InverseBoolToVisibilityConverter.cs new file mode 100644 index 0000000..80c9bb7 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/InverseBoolToVisibilityConverter.cs @@ -0,0 +1,83 @@ +/************************************************************************************* + + 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.Data; +using System.Windows; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + [ValueConversion(typeof(bool), typeof(Visibility))] + public class InverseBoolToVisibilityConverter : IValueConverter + { + + #region IValueConverter Members + /// + /// Converts a value. + /// + /// The value produced by the binding source. + /// The type of the binding target property. + /// The converter parameter to use. + /// The culture to use in the converter. + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (value is bool && targetType == typeof(Visibility)) + { + bool val = !(bool)value; + if (val) + return Visibility.Visible; + else + if (parameter != null && parameter is Visibility ) + return parameter; + else + return Visibility.Collapsed; + } + throw new ArgumentException("Invalid argument/return type. Expected argument: bool and return type: Visibility"); + } + + /// + /// Converts a value. + /// + /// The value that is produced by the binding target. + /// The type to convert to. + /// The converter parameter to use. + /// The culture to use in the converter. + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (value is Visibility && targetType == typeof(bool)) + { + Visibility val = (Visibility)value; + if (val == Visibility.Visible) + return false; + else + return true; + } + throw new ArgumentException("Invalid argument/return type. Expected argument: Visibility and return type: bool"); + } + #endregion + } + + +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/LayoutItemFromLayoutModelConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/LayoutItemFromLayoutModelConverter.cs new file mode 100644 index 0000000..e1f6e39 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/LayoutItemFromLayoutModelConverter.cs @@ -0,0 +1,50 @@ +/************************************************************************************* + + 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.Data; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + public class LayoutItemFromLayoutModelConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + var layoutModel = value as LayoutContent; + if (layoutModel == null) + return null; + if (layoutModel.Root == null) + return null; + if (layoutModel.Root.Manager == null) + return null; + + var layoutItemModel = layoutModel.Root.Manager.GetLayoutItemFromModel(layoutModel); + if (layoutItemModel == null) + return Binding.DoNothing; + + return layoutItemModel; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/NullToDoNothingConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/NullToDoNothingConverter.cs new file mode 100644 index 0000000..cfcf2ca --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/NullToDoNothingConverter.cs @@ -0,0 +1,40 @@ +/************************************************************************************* + + 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.Data; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + public class NullToDoNothingConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (value == null) + return Binding.DoNothing; + + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Converters/UriSourceToBitmapImageConverter.cs b/Src/Xceed.Wpf.AvalonDock/Converters/UriSourceToBitmapImageConverter.cs new file mode 100644 index 0000000..c9e1193 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Converters/UriSourceToBitmapImageConverter.cs @@ -0,0 +1,42 @@ +/************************************************************************************* + + 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.Data; +using System.Windows.Media.Imaging; +using System.Windows.Controls; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + public class UriSourceToBitmapImageConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (value == null) + return Binding.DoNothing; + //return (Uri)value; + return new Image() { Source = new BitmapImage((Uri)value) } ; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/DockingManager.cs b/Src/Xceed.Wpf.AvalonDock/DockingManager.cs new file mode 100644 index 0000000..c941e0c --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/DockingManager.cs @@ -0,0 +1,3262 @@ +/************************************************************************************* + + 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.Controls; +using System.Windows; +using System.Windows.Markup; +using System.ComponentModel; +using System.Windows.Interop; +using System.Diagnostics; + +using Xceed.Wpf.AvalonDock.Layout; +using Xceed.Wpf.AvalonDock.Controls; +using System.Windows.Input; +using System.Collections; +using System.Collections.Specialized; +using System.Windows.Data; +using System.Windows.Threading; +using Xceed.Wpf.AvalonDock.Commands; +using Xceed.Wpf.AvalonDock.Themes; + +namespace Xceed.Wpf.AvalonDock +{ + [ContentProperty("Layout")] + [TemplatePart(Name="PART_AutoHideArea")] + public class DockingManager : Control, IOverlayWindowHost//, ILogicalChildrenContainer + { + private ResourceDictionary currentThemeResourceDictionary; // = null + + static DockingManager() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(DockingManager), new FrameworkPropertyMetadata(typeof(DockingManager))); + FocusableProperty.OverrideMetadata(typeof(DockingManager), new FrameworkPropertyMetadata(false)); + HwndSource.DefaultAcquireHwndFocusInMenuMode = false; + } + + + public DockingManager() + { +#if !VS2008 + Layout = new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) }; +#else + this.SetCurrentValue( DockingManager.LayoutProperty, new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) } ); +#endif + this.Loaded += new RoutedEventHandler(DockingManager_Loaded); + this.Unloaded += new RoutedEventHandler(DockingManager_Unloaded); + } + + #region Layout + + /// + /// Layout Dependency Property + /// + public static readonly DependencyProperty LayoutProperty = + DependencyProperty.Register("Layout", typeof(LayoutRoot), typeof(DockingManager), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnLayoutChanged), + new CoerceValueCallback(CoerceLayoutValue))); + + /// + /// Gets or sets the Layout property. This dependency property + /// indicates layout tree. + /// + public LayoutRoot Layout + { + get { return (LayoutRoot)GetValue(LayoutProperty); } + set { SetValue(LayoutProperty, value); } + } + + /// + /// Handles changes to the Layout property. + /// + private static void OnLayoutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutChanged(e.OldValue as LayoutRoot, e.NewValue as LayoutRoot); + } + + /// + /// Provides derived classes an opportunity to handle changes to the property. + /// + protected virtual void OnLayoutChanged(LayoutRoot oldLayout, LayoutRoot newLayout) + { + if (oldLayout != null) + { + oldLayout.PropertyChanged -= new PropertyChangedEventHandler(OnLayoutRootPropertyChanged); + oldLayout.Updated -= new EventHandler(OnLayoutRootUpdated); + } + + foreach (var fwc in _fwList.ToArray()) + { + fwc.KeepContentVisibleOnClose = true; + fwc.InternalClose(); + } + + _fwList.Clear(); + + DetachDocumentsSource(oldLayout, DocumentsSource); + DetachAnchorablesSource(oldLayout, AnchorablesSource); + + if (oldLayout != null && + oldLayout.Manager == this) + oldLayout.Manager = null; + + ClearLogicalChildrenList(); + DetachLayoutItems(); + + Layout.Manager = this; + + AttachLayoutItems(); + AttachDocumentsSource(newLayout, DocumentsSource); + AttachAnchorablesSource(newLayout, AnchorablesSource); + + if (IsLoaded) + { + LayoutRootPanel = CreateUIElementForModel(Layout.RootPanel) as LayoutPanelControl; + LeftSidePanel = CreateUIElementForModel(Layout.LeftSide) as LayoutAnchorSideControl; + TopSidePanel = CreateUIElementForModel(Layout.TopSide) as LayoutAnchorSideControl; + RightSidePanel = CreateUIElementForModel(Layout.RightSide) as LayoutAnchorSideControl; + BottomSidePanel = CreateUIElementForModel(Layout.BottomSide) as LayoutAnchorSideControl; + + foreach (var fw in Layout.FloatingWindows.ToArray()) + { + if (fw.IsValid) + _fwList.Add(CreateUIElementForModel(fw) as LayoutFloatingWindowControl); + } + + foreach (var fw in _fwList) + { + //fw.Owner = Window.GetWindow(this); + //fw.SetParentToMainWindowOf(this); + } + } + + + if (newLayout != null) + { + newLayout.PropertyChanged += new PropertyChangedEventHandler(OnLayoutRootPropertyChanged); + newLayout.Updated += new EventHandler(OnLayoutRootUpdated); + } + + if (LayoutChanged != null) + LayoutChanged(this, EventArgs.Empty); + + //if (Layout != null) + // Layout.CollectGarbage(); + + CommandManager.InvalidateRequerySuggested(); + } + + // DispatcherOperation _setFocusAsyncOperation = null; + + void OnLayoutRootPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "RootPanel") + { + if (IsInitialized) + { + var layoutRootPanel = CreateUIElementForModel(Layout.RootPanel) as LayoutPanelControl; + LayoutRootPanel = layoutRootPanel; + } + } + else if (e.PropertyName == "ActiveContent") + { + if (Layout.ActiveContent != null) + { + //Debug.WriteLine(new StackTrace().ToString()); + + //set focus on active element only after a layout pass is completed + //it's possible that it is not yet visible in the visual tree + //if (_setFocusAsyncOperation == null) + //{ + // _setFocusAsyncOperation = Dispatcher.BeginInvoke(new Action(() => + // { + if (Layout.ActiveContent != null) + FocusElementManager.SetFocusOnLastElement(Layout.ActiveContent); + //_setFocusAsyncOperation = null; + // } ), DispatcherPriority.Input ); + //} + } + + //if (!_insideInternalSetActiveContent) + // ActiveContent = Layout.ActiveContent != null ? + // Layout.ActiveContent.Content : null; + if( !_insideInternalSetActiveContent && (Layout.ActiveContent != null) ) + { + this.ActiveContent = Layout.ActiveContent.Content; + } + } + } + + void OnLayoutRootUpdated(object sender, EventArgs e) + { + CommandManager.InvalidateRequerySuggested(); + } + + + /// + /// Event fired when property changes + /// + public event EventHandler LayoutChanged; + + /// + /// Coerces the value. + /// + private static object CoerceLayoutValue(DependencyObject d, object value) + { + if (value == null) + return new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) }; + + ((DockingManager)d).OnLayoutChanging(value as LayoutRoot); + + return value; + } + + /// + /// Event fired when property is about to be changed + /// + public event EventHandler LayoutChanging; + + void OnLayoutChanging(LayoutRoot newLayout) + { + if (LayoutChanging != null) + LayoutChanging(this, EventArgs.Empty); + } + + + #region LayoutUpdateStrategy + + /// + /// LayoutUpdateStrategy Dependency Property + /// + public static readonly DependencyProperty LayoutUpdateStrategyProperty = + DependencyProperty.Register("LayoutUpdateStrategy", typeof(ILayoutUpdateStrategy), typeof(DockingManager), + new FrameworkPropertyMetadata((ILayoutUpdateStrategy)null)); + + /// + /// Gets or sets the LayoutUpdateStrategy property. This dependency property + /// indicates the strategy class to call when AvalonDock needs to positionate a LayoutAnchorable inside an existing layout. + /// + /// Sometimes it's impossible to automatically insert an anchorable in the layout without specifing the target parent pane. + /// Set this property to an object that will be asked to insert the anchorable to the desidered position. + public ILayoutUpdateStrategy LayoutUpdateStrategy + { + get { return (ILayoutUpdateStrategy)GetValue(LayoutUpdateStrategyProperty); } + set { SetValue(LayoutUpdateStrategyProperty, value); } + } + + #endregion + + + + #endregion + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + // SetupAutoHideWindow(); + } + + protected override void OnInitialized( EventArgs e ) + { + base.OnInitialized(e); + } + + void DockingManager_Loaded(object sender, RoutedEventArgs e) + { + if (!DesignerProperties.GetIsInDesignMode(this)) + { + if( Layout.Manager == this ) + { + LayoutRootPanel = CreateUIElementForModel( Layout.RootPanel ) as LayoutPanelControl; + LeftSidePanel = CreateUIElementForModel( Layout.LeftSide ) as LayoutAnchorSideControl; + TopSidePanel = CreateUIElementForModel( Layout.TopSide ) as LayoutAnchorSideControl; + RightSidePanel = CreateUIElementForModel( Layout.RightSide ) as LayoutAnchorSideControl; + BottomSidePanel = CreateUIElementForModel( Layout.BottomSide ) as LayoutAnchorSideControl; + } + + SetupAutoHideWindow(); + + //load windows not already loaded! + foreach (var fw in Layout.FloatingWindows.Where(fw => !_fwList.Any(fwc => fwc.Model == fw))) + _fwList.Add(CreateUIElementForModel(fw) as LayoutFloatingWindowControl); + + //create the overlaywindow if it's possible + if (IsVisible) + CreateOverlayWindow(); + FocusElementManager.SetupFocusManagement(this); + } + } + + void DockingManager_Unloaded(object sender, RoutedEventArgs e) + { + + if (!DesignerProperties.GetIsInDesignMode(this)) + { + if( _autoHideWindowManager != null ) + { + _autoHideWindowManager.HideAutoWindow(); + } + + if( AutoHideWindow != null ) + AutoHideWindow.Dispose(); + + foreach (var fw in _fwList.ToArray()) + { + //fw.Owner = null; + fw.SetParentWindowToNull(); + fw.KeepContentVisibleOnClose = true; + fw.Close(); + } + + DestroyOverlayWindow(); + FocusElementManager.FinalizeFocusManagement(this); + } + } + + internal UIElement CreateUIElementForModel(ILayoutElement model) + { + if (model is LayoutPanel) + return new LayoutPanelControl(model as LayoutPanel); + if (model is LayoutAnchorablePaneGroup) + return new LayoutAnchorablePaneGroupControl(model as LayoutAnchorablePaneGroup); + if (model is LayoutDocumentPaneGroup) + return new LayoutDocumentPaneGroupControl(model as LayoutDocumentPaneGroup); + + if (model is LayoutAnchorSide) + { + var templateModelView = new LayoutAnchorSideControl(model as LayoutAnchorSide); + templateModelView.SetBinding(LayoutAnchorSideControl.TemplateProperty, new Binding("AnchorSideTemplate") { Source = this }); + return templateModelView; + } + if (model is LayoutAnchorGroup) + { + var templateModelView = new LayoutAnchorGroupControl(model as LayoutAnchorGroup); + templateModelView.SetBinding(LayoutAnchorGroupControl.TemplateProperty, new Binding("AnchorGroupTemplate") { Source = this }); + return templateModelView; + } + + if (model is LayoutDocumentPane) + { + var templateModelView = new LayoutDocumentPaneControl(model as LayoutDocumentPane); + templateModelView.SetBinding(LayoutDocumentPaneControl.StyleProperty, new Binding("DocumentPaneControlStyle") { Source = this }); + return templateModelView; + } + if (model is LayoutAnchorablePane) + { + var templateModelView = new LayoutAnchorablePaneControl(model as LayoutAnchorablePane); + templateModelView.SetBinding(LayoutAnchorablePaneControl.StyleProperty, new Binding("AnchorablePaneControlStyle") { Source = this }); + return templateModelView; + } + + if (model is LayoutAnchorableFloatingWindow) + { + if (DesignerProperties.GetIsInDesignMode(this)) + return null; + var modelFW = model as LayoutAnchorableFloatingWindow; + var newFW = new LayoutAnchorableFloatingWindowControl(modelFW) + { + //Owner = Window.GetWindow(this) + }; + newFW.SetParentToMainWindowOf(this); + + var paneForExtensions = modelFW.RootPanel.Children.OfType().FirstOrDefault(); + if (paneForExtensions != null) + { + //ensure that floating window position is inside current (or nearest) monitor + paneForExtensions.KeepInsideNearestMonitor(); + + newFW.Left = paneForExtensions.FloatingLeft; + newFW.Top = paneForExtensions.FloatingTop; + newFW.Width = paneForExtensions.FloatingWidth; + newFW.Height = paneForExtensions.FloatingHeight; + } + + newFW.ShowInTaskbar = false; + newFW.Show(); + // Do not set the WindowState before showing or it will be lost + if( paneForExtensions != null && paneForExtensions.IsMaximized ) + { + newFW.WindowState = WindowState.Maximized; + } + return newFW; + } + + if (model is LayoutDocumentFloatingWindow) + { + if (DesignerProperties.GetIsInDesignMode(this)) + return null; + var modelFW = model as LayoutDocumentFloatingWindow; + var newFW = new LayoutDocumentFloatingWindowControl(modelFW) + { + //Owner = Window.GetWindow(this) + }; + newFW.SetParentToMainWindowOf(this); + + var paneForExtensions = modelFW.RootDocument; + if (paneForExtensions != null) + { + //ensure that floating window position is inside current (or nearest) monitor + paneForExtensions.KeepInsideNearestMonitor(); + + newFW.Left = paneForExtensions.FloatingLeft; + newFW.Top = paneForExtensions.FloatingTop; + newFW.Width = paneForExtensions.FloatingWidth; + newFW.Height = paneForExtensions.FloatingHeight; + } + + newFW.ShowInTaskbar = false; + newFW.Show(); + // Do not set the WindowState before showing or it will be lost + if( paneForExtensions != null && paneForExtensions.IsMaximized ) + { + newFW.WindowState = WindowState.Maximized; + } + return newFW; + } + + if (model is LayoutDocument) + { + var templateModelView = new LayoutDocumentControl() { Model = model as LayoutDocument }; + return templateModelView; + } + + return null; + } + + + + #region DocumentPaneTemplate + + /// + /// DocumentPaneTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentPaneTemplateProperty = + DependencyProperty.Register("DocumentPaneTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null, + new PropertyChangedCallback(OnDocumentPaneTemplateChanged))); + + /// + /// Gets or sets the DocumentPaneDataTemplate property. This dependency property + /// indicates . + /// + public ControlTemplate DocumentPaneTemplate + { + get { return (ControlTemplate)GetValue(DocumentPaneTemplateProperty); } + set { SetValue(DocumentPaneTemplateProperty, value); } + } + + /// + /// Handles changes to the DocumentPaneTemplate property. + /// + private static void OnDocumentPaneTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentPaneTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneTemplate property. + /// + protected virtual void OnDocumentPaneTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region AnchorablePaneTemplate + + /// + /// AnchorablePaneTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorablePaneTemplateProperty = + DependencyProperty.Register("AnchorablePaneTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null, + new PropertyChangedCallback(OnAnchorablePaneTemplateChanged))); + + /// + /// Gets or sets the AnchorablePaneTemplate property. This dependency property + /// indicates .... + /// + public ControlTemplate AnchorablePaneTemplate + { + get { return (ControlTemplate)GetValue(AnchorablePaneTemplateProperty); } + set { SetValue(AnchorablePaneTemplateProperty, value); } + } + + /// + /// Handles changes to the AnchorablePaneDataTemplate property. + /// + private static void OnAnchorablePaneTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorablePaneTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorablePaneDataTemplate property. + /// + protected virtual void OnAnchorablePaneTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region AnchorSideTemplate + + /// + /// AnchorSideTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorSideTemplateProperty = + DependencyProperty.Register("AnchorSideTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null)); + + /// + /// Gets or sets the AnchorSideTemplate property. This dependency property + /// indicates .... + /// + public ControlTemplate AnchorSideTemplate + { + get { return (ControlTemplate)GetValue(AnchorSideTemplateProperty); } + set { SetValue(AnchorSideTemplateProperty, value); } + } + + #endregion + + #region AnchorGroupTemplate + + /// + /// AnchorGroupTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorGroupTemplateProperty = + DependencyProperty.Register("AnchorGroupTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null)); + + /// + /// Gets or sets the AnchorGroupTemplate property. This dependency property + /// indicates the template used to render the AnchorGroup control. + /// + public ControlTemplate AnchorGroupTemplate + { + get { return (ControlTemplate)GetValue(AnchorGroupTemplateProperty); } + set { SetValue(AnchorGroupTemplateProperty, value); } + } + + #endregion + + #region AnchorTemplate + + /// + /// AnchorTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorTemplateProperty = + DependencyProperty.Register("AnchorTemplate", typeof(ControlTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((ControlTemplate)null)); + + /// + /// Gets or sets the AnchorTemplate property. This dependency property + /// indicates .... + /// + public ControlTemplate AnchorTemplate + { + get { return (ControlTemplate)GetValue(AnchorTemplateProperty); } + set { SetValue(AnchorTemplateProperty, value); } + } + + #endregion + + #region DocumentPaneControlStyle + + /// + /// DocumentPaneControlStyle Dependency Property + /// + public static readonly DependencyProperty DocumentPaneControlStyleProperty = + DependencyProperty.Register("DocumentPaneControlStyle", typeof(Style), typeof(DockingManager), + new FrameworkPropertyMetadata((Style)null, + new PropertyChangedCallback(OnDocumentPaneControlStyleChanged))); + + /// + /// Gets or sets the DocumentPaneControlStyle property. This dependency property + /// indicates .... + /// + public Style DocumentPaneControlStyle + { + get { return (Style)GetValue(DocumentPaneControlStyleProperty); } + set { SetValue(DocumentPaneControlStyleProperty, value); } + } + + /// + /// Handles changes to the DocumentPaneControlStyle property. + /// + private static void OnDocumentPaneControlStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentPaneControlStyleChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneControlStyle property. + /// + protected virtual void OnDocumentPaneControlStyleChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region AnchorablePaneControlStyle + + /// + /// AnchorablePaneControlStyle Dependency Property + /// + public static readonly DependencyProperty AnchorablePaneControlStyleProperty = + DependencyProperty.Register("AnchorablePaneControlStyle", typeof(Style), typeof(DockingManager), + new FrameworkPropertyMetadata((Style)null, + new PropertyChangedCallback(OnAnchorablePaneControlStyleChanged))); + + /// + /// Gets or sets the AnchorablePaneControlStyle property. This dependency property + /// indicates the style to apply to AnchorablePaneControl. + /// + public Style AnchorablePaneControlStyle + { + get { return (Style)GetValue(AnchorablePaneControlStyleProperty); } + set { SetValue(AnchorablePaneControlStyleProperty, value); } + } + + /// + /// Handles changes to the AnchorablePaneControlStyle property. + /// + private static void OnAnchorablePaneControlStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorablePaneControlStyleChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorablePaneControlStyle property. + /// + protected virtual void OnAnchorablePaneControlStyleChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region DocumentHeaderTemplate + + /// + /// DocumentHeaderTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentHeaderTemplateProperty = + DependencyProperty.Register("DocumentHeaderTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, + new PropertyChangedCallback(OnDocumentHeaderTemplateChanged), + new CoerceValueCallback(CoerceDocumentHeaderTemplateValue))); + + /// + /// Gets or sets the DocumentHeaderTemplate property. This dependency property + /// indicates data template to use for document header. + /// + public DataTemplate DocumentHeaderTemplate + { + get { return (DataTemplate)GetValue(DocumentHeaderTemplateProperty); } + set { SetValue(DocumentHeaderTemplateProperty, value); } + } + + /// + /// Handles changes to the DocumentHeaderTemplate property. + /// + private static void OnDocumentHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentHeaderTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplate property. + /// + protected virtual void OnDocumentHeaderTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the DocumentHeaderTemplate value. + /// + private static object CoerceDocumentHeaderTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(DocumentHeaderTemplateSelectorProperty) != null) + return null; + return value; + } + + #endregion + + #region DocumentHeaderTemplateSelector + + /// + /// DocumentHeaderTemplateSelector Dependency Property + /// + public static readonly DependencyProperty DocumentHeaderTemplateSelectorProperty = + DependencyProperty.Register("DocumentHeaderTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, + new PropertyChangedCallback(OnDocumentHeaderTemplateSelectorChanged), + new CoerceValueCallback(CoerceDocumentHeaderTemplateSelectorValue))); + + /// + /// Gets or sets the DocumentHeaderTemplateSelector property. This dependency property + /// indicates the template selector that is used when selcting the data template for the header. + /// + public DataTemplateSelector DocumentHeaderTemplateSelector + { + get { return (DataTemplateSelector)GetValue(DocumentHeaderTemplateSelectorProperty); } + set { SetValue(DocumentHeaderTemplateSelectorProperty, value); } + } + + /// + /// Handles changes to the DocumentHeaderTemplateSelector property. + /// + private static void OnDocumentHeaderTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentHeaderTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplateSelector property. + /// + protected virtual void OnDocumentHeaderTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null && + DocumentHeaderTemplate != null) + DocumentHeaderTemplate = null; + + if (DocumentPaneMenuItemHeaderTemplateSelector == null) + DocumentPaneMenuItemHeaderTemplateSelector = DocumentHeaderTemplateSelector; + + } + + /// + /// Coerces the DocumentHeaderTemplateSelector value. + /// + private static object CoerceDocumentHeaderTemplateSelectorValue(DependencyObject d, object value) + { + return value; + } + + #endregion + + #region DocumentTitleTemplate + + /// + /// DocumentTitleTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentTitleTemplateProperty = + DependencyProperty.Register("DocumentTitleTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, + new PropertyChangedCallback(OnDocumentTitleTemplateChanged), + new CoerceValueCallback(CoerceDocumentTitleTemplateValue))); + + /// + /// Gets or sets the DocumentTitleTemplate property. This dependency property + /// indicates the datatemplate to use when creating the title for a document. + /// + public DataTemplate DocumentTitleTemplate + { + get { return (DataTemplate)GetValue(DocumentTitleTemplateProperty); } + set { SetValue(DocumentTitleTemplateProperty, value); } + } + + /// + /// Handles changes to the DocumentTitleTemplate property. + /// + private static void OnDocumentTitleTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentTitleTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplate property. + /// + protected virtual void OnDocumentTitleTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the DocumentTitleTemplate value. + /// + private static object CoerceDocumentTitleTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(DocumentTitleTemplateSelectorProperty) != null) + return null; + + return value; + } + + #endregion + + #region DocumentTitleTemplateSelector + + /// + /// DocumentTitleTemplateSelector Dependency Property + /// + public static readonly DependencyProperty DocumentTitleTemplateSelectorProperty = + DependencyProperty.Register("DocumentTitleTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, + new PropertyChangedCallback(OnDocumentTitleTemplateSelectorChanged), + new CoerceValueCallback(CoerceDocumentTitleTemplateSelectorValue))); + + /// + /// Gets or sets the DocumentTitleTemplateSelector property. This dependency property + /// indicates the data template selector to use when creating the data template for the title. + /// + public DataTemplateSelector DocumentTitleTemplateSelector + { + get { return (DataTemplateSelector)GetValue(DocumentTitleTemplateSelectorProperty); } + set { SetValue(DocumentTitleTemplateSelectorProperty, value); } + } + + /// + /// Handles changes to the DocumentTitleTemplateSelector property. + /// + private static void OnDocumentTitleTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentTitleTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplateSelector property. + /// + protected virtual void OnDocumentTitleTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null) + DocumentTitleTemplate = null; + } + + /// + /// Coerces the DocumentTitleTemplateSelector value. + /// + private static object CoerceDocumentTitleTemplateSelectorValue(DependencyObject d, object value) + { + return value; + } + + #endregion + + #region AnchorableTitleTemplate + + /// + /// AnchorableTitleTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorableTitleTemplateProperty = + DependencyProperty.Register("AnchorableTitleTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, + new PropertyChangedCallback(OnAnchorableTitleTemplateChanged), + new CoerceValueCallback(CoerceAnchorableTitleTemplateValue))); + + /// + /// Gets or sets the AnchorableTitleTemplate property. This dependency property + /// indicates the data template to use for anchorables title. + /// + public DataTemplate AnchorableTitleTemplate + { + get { return (DataTemplate)GetValue(AnchorableTitleTemplateProperty); } + set { SetValue(AnchorableTitleTemplateProperty, value); } + } + + /// + /// Handles changes to the AnchorableTitleTemplate property. + /// + private static void OnAnchorableTitleTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorableTitleTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplate property. + /// + protected virtual void OnAnchorableTitleTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the AnchorableTitleTemplate value. + /// + private static object CoerceAnchorableTitleTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(AnchorableTitleTemplateSelectorProperty) != null) + return null; + return value; + } + + #endregion + + #region AnchorableTitleTemplateSelector + + /// + /// AnchorableTitleTemplateSelector Dependency Property + /// + public static readonly DependencyProperty AnchorableTitleTemplateSelectorProperty = + DependencyProperty.Register("AnchorableTitleTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, + new PropertyChangedCallback(OnAnchorableTitleTemplateSelectorChanged))); + + /// + /// Gets or sets the AnchorableTitleTemplateSelector property. This dependency property + /// indicates selctor to use when selecting data template for the title of anchorables. + /// + public DataTemplateSelector AnchorableTitleTemplateSelector + { + get { return (DataTemplateSelector)GetValue(AnchorableTitleTemplateSelectorProperty); } + set { SetValue(AnchorableTitleTemplateSelectorProperty, value); } + } + + /// + /// Handles changes to the AnchorableTitleTemplateSelector property. + /// + private static void OnAnchorableTitleTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorableTitleTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplateSelector property. + /// + protected virtual void OnAnchorableTitleTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null && + AnchorableTitleTemplate != null) + AnchorableTitleTemplate = null; + } + + #endregion + + #region AnchorableHeaderTemplate + + /// + /// AnchorableHeaderTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorableHeaderTemplateProperty = + DependencyProperty.Register("AnchorableHeaderTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, + new PropertyChangedCallback(OnAnchorableHeaderTemplateChanged), + new CoerceValueCallback(CoerceAnchorableHeaderTemplateValue))); + + /// + /// Gets or sets the AnchorableHeaderTemplate property. This dependency property + /// indicates the data template to use for anchorable templates. + /// + public DataTemplate AnchorableHeaderTemplate + { + get { return (DataTemplate)GetValue(AnchorableHeaderTemplateProperty); } + set { SetValue(AnchorableHeaderTemplateProperty, value); } + } + + /// + /// Handles changes to the AnchorableHeaderTemplate property. + /// + private static void OnAnchorableHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorableHeaderTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplate property. + /// + protected virtual void OnAnchorableHeaderTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the AnchorableHeaderTemplate value. + /// + private static object CoerceAnchorableHeaderTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(AnchorableHeaderTemplateSelectorProperty) != null) + return null; + + return value; + } + + #endregion + + #region AnchorableHeaderTemplateSelector + + /// + /// AnchorableHeaderTemplateSelector Dependency Property + /// + public static readonly DependencyProperty AnchorableHeaderTemplateSelectorProperty = + DependencyProperty.Register("AnchorableHeaderTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, + new PropertyChangedCallback(OnAnchorableHeaderTemplateSelectorChanged))); + + /// + /// Gets or sets the AnchorableHeaderTemplateSelector property. This dependency property + /// indicates the selector to use when selecting the data template for anchorable headers. + /// + public DataTemplateSelector AnchorableHeaderTemplateSelector + { + get { return (DataTemplateSelector)GetValue(AnchorableHeaderTemplateSelectorProperty); } + set { SetValue(AnchorableHeaderTemplateSelectorProperty, value); } + } + + /// + /// Handles changes to the AnchorableHeaderTemplateSelector property. + /// + private static void OnAnchorableHeaderTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorableHeaderTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplateSelector property. + /// + protected virtual void OnAnchorableHeaderTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null) + AnchorableHeaderTemplate = null; + } + + #endregion + + #region LayoutRootPanel + + /// + /// LayoutRootPanel Dependency Property + /// + public static readonly DependencyProperty LayoutRootPanelProperty = + DependencyProperty.Register("LayoutRootPanel", typeof(LayoutPanelControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutPanelControl)null, + new PropertyChangedCallback(OnLayoutRootPanelChanged))); + + /// + /// Gets or sets the LayoutRootPanel property. This dependency property + /// indicates the layout panel control which is attached to the Layout.Root property. + /// + public LayoutPanelControl LayoutRootPanel + { + get { return (LayoutPanelControl)GetValue(LayoutRootPanelProperty); } + set { SetValue(LayoutRootPanelProperty, value); } + } + + /// + /// Handles changes to the LayoutRootPanel property. + /// + private static void OnLayoutRootPanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutRootPanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LayoutRootPanel property. + /// + protected virtual void OnLayoutRootPanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region RightSidePanel + + /// + /// RightSidePanel Dependency Property + /// + public static readonly DependencyProperty RightSidePanelProperty = + DependencyProperty.Register("RightSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, + new PropertyChangedCallback(OnRightSidePanelChanged))); + + /// + /// Gets or sets the RightSidePanel property. This dependency property + /// indicates right side anchor panel. + /// + public LayoutAnchorSideControl RightSidePanel + { + get { return (LayoutAnchorSideControl)GetValue(RightSidePanelProperty); } + set { SetValue(RightSidePanelProperty, value); } + } + + /// + /// Handles changes to the RightSidePanel property. + /// + private static void OnRightSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnRightSidePanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the RightSidePanel property. + /// + protected virtual void OnRightSidePanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region LeftSidePanel + + /// + /// LeftSidePanel Dependency Property + /// + public static readonly DependencyProperty LeftSidePanelProperty = + DependencyProperty.Register("LeftSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, + new PropertyChangedCallback(OnLeftSidePanelChanged))); + + /// + /// Gets or sets the LeftSidePanel property. This dependency property + /// indicates the left side panel control. + /// + public LayoutAnchorSideControl LeftSidePanel + { + get { return (LayoutAnchorSideControl)GetValue(LeftSidePanelProperty); } + set { SetValue(LeftSidePanelProperty, value); } + } + + /// + /// Handles changes to the LeftSidePanel property. + /// + private static void OnLeftSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLeftSidePanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LeftSidePanel property. + /// + protected virtual void OnLeftSidePanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region TopSidePanel + + /// + /// TopSidePanel Dependency Property + /// + public static readonly DependencyProperty TopSidePanelProperty = + DependencyProperty.Register("TopSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, + new PropertyChangedCallback(OnTopSidePanelChanged))); + + /// + /// Gets or sets the TopSidePanel property. This dependency property + /// indicates top side control panel. + /// + public LayoutAnchorSideControl TopSidePanel + { + get { return (LayoutAnchorSideControl)GetValue(TopSidePanelProperty); } + set { SetValue(TopSidePanelProperty, value); } + } + + /// + /// Handles changes to the TopSidePanel property. + /// + private static void OnTopSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnTopSidePanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the TopSidePanel property. + /// + protected virtual void OnTopSidePanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region BottomSidePanel + + /// + /// BottomSidePanel Dependency Property + /// + public static readonly DependencyProperty BottomSidePanelProperty = + DependencyProperty.Register("BottomSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, + new PropertyChangedCallback(OnBottomSidePanelChanged))); + + /// + /// Gets or sets the BottomSidePanel property. This dependency property + /// indicates bottom side panel control. + /// + public LayoutAnchorSideControl BottomSidePanel + { + get { return (LayoutAnchorSideControl)GetValue(BottomSidePanelProperty); } + set { SetValue(BottomSidePanelProperty, value); } + } + + /// + /// Handles changes to the BottomSidePanel property. + /// + private static void OnBottomSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnBottomSidePanelChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the BottomSidePanel property. + /// + protected virtual void OnBottomSidePanelChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + } + + #endregion + + #region LogicalChildren + + List _logicalChildren = new List(); + + protected override System.Collections.IEnumerator LogicalChildren + { + get + { + return _logicalChildren.Select(ch => ch.GetValueOrDefault()).GetEnumerator(); + } + } + + public System.Collections.IEnumerator LogicalChildrenPublic + { + get + { + return this.LogicalChildren; + } + } + + + internal void InternalAddLogicalChild(object element) + { +#if DEBUG + if (_logicalChildren.Select(ch => ch.GetValueOrDefault()).Contains(element)) + new InvalidOperationException(); +#endif + if (_logicalChildren.Select(ch => ch.GetValueOrDefault()).Contains(element)) + return; + + _logicalChildren.Add(new WeakReference(element)); + AddLogicalChild(element); + } + + internal void InternalRemoveLogicalChild(object element) + { + var wrToRemove = _logicalChildren.FirstOrDefault(ch => ch.GetValueOrDefault() == element); + if (wrToRemove != null) + _logicalChildren.Remove(wrToRemove); + RemoveLogicalChild(element); + } + + void ClearLogicalChildrenList() + { + foreach (var child in _logicalChildren.Select(ch => ch.GetValueOrDefault()).ToArray()) + RemoveLogicalChild(child); + _logicalChildren.Clear(); + } + + #endregion + + #region AutoHide window + internal void ShowAutoHideWindow(LayoutAnchorControl anchor) + { + _autoHideWindowManager.ShowAutoHideWindow(anchor); + //if (_autohideArea == null) + // return; + + //if (AutoHideWindow != null && AutoHideWindow.Model == anchor.Model) + // return; + + //Trace.WriteLine("ShowAutoHideWindow()"); + + //_currentAutohiddenAnchor = new WeakReference(anchor); + + //HideAutoHideWindow(anchor); + + //SetAutoHideWindow(new LayoutAutoHideWindowControl(anchor)); + //AutoHideWindow.Show(); + } + + internal void HideAutoHideWindow(LayoutAnchorControl anchor) + { + _autoHideWindowManager.HideAutoWindow(anchor); + } + + + void SetupAutoHideWindow() + { + _autohideArea = GetTemplateChild("PART_AutoHideArea") as FrameworkElement; + + if (_autoHideWindowManager != null) + _autoHideWindowManager.HideAutoWindow(); + else + _autoHideWindowManager = new AutoHideWindowManager(this); + + if (AutoHideWindow != null) + AutoHideWindow.Dispose(); + + SetAutoHideWindow(new LayoutAutoHideWindowControl()); + } + + AutoHideWindowManager _autoHideWindowManager; + + FrameworkElement _autohideArea; + internal FrameworkElement GetAutoHideAreaElement() + { + return _autohideArea; + } + + #region AutoHideWindow + + /// + /// AutoHideWindow Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey AutoHideWindowPropertyKey + = DependencyProperty.RegisterReadOnly("AutoHideWindow", typeof(LayoutAutoHideWindowControl), typeof(DockingManager), + new FrameworkPropertyMetadata((LayoutAutoHideWindowControl)null, + new PropertyChangedCallback(OnAutoHideWindowChanged))); + + public static readonly DependencyProperty AutoHideWindowProperty + = AutoHideWindowPropertyKey.DependencyProperty; + + /// + /// Gets the AutoHideWindow property. This dependency property + /// indicates the currently shown autohide window. + /// + public LayoutAutoHideWindowControl AutoHideWindow + { + get { return (LayoutAutoHideWindowControl)GetValue(AutoHideWindowProperty); } + } + + /// + /// Provides a secure method for setting the AutoHideWindow property. + /// This dependency property indicates the currently shown autohide window. + /// + /// The new value for the property. + protected void SetAutoHideWindow(LayoutAutoHideWindowControl value) + { + SetValue(AutoHideWindowPropertyKey, value); + } + + /// + /// Handles changes to the AutoHideWindow property. + /// + private static void OnAutoHideWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAutoHideWindowChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AutoHideWindow property. + /// + protected virtual void OnAutoHideWindowChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + InternalRemoveLogicalChild(e.OldValue); + if (e.NewValue != null) + InternalAddLogicalChild(e.NewValue); + + } + + #endregion + + + + #endregion + // #region AutoHide window + //WeakReference _currentAutohiddenAnchor = null; + //internal void ShowAutoHideWindow(LayoutAnchorControl anchor) + //{ + // if (_autohideArea == null) + // return; + + // if (AutoHideWindow != null && AutoHideWindow.Model == anchor.Model) + // return; + + // Trace.WriteLine("ShowAutoHideWindow()"); + + // _currentAutohiddenAnchor = new WeakReference(anchor); + + // HideAutoHideWindow(anchor); + + // SetAutoHideWindow(new LayoutAutoHideWindowControl(anchor)); + //} + + //internal void HideAutoHideWindow(LayoutAnchorControl anchor) + //{ + // if (AutoHideWindow != null) + // { + // if (anchor == _currentAutohiddenAnchor.GetValueOrDefault()) + // { + // Trace.WriteLine("AutoHideWindow()"); + // AutoHideWindow.Dispose(); + // SetAutoHideWindow(null); + // } + // } + //} + + //FrameworkElement _autohideArea; + //internal FrameworkElement GetAutoHideAreaElement() + //{ + // return _autohideArea; + //} + + //void SetupAutoHideArea() + //{ + // _autohideArea = GetTemplateChild("PART_AutoHideArea") as FrameworkElement; + //} + + // #region AutoHideWindow + + ///// + ///// AutoHideWindow Read-Only Dependency Property + ///// + //private static readonly DependencyPropertyKey AutoHideWindowPropertyKey + // = DependencyProperty.RegisterReadOnly("AutoHideWindow", typeof(LayoutAutoHideWindowControl), typeof(DockingManager), + // new FrameworkPropertyMetadata((LayoutAutoHideWindowControl)null, + // new PropertyChangedCallback(OnAutoHideWindowChanged))); + + //public static readonly DependencyProperty AutoHideWindowProperty + // = AutoHideWindowPropertyKey.DependencyProperty; + + ///// + ///// Gets the AutoHideWindow property. This dependency property + ///// indicates the currently shown autohide window. + ///// + //public LayoutAutoHideWindowControl AutoHideWindow + //{ + // get { return (LayoutAutoHideWindowControl)GetValue(AutoHideWindowProperty); } + //} + + ///// + ///// Provides a secure method for setting the AutoHideWindow property. + ///// This dependency property indicates the currently shown autohide window. + ///// + ///// The new value for the property. + //protected void SetAutoHideWindow(LayoutAutoHideWindowControl value) + //{ + // SetValue(AutoHideWindowPropertyKey, value); + //} + + ///// + ///// Handles changes to the AutoHideWindow property. + ///// + //private static void OnAutoHideWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + //{ + // ((DockingManager)d).OnAutoHideWindowChanged(e); + //} + + ///// + ///// Provides derived classes an opportunity to handle changes to the AutoHideWindow property. + ///// + //protected virtual void OnAutoHideWindowChanged(DependencyPropertyChangedEventArgs e) + //{ + // if (e.OldValue != null) + // ((ILogicalChildrenContainer)this).InternalRemoveLogicalChild(e.OldValue); + // if (e.NewValue != null) + // ((ILogicalChildrenContainer)this).InternalAddLogicalChild(e.NewValue); + //} + + // #endregion + + + + // #endregion + + #region Floating Windows + List _fwList = new List(); + + internal void StartDraggingFloatingWindowForContent(LayoutContent contentModel, bool startDrag = true) + { + if (!contentModel.CanFloat) + return; + var contentModelAsAnchorable = contentModel as LayoutAnchorable; + if (contentModelAsAnchorable != null && + contentModelAsAnchorable.IsAutoHidden) + contentModelAsAnchorable.ToggleAutoHide(); + + var parentPane = contentModel.Parent as ILayoutPane; + var parentPaneAsPositionableElement = contentModel.Parent as ILayoutPositionableElement; + var parentPaneAsWithActualSize = contentModel.Parent as ILayoutPositionableElementWithActualSize; + var contentModelParentChildrenIndex = parentPane.Children.ToList().IndexOf(contentModel); + + if (contentModel.FindParent() == null) + { + ((ILayoutPreviousContainer)contentModel).PreviousContainer = parentPane; + contentModel.PreviousContainerIndex = contentModelParentChildrenIndex; + } + + parentPane.RemoveChildAt(contentModelParentChildrenIndex); + + double fwWidth = contentModel.FloatingWidth; + double fwHeight = contentModel.FloatingHeight; + + if (fwWidth == 0.0) + fwWidth = parentPaneAsPositionableElement.FloatingWidth; + if (fwHeight == 0.0) + fwHeight = parentPaneAsPositionableElement.FloatingHeight; + + if (fwWidth == 0.0) + fwWidth = parentPaneAsWithActualSize.ActualWidth; + if (fwHeight == 0.0) + fwHeight = parentPaneAsWithActualSize.ActualHeight; + + LayoutFloatingWindow fw; + LayoutFloatingWindowControl fwc; + if (contentModel is LayoutAnchorable) + { + var anchorableContent = contentModel as LayoutAnchorable; + fw = new LayoutAnchorableFloatingWindow() + { + RootPanel = new LayoutAnchorablePaneGroup( + new LayoutAnchorablePane(anchorableContent) + { + DockWidth = parentPaneAsPositionableElement.DockWidth, + DockHeight = parentPaneAsPositionableElement.DockHeight, + DockMinHeight = parentPaneAsPositionableElement.DockMinHeight, + DockMinWidth = parentPaneAsPositionableElement.DockMinWidth, + FloatingLeft = parentPaneAsPositionableElement.FloatingLeft, + FloatingTop = parentPaneAsPositionableElement.FloatingTop, + FloatingWidth = parentPaneAsPositionableElement.FloatingWidth, + FloatingHeight = parentPaneAsPositionableElement.FloatingHeight, + }) + }; + + Layout.FloatingWindows.Add(fw); + + fwc = new LayoutAnchorableFloatingWindowControl( + fw as LayoutAnchorableFloatingWindow) + { + Width = fwWidth, + Height = fwHeight, + Left = contentModel.FloatingLeft, + Top = contentModel.FloatingTop + }; + } + else + { + var anchorableDocument = contentModel as LayoutDocument; + fw = new LayoutDocumentFloatingWindow() + { + RootDocument = anchorableDocument + }; + + Layout.FloatingWindows.Add(fw); + + fwc = new LayoutDocumentFloatingWindowControl( + fw as LayoutDocumentFloatingWindow) + { + Width = fwWidth, + Height = fwHeight, + Left = contentModel.FloatingLeft, + Top = contentModel.FloatingTop + }; + } + + + //fwc.Owner = Window.GetWindow(this); + //fwc.SetParentToMainWindowOf(this); + + + _fwList.Add(fwc); + + Layout.CollectGarbage(); + + UpdateLayout(); + + Dispatcher.BeginInvoke(new Action(() => + { + if (startDrag) + fwc.AttachDrag(); + fwc.Show(); + }), DispatcherPriority.Send); + } + + internal void StartDraggingFloatingWindowForPane(LayoutAnchorablePane paneModel) + { + if (paneModel.Children.Any(c => !c.CanFloat)) + return; + var paneAsPositionableElement = paneModel as ILayoutPositionableElement; + var paneAsWithActualSize = paneModel as ILayoutPositionableElementWithActualSize; + + double fwWidth = paneAsPositionableElement.FloatingWidth; + double fwHeight = paneAsPositionableElement.FloatingHeight; + double fwLeft = paneAsPositionableElement.FloatingLeft; + double fwTop = paneAsPositionableElement.FloatingTop; + + + + if (fwWidth == 0.0) + fwWidth = paneAsWithActualSize.ActualWidth; + if (fwHeight == 0.0) + fwHeight = paneAsWithActualSize.ActualHeight; + + var destPane = new LayoutAnchorablePane() + { + DockWidth = paneAsPositionableElement.DockWidth, + DockHeight = paneAsPositionableElement.DockHeight, + DockMinHeight = paneAsPositionableElement.DockMinHeight, + DockMinWidth = paneAsPositionableElement.DockMinWidth, + FloatingLeft = paneAsPositionableElement.FloatingLeft, + FloatingTop = paneAsPositionableElement.FloatingTop, + FloatingWidth = paneAsPositionableElement.FloatingWidth, + FloatingHeight = paneAsPositionableElement.FloatingHeight, + }; + + bool savePreviousContainer = paneModel.FindParent() == null; + int currentSelectedContentIndex = paneModel.SelectedContentIndex; + while (paneModel.Children.Count > 0) + { + var contentModel = paneModel.Children[paneModel.Children.Count - 1] as LayoutAnchorable; + + if (savePreviousContainer) + { + var contentModelAsPreviousContainer = contentModel as ILayoutPreviousContainer; + contentModelAsPreviousContainer.PreviousContainer = paneModel; + contentModel.PreviousContainerIndex = paneModel.Children.Count - 1; + } + + paneModel.RemoveChildAt(paneModel.Children.Count - 1); + destPane.Children.Insert(0, contentModel); + } + + if (destPane.Children.Count > 0) + { + destPane.SelectedContentIndex = currentSelectedContentIndex; + } + + + LayoutFloatingWindow fw; + LayoutFloatingWindowControl fwc; + fw = new LayoutAnchorableFloatingWindow() + { + RootPanel = new LayoutAnchorablePaneGroup( + destPane) + { + DockHeight = destPane.DockHeight, + DockWidth = destPane.DockWidth, + DockMinHeight = destPane.DockMinHeight, + DockMinWidth = destPane.DockMinWidth, + } + }; + + Layout.FloatingWindows.Add(fw); + + fwc = new LayoutAnchorableFloatingWindowControl( + fw as LayoutAnchorableFloatingWindow) + { + Width = fwWidth, + Height = fwHeight + }; + + + + //fwc.Owner = Window.GetWindow(this); + //fwc.SetParentToMainWindowOf(this); + + + _fwList.Add(fwc); + + Layout.CollectGarbage(); + + InvalidateArrange(); + + fwc.AttachDrag(); + fwc.Show(); + + } + + internal IEnumerable GetFloatingWindowsByZOrder() + { + var parentWindow = Window.GetWindow(this); + + if (parentWindow == null) + yield break; + + IntPtr windowParentHanlde = new WindowInteropHelper(parentWindow).Handle; + + IntPtr currentHandle = Win32Helper.GetWindow(windowParentHanlde, (uint)Win32Helper.GetWindow_Cmd.GW_HWNDFIRST); + while (currentHandle != IntPtr.Zero) + { + LayoutFloatingWindowControl ctrl = _fwList.FirstOrDefault(fw => new WindowInteropHelper(fw).Handle == currentHandle); + if (ctrl != null && ctrl.Model.Root.Manager == this) + yield return ctrl; + + currentHandle = Win32Helper.GetWindow(currentHandle, (uint)Win32Helper.GetWindow_Cmd.GW_HWNDNEXT); + } + } + + internal void RemoveFloatingWindow(LayoutFloatingWindowControl floatingWindow) + { + _fwList.Remove(floatingWindow); + } + + public IEnumerable FloatingWindows + { + get { return _fwList; } + } + #endregion + + #region OverlayWindow + + bool IOverlayWindowHost.HitTest(Point dragPoint) + { + Rect detectionRect = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); + return detectionRect.Contains(dragPoint); + } + + DockingManager IOverlayWindowHost.Manager + { + get { return this; } + } + + OverlayWindow _overlayWindow = null; + void CreateOverlayWindow() + { + if (_overlayWindow == null) + { + _overlayWindow = new OverlayWindow(this); + } + Rect rectWindow = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); + _overlayWindow.Left = rectWindow.Left; + _overlayWindow.Top = rectWindow.Top; + _overlayWindow.Width = rectWindow.Width; + _overlayWindow.Height = rectWindow.Height; + } + + void DestroyOverlayWindow() + { + if (_overlayWindow != null) + { + _overlayWindow.Close(); + _overlayWindow = null; + } + } + + IOverlayWindow IOverlayWindowHost.ShowOverlayWindow(LayoutFloatingWindowControl draggingWindow) + { + CreateOverlayWindow(); + _overlayWindow.Owner = draggingWindow; + _overlayWindow.EnableDropTargets(); + _overlayWindow.Show(); + return _overlayWindow; + } + + void IOverlayWindowHost.HideOverlayWindow() + { + _areas = null; + _overlayWindow.Owner = null; + _overlayWindow.HideDropTargets(); + } + + List _areas = null; + + IEnumerable IOverlayWindowHost.GetDropAreas(LayoutFloatingWindowControl draggingWindow) + { + if (_areas != null) + return _areas; + + bool isDraggingDocuments = draggingWindow.Model is LayoutDocumentFloatingWindow; + + _areas = new List(); + + if (!isDraggingDocuments) + { + _areas.Add(new DropArea( + this, + DropAreaType.DockingManager)); + + foreach (var areaHost in this.FindVisualChildren()) + { + if (areaHost.Model.Descendents().Any()) + { + _areas.Add(new DropArea( + areaHost, + DropAreaType.AnchorablePane)); + } + } + } + + foreach (var areaHost in this.FindVisualChildren()) + { + _areas.Add(new DropArea( + areaHost, + DropAreaType.DocumentPane)); + } + + foreach (var areaHost in this.FindVisualChildren()) + { + var documentGroupModel = areaHost.Model as LayoutDocumentPaneGroup; + if (documentGroupModel.Children.Where(c => c.IsVisible).Count() == 0) + { + _areas.Add(new DropArea( + areaHost, + DropAreaType.DocumentPaneGroup)); + } + } + + return _areas; + } + + protected override Size ArrangeOverride(Size arrangeBounds) + { + _areas = null; + return base.ArrangeOverride(arrangeBounds); + } + + #endregion + + #region LayoutDocument & LayoutAnchorable Templates + + #region LayoutItemTemplate + + /// + /// LayoutItemTemplate Dependency Property + /// + public static readonly DependencyProperty LayoutItemTemplateProperty = + DependencyProperty.Register("LayoutItemTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, + new PropertyChangedCallback(OnLayoutItemTemplateChanged))); + + /// + /// Gets or sets the AnchorableTemplate property. This dependency property + /// indicates the template to use to render anchorable and document contents. + /// + public DataTemplate LayoutItemTemplate + { + get { return (DataTemplate)GetValue(LayoutItemTemplateProperty); } + set { SetValue(LayoutItemTemplateProperty, value); } + } + + /// + /// Handles changes to the AnchorableTemplate property. + /// + private static void OnLayoutItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutItemTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableTemplate property. + /// + protected virtual void OnLayoutItemTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + #region LayoutItemTemplateSelector + + /// + /// LayoutItemTemplateSelector Dependency Property + /// + public static readonly DependencyProperty LayoutItemTemplateSelectorProperty = + DependencyProperty.Register("LayoutItemTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, + new PropertyChangedCallback(OnLayoutItemTemplateSelectorChanged))); + + /// + /// Gets or sets the LayoutItemTemplateSelector property. This dependency property + /// indicates selector object to use for anchorable templates. + /// + public DataTemplateSelector LayoutItemTemplateSelector + { + get { return (DataTemplateSelector)GetValue(LayoutItemTemplateSelectorProperty); } + set { SetValue(LayoutItemTemplateSelectorProperty, value); } + } + + /// + /// Handles changes to the LayoutItemTemplateSelector property. + /// + private static void OnLayoutItemTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutItemTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LayoutItemTemplateSelector property. + /// + protected virtual void OnLayoutItemTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + } + + #endregion + + + #endregion + + #region DocumentsSource + + /// + /// DocumentsSource Dependency Property + /// + public static readonly DependencyProperty DocumentsSourceProperty = + DependencyProperty.Register("DocumentsSource", typeof(IEnumerable), typeof(DockingManager), + new FrameworkPropertyMetadata((IEnumerable)null, + new PropertyChangedCallback(OnDocumentsSourceChanged))); + + /// + /// Gets or sets the DocumentsSource property. This dependency property + /// indicates the source collection of documents. + /// + public IEnumerable DocumentsSource + { + get + { + return (IEnumerable)GetValue(DocumentsSourceProperty); + } + set + { + SetValue(DocumentsSourceProperty, value); + } + } + + /// + /// Handles changes to the DocumentsSource property. + /// + private static void OnDocumentsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentsSourceChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentsSource property. + /// + protected virtual void OnDocumentsSourceChanged(DependencyPropertyChangedEventArgs e) + { + DetachDocumentsSource(Layout, e.OldValue as IEnumerable); + AttachDocumentsSource(Layout, e.NewValue as IEnumerable); + } + + + void AttachDocumentsSource(LayoutRoot layout, IEnumerable documentsSource) + { + if (documentsSource == null) + return; + + if (layout == null) + return; + + //if (layout.Descendents().OfType().Any()) + // throw new InvalidOperationException("Unable to set the DocumentsSource property if LayoutDocument objects are already present in the model"); + var documentsImported = layout.Descendents().OfType().Select(d => d.Content).ToArray(); + var documents = documentsSource as IEnumerable; + var listOfDocumentsToImport = new List(documents.OfType()); + + foreach (var document in listOfDocumentsToImport.ToArray()) + { + if (documentsImported.Contains(document)) + listOfDocumentsToImport.Remove(document); + } + + + LayoutDocumentPane documentPane = null; + if (layout.LastFocusedDocument != null) + { + documentPane = layout.LastFocusedDocument.Parent as LayoutDocumentPane; + } + + if (documentPane == null) + { + documentPane = layout.Descendents().OfType().FirstOrDefault(); + } + + //if (documentPane == null) + // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + + _suspendLayoutItemCreation = true; + foreach (var documentContentToImport in listOfDocumentsToImport) + { + + //documentPane.Children.Add(new LayoutDocument() { Content = documentToImport }); + + var documentToImport = new LayoutDocument() + { + Content = documentContentToImport + }; + + bool added = false; + if (LayoutUpdateStrategy != null) + { + added = LayoutUpdateStrategy.BeforeInsertDocument(layout, documentToImport, documentPane); + } + + if (!added) + { + if (documentPane == null) + throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + + documentPane.Children.Add(documentToImport); + added = true; + } + + if (LayoutUpdateStrategy != null) + LayoutUpdateStrategy.AfterInsertDocument(layout, documentToImport); + + + CreateDocumentLayoutItem(documentToImport); + + } + _suspendLayoutItemCreation = false; + + + var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; + if (documentsSourceAsNotifier != null) + documentsSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler(documentsSourceElementsChanged); + } + + internal bool SuspendDocumentsSourceBinding = false; + + void documentsSourceElementsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (Layout == null) + return; + + //When deserializing documents are created automatically by the deserializer + if (SuspendDocumentsSourceBinding) + return; + + //handle remove + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.OldItems != null) + { + var documentsToRemove = Layout.Descendents().OfType().Where(d => e.OldItems.Contains(d.Content)).ToArray(); + foreach (var documentToRemove in documentsToRemove) + { + (documentToRemove.Parent as ILayoutContainer).RemoveChild( + documentToRemove); + this.RemoveViewFromLogicalChild( documentToRemove ); + } + } + } + + //handle add + if (e.NewItems != null && + (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) + { + if (e.NewItems != null) + { + LayoutDocumentPane documentPane = null; + if (Layout.LastFocusedDocument != null) + { + documentPane = Layout.LastFocusedDocument.Parent as LayoutDocumentPane; + } + + if (documentPane == null) + { + documentPane = Layout.Descendents().OfType().FirstOrDefault(); + } + + //if (documentPane == null) + // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + + _suspendLayoutItemCreation = true; + + foreach (var documentContentToImport in e.NewItems) + { + var documentToImport = new LayoutDocument() + { + Content = documentContentToImport + }; + + bool added = false; + if (LayoutUpdateStrategy != null) + { + added = LayoutUpdateStrategy.BeforeInsertDocument(Layout, documentToImport, documentPane); + } + + if (!added) + { + if (documentPane == null) + throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + + documentPane.Children.Add(documentToImport); + added = true; + } + + if (LayoutUpdateStrategy != null) + { + LayoutUpdateStrategy.AfterInsertDocument(Layout, documentToImport); + } + + + var root = documentToImport.Root; + + if (root != null && root.Manager == this) + { + CreateDocumentLayoutItem(documentToImport); + } + } + _suspendLayoutItemCreation = false; + } + } + + if (e.Action == NotifyCollectionChangedAction.Reset) + { + //NOTE: I'm going to clear every document present in layout but + //some documents may have been added directly to the layout, for now I clear them too + var documentsToRemove = Layout.Descendents().OfType().ToArray(); + foreach (var documentToRemove in documentsToRemove) + { + (documentToRemove.Parent as ILayoutContainer).RemoveChild( + documentToRemove); + this.RemoveViewFromLogicalChild( documentToRemove ); + } + } + + if (Layout != null) + { + Layout.CollectGarbage(); + } + } + + void DetachDocumentsSource(LayoutRoot layout, IEnumerable documentsSource) + { + if (documentsSource == null) + return; + + if (layout == null) + return; + + var documentsToRemove = layout.Descendents().OfType() + .Where(d => documentsSource.Contains(d.Content)).ToArray(); + + foreach (var documentToRemove in documentsToRemove) + { + (documentToRemove.Parent as ILayoutContainer).RemoveChild( + documentToRemove); + this.RemoveViewFromLogicalChild( documentToRemove ); + } + + var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; + if (documentsSourceAsNotifier != null) + documentsSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler(documentsSourceElementsChanged); + } + + + #endregion + + #region DocumentCloseCommand + + internal void _ExecuteCloseCommand(LayoutDocument document) + { + if (DocumentClosing != null) + { + var evargs = new DocumentClosingEventArgs(document); + DocumentClosing(this, evargs); + if (evargs.Cancel) + return; + } + + if( document.CloseDocument() ) + { + this.RemoveViewFromLogicalChild( document ); + + if( DocumentClosed != null ) + { + var evargs = new DocumentClosedEventArgs( document ); + DocumentClosed( this, evargs ); + } + } + } + + /// + /// Event fired when a document is about to be closed + /// + /// Subscribers have the opportuniy to cancel the operation. + public event EventHandler DocumentClosing; + + /// + /// Event fired after a document is closed + /// + public event EventHandler DocumentClosed; + + + + #endregion + + internal void _ExecuteCloseAllButThisCommand(LayoutContent contentSelected) + { + foreach (var contentToClose in Layout.Descendents().OfType().Where(d => d != contentSelected && (d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow)).ToArray()) + { + this.Close( contentToClose ); + } + } + + internal void _ExecuteCloseAllCommand( LayoutContent contentSelected ) + { + foreach( var contentToClose in Layout.Descendents().OfType().Where( d => ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).ToArray() ) + { + this.Close( contentToClose ); + } + } + + private void Close( LayoutContent contentToClose ) + { + if( !contentToClose.CanClose ) + return; + + var layoutItem = GetLayoutItemFromModel( contentToClose ); + if( layoutItem.CloseCommand != null ) + { + if( layoutItem.CloseCommand.CanExecute( null ) ) + layoutItem.CloseCommand.Execute( null ); + } + else + { + if( contentToClose is LayoutDocument ) + _ExecuteCloseCommand( contentToClose as LayoutDocument ); + else if( contentToClose is LayoutAnchorable ) + _ExecuteCloseCommand( contentToClose as LayoutAnchorable ); + } + } + + #region DocumentContextMenu + + /// + /// DocumentContextMenu Dependency Property + /// + public static readonly DependencyProperty DocumentContextMenuProperty = + DependencyProperty.Register("DocumentContextMenu", typeof(ContextMenu), typeof(DockingManager), + new FrameworkPropertyMetadata((ContextMenu)null)); + + /// + /// Gets or sets the DocumentContextMenu property. This dependency property + /// indicates context menu to show for documents. + /// + public ContextMenu DocumentContextMenu + { + get { return (ContextMenu)GetValue(DocumentContextMenuProperty); } + set { SetValue(DocumentContextMenuProperty, value); } + } + + #endregion + + #region AnchorablesSource + + /// + /// AnchorablesSource Dependency Property + /// + public static readonly DependencyProperty AnchorablesSourceProperty = + DependencyProperty.Register("AnchorablesSource", typeof(IEnumerable), typeof(DockingManager), + new FrameworkPropertyMetadata((IEnumerable)null, + new PropertyChangedCallback(OnAnchorablesSourceChanged))); + + /// + /// Gets or sets the AnchorablesSource property. This dependency property + /// indicates source collection of anchorables. + /// + public IEnumerable AnchorablesSource + { + get + { + return (IEnumerable)GetValue(AnchorablesSourceProperty); + } + set + { + SetValue(AnchorablesSourceProperty, value); + } + } + + /// + /// Handles changes to the AnchorablesSource property. + /// + private static void OnAnchorablesSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnAnchorablesSourceChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the AnchorablesSource property. + /// + protected virtual void OnAnchorablesSourceChanged(DependencyPropertyChangedEventArgs e) + { + DetachAnchorablesSource(Layout, e.OldValue as IEnumerable); + AttachAnchorablesSource(Layout, e.NewValue as IEnumerable); + } + + void AttachAnchorablesSource(LayoutRoot layout, IEnumerable anchorablesSource) + { + if (anchorablesSource == null) + return; + + if (layout == null) + return; + + //if (layout.Descendents().OfType().Any()) + // throw new InvalidOperationException("Unable to set the AnchorablesSource property if LayoutAnchorable objects are already present in the model"); + var anchorablesImported = layout.Descendents().OfType().Select(d => d.Content).ToArray(); + var anchorables = anchorablesSource as IEnumerable; + var listOfAnchorablesToImport = new List(anchorables.OfType()); + + foreach (var document in listOfAnchorablesToImport.ToArray()) + { + if (anchorablesImported.Contains(document)) + listOfAnchorablesToImport.Remove(document); + } + + LayoutAnchorablePane anchorablePane = null; + if (layout.ActiveContent != null) + { + //look for active content parent pane + anchorablePane = layout.ActiveContent.Parent as LayoutAnchorablePane; + } + + if (anchorablePane == null) + { + //look for a pane on the right side + anchorablePane = layout.Descendents().OfType().Where(pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right).FirstOrDefault(); + } + + if (anchorablePane == null) + { + //look for an available pane + anchorablePane = layout.Descendents().OfType().FirstOrDefault(); + } + + _suspendLayoutItemCreation = true; + foreach (var anchorableContentToImport in listOfAnchorablesToImport) + { + var anchorableToImport = new LayoutAnchorable() + { + Content = anchorableContentToImport + }; + + bool added = false; + if (LayoutUpdateStrategy != null) + { + added = LayoutUpdateStrategy.BeforeInsertAnchorable(layout, anchorableToImport, anchorablePane); + } + + if (!added) + { + if (anchorablePane == null) + { + var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + if (layout.RootPanel != null) + { + mainLayoutPanel.Children.Add(layout.RootPanel); + } + + layout.RootPanel = mainLayoutPanel; + anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength(200.0, GridUnitType.Pixel) }; + mainLayoutPanel.Children.Add(anchorablePane); + } + + anchorablePane.Children.Add(anchorableToImport); + added = true; + } + + if (LayoutUpdateStrategy != null) + LayoutUpdateStrategy.AfterInsertAnchorable(layout, anchorableToImport); + + + CreateAnchorableLayoutItem(anchorableToImport); + + } + + _suspendLayoutItemCreation = false; + + var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; + if (anchorablesSourceAsNotifier != null) + anchorablesSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler(anchorablesSourceElementsChanged); + } + + internal bool SuspendAnchorablesSourceBinding = false; + + void anchorablesSourceElementsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (Layout == null) + return; + + //When deserializing documents are created automatically by the deserializer + if (SuspendAnchorablesSourceBinding) + return; + + //handle remove + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.OldItems != null) + { + var anchorablesToRemove = Layout.Descendents().OfType().Where(d => e.OldItems.Contains(d.Content)).ToArray(); + foreach (var anchorableToRemove in anchorablesToRemove) + { + anchorableToRemove.Content = null; + (anchorableToRemove.Parent as ILayoutContainer).RemoveChild( + anchorableToRemove); + this.RemoveViewFromLogicalChild( anchorableToRemove ); + } + } + } + + //handle add + if (e.NewItems != null && + (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) + { + if (e.NewItems != null) + { + LayoutAnchorablePane anchorablePane = null; + + if (Layout.ActiveContent != null) + { + //look for active content parent pane + anchorablePane = Layout.ActiveContent.Parent as LayoutAnchorablePane; + } + + if (anchorablePane == null) + { + //look for a pane on the right side + anchorablePane = Layout.Descendents().OfType().Where(pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right).FirstOrDefault(); + } + + if (anchorablePane == null) + { + //look for an available pane + anchorablePane = Layout.Descendents().OfType().FirstOrDefault(); + } + + _suspendLayoutItemCreation = true; + foreach (var anchorableContentToImport in e.NewItems) + { + var anchorableToImport = new LayoutAnchorable() + { + Content = anchorableContentToImport + }; + + bool added = false; + if (LayoutUpdateStrategy != null) + { + added = LayoutUpdateStrategy.BeforeInsertAnchorable(Layout, anchorableToImport, anchorablePane); + } + + if (!added) + { + if (anchorablePane == null) + { + var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + if (Layout.RootPanel != null) + { + mainLayoutPanel.Children.Add(Layout.RootPanel); + } + + Layout.RootPanel = mainLayoutPanel; + anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength(200.0, GridUnitType.Pixel) }; + mainLayoutPanel.Children.Add(anchorablePane); + } + + anchorablePane.Children.Add(anchorableToImport); + added = true; + } + + if (LayoutUpdateStrategy != null) + { + LayoutUpdateStrategy.AfterInsertAnchorable(Layout, anchorableToImport); + } + + var root = anchorableToImport.Root; + + if (root != null && root.Manager == this) + { + CreateAnchorableLayoutItem(anchorableToImport); + } + + } + _suspendLayoutItemCreation = false; + } + } + + if (e.Action == NotifyCollectionChangedAction.Reset) + { + //NOTE: I'm going to clear every anchorable present in layout but + //some anchorable may have been added directly to the layout, for now I clear them too + var anchorablesToRemove = Layout.Descendents().OfType().ToArray(); + foreach (var anchorableToRemove in anchorablesToRemove) + { + (anchorableToRemove.Parent as ILayoutContainer).RemoveChild( + anchorableToRemove); + this.RemoveViewFromLogicalChild( anchorableToRemove ); + } + } + + if (Layout != null) + Layout.CollectGarbage(); + } + + void DetachAnchorablesSource(LayoutRoot layout, IEnumerable anchorablesSource) + { + if (anchorablesSource == null) + return; + + if (layout == null) + return; + + var anchorablesToRemove = layout.Descendents().OfType() + .Where(d => anchorablesSource.Contains(d.Content)).ToArray(); + + foreach (var anchorableToRemove in anchorablesToRemove) + { + (anchorableToRemove.Parent as ILayoutContainer).RemoveChild( + anchorableToRemove); + this.RemoveViewFromLogicalChild( anchorableToRemove ); + } + + var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; + if (anchorablesSourceAsNotifier != null) + anchorablesSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler(anchorablesSourceElementsChanged); + } + + #endregion + + internal void _ExecuteCloseCommand(LayoutAnchorable anchorable) + { + var model = anchorable as LayoutAnchorable; + if (model != null ) + { + model.CloseAnchorable(); + this.RemoveViewFromLogicalChild( anchorable ); + } + } + + internal void _ExecuteHideCommand(LayoutAnchorable anchorable) + { + var model = anchorable as LayoutAnchorable; + if (model != null) + { + //by default hide the anchorable + model.Hide(); + } + } + + internal void _ExecuteAutoHideCommand(LayoutAnchorable _anchorable) + { + _anchorable.ToggleAutoHide(); + } + + internal void _ExecuteFloatCommand(LayoutContent contentToFloat) + { + contentToFloat.Float(); + } + + internal void _ExecuteDockCommand(LayoutAnchorable anchorable) + { + anchorable.Dock(); + } + + internal void _ExecuteDockAsDocumentCommand(LayoutContent content) + { + content.DockAsDocument(); + } + + private void RemoveViewFromLogicalChild( LayoutContent layoutContent ) + { + if( layoutContent == null ) + return; + + var layoutItem = this.GetLayoutItemFromModel( layoutContent ); + if( layoutItem != null ) + { + if( layoutItem.IsViewExists() ) + { + this.InternalRemoveLogicalChild( layoutItem.View ); + } + } + } + + #region ActiveContent + + /// + /// ActiveContent Dependency Property + /// + public static readonly DependencyProperty ActiveContentProperty = + DependencyProperty.Register("ActiveContent", typeof(object), typeof(DockingManager), + new FrameworkPropertyMetadata((object)null, + new PropertyChangedCallback(OnActiveContentChanged))); + + /// + /// Gets or sets the ActiveContent property. This dependency property + /// indicates the content currently active. + /// + public object ActiveContent + { + get { return (object)GetValue(ActiveContentProperty); } + set { SetValue(ActiveContentProperty, value); } + } + + /// + /// Handles changes to the ActiveContent property. + /// + private static void OnActiveContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).InternalSetActiveContent(e.NewValue); + ((DockingManager)d).OnActiveContentChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the ActiveContent property. + /// + protected virtual void OnActiveContentChanged(DependencyPropertyChangedEventArgs e) + { + if (ActiveContentChanged != null) + ActiveContentChanged(this, EventArgs.Empty); + } + + + bool _insideInternalSetActiveContent = false; + void InternalSetActiveContent(object contentObject) + { + var layoutContent = Layout.Descendents().OfType().FirstOrDefault(lc => lc == contentObject || lc.Content == contentObject); + _insideInternalSetActiveContent = true; + Layout.ActiveContent = layoutContent; + _insideInternalSetActiveContent = false; + } + + public event EventHandler ActiveContentChanged; + + #endregion + + #region AnchorableContextMenu + + /// + /// AnchorableContextMenu Dependency Property + /// + public static readonly DependencyProperty AnchorableContextMenuProperty = + DependencyProperty.Register("AnchorableContextMenu", typeof(ContextMenu), typeof(DockingManager), + new FrameworkPropertyMetadata((ContextMenu)null)); + + /// + /// Gets or sets the AnchorableContextMenu property. This dependency property + /// indicates the context menu to show up for anchorables. + /// + public ContextMenu AnchorableContextMenu + { + get { return (ContextMenu)GetValue(AnchorableContextMenuProperty); } + set { SetValue(AnchorableContextMenuProperty, value); } + } + + #endregion + + #region Theme + + /// + /// Theme Dependency Property + /// + public static readonly DependencyProperty ThemeProperty = + DependencyProperty.Register("Theme", typeof(Theme), typeof(DockingManager), + new FrameworkPropertyMetadata(null, + new PropertyChangedCallback(OnThemeChanged))); + + /// + /// Gets or sets the Theme property. This dependency property + /// indicates the theme to use for AvalonDock controls. + /// + public Theme Theme + { + get { return (Theme)GetValue(ThemeProperty); } + set { SetValue(ThemeProperty, value); } + } + + /// + /// Handles changes to the Theme property. + /// + private static void OnThemeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnThemeChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the Theme property. + /// + protected virtual void OnThemeChanged(DependencyPropertyChangedEventArgs e) + { + var oldTheme = e.OldValue as Theme; + var newTheme = e.NewValue as Theme; + var resources = this.Resources; + if (oldTheme != null) + { + if( oldTheme is DictionaryTheme ) + { + if( currentThemeResourceDictionary != null ) + { + resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); + currentThemeResourceDictionary = null; + } + } + else + { + var resourceDictionaryToRemove = + resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); + if( resourceDictionaryToRemove != null ) + resources.MergedDictionaries.Remove( + resourceDictionaryToRemove ); + } + } + + if (newTheme != null) + { + if( newTheme is DictionaryTheme ) + { + currentThemeResourceDictionary = ( ( DictionaryTheme )newTheme ).ThemeResourceDictionary; + resources.MergedDictionaries.Add( currentThemeResourceDictionary ); + } + else + { + resources.MergedDictionaries.Add(new ResourceDictionary() { Source = newTheme.GetResourceUri() }); + } + } + + foreach (var fwc in _fwList) + fwc.UpdateThemeResources(oldTheme); + + if (_navigatorWindow != null) + _navigatorWindow.UpdateThemeResources(); + + if (_overlayWindow != null) + _overlayWindow.UpdateThemeResources(); + } + + #endregion + + #region GridSplitterWidth + + /// + /// GridSplitterWidth Dependency Property + /// + public static readonly DependencyProperty GridSplitterWidthProperty = + DependencyProperty.Register("GridSplitterWidth", typeof(double), typeof(DockingManager), + new FrameworkPropertyMetadata((double)6.0)); + + /// + /// Gets or sets the GridSplitterWidth property. This dependency property + /// indicates width of grid splitters. + /// + public double GridSplitterWidth + { + get { return (double)GetValue(GridSplitterWidthProperty); } + set { SetValue(GridSplitterWidthProperty, value); } + } + + #endregion + + #region GridSplitterHeight + + /// + /// GridSplitterHeight Dependency Property + /// + public static readonly DependencyProperty GridSplitterHeightProperty = + DependencyProperty.Register("GridSplitterHeight", typeof(double), typeof(DockingManager), + new FrameworkPropertyMetadata((double)6.0)); + + /// + /// Gets or sets the GridSplitterHeight property. This dependency property + /// indicates height of grid splitters. + /// + public double GridSplitterHeight + { + get { return (double)GetValue(GridSplitterHeightProperty); } + set { SetValue(GridSplitterHeightProperty, value); } + } + + #endregion + + internal void _ExecuteContentActivateCommand(LayoutContent content) + { + content.IsActive = true; + } + + #region DocumentPaneMenuItemHeaderTemplate + + /// + /// DocumentPaneMenuItemHeaderTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateProperty = + DependencyProperty.Register("DocumentPaneMenuItemHeaderTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null, + new PropertyChangedCallback(OnDocumentPaneMenuItemHeaderTemplateChanged), + new CoerceValueCallback(CoerceDocumentPaneMenuItemHeaderTemplateValue))); + + /// + /// Gets or sets the DocumentPaneMenuItemHeaderTemplate property. This dependency property + /// indicates the header template to use while creating menu items for the document panes. + /// + public DataTemplate DocumentPaneMenuItemHeaderTemplate + { + get { return (DataTemplate)GetValue(DocumentPaneMenuItemHeaderTemplateProperty); } + set { SetValue(DocumentPaneMenuItemHeaderTemplateProperty, value); } + } + + /// + /// Handles changes to the DocumentPaneMenuItemHeaderTemplate property. + /// + private static void OnDocumentPaneMenuItemHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentPaneMenuItemHeaderTemplateChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplate property. + /// + protected virtual void OnDocumentPaneMenuItemHeaderTemplateChanged(DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces the DocumentPaneMenuItemHeaderTemplate value. + /// + private static object CoerceDocumentPaneMenuItemHeaderTemplateValue(DependencyObject d, object value) + { + if (value != null && + d.GetValue(DocumentPaneMenuItemHeaderTemplateSelectorProperty) != null) + return null; + if (value == null) + return d.GetValue(DocumentHeaderTemplateProperty); + + return value; + } + + #endregion + + #region DocumentPaneMenuItemHeaderTemplateSelector + + /// + /// DocumentPaneMenuItemHeaderTemplateSelector Dependency Property + /// + public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateSelectorProperty = + DependencyProperty.Register("DocumentPaneMenuItemHeaderTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null, + new PropertyChangedCallback(OnDocumentPaneMenuItemHeaderTemplateSelectorChanged), + new CoerceValueCallback(CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue))); + + /// + /// Gets or sets the DocumentPaneMenuItemHeaderTemplateSelector property. This dependency property + /// indicates the data template selector to use for the menu items show when user select the DocumentPane document switch context menu. + /// + public DataTemplateSelector DocumentPaneMenuItemHeaderTemplateSelector + { + get { return (DataTemplateSelector)GetValue(DocumentPaneMenuItemHeaderTemplateSelectorProperty); } + set { SetValue(DocumentPaneMenuItemHeaderTemplateSelectorProperty, value); } + } + + /// + /// Handles changes to the DocumentPaneMenuItemHeaderTemplateSelector property. + /// + private static void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnDocumentPaneMenuItemHeaderTemplateSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplateSelector property. + /// + protected virtual void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue != null && + DocumentPaneMenuItemHeaderTemplate != null) + DocumentPaneMenuItemHeaderTemplate = null; + + } + + /// + /// Coerces the DocumentPaneMenuItemHeaderTemplateSelector value. + /// + private static object CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue(DependencyObject d, object value) + { + return value; + } + + #endregion + + #region IconContentTemplate + + /// + /// IconContentTemplate Dependency Property + /// + public static readonly DependencyProperty IconContentTemplateProperty = + DependencyProperty.Register("IconContentTemplate", typeof(DataTemplate), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplate)null)); + + /// + /// Gets or sets the IconContentTemplate property. This dependency property + /// indicates the data template to use while extracting the icon from model. + /// + public DataTemplate IconContentTemplate + { + get { return (DataTemplate)GetValue(IconContentTemplateProperty); } + set { SetValue(IconContentTemplateProperty, value); } + } + + #endregion + + #region IconContentTemplateSelector + + /// + /// IconContentTemplateSelector Dependency Property + /// + public static readonly DependencyProperty IconContentTemplateSelectorProperty = + DependencyProperty.Register("IconContentTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((DataTemplateSelector)null)); + + /// + /// Gets or sets the IconContentTemplateSelector property. This dependency property + /// indicates data template selector to use while selecting the datatamplate for content icons. + /// + public DataTemplateSelector IconContentTemplateSelector + { + get { return (DataTemplateSelector)GetValue(IconContentTemplateSelectorProperty); } + set { SetValue(IconContentTemplateSelectorProperty, value); } + } + + #endregion + + #region LayoutItems + + List _layoutItems = new List(); + + bool _suspendLayoutItemCreation = false; + + void DetachLayoutItems() + { + if (Layout != null) + { + _layoutItems.ForEach(i => i.Detach()); + _layoutItems.Clear(); + Layout.ElementAdded -= new EventHandler(Layout_ElementAdded); + Layout.ElementRemoved -= new EventHandler(Layout_ElementRemoved); + } + } + + void Layout_ElementRemoved(object sender, LayoutElementEventArgs e) + { + if (_suspendLayoutItemCreation) + return; + + CollectLayoutItemsDeleted(); + } + + void Layout_ElementAdded(object sender, LayoutElementEventArgs e) + { + if (_suspendLayoutItemCreation) + return; + + foreach (var content in Layout.Descendents().OfType()) + { + if (content is LayoutDocument) + CreateDocumentLayoutItem(content as LayoutDocument); + else //if (content is LayoutAnchorable) + CreateAnchorableLayoutItem(content as LayoutAnchorable); + } + + CollectLayoutItemsDeleted(); + } + + + DispatcherOperation _collectLayoutItemsOperations = null; + void CollectLayoutItemsDeleted() + { + if (_collectLayoutItemsOperations != null) + return; + _collectLayoutItemsOperations = Dispatcher.BeginInvoke(new Action(() => + { + _collectLayoutItemsOperations = null; + foreach (var itemToRemove in _layoutItems.Where(item => item.LayoutElement.Root != Layout).ToArray()) + { + + if (itemToRemove != null && + itemToRemove.Model != null && + itemToRemove.Model is UIElement) + { + //((ILogicalChildrenContainer)this).InternalRemoveLogicalChild(itemToRemove.Model as UIElement); + } + + itemToRemove.Detach(); + _layoutItems.Remove(itemToRemove); + + } + })); + } + + + void AttachLayoutItems() + { + if (Layout != null) + { + foreach (var document in Layout.Descendents().OfType().ToArray()) + { + CreateDocumentLayoutItem(document); + //var documentItem = new LayoutDocumentItem(); + //documentItem.Attach(document); + //ApplyStyleToLayoutItem(documentItem); + //_layoutItems.Add(documentItem); + } + foreach (var anchorable in Layout.Descendents().OfType().ToArray()) + { + CreateAnchorableLayoutItem(anchorable); + //var anchorableItem = new LayoutAnchorableItem(); + //anchorableItem.Attach(anchorable); + //ApplyStyleToLayoutItem(anchorableItem); + //_layoutItems.Add(anchorableItem); + } + + Layout.ElementAdded += new EventHandler(Layout_ElementAdded); + Layout.ElementRemoved += new EventHandler(Layout_ElementRemoved); + } + } + + void ApplyStyleToLayoutItem(LayoutItem layoutItem) + { + layoutItem._ClearDefaultBindings(); + if (LayoutItemContainerStyle != null) + layoutItem.Style = LayoutItemContainerStyle; + else if (LayoutItemContainerStyleSelector != null) + layoutItem.Style = LayoutItemContainerStyleSelector.SelectStyle(layoutItem.Model, layoutItem); + layoutItem._SetDefaultBindings(); + } + + void CreateAnchorableLayoutItem(LayoutAnchorable contentToAttach) + { + if (_layoutItems.Any(item => item.LayoutElement == contentToAttach)) + return; + + var layoutItem = new LayoutAnchorableItem(); + layoutItem.Attach(contentToAttach); + ApplyStyleToLayoutItem(layoutItem); + _layoutItems.Add(layoutItem); + + if (contentToAttach != null && + contentToAttach.Content != null && + contentToAttach.Content is UIElement) + { + InternalAddLogicalChild(contentToAttach.Content); + } + + } + + void CreateDocumentLayoutItem(LayoutDocument contentToAttach) + { + if (_layoutItems.Any(item => item.LayoutElement == contentToAttach)) + return; + + var layoutItem = new LayoutDocumentItem(); + layoutItem.Attach(contentToAttach); + ApplyStyleToLayoutItem(layoutItem); + _layoutItems.Add(layoutItem); + + if (contentToAttach != null && + contentToAttach.Content != null && + contentToAttach.Content is UIElement) + { + InternalAddLogicalChild(contentToAttach.Content); + } + + } + + #region LayoutItemContainerStyle + + /// + /// LayoutItemContainerStyle Dependency Property + /// + public static readonly DependencyProperty LayoutItemContainerStyleProperty = + DependencyProperty.Register("LayoutItemContainerStyle", typeof(Style), typeof(DockingManager), + new FrameworkPropertyMetadata((Style)null, + new PropertyChangedCallback(OnLayoutItemContainerStyleChanged))); + + /// + /// Gets or sets the LayoutItemContainerStyle property. This dependency property + /// indicates the style to apply to LayoutDocumentItem objects. A LayoutDocumentItem object is created when a new LayoutDocument is created inside the current Layout. + /// + public Style LayoutItemContainerStyle + { + get { return (Style)GetValue(LayoutItemContainerStyleProperty); } + set { SetValue(LayoutItemContainerStyleProperty, value); } + } + + /// + /// Handles changes to the LayoutItemContainerStyle property. + /// + private static void OnLayoutItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutItemContainerStyleChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyle property. + /// + protected virtual void OnLayoutItemContainerStyleChanged(DependencyPropertyChangedEventArgs e) + { + AttachLayoutItems(); + } + + #endregion + + #region LayoutItemContainerStyleSelector + + /// + /// LayoutItemContainerStyleSelector Dependency Property + /// + public static readonly DependencyProperty LayoutItemContainerStyleSelectorProperty = + DependencyProperty.Register("LayoutItemContainerStyleSelector", typeof(StyleSelector), typeof(DockingManager), + new FrameworkPropertyMetadata((StyleSelector)null, + new PropertyChangedCallback(OnLayoutItemContainerStyleSelectorChanged))); + + /// + /// Gets or sets the LayoutItemContainerStyleSelector property. This dependency property + /// indicates style selector of the LayoutDocumentItemStyle. + /// + public StyleSelector LayoutItemContainerStyleSelector + { + get { return (StyleSelector)GetValue(LayoutItemContainerStyleSelectorProperty); } + set { SetValue(LayoutItemContainerStyleSelectorProperty, value); } + } + + /// + /// Handles changes to the LayoutItemContainerStyleSelector property. + /// + private static void OnLayoutItemContainerStyleSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((DockingManager)d).OnLayoutItemContainerStyleSelectorChanged(e); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyleSelector property. + /// + protected virtual void OnLayoutItemContainerStyleSelectorChanged(DependencyPropertyChangedEventArgs e) + { + AttachLayoutItems(); + } + + #endregion + + /// + /// Return the LayoutItem wrapper for the content passed as argument + /// + /// LayoutContent to search + /// Either a LayoutAnchorableItem or LayoutDocumentItem which contains the LayoutContent passed as argument + public LayoutItem GetLayoutItemFromModel(LayoutContent content) + { + return _layoutItems.FirstOrDefault(item => item.LayoutElement == content); + } + #endregion + + #region NavigatorWindow + NavigatorWindow _navigatorWindow = null; + + void ShowNavigatorWindow() + { + if (_navigatorWindow == null) + { + _navigatorWindow = new NavigatorWindow(this) + { + Owner = Window.GetWindow(this), + WindowStartupLocation = WindowStartupLocation.CenterOwner + }; + } + + _navigatorWindow.ShowDialog(); + _navigatorWindow = null; + } + + bool IsNavigatorWindowActive + { + get { return _navigatorWindow != null; } + } + + + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + { + if (e.IsDown && e.Key == Key.Tab) + { + if (!IsNavigatorWindowActive) + { + ShowNavigatorWindow(); + e.Handled = true; + } + } + } + + base.OnPreviewKeyDown(e); + } + + #endregion + + #region ShowSystemMenu + + /// + /// ShowSystemMenu Dependency Property + /// + public static readonly DependencyProperty ShowSystemMenuProperty = + DependencyProperty.Register("ShowSystemMenu", typeof(bool), typeof(DockingManager), + new FrameworkPropertyMetadata((bool)true)); + + /// + /// Gets or sets the ShowSystemMenu property. This dependency property + /// indicates if floating windows should show the system menu when a custom context menu is not defined. + /// + public bool ShowSystemMenu + { + get { return (bool)GetValue(ShowSystemMenuProperty); } + set { SetValue(ShowSystemMenuProperty, value); } + } + + #endregion + + #region AllowMixedOrientation + + /// + /// AllowMixedOrientation Dependency Property + /// + public static readonly DependencyProperty AllowMixedOrientationProperty = + DependencyProperty.Register("AllowMixedOrientation", typeof(bool), typeof(DockingManager), + new FrameworkPropertyMetadata((bool)false)); + + /// + /// Gets or sets the AllowMixedOrientation property. This dependency property + /// indicates if the manager should allow mixed orientation for document panes. + /// + public bool AllowMixedOrientation + { + get { return (bool)GetValue(AllowMixedOrientationProperty); } + set { SetValue(AllowMixedOrientationProperty, value); } + } + + #endregion + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/DocumentClosedEventArgs.cs b/Src/Xceed.Wpf.AvalonDock/DocumentClosedEventArgs.cs new file mode 100644 index 0000000..a4deef0 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/DocumentClosedEventArgs.cs @@ -0,0 +1,38 @@ +/************************************************************************************* + + 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 Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock +{ + public class DocumentClosedEventArgs : EventArgs + { + public DocumentClosedEventArgs(LayoutDocument document) + { + Document = document; + } + + public LayoutDocument Document + { + get; + private set; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/DocumentClosingEventArgs.cs b/Src/Xceed.Wpf.AvalonDock/DocumentClosingEventArgs.cs new file mode 100644 index 0000000..eff48fa --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/DocumentClosingEventArgs.cs @@ -0,0 +1,39 @@ +/************************************************************************************* + + 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.ComponentModel; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock +{ + public class DocumentClosingEventArgs : CancelEventArgs + { + public DocumentClosingEventArgs(LayoutDocument document) + { + Document = document; + } + + public LayoutDocument Document + { + get; + private set; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Extentions.cs b/Src/Xceed.Wpf.AvalonDock/Extentions.cs new file mode 100644 index 0000000..4ca534f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Extentions.cs @@ -0,0 +1,60 @@ +/************************************************************************************* + + 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.Collections; + +namespace Xceed.Wpf.AvalonDock +{ + internal static class Extensions + { + public static bool Contains(this IEnumerable collection, object item) + { + foreach (var o in collection) + if (o == item) + return true; + + return false; + } + + + public static void ForEach(this IEnumerable collection, Action action) + { + foreach (T v in collection) + action(v); + } + + + public static int IndexOf(this T[] array, T value) where T : class + { + for (int i = 0; i < array.Length; i++) + if (array[i] == value) + return i; + + return -1; + } + + public static V GetValueOrDefault(this WeakReference wr) + { + if (wr == null || !wr.IsAlive) + return default(V); + return (V)wr.Target; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/AnchorSide.cs b/Src/Xceed.Wpf.AvalonDock/Layout/AnchorSide.cs new file mode 100644 index 0000000..78d1096 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/AnchorSide.cs @@ -0,0 +1,34 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public enum AnchorSide + { + Left, + + Top, + + Right, + + Bottom + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/AnchorableShowStrategy.cs b/Src/Xceed.Wpf.AvalonDock/Layout/AnchorableShowStrategy.cs new file mode 100644 index 0000000..437cff1 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/AnchorableShowStrategy.cs @@ -0,0 +1,33 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [Flags] + public enum AnchorableShowStrategy : byte + { + Most = 0x0001, + Left = 0x0002, + Right = 0x0004, + Top = 0x0010, + Bottom= 0x0020, + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ChildrenTreeChangedEventArgs.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ChildrenTreeChangedEventArgs.cs new file mode 100644 index 0000000..68e81a1 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ChildrenTreeChangedEventArgs.cs @@ -0,0 +1,46 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public enum ChildrenTreeChange + { + /// + /// Direct insert/remove operation has been perfomed to the group + /// + DirectChildrenChanged, + + /// + /// An element below in the hierarchy as been added/removed + /// + TreeChanged + } + + public class ChildrenTreeChangedEventArgs : EventArgs + { + public ChildrenTreeChangedEventArgs(ChildrenTreeChange change) + { + Change = change; + } + + public ChildrenTreeChange Change { get; private set; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/Extentions.cs b/Src/Xceed.Wpf.AvalonDock/Layout/Extentions.cs new file mode 100644 index 0000000..56ff1c6 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/Extentions.cs @@ -0,0 +1,169 @@ +/************************************************************************************* + + 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; +using System.Windows.Media; +using System.Windows.Media.Media3D; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public static class Extensions + { + public static IEnumerable Descendents(this ILayoutElement element) + { + var container = element as ILayoutContainer; + if (container != null) + { + foreach (var childElement in container.Children) + { + yield return childElement; + foreach (var childChildElement in childElement.Descendents()) + yield return childChildElement; + } + } + } + + public static T FindParent(this ILayoutElement element) //where T : ILayoutContainer + { + var parent = element.Parent; + while (parent != null && + !(parent is T)) + parent = parent.Parent; + + + return (T)parent; + } + + public static ILayoutRoot GetRoot(this ILayoutElement element) //where T : ILayoutContainer + { + if (element is ILayoutRoot) + return element as ILayoutRoot; + + var parent = element.Parent; + while (parent != null && + !(parent is ILayoutRoot)) + parent = parent.Parent; + + return (ILayoutRoot)parent; + } + + public static bool ContainsChildOfType(this ILayoutContainer element) + { + foreach (var childElement in element.Descendents()) + if (childElement is T) + return true; + + return false; + } + + public static bool ContainsChildOfType(this ILayoutContainer container) + { + foreach (var childElement in container.Descendents()) + if (childElement is T || childElement is S) + return true; + + return false; + } + + public static bool IsOfType(this ILayoutContainer container) + { + return container is T || container is S; + } + + public static AnchorSide GetSide(this ILayoutElement element) + { + var parentContainer = element.Parent as ILayoutOrientableGroup; + if (parentContainer != null) + { + if (!parentContainer.ContainsChildOfType()) + return GetSide(parentContainer); + + foreach (var childElement in parentContainer.Children) + { + if (childElement == element || + childElement.Descendents().Contains(element)) + return parentContainer.Orientation == System.Windows.Controls.Orientation.Horizontal ? + AnchorSide.Left : AnchorSide.Top; + + var childElementAsContainer = childElement as ILayoutContainer; + if (childElementAsContainer != null && + (childElementAsContainer.IsOfType() || + childElementAsContainer.ContainsChildOfType())) + { + return parentContainer.Orientation == System.Windows.Controls.Orientation.Horizontal ? + AnchorSide.Right : AnchorSide.Bottom; + } + } + } + + Debug.Fail("Unable to find the side for an element, possible layout problem!"); + return AnchorSide.Right; + } + + + internal static void KeepInsideNearestMonitor(this ILayoutElementForFloatingWindow paneInsideFloatingWindow) + { + Win32Helper.RECT r = new Win32Helper.RECT(); + r.Left = (int)paneInsideFloatingWindow.FloatingLeft; + r.Top = (int)paneInsideFloatingWindow.FloatingTop; + r.Bottom = r.Top + (int)paneInsideFloatingWindow.FloatingHeight; + r.Right = r.Left + (int)paneInsideFloatingWindow.FloatingWidth; + + uint MONITOR_DEFAULTTONEAREST = 0x00000002; + uint MONITOR_DEFAULTTONULL = 0x00000000; + + System.IntPtr monitor = Win32Helper.MonitorFromRect(ref r, MONITOR_DEFAULTTONULL); + if (monitor == System.IntPtr.Zero) + { + System.IntPtr nearestmonitor = Win32Helper.MonitorFromRect(ref r, MONITOR_DEFAULTTONEAREST); + if (nearestmonitor != System.IntPtr.Zero) + { + Win32Helper.MonitorInfo monitorInfo = new Win32Helper.MonitorInfo(); + monitorInfo.Size = Marshal.SizeOf(monitorInfo); + Win32Helper.GetMonitorInfo(nearestmonitor, monitorInfo); + + if (paneInsideFloatingWindow.FloatingLeft < monitorInfo.Work.Left) + { + paneInsideFloatingWindow.FloatingLeft = monitorInfo.Work.Left + 10; + } + + if (paneInsideFloatingWindow.FloatingLeft + paneInsideFloatingWindow.FloatingWidth > monitorInfo.Work.Right) + { + paneInsideFloatingWindow.FloatingLeft = monitorInfo.Work.Right - (paneInsideFloatingWindow.FloatingWidth + 10); + } + + if (paneInsideFloatingWindow.FloatingTop < monitorInfo.Work.Top) + { + paneInsideFloatingWindow.FloatingTop = monitorInfo.Work.Top + 10; + } + + if (paneInsideFloatingWindow.FloatingTop + paneInsideFloatingWindow.FloatingHeight > monitorInfo.Work.Bottom) + { + paneInsideFloatingWindow.FloatingTop = monitorInfo.Work.Bottom - (paneInsideFloatingWindow.FloatingHeight + 10); + } + } + } + + } + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutAnchorablePane.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutAnchorablePane.cs new file mode 100644 index 0000000..19f1ed7 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutAnchorablePane.cs @@ -0,0 +1,27 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutAnchorablePane : ILayoutPanelElement, ILayoutPane + { + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutContainer.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutContainer.cs new file mode 100644 index 0000000..83793a4 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutContainer.cs @@ -0,0 +1,31 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutContainer : ILayoutElement + { + IEnumerable Children { get; } + void RemoveChild(ILayoutElement element); + void ReplaceChild(ILayoutElement oldElement, ILayoutElement newElement); + int ChildrenCount { get; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutContentSelector.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutContentSelector.cs new file mode 100644 index 0000000..0339b5f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutContentSelector.cs @@ -0,0 +1,32 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutContentSelector + { + int SelectedContentIndex { get; set; } + + int IndexOf(LayoutContent content); + + LayoutContent SelectedContent { get; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutControl.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutControl.cs new file mode 100644 index 0000000..bce567e --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutControl.cs @@ -0,0 +1,28 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutControl + { + ILayoutElement Model { get; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutDocumentPane.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutDocumentPane.cs new file mode 100644 index 0000000..b139640 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutDocumentPane.cs @@ -0,0 +1,27 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutDocumentPane : ILayoutPanelElement, ILayoutPane + { + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutElement.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutElement.cs new file mode 100644 index 0000000..ffa9b96 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutElement.cs @@ -0,0 +1,30 @@ +/************************************************************************************* + + 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.ComponentModel; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutElement : INotifyPropertyChanged, INotifyPropertyChanging + { + ILayoutContainer Parent { get; } + ILayoutRoot Root { get; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutElementWithVisibility.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutElementWithVisibility.cs new file mode 100644 index 0000000..c0bba85 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutElementWithVisibility.cs @@ -0,0 +1,28 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutElementWithVisibility + { + void ComputeVisibility(); + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutGroup.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutGroup.cs new file mode 100644 index 0000000..0176ab1 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutGroup.cs @@ -0,0 +1,32 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutGroup : ILayoutContainer + { + int IndexOfChild(ILayoutElement element); + void InsertChildAt(int index, ILayoutElement element); + void RemoveChildAt(int index); + void ReplaceChildAt(int index, ILayoutElement element); + event EventHandler ChildrenCollectionChanged; + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutOrientableElement.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutOrientableElement.cs new file mode 100644 index 0000000..af0d6e7 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutOrientableElement.cs @@ -0,0 +1,29 @@ +/************************************************************************************* + + 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.Controls; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutOrientableGroup : ILayoutGroup + { + Orientation Orientation { get; set; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPane.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPane.cs new file mode 100644 index 0000000..699f61a --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPane.cs @@ -0,0 +1,30 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutPane : ILayoutContainer, ILayoutElementWithVisibility + { + void MoveChild(int oldIndex, int newIndex); + + void RemoveChildAt(int childIndex); + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPaneSerializable.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPaneSerializable.cs new file mode 100644 index 0000000..abe0010 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPaneSerializable.cs @@ -0,0 +1,28 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + interface ILayoutPaneSerializable + { + string Id { get; set; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPanelElement.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPanelElement.cs new file mode 100644 index 0000000..f451c60 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPanelElement.cs @@ -0,0 +1,29 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutPanelElement : ILayoutElement + { + bool IsVisible { get; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPositionableElement.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPositionableElement.cs new file mode 100644 index 0000000..a4e3b10 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPositionableElement.cs @@ -0,0 +1,62 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + internal interface ILayoutPositionableElement : ILayoutElement, ILayoutElementForFloatingWindow + { + GridLength DockWidth + { + get; + set; + } + + GridLength DockHeight + { + get; + set; + } + + double DockMinWidth { get; set; } + double DockMinHeight { get; set; } + + + + bool IsVisible { get; } + } + + + internal interface ILayoutPositionableElementWithActualSize + { + double ActualWidth { get; set; } + double ActualHeight { get; set; } + } + + internal interface ILayoutElementForFloatingWindow + { + double FloatingWidth { get; set; } + double FloatingHeight { get; set; } + double FloatingLeft { get; set; } + double FloatingTop { get; set; } + bool IsMaximized { get; set; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPreviousContainer.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPreviousContainer.cs new file mode 100644 index 0000000..6e23572 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutPreviousContainer.cs @@ -0,0 +1,30 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + interface ILayoutPreviousContainer + { + ILayoutContainer PreviousContainer { get; set; } + + string PreviousContainerId { get; set; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutRoot.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutRoot.cs new file mode 100644 index 0000000..e170d4a --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutRoot.cs @@ -0,0 +1,43 @@ +/************************************************************************************* + + 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.Collections.ObjectModel; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutRoot + { + DockingManager Manager { get; } + + LayoutPanel RootPanel { get; } + + LayoutAnchorSide TopSide { get; } + LayoutAnchorSide LeftSide { get; } + LayoutAnchorSide RightSide { get; } + LayoutAnchorSide BottomSide { get; } + + LayoutContent ActiveContent { get; set; } + + void CollectGarbage(); + + ObservableCollection FloatingWindows { get; } + ObservableCollection Hidden { get; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutUpdateStrategy.cs b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutUpdateStrategy.cs new file mode 100644 index 0000000..f9e0d31 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/ILayoutUpdateStrategy.cs @@ -0,0 +1,45 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public interface ILayoutUpdateStrategy + { + bool BeforeInsertAnchorable( + LayoutRoot layout, + LayoutAnchorable anchorableToShow, + ILayoutContainer destinationContainer); + + void AfterInsertAnchorable( + LayoutRoot layout, + LayoutAnchorable anchorableShown); + + + bool BeforeInsertDocument( + LayoutRoot layout, + LayoutDocument anchorableToShow, + ILayoutContainer destinationContainer); + + void AfterInsertDocument( + LayoutRoot layout, + LayoutDocument anchorableShown); + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorGroup.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorGroup.cs new file mode 100644 index 0000000..45d7792 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorGroup.cs @@ -0,0 +1,111 @@ +/************************************************************************************* + + 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.Collections.ObjectModel; +using System.Windows.Markup; +using System.Xml.Serialization; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty("Children")] + [Serializable] + public class LayoutAnchorGroup : LayoutGroup, ILayoutPreviousContainer, ILayoutPaneSerializable + { + public LayoutAnchorGroup() + { + } + + protected override bool GetVisibility() + { + return Children.Count > 0; + } + + + #region PreviousContainer + + [field:NonSerialized] + private ILayoutContainer _previousContainer = null; + [XmlIgnore] + ILayoutContainer ILayoutPreviousContainer.PreviousContainer + { + get { return _previousContainer; } + set + { + if (_previousContainer != value) + { + _previousContainer = value; + RaisePropertyChanged("PreviousContainer"); + var paneSerializable = _previousContainer as ILayoutPaneSerializable; + if (paneSerializable != null && + paneSerializable.Id == null) + paneSerializable.Id = Guid.NewGuid().ToString(); + } + } + } + + #endregion + + string _id; + string ILayoutPaneSerializable.Id + { + get + { + return _id; + } + set + { + _id = value; + } + } + + string ILayoutPreviousContainer.PreviousContainerId + { + get; + set; + } + + public override void WriteXml(System.Xml.XmlWriter writer) + { + if (_id != null) + writer.WriteAttributeString("Id", _id); + if (_previousContainer != null) + { + var paneSerializable = _previousContainer as ILayoutPaneSerializable; + if (paneSerializable != null) + { + writer.WriteAttributeString("PreviousContainerId", paneSerializable.Id); + } + } + + base.WriteXml(writer); + } + + public override void ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToAttribute("Id")) + _id = reader.Value; + if (reader.MoveToAttribute("PreviousContainerId")) + ((ILayoutPreviousContainer)this).PreviousContainerId = reader.Value; + + + base.ReadXml(reader); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorSide.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorSide.cs new file mode 100644 index 0000000..a22cf4f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorSide.cs @@ -0,0 +1,83 @@ +/************************************************************************************* + + 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.Collections.ObjectModel; +using System.Windows.Markup; +using Xceed.Wpf.AvalonDock.Controls; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty("Children")] + [Serializable] + public class LayoutAnchorSide : LayoutGroup + { + public LayoutAnchorSide() + { + } + + protected override bool GetVisibility() + { + return Children.Count > 0; + } + + + protected override void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue) + { + base.OnParentChanged(oldValue, newValue); + + UpdateSide(); + } + + private void UpdateSide() + { + if (Root.LeftSide == this) + Side = AnchorSide.Left; + else if (Root.TopSide == this) + Side = AnchorSide.Top; + else if (Root.RightSide == this) + Side = AnchorSide.Right; + else if (Root.BottomSide == this) + Side = AnchorSide.Bottom; + } + + + #region Side + + private AnchorSide _side; + public AnchorSide Side + { + get { return _side; } + private set + { + if (_side != value) + { + RaisePropertyChanging("Side"); + _side = value; + RaisePropertyChanged("Side"); + } + } + } + + #endregion + + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorable.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorable.cs new file mode 100644 index 0000000..6a3397f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorable.cs @@ -0,0 +1,655 @@ +/************************************************************************************* + + 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; +using System.Xml.Serialization; +using System.Windows.Controls; +using System.Globalization; +using System.ComponentModel; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [Serializable] + public class LayoutAnchorable : LayoutContent + { + #region IsVisible + [XmlIgnore] + public bool IsVisible + { + get + { + return Parent != null && !(Parent is LayoutRoot); + } + set + { + if (value) + { + Show(); + } + else + { + Hide(); + } + } + } + + public event EventHandler IsVisibleChanged; + + void NotifyIsVisibleChanged() + { + if (IsVisibleChanged != null) + IsVisibleChanged(this, EventArgs.Empty); + } + + [XmlIgnore] + public bool IsHidden + { + get + { + return (Parent is LayoutRoot); + } + } + + protected override void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue) + { + UpdateParentVisibility(); + RaisePropertyChanged("IsVisible"); + NotifyIsVisibleChanged(); + RaisePropertyChanged("IsHidden"); + RaisePropertyChanged("IsAutoHidden"); + base.OnParentChanged(oldValue, newValue); + } + + void UpdateParentVisibility() + { + var parentPane = Parent as ILayoutElementWithVisibility; + if (parentPane != null) + parentPane.ComputeVisibility(); + } + + #endregion + + #region AutoHideWidth + + private double _autohideWidth = 0.0; + public double AutoHideWidth + { + get { return _autohideWidth; } + set + { + if (_autohideWidth != value) + { + RaisePropertyChanging("AutoHideWidth"); + value = Math.Max(value, _autohideMinWidth); + _autohideWidth = value; + RaisePropertyChanged("AutoHideWidth"); + } + } + } + + #endregion + + #region AutoHideMinWidth + + private double _autohideMinWidth = 100.0; + public double AutoHideMinWidth + { + get { return _autohideMinWidth; } + set + { + if (_autohideMinWidth != value) + { + RaisePropertyChanging("AutoHideMinWidth"); + if (value < 0) + throw new ArgumentException("value"); + _autohideMinWidth = value; + RaisePropertyChanged("AutoHideMinWidth"); + } + } + } + + #endregion + + #region AutoHideHeight + + private double _autohideHeight = 0.0; + public double AutoHideHeight + { + get { return _autohideHeight; } + set + { + if (_autohideHeight != value) + { + RaisePropertyChanging("AutoHideHeight"); + value = Math.Max(value, _autohideMinHeight); + _autohideHeight = value; + RaisePropertyChanged("AutoHideHeight"); + } + } + } + + #endregion + + #region AutoHideMinHeight + + private double _autohideMinHeight = 100.0; + public double AutoHideMinHeight + { + get { return _autohideMinHeight; } + set + { + if (_autohideMinHeight != value) + { + RaisePropertyChanging("AutoHideMinHeight"); + if (value < 0) + throw new ArgumentException("value"); + _autohideMinHeight = value; + RaisePropertyChanged("AutoHideMinHeight"); + } + } + } + + #endregion + + /// + /// Hide this contents + /// + /// Add this content to collection of parent root. + public void Hide(bool cancelable = true) + { + if (!IsVisible) + { + IsSelected = true; + IsActive = true; + return; + } + + if (cancelable) + { + CancelEventArgs args = new CancelEventArgs(); + OnHiding(args); + if (args.Cancel) + return; + } + + RaisePropertyChanging("IsHidden"); + RaisePropertyChanging("IsVisible"); + //if (Parent is ILayoutPane) + { + var parentAsGroup = Parent as ILayoutGroup; + PreviousContainer = parentAsGroup; + PreviousContainerIndex = parentAsGroup.IndexOfChild(this); + } + Root.Hidden.Add(this); + RaisePropertyChanged("IsVisible"); + RaisePropertyChanged("IsHidden"); + NotifyIsVisibleChanged(); + } + + public event EventHandler Hiding; + + protected virtual void OnHiding(CancelEventArgs args) + { + if (Hiding != null) + Hiding(this, args); + } + + + /// + /// Show the content + /// + /// Try to show the content where it was previously hidden. + public void Show() + { + if (IsVisible) + return; + + if (!IsHidden) + throw new InvalidOperationException(); + + RaisePropertyChanging("IsHidden"); + RaisePropertyChanging("IsVisible"); + + bool added = false; + var root = Root; + if (root != null && root.Manager != null) + { + if (root.Manager.LayoutUpdateStrategy != null) + added = root.Manager.LayoutUpdateStrategy.BeforeInsertAnchorable(root as LayoutRoot, this, PreviousContainer); + } + + if (!added && PreviousContainer != null) + { + var previousContainerAsLayoutGroup = PreviousContainer as ILayoutGroup; + if (PreviousContainerIndex < previousContainerAsLayoutGroup.ChildrenCount) + previousContainerAsLayoutGroup.InsertChildAt(PreviousContainerIndex, this); + else + previousContainerAsLayoutGroup.InsertChildAt(previousContainerAsLayoutGroup.ChildrenCount, this); + IsSelected = true; + IsActive = true; + } + + if (root != null && root.Manager != null) + { + if (root.Manager.LayoutUpdateStrategy != null) + { + root.Manager.LayoutUpdateStrategy.AfterInsertAnchorable(root as LayoutRoot, this); + } + } + + PreviousContainer = null; + PreviousContainerIndex = -1; + + RaisePropertyChanged("IsVisible"); + RaisePropertyChanged("IsHidden"); + NotifyIsVisibleChanged(); + } + + protected override void InternalDock() + { + var root = Root as LayoutRoot; + LayoutAnchorablePane anchorablePane = null; + + if (root.ActiveContent != null && + root.ActiveContent != this) + { + //look for active content parent pane + anchorablePane = root.ActiveContent.Parent as LayoutAnchorablePane; + } + + if (anchorablePane == null) + { + //look for a pane on the right side + anchorablePane = root.Descendents().OfType().Where(pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right).FirstOrDefault(); + } + + if (anchorablePane == null) + { + //look for an available pane + anchorablePane = root.Descendents().OfType().FirstOrDefault(); + } + + + bool added = false; + if (root.Manager.LayoutUpdateStrategy != null) + { + added = root.Manager.LayoutUpdateStrategy.BeforeInsertAnchorable(root, this, anchorablePane); + } + + if (!added) + { + if (anchorablePane == null) + { + var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + if (root.RootPanel != null) + { + mainLayoutPanel.Children.Add(root.RootPanel); + } + + root.RootPanel = mainLayoutPanel; + anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength(200.0, GridUnitType.Pixel) }; + mainLayoutPanel.Children.Add(anchorablePane); + } + + anchorablePane.Children.Add(this); + added = true; + } + + if (root.Manager.LayoutUpdateStrategy != null) + { + root.Manager.LayoutUpdateStrategy.AfterInsertAnchorable(root, this); + } + + base.InternalDock(); + } + + /// + /// Add the anchorable to a DockingManager layout + /// + /// + /// + public void AddToLayout(DockingManager manager, AnchorableShowStrategy strategy) + { + if (IsVisible || + IsHidden) + throw new InvalidOperationException(); + + + bool most = (strategy & AnchorableShowStrategy.Most) == AnchorableShowStrategy.Most; + bool left = (strategy & AnchorableShowStrategy.Left) == AnchorableShowStrategy.Left; + bool right = (strategy & AnchorableShowStrategy.Right) == AnchorableShowStrategy.Right; + bool top = (strategy & AnchorableShowStrategy.Top) == AnchorableShowStrategy.Top; + bool bottom = (strategy & AnchorableShowStrategy.Bottom) == AnchorableShowStrategy.Bottom; + + if (!most) + { + var side = AnchorSide.Left; + if (left) + side = AnchorSide.Left; + if (right) + side = AnchorSide.Right; + if (top) + side = AnchorSide.Top; + if (bottom) + side = AnchorSide.Bottom; + + var anchorablePane = manager.Layout.Descendents().OfType().FirstOrDefault(p => p.GetSide() == side); + if (anchorablePane != null) + anchorablePane.Children.Add(this); + else + most = true; + } + + + if (most) + { + if (manager.Layout.RootPanel == null) + manager.Layout.RootPanel = new LayoutPanel() { Orientation = (left || right ? Orientation.Horizontal : Orientation.Vertical) }; + + if (left || right) + { + if (manager.Layout.RootPanel.Orientation == Orientation.Vertical && + manager.Layout.RootPanel.ChildrenCount > 1) + { + manager.Layout.RootPanel = new LayoutPanel(manager.Layout.RootPanel); + } + + manager.Layout.RootPanel.Orientation = Orientation.Horizontal; + + if (left) + manager.Layout.RootPanel.Children.Insert(0, new LayoutAnchorablePane(this)); + else + manager.Layout.RootPanel.Children.Add(new LayoutAnchorablePane(this)); + } + else + { + if (manager.Layout.RootPanel.Orientation == Orientation.Horizontal && + manager.Layout.RootPanel.ChildrenCount > 1) + { + manager.Layout.RootPanel = new LayoutPanel(manager.Layout.RootPanel); + } + + manager.Layout.RootPanel.Orientation = Orientation.Vertical; + + if (top) + manager.Layout.RootPanel.Children.Insert(0, new LayoutAnchorablePane(this)); + else + manager.Layout.RootPanel.Children.Add(new LayoutAnchorablePane(this)); + } + + } + } + + + /// + /// Get a value indicating if the anchorable is anchored to a border in an autohide status + /// + public bool IsAutoHidden + { + get { return Parent != null && Parent is LayoutAnchorGroup; } + } + + + #region AutoHide + public void ToggleAutoHide() + { + #region Anchorable is already auto hidden + if (IsAutoHidden) + { + var parentGroup = Parent as LayoutAnchorGroup; + var parentSide = parentGroup.Parent as LayoutAnchorSide; + var previousContainer = ((ILayoutPreviousContainer)parentGroup).PreviousContainer as LayoutAnchorablePane; + + if (previousContainer == null) + { + AnchorSide side = (parentGroup.Parent as LayoutAnchorSide).Side; + switch (side) + { + case AnchorSide.Right: + if (parentGroup.Root.RootPanel.Orientation == Orientation.Horizontal) + { + previousContainer = new LayoutAnchorablePane(); + previousContainer.DockMinWidth = this.AutoHideMinWidth; + parentGroup.Root.RootPanel.Children.Add(previousContainer); + } + else + { + previousContainer = new LayoutAnchorablePane(); + LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + LayoutRoot root = parentGroup.Root as LayoutRoot; + LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; + root.RootPanel = panel; + panel.Children.Add(oldRootPanel); + panel.Children.Add(previousContainer); + } + break; + case AnchorSide.Left: + if (parentGroup.Root.RootPanel.Orientation == Orientation.Horizontal) + { + previousContainer = new LayoutAnchorablePane(); + previousContainer.DockMinWidth = this.AutoHideMinWidth; + parentGroup.Root.RootPanel.Children.Insert(0, previousContainer); + } + else + { + previousContainer = new LayoutAnchorablePane(); + LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + LayoutRoot root = parentGroup.Root as LayoutRoot; + LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; + root.RootPanel = panel; + panel.Children.Add(previousContainer); + panel.Children.Add(oldRootPanel); + } + break; + case AnchorSide.Top: + if (parentGroup.Root.RootPanel.Orientation == Orientation.Vertical) + { + previousContainer = new LayoutAnchorablePane(); + previousContainer.DockMinHeight = this.AutoHideMinHeight; + parentGroup.Root.RootPanel.Children.Insert(0, previousContainer); + } + else + { + previousContainer = new LayoutAnchorablePane(); + LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Vertical }; + LayoutRoot root = parentGroup.Root as LayoutRoot; + LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; + root.RootPanel = panel; + panel.Children.Add(previousContainer); + panel.Children.Add(oldRootPanel); + } + break; + case AnchorSide.Bottom: + if (parentGroup.Root.RootPanel.Orientation == Orientation.Vertical) + { + previousContainer = new LayoutAnchorablePane(); + previousContainer.DockMinHeight = this.AutoHideMinHeight; + parentGroup.Root.RootPanel.Children.Add(previousContainer); + } + else + { + previousContainer = new LayoutAnchorablePane(); + LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Vertical }; + LayoutRoot root = parentGroup.Root as LayoutRoot; + LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; + root.RootPanel = panel; + panel.Children.Add(oldRootPanel); + panel.Children.Add(previousContainer); + } + break; + } + } + else + { + //I'm about to remove parentGroup, redirect any content (ie hidden contents) that point to it + //to previousContainer + LayoutRoot root = parentGroup.Root as LayoutRoot; + foreach (var cnt in root.Descendents().OfType().Where(c => c.PreviousContainer == parentGroup)) + { + cnt.PreviousContainer = previousContainer; + } + } + + + foreach (var anchorableToToggle in parentGroup.Children.ToArray()) + { + previousContainer.Children.Add(anchorableToToggle); + } + + parentSide.Children.Remove(parentGroup); + } + #endregion + #region Anchorable is docked + else if (Parent is LayoutAnchorablePane) + { + var root = Root; + var parentPane = Parent as LayoutAnchorablePane; + + var newAnchorGroup = new LayoutAnchorGroup(); + + ((ILayoutPreviousContainer)newAnchorGroup).PreviousContainer = parentPane; + + foreach (var anchorableToImport in parentPane.Children.ToArray()) + newAnchorGroup.Children.Add(anchorableToImport); + + //detect anchor side for the pane + var anchorSide = parentPane.GetSide(); + + switch (anchorSide) + { + case AnchorSide.Right: + root.RightSide.Children.Add(newAnchorGroup); + break; + case AnchorSide.Left: + root.LeftSide.Children.Add(newAnchorGroup); + break; + case AnchorSide.Top: + root.TopSide.Children.Add(newAnchorGroup); + break; + case AnchorSide.Bottom: + root.BottomSide.Children.Add(newAnchorGroup); + break; + } + } + #endregion + } + + #endregion + + #region CanHide + + private bool _canHide = true; + public bool CanHide + { + get { return _canHide; } + set + { + if (_canHide != value) + { + _canHide = value; + RaisePropertyChanged("CanHide"); + } + } + } + + #endregion + + #region CanAutoHide + + private bool _canAutoHide = true; + public bool CanAutoHide + { + get { return _canAutoHide; } + set + { + if (_canAutoHide != value) + { + _canAutoHide = value; + RaisePropertyChanged("CanAutoHide"); + } + } + } + + #endregion + + + public override void ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToAttribute("CanHide")) + CanHide = bool.Parse(reader.Value); + if (reader.MoveToAttribute("CanAutoHide")) + CanAutoHide = bool.Parse(reader.Value); + if (reader.MoveToAttribute("AutoHideWidth")) + AutoHideWidth = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("AutoHideHeight")) + AutoHideHeight = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("AutoHideMinWidth")) + AutoHideMinWidth = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("AutoHideMinHeight")) + AutoHideMinHeight = double.Parse(reader.Value, CultureInfo.InvariantCulture); + + base.ReadXml(reader); + } + + public override void WriteXml(System.Xml.XmlWriter writer) + { + if (!CanHide) + writer.WriteAttributeString("CanHide", CanHide.ToString()); + if (!CanAutoHide) + writer.WriteAttributeString("CanAutoHide", CanAutoHide.ToString(CultureInfo.InvariantCulture)); + if (AutoHideWidth > 0) + writer.WriteAttributeString("AutoHideWidth", AutoHideWidth.ToString(CultureInfo.InvariantCulture)); + if (AutoHideHeight > 0) + writer.WriteAttributeString("AutoHideHeight", AutoHideHeight.ToString(CultureInfo.InvariantCulture)); + if (AutoHideMinWidth != 25.0) + writer.WriteAttributeString("AutoHideMinWidth", AutoHideMinWidth.ToString(CultureInfo.InvariantCulture)); + if (AutoHideMinHeight != 25.0) + writer.WriteAttributeString("AutoHideMinHeight", AutoHideMinHeight.ToString(CultureInfo.InvariantCulture)); + + + base.WriteXml(writer); + } + + public override void Close() + { + this.CloseAnchorable(); + } + + internal void CloseAnchorable() + { + if( this.TestCanClose() ) + { + if( this.IsAutoHidden ) + this.ToggleAutoHide(); + + this.CloseInternal(); + } + } + + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( "Anchorable()" ); + } +#endif + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorableFloatingWindow.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorableFloatingWindow.cs new file mode 100644 index 0000000..b6bb242 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorableFloatingWindow.cs @@ -0,0 +1,181 @@ +/************************************************************************************* + + 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.Markup; +using System.Diagnostics; +using System.Xml.Serialization; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [Serializable] + [ContentProperty("RootPanel")] + public class LayoutAnchorableFloatingWindow : LayoutFloatingWindow, ILayoutElementWithVisibility + { + public LayoutAnchorableFloatingWindow() + { + + } + + #region RootPanel + + private LayoutAnchorablePaneGroup _rootPanel = null; + public LayoutAnchorablePaneGroup RootPanel + { + get { return _rootPanel; } + set + { + if (_rootPanel != value) + { + RaisePropertyChanging("RootPanel"); + + if (_rootPanel != null) + _rootPanel.ChildrenTreeChanged -= new EventHandler(_rootPanel_ChildrenTreeChanged); + + _rootPanel = value; + if (_rootPanel != null) + _rootPanel.Parent = this; + + if (_rootPanel != null) + _rootPanel.ChildrenTreeChanged += new EventHandler(_rootPanel_ChildrenTreeChanged); + + RaisePropertyChanged("RootPanel"); + RaisePropertyChanged("IsSinglePane"); + RaisePropertyChanged("SinglePane"); + RaisePropertyChanged("Children"); + RaisePropertyChanged("ChildrenCount"); + ((ILayoutElementWithVisibility)this).ComputeVisibility(); + } + } + } + + void _rootPanel_ChildrenTreeChanged(object sender, ChildrenTreeChangedEventArgs e) + { + RaisePropertyChanged("IsSinglePane"); + RaisePropertyChanged("SinglePane"); + + } + + public bool IsSinglePane + { + get + { + return RootPanel != null && RootPanel.Descendents().OfType().Where(p => p.IsVisible).Count() == 1; + } + } + + public ILayoutAnchorablePane SinglePane + { + get + { + if (!IsSinglePane) + return null; + + var singlePane = RootPanel.Descendents().OfType().Single(p => p.IsVisible); + singlePane.UpdateIsDirectlyHostedInFloatingWindow(); + return singlePane; + } + } + + #endregion + + public override IEnumerable Children + { + get + { + if (ChildrenCount == 1) + yield return RootPanel; + + yield break; + } + } + + public override void RemoveChild(ILayoutElement element) + { + Debug.Assert(element == RootPanel && element != null); + RootPanel = null; + } + + public override void ReplaceChild(ILayoutElement oldElement, ILayoutElement newElement) + { + Debug.Assert(oldElement == RootPanel && oldElement != null); + RootPanel = newElement as LayoutAnchorablePaneGroup; + } + + public override int ChildrenCount + { + get + { + if (RootPanel == null) + return 0; + return 1; + } + } + + #region IsVisible + [NonSerialized] + private bool _isVisible = true; + + [XmlIgnore] + public bool IsVisible + { + get { return _isVisible; } + private set + { + if (_isVisible != value) + { + RaisePropertyChanging("IsVisible"); + _isVisible = value; + RaisePropertyChanged("IsVisible"); + if (IsVisibleChanged != null) + IsVisibleChanged(this, EventArgs.Empty); + } + } + } + + public event EventHandler IsVisibleChanged; + + #endregion + + + void ILayoutElementWithVisibility.ComputeVisibility() + { + if (RootPanel != null) + IsVisible = RootPanel.IsVisible; + else + IsVisible = false; + + } + + public override bool IsValid + { + get { return RootPanel != null; } + } + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( "FloatingAnchorableWindow()" ); + + RootPanel.ConsoleDump(tab + 1); + } +#endif + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorablePane.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorablePane.cs new file mode 100644 index 0000000..14b00d2 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorablePane.cs @@ -0,0 +1,280 @@ +/************************************************************************************* + + 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.Collections.ObjectModel; +using System.Windows.Markup; +using System.ComponentModel; +using System.Xml.Serialization; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty("Children")] + [Serializable] + public class LayoutAnchorablePane : LayoutPositionableGroup, ILayoutAnchorablePane, ILayoutPositionableElement, ILayoutContentSelector, ILayoutPaneSerializable + { + public LayoutAnchorablePane() + { + } + + public LayoutAnchorablePane(LayoutAnchorable anchorable) + { + Children.Add(anchorable); + } + + protected override bool GetVisibility() + { + return Children.Count > 0 && Children.Any(c => c.IsVisible); + } + + #region SelectedContentIndex + + private int _selectedIndex = -1; + public int SelectedContentIndex + { + get { return _selectedIndex; } + set + { + if (value < 0 || + value >= Children.Count) + value = -1; + + if (_selectedIndex != value) + { + RaisePropertyChanging("SelectedContentIndex"); + RaisePropertyChanging("SelectedContent"); + if (_selectedIndex >= 0 && + _selectedIndex < Children.Count) + Children[_selectedIndex].IsSelected = false; + + _selectedIndex = value; + + if (_selectedIndex >= 0 && + _selectedIndex < Children.Count) + Children[_selectedIndex].IsSelected = true; + + RaisePropertyChanged("SelectedContentIndex"); + RaisePropertyChanged("SelectedContent"); + } + } + } + + protected override void ChildMoved(int oldIndex, int newIndex) + { + if (_selectedIndex == oldIndex) + { + RaisePropertyChanging("SelectedContentIndex"); + _selectedIndex = newIndex; + RaisePropertyChanged("SelectedContentIndex"); + } + + + base.ChildMoved(oldIndex, newIndex); + } + + public LayoutContent SelectedContent + { + get + { + return _selectedIndex == -1 ? null : Children[_selectedIndex]; + } + } + #endregion + + protected override void OnChildrenCollectionChanged() + { + AutoFixSelectedContent(); + for (int i = 0; i < Children.Count; i++) + { + if (Children[i].IsSelected) + { + SelectedContentIndex = i; + break; + } + } + + RaisePropertyChanged("CanClose"); + RaisePropertyChanged("CanHide"); + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); + base.OnChildrenCollectionChanged(); + } + + [XmlIgnore] + bool _autoFixSelectedContent = true; + void AutoFixSelectedContent() + { + if (_autoFixSelectedContent) + { + if (SelectedContentIndex >= ChildrenCount) + SelectedContentIndex = Children.Count - 1; + + if (SelectedContentIndex == -1 && ChildrenCount > 0) + SetNextSelectedIndex(); + } + } + + public int IndexOf(LayoutContent content) + { + var anchorableChild = content as LayoutAnchorable; + if (anchorableChild == null) + return -1; + + return Children.IndexOf(anchorableChild); + } + + + public bool IsDirectlyHostedInFloatingWindow + { + get + { + var parentFloatingWindow = this.FindParent(); + if (parentFloatingWindow != null) + return parentFloatingWindow.IsSinglePane; + + return false; + //return Parent != null && Parent.ChildrenCount == 1 && Parent.Parent is LayoutFloatingWindow; + } + } + + internal void SetNextSelectedIndex() + { + SelectedContentIndex = -1; + for( int i = 0; i < this.Children.Count; ++i ) + { + if( Children[ i ].IsEnabled ) + { + SelectedContentIndex = i; + return; + } + } + } + + internal void UpdateIsDirectlyHostedInFloatingWindow() + { + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); + } + + public bool IsHostedInFloatingWindow + { + get + { + return this.FindParent() != null; + } + } + + protected override void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue) + { + var oldGroup = oldValue as ILayoutGroup; + if (oldGroup != null) + oldGroup.ChildrenCollectionChanged -= new EventHandler(OnParentChildrenCollectionChanged); + + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); + + var newGroup = newValue as ILayoutGroup; + if (newGroup != null) + newGroup.ChildrenCollectionChanged += new EventHandler(OnParentChildrenCollectionChanged); + + base.OnParentChanged(oldValue, newValue); + } + + void OnParentChildrenCollectionChanged(object sender, EventArgs e) + { + RaisePropertyChanged("IsDirectlyHostedInFloatingWindow"); + } + + string _id; + + string ILayoutPaneSerializable.Id + { + get + { + return _id; + } + set + { + _id = value; + } + } + + #region Name + + private string _name = null; + public string Name + { + get { return _name; } + set + { + if (_name != value) + { + _name = value; + RaisePropertyChanged("Name"); + } + } + } + + #endregion + + + + public override void WriteXml(System.Xml.XmlWriter writer) + { + if (_id != null) + writer.WriteAttributeString("Id", _id); + if (_name != null) + writer.WriteAttributeString("Name", _name); + + base.WriteXml(writer); + } + + public override void ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToAttribute("Id")) + _id = reader.Value; + if (reader.MoveToAttribute("Name")) + _name = reader.Value; + + _autoFixSelectedContent = false; + base.ReadXml(reader); + _autoFixSelectedContent = true; + AutoFixSelectedContent(); + } + + + public bool CanHide + { + get { return Children.All(a => a.CanHide); } + } + + public bool CanClose + { + get { return Children.All(a => a.CanClose);} + } + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( "AnchorablePane()" ); + + foreach (LayoutElement child in Children) + child.ConsoleDump(tab + 1); + } +#endif + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorablePaneGroup.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorablePaneGroup.cs new file mode 100644 index 0000000..d602d35 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorablePaneGroup.cs @@ -0,0 +1,129 @@ +/************************************************************************************* + + 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.Collections.ObjectModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Markup; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty("Children")] + [Serializable] + public class LayoutAnchorablePaneGroup : LayoutPositionableGroup, ILayoutAnchorablePane, ILayoutOrientableGroup + { + public LayoutAnchorablePaneGroup() + { + } + + public LayoutAnchorablePaneGroup(LayoutAnchorablePane firstChild) + { + Children.Add(firstChild); + } + + #region Orientation + + private Orientation _orientation; + public Orientation Orientation + { + get { return _orientation; } + set + { + if (_orientation != value) + { + RaisePropertyChanging("Orientation"); + _orientation = value; + RaisePropertyChanged("Orientation"); + } + } + } + + #endregion + + protected override bool GetVisibility() + { + return Children.Count > 0 && Children.Any(c => c.IsVisible); + } + + protected override void OnIsVisibleChanged() + { + UpdateParentVisibility(); + base.OnIsVisibleChanged(); + } + + void UpdateParentVisibility() + { + var parentPane = Parent as ILayoutElementWithVisibility; + if (parentPane != null) + parentPane.ComputeVisibility(); + } + + protected override void OnDockWidthChanged() + { + if (DockWidth.IsAbsolute && ChildrenCount == 1) + ((ILayoutPositionableElement)Children[0]).DockWidth = DockWidth; + + base.OnDockWidthChanged(); + } + + protected override void OnDockHeightChanged() + { + if (DockHeight.IsAbsolute && ChildrenCount == 1) + ((ILayoutPositionableElement)Children[0]).DockHeight = DockHeight; + base.OnDockHeightChanged(); + } + + protected override void OnChildrenCollectionChanged() + { + if (DockWidth.IsAbsolute && ChildrenCount == 1) + ((ILayoutPositionableElement)Children[0]).DockWidth = DockWidth; + if (DockHeight.IsAbsolute && ChildrenCount == 1) + ((ILayoutPositionableElement)Children[0]).DockHeight = DockHeight; + base.OnChildrenCollectionChanged(); + } + + public override void WriteXml(System.Xml.XmlWriter writer) + { + writer.WriteAttributeString("Orientation", Orientation.ToString()); + base.WriteXml(writer); + } + + public override void ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToAttribute("Orientation")) + Orientation = (Orientation)Enum.Parse(typeof(Orientation), reader.Value, true); + base.ReadXml(reader); + } + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( string.Format( "AnchorablePaneGroup({0})", Orientation ) ); + + foreach (LayoutElement child in Children) + child.ConsoleDump(tab + 1); + } +#endif + + + } + +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutContent.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutContent.cs new file mode 100644 index 0000000..b50807d --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutContent.cs @@ -0,0 +1,800 @@ +/************************************************************************************* + + 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.Markup; +using System.Xml.Serialization; +using System.Windows; +using System.Globalization; +using System.Windows.Media; +using System.ComponentModel; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty("Content")] + [Serializable] + public abstract class LayoutContent : LayoutElement, IXmlSerializable, ILayoutElementForFloatingWindow, IComparable, ILayoutPreviousContainer + { + internal LayoutContent() + { } + + #region Title + + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register( "Title", typeof( string ), typeof( LayoutContent ), new UIPropertyMetadata( null, OnTitlePropertyChanged, CoerceTitleValue ) ); + + public string Title + { + get { return ( string )GetValue( TitleProperty ); } + set { SetValue( TitleProperty, value ); } + } + + private static object CoerceTitleValue( DependencyObject obj, object value ) + { + var lc = ( LayoutContent )obj; + if( ( ( string )value ) != lc.Title ) + { + lc.RaisePropertyChanging( LayoutContent.TitleProperty.Name ); + } + return value; + } + + private static void OnTitlePropertyChanged( DependencyObject obj, DependencyPropertyChangedEventArgs args ) + { + ( ( LayoutContent )obj ).RaisePropertyChanged( LayoutContent.TitleProperty.Name ); + } + + #endregion //Title + + #region Content + [NonSerialized] + private object _content = null; + [XmlIgnore] + public object Content + { + get { return _content; } + set + { + if (_content != value) + { + RaisePropertyChanging("Content"); + _content = value; + RaisePropertyChanged("Content"); + } + } + } + + #endregion + + #region ContentId + + private string _contentId = null; + public string ContentId + { + get + { + if (_contentId == null) + { + var contentAsControl = _content as FrameworkElement; + if (contentAsControl != null && !string.IsNullOrWhiteSpace(contentAsControl.Name)) + return contentAsControl.Name; + } + return _contentId; + } + set + { + if (_contentId != value) + { + _contentId = value; + RaisePropertyChanged("ContentId"); + } + } + } + + #endregion + + #region IsSelected + + private bool _isSelected = false; + public bool IsSelected + { + get { return _isSelected; } + set + { + if (_isSelected != value) + { + bool oldValue = _isSelected; + RaisePropertyChanging("IsSelected"); + _isSelected = value; + var parentSelector = (Parent as ILayoutContentSelector); + if (parentSelector != null) + parentSelector.SelectedContentIndex = _isSelected ? parentSelector.IndexOf(this) : -1; + OnIsSelectedChanged(oldValue, value); + RaisePropertyChanged("IsSelected"); + } + } + } + + /// + /// Provides derived classes an opportunity to handle changes to the IsSelected property. + /// + protected virtual void OnIsSelectedChanged(bool oldValue, bool newValue) + { + if (IsSelectedChanged != null) + IsSelectedChanged(this, EventArgs.Empty); + } + + public event EventHandler IsSelectedChanged; + + #endregion + + #region IsActive + + [field: NonSerialized] + private bool _isActive = false; + [XmlIgnore] + public bool IsActive + { + get { return _isActive; } + set + { + if (_isActive != value) + { + RaisePropertyChanging("IsActive"); + bool oldValue = _isActive; + + _isActive = value; + + var root = Root; + if (root != null && _isActive) + root.ActiveContent = this; + + if (_isActive) + IsSelected = true; + + OnIsActiveChanged(oldValue, value); + RaisePropertyChanged("IsActive"); + } + } + } + + /// + /// Provides derived classes an opportunity to handle changes to the IsActive property. + /// + protected virtual void OnIsActiveChanged(bool oldValue, bool newValue) + { + if (newValue) + LastActivationTimeStamp = DateTime.Now; + + if (IsActiveChanged != null) + IsActiveChanged(this, EventArgs.Empty); + } + + public event EventHandler IsActiveChanged; + + #endregion + + #region IsLastFocusedDocument + + private bool _isLastFocusedDocument = false; + public bool IsLastFocusedDocument + { + get { return _isLastFocusedDocument; } + internal set + { + if (_isLastFocusedDocument != value) + { + RaisePropertyChanging("IsLastFocusedDocument"); + _isLastFocusedDocument = value; + RaisePropertyChanged("IsLastFocusedDocument"); + } + } + } + + #endregion + + #region PreviousContainer + + [field: NonSerialized] + private ILayoutContainer _previousContainer = null; + + [XmlIgnore] + ILayoutContainer ILayoutPreviousContainer.PreviousContainer + { + get { return _previousContainer; } + set + { + if (_previousContainer != value) + { + _previousContainer = value; + RaisePropertyChanged("PreviousContainer"); + + var paneSerializable = _previousContainer as ILayoutPaneSerializable; + if (paneSerializable != null && + paneSerializable.Id == null) + paneSerializable.Id = Guid.NewGuid().ToString(); + } + } + } + + protected ILayoutContainer PreviousContainer + { + get { return ((ILayoutPreviousContainer)this).PreviousContainer; } + set { ((ILayoutPreviousContainer)this).PreviousContainer = value; } + } + + [XmlIgnore] + string ILayoutPreviousContainer.PreviousContainerId + { + get; + set; + } + + protected string PreviousContainerId + { + get { return ((ILayoutPreviousContainer)this).PreviousContainerId; } + set { ((ILayoutPreviousContainer)this).PreviousContainerId = value; } + } + + #endregion + + #region PreviousContainerIndex + [field: NonSerialized] + private int _previousContainerIndex = -1; + [XmlIgnore] + public int PreviousContainerIndex + { + get { return _previousContainerIndex; } + set + { + if (_previousContainerIndex != value) + { + _previousContainerIndex = value; + RaisePropertyChanged("PreviousContainerIndex"); + } + } + } + + #endregion + + #region LastActivationTimeStamp + + private DateTime? _lastActivationTimeStamp = null; + public DateTime? LastActivationTimeStamp + { + get { return _lastActivationTimeStamp; } + set + { + if (_lastActivationTimeStamp != value) + { + _lastActivationTimeStamp = value; + RaisePropertyChanged("LastActivationTimeStamp"); + } + } + } + + #endregion + + protected override void OnParentChanging(ILayoutContainer oldValue, ILayoutContainer newValue) + { + var root = Root; + + if (oldValue != null) + IsSelected = false; + + //if (root != null && _isActive && newValue == null) + // root.ActiveContent = null; + + base.OnParentChanging(oldValue, newValue); + } + + protected override void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue) + { + if (IsSelected && Parent != null && Parent is ILayoutContentSelector) + { + var parentSelector = (Parent as ILayoutContentSelector); + parentSelector.SelectedContentIndex = parentSelector.IndexOf(this); + } + + //var root = Root; + //if (root != null && _isActive) + // root.ActiveContent = this; + + base.OnParentChanged(oldValue, newValue); + } + + /// + /// Test if the content can be closed + /// + /// + internal bool TestCanClose() + { + CancelEventArgs args = new CancelEventArgs(); + + OnClosing(args); + + if (args.Cancel) + return false; + + return true; + } + + internal void CloseInternal() + { + var root = Root; + var parentAsContainer = Parent as ILayoutContainer; + parentAsContainer.RemoveChild( this ); + if( root != null ) + root.CollectGarbage(); + + OnClosed(); + } + + /// + /// Close the content + /// + /// Please note that usually the anchorable is only hidden (not closed). By default when user click the X button it only hides the content. + public abstract void Close(); + + /// + /// Event fired when the content is closed (i.e. removed definitely from the layout) + /// + public event EventHandler Closed; + + protected virtual void OnClosed() + { + if (Closed != null) + Closed(this, EventArgs.Empty); + } + + /// + /// Event fired when the content is about to be closed (i.e. removed definitely from the layout) + /// + /// Please note that LayoutAnchorable also can be hidden. Usually user hide anchorables when click the 'X' button. To completely close + /// an anchorable the user should click the 'Close' menu item from the context menu. When an LayoutAnchorable is hidden its visibility changes to false and + /// IsHidden property is set to true. + /// Hanlde the Hiding event for the LayoutAnchorable to cancel the hide operation. + public event EventHandler Closing; + + protected virtual void OnClosing(CancelEventArgs args) + { + if (Closing != null) + Closing(this, args); + } + + public System.Xml.Schema.XmlSchema GetSchema() + { + return null; + } + + public virtual void ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToAttribute("Title")) + Title = reader.Value; + //if (reader.MoveToAttribute("IconSource")) + // IconSource = new Uri(reader.Value, UriKind.RelativeOrAbsolute); + + if (reader.MoveToAttribute("IsSelected")) + IsSelected = bool.Parse(reader.Value); + if (reader.MoveToAttribute("ContentId")) + ContentId = reader.Value; + if (reader.MoveToAttribute("IsLastFocusedDocument")) + IsLastFocusedDocument = bool.Parse(reader.Value); + if (reader.MoveToAttribute("PreviousContainerId")) + PreviousContainerId = reader.Value; + if (reader.MoveToAttribute("PreviousContainerIndex")) + PreviousContainerIndex = int.Parse(reader.Value); + + if (reader.MoveToAttribute("FloatingLeft")) + FloatingLeft = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("FloatingTop")) + FloatingTop = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("FloatingWidth")) + FloatingWidth = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("FloatingHeight")) + FloatingHeight = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("IsMaximized")) + IsMaximized = bool.Parse(reader.Value); + if (reader.MoveToAttribute("CanClose")) + CanClose = bool.Parse(reader.Value); + if (reader.MoveToAttribute("CanFloat")) + CanFloat = bool.Parse(reader.Value); + if (reader.MoveToAttribute("LastActivationTimeStamp")) + LastActivationTimeStamp = DateTime.Parse(reader.Value, CultureInfo.InvariantCulture); + + reader.Read(); + } + + public virtual void WriteXml(System.Xml.XmlWriter writer) + { + if (!string.IsNullOrWhiteSpace(Title)) + writer.WriteAttributeString("Title", Title); + + //if (IconSource != null) + // writer.WriteAttributeString("IconSource", IconSource.ToString()); + + if (IsSelected) + writer.WriteAttributeString("IsSelected", IsSelected.ToString()); + + if (IsLastFocusedDocument) + writer.WriteAttributeString("IsLastFocusedDocument", IsLastFocusedDocument.ToString()); + + if (!string.IsNullOrWhiteSpace(ContentId)) + writer.WriteAttributeString("ContentId", ContentId); + + + if (ToolTip != null && ToolTip is string) + if (!string.IsNullOrWhiteSpace((string)ToolTip)) + writer.WriteAttributeString("ToolTip", (string)ToolTip); + + if (FloatingLeft != 0.0) + writer.WriteAttributeString("FloatingLeft", FloatingLeft.ToString(CultureInfo.InvariantCulture)); + if (FloatingTop != 0.0) + writer.WriteAttributeString("FloatingTop", FloatingTop.ToString(CultureInfo.InvariantCulture)); + if (FloatingWidth != 0.0) + writer.WriteAttributeString("FloatingWidth", FloatingWidth.ToString(CultureInfo.InvariantCulture)); + if (FloatingHeight != 0.0) + writer.WriteAttributeString("FloatingHeight", FloatingHeight.ToString(CultureInfo.InvariantCulture)); + + if (IsMaximized) + writer.WriteAttributeString("IsMaximized", IsMaximized.ToString()); + if (!CanClose) + writer.WriteAttributeString("CanClose", CanClose.ToString()); + if (!CanFloat) + writer.WriteAttributeString("CanFloat", CanFloat.ToString()); + + if (LastActivationTimeStamp != null) + writer.WriteAttributeString("LastActivationTimeStamp", LastActivationTimeStamp.Value.ToString(CultureInfo.InvariantCulture)); + + if (_previousContainer != null) + { + var paneSerializable = _previousContainer as ILayoutPaneSerializable; + if (paneSerializable != null) + { + writer.WriteAttributeString("PreviousContainerId", paneSerializable.Id); + writer.WriteAttributeString("PreviousContainerIndex", _previousContainerIndex.ToString()); + } + } + + } + + #region FloatingWidth + + private double _floatingWidth = 0.0; + public double FloatingWidth + { + get { return _floatingWidth; } + set + { + if (_floatingWidth != value) + { + RaisePropertyChanging("FloatingWidth"); + _floatingWidth = value; + RaisePropertyChanged("FloatingWidth"); + } + } + } + + #endregion + + #region FloatingHeight + + private double _floatingHeight = 0.0; + public double FloatingHeight + { + get { return _floatingHeight; } + set + { + if (_floatingHeight != value) + { + RaisePropertyChanging("FloatingHeight"); + _floatingHeight = value; + RaisePropertyChanged("FloatingHeight"); + } + } + } + + #endregion + + #region FloatingLeft + + private double _floatingLeft = 0.0; + public double FloatingLeft + { + get { return _floatingLeft; } + set + { + if (_floatingLeft != value) + { + RaisePropertyChanging("FloatingLeft"); + _floatingLeft = value; + RaisePropertyChanged("FloatingLeft"); + } + } + } + + #endregion + + #region FloatingTop + + private double _floatingTop = 0.0; + public double FloatingTop + { + get { return _floatingTop; } + set + { + if (_floatingTop != value) + { + RaisePropertyChanging("FloatingTop"); + _floatingTop = value; + RaisePropertyChanged("FloatingTop"); + } + } + } + + #endregion + + #region IsMaximized + + private bool _isMaximized = false; + public bool IsMaximized + { + get { return _isMaximized; } + set + { + if (_isMaximized != value) + { + RaisePropertyChanging("IsMaximized"); + _isMaximized = value; + RaisePropertyChanged("IsMaximized"); + } + } + } + + #endregion + + #region ToolTip + + private object _toolTip = null; + public object ToolTip + { + get { return _toolTip; } + set + { + if (_toolTip != value) + { + _toolTip = value; + RaisePropertyChanged("ToolTip"); + } + } + } + + #endregion + + public bool IsFloating + { + get { return this.FindParent() != null; } + } + + #region IconSource + + private ImageSource _iconSource = null; + public ImageSource IconSource + { + get { return _iconSource; } + set + { + if (_iconSource != value) + { + _iconSource = value; + RaisePropertyChanged("IconSource"); + } + } + } + + #endregion + + public int CompareTo(LayoutContent other) + { + var contentAsComparable = Content as IComparable; + if (contentAsComparable != null) + { + return contentAsComparable.CompareTo(other.Content); + } + + return string.Compare(Title, other.Title); + } + + /// + /// Float the content in a popup window + /// + public void Float() + { + if (PreviousContainer != null && + PreviousContainer.FindParent() != null) + { + + var currentContainer = Parent as ILayoutPane; + var currentContainerIndex = (currentContainer as ILayoutGroup).IndexOfChild(this); + var previousContainerAsLayoutGroup = PreviousContainer as ILayoutGroup; + + if (PreviousContainerIndex < previousContainerAsLayoutGroup.ChildrenCount) + previousContainerAsLayoutGroup.InsertChildAt(PreviousContainerIndex, this); + else + previousContainerAsLayoutGroup.InsertChildAt(previousContainerAsLayoutGroup.ChildrenCount, this); + + PreviousContainer = currentContainer; + PreviousContainerIndex = currentContainerIndex; + + IsSelected = true; + IsActive = true; + + Root.CollectGarbage(); + } + else + { + Root.Manager.StartDraggingFloatingWindowForContent(this, false); + + IsSelected = true; + IsActive = true; + } + + } + + /// + /// Dock the content as document + /// + public void DockAsDocument() + { + var root = Root as LayoutRoot; + if (root == null) + throw new InvalidOperationException(); + if (Parent is LayoutDocumentPane) + return; + + if (PreviousContainer is LayoutDocumentPane) + { + Dock(); + return; + } + + LayoutDocumentPane newParentPane; + if (root.LastFocusedDocument != null) + { + newParentPane = root.LastFocusedDocument.Parent as LayoutDocumentPane; + } + else + { + newParentPane = root.Descendents().OfType().FirstOrDefault(); + } + + if (newParentPane != null) + { + newParentPane.Children.Add(this); + root.CollectGarbage(); + } + + IsSelected = true; + IsActive = true; + } + + /// + /// Re-dock the content to its previous container + /// + public void Dock() + { + if (PreviousContainer != null) + { + var currentContainer = Parent as ILayoutContainer; + var currentContainerIndex = (currentContainer is ILayoutGroup) ? (currentContainer as ILayoutGroup).IndexOfChild(this) : -1; + var previousContainerAsLayoutGroup = PreviousContainer as ILayoutGroup; + + if (PreviousContainerIndex < previousContainerAsLayoutGroup.ChildrenCount) + previousContainerAsLayoutGroup.InsertChildAt(PreviousContainerIndex, this); + else + previousContainerAsLayoutGroup.InsertChildAt(previousContainerAsLayoutGroup.ChildrenCount, this); + + if (currentContainerIndex > -1) + { + PreviousContainer = currentContainer; + PreviousContainerIndex = currentContainerIndex; + } + else + { + PreviousContainer = null; + PreviousContainerIndex = 0; + } + + IsSelected = true; + IsActive = true; + } + else + { + InternalDock(); + } + + + Root.CollectGarbage(); + + } + + protected virtual void InternalDock() + { + + } + + + #region CanClose + + private bool _canClose = true; + public bool CanClose + { + get { return _canClose; } + set + { + if (_canClose != value) + { + _canClose = value; + RaisePropertyChanged("CanClose"); + } + } + } + + #endregion + + #region CanFloat + + private bool _canFloat = true; + public bool CanFloat + { + get { return _canFloat; } + set + { + if (_canFloat != value) + { + _canFloat = value; + RaisePropertyChanged("CanFloat"); + } + } + } + + #endregion + + #region IsEnabled + + private bool _isEnabled = true; + public bool IsEnabled + { + get + { + return _isEnabled; + } + set + { + if( _isEnabled != value ) + { + _isEnabled = value; + RaisePropertyChanged( "IsEnabled" ); + } + } + } + + #endregion + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocument.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocument.cs new file mode 100644 index 0000000..04b35c6 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocument.cs @@ -0,0 +1,141 @@ +/************************************************************************************* + + 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.Globalization; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [Serializable] + public class LayoutDocument : LayoutContent + { + public bool IsVisible + { + get { return true; } + } + + #region Description + + private string _description = null; + public string Description + { + get { return _description; } + set + { + if (_description != value) + { + _description = value; + RaisePropertyChanged("Description"); + } + } + } + + #endregion + + public override void WriteXml(System.Xml.XmlWriter writer) + { + base.WriteXml(writer); + + if (!string.IsNullOrWhiteSpace(Description)) + writer.WriteAttributeString("Description", Description); + + } + + public override void ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToAttribute("Description")) + Description = reader.Value; + + base.ReadXml(reader); + } + + public override void Close() + { + if( ( this.Root != null ) && ( this.Root.Manager != null ) ) + { + var dockingManager = this.Root.Manager; + dockingManager._ExecuteCloseCommand( this ); + } + else + { + this.CloseDocument(); + } + } + + internal bool CloseDocument() + { + if( this.TestCanClose() ) + { + this.CloseInternal(); + return true; + } + + return false; + } + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( "Document()" ); + } +#endif + + + protected override void InternalDock() + { + var root = Root as LayoutRoot; + LayoutDocumentPane documentPane = null; + if (root.LastFocusedDocument != null && + root.LastFocusedDocument != this) + { + documentPane = root.LastFocusedDocument.Parent as LayoutDocumentPane; + } + + if (documentPane == null) + { + documentPane = root.Descendents().OfType().FirstOrDefault(); + } + + + bool added = false; + if (root.Manager.LayoutUpdateStrategy != null) + { + added = root.Manager.LayoutUpdateStrategy.BeforeInsertDocument(root, this, documentPane); + } + + if (!added) + { + if (documentPane == null) + throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + + documentPane.Children.Add(this); + added = true; + } + + if (root.Manager.LayoutUpdateStrategy != null) + { + root.Manager.LayoutUpdateStrategy.AfterInsertDocument(root, this); + } + + + base.InternalDock(); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentFloatingWindow.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentFloatingWindow.cs new file mode 100644 index 0000000..d28f18c --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentFloatingWindow.cs @@ -0,0 +1,107 @@ +/************************************************************************************* + + 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.Markup; +using System.Diagnostics; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty("RootDocument")] + [Serializable] + public class LayoutDocumentFloatingWindow : LayoutFloatingWindow + { + public LayoutDocumentFloatingWindow() + { + + } + + #region RootDocument + + private LayoutDocument _rootDocument = null; + public LayoutDocument RootDocument + { + get { return _rootDocument; } + set + { + if (_rootDocument != value) + { + RaisePropertyChanging("RootDocument"); + _rootDocument = value; + if (_rootDocument != null) + _rootDocument.Parent = this; + RaisePropertyChanged("RootDocument"); + + if (RootDocumentChanged != null) + RootDocumentChanged(this, EventArgs.Empty); + } + } + } + + + public event EventHandler RootDocumentChanged; + + #endregion + + public override IEnumerable Children + { + get + { + if (RootDocument == null) + yield break; + + yield return RootDocument; + } + } + + public override void RemoveChild(ILayoutElement element) + { + Debug.Assert(element == RootDocument && element != null); + RootDocument = null; + } + + public override void ReplaceChild(ILayoutElement oldElement, ILayoutElement newElement) + { + Debug.Assert(oldElement == RootDocument && oldElement != null); + RootDocument = newElement as LayoutDocument; + } + + public override int ChildrenCount + { + get { return RootDocument != null ? 1 : 0; } + } + + public override bool IsValid + { + get { return RootDocument != null; } + } + + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( "FloatingDocumentWindow()" ); + + RootDocument.ConsoleDump(tab + 1); + } +#endif + } + +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPane.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPane.cs new file mode 100644 index 0000000..3ff3e43 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPane.cs @@ -0,0 +1,235 @@ +/************************************************************************************* + + 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.Collections.ObjectModel; +using System.Windows.Markup; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty( "Children" )] + [Serializable] + public class LayoutDocumentPane : LayoutPositionableGroup, ILayoutDocumentPane, ILayoutPositionableElement, ILayoutContentSelector, ILayoutPaneSerializable + { + public LayoutDocumentPane() + { + } + public LayoutDocumentPane( LayoutContent firstChild ) + { + Children.Add( firstChild ); + } + + protected override bool GetVisibility() + { + if( Parent is LayoutDocumentPaneGroup ) + return ChildrenCount > 0; + + return true; + } + + #region ShowHeader + + private bool _showHeader = true; + public bool ShowHeader + { + get + { + return _showHeader; + } + set + { + if( value != _showHeader ) + { + _showHeader = value; + RaisePropertyChanged( "ShowHeader" ); + } + } + } + + #endregion + + #region SelectedContentIndex + + private int _selectedIndex = -1; + public int SelectedContentIndex + { + get + { + return _selectedIndex; + } + set + { + if( value < 0 || + value >= Children.Count ) + value = -1; + + if( _selectedIndex != value ) + { + RaisePropertyChanging( "SelectedContentIndex" ); + RaisePropertyChanging( "SelectedContent" ); + if( _selectedIndex >= 0 && + _selectedIndex < Children.Count ) + Children[ _selectedIndex ].IsSelected = false; + + _selectedIndex = value; + + if( _selectedIndex >= 0 && + _selectedIndex < Children.Count ) + Children[ _selectedIndex ].IsSelected = true; + + RaisePropertyChanged( "SelectedContentIndex" ); + RaisePropertyChanged( "SelectedContent" ); + } + } + } + + protected override void ChildMoved( int oldIndex, int newIndex ) + { + if( _selectedIndex == oldIndex ) + { + RaisePropertyChanging( "SelectedContentIndex" ); + _selectedIndex = newIndex; + RaisePropertyChanged( "SelectedContentIndex" ); + } + + + base.ChildMoved( oldIndex, newIndex ); + } + + public LayoutContent SelectedContent + { + get + { + return _selectedIndex == -1 ? null : Children[ _selectedIndex ]; + } + } + #endregion + + protected override void OnChildrenCollectionChanged() + { + if( SelectedContentIndex >= ChildrenCount ) + SelectedContentIndex = Children.Count - 1; + if( SelectedContentIndex == -1 && ChildrenCount > 0 ) + { + if( Root == null ) + { + SetNextSelectedIndex(); + } + else + { + var childrenToSelect = Children.OrderByDescending( c => c.LastActivationTimeStamp.GetValueOrDefault() ).First(); + SelectedContentIndex = Children.IndexOf( childrenToSelect ); + childrenToSelect.IsActive = true; + } + } + + base.OnChildrenCollectionChanged(); + + RaisePropertyChanged( "ChildrenSorted" ); + } + + public int IndexOf( LayoutContent content ) + { + return Children.IndexOf( content ); + } + + protected override void OnIsVisibleChanged() + { + UpdateParentVisibility(); + base.OnIsVisibleChanged(); + } + + internal void SetNextSelectedIndex() + { + SelectedContentIndex = -1; + for( int i = 0; i < this.Children.Count; ++i ) + { + if( Children[ i ].IsEnabled ) + { + SelectedContentIndex = i; + return; + } + } + } + + void UpdateParentVisibility() + { + var parentPane = Parent as ILayoutElementWithVisibility; + if( parentPane != null ) + parentPane.ComputeVisibility(); + } + + public IEnumerable ChildrenSorted + { + get + { + var listSorted = Children.ToList(); + listSorted.Sort(); + return listSorted; + } + } + + string _id; + string ILayoutPaneSerializable.Id + { + get + { + return _id; + } + set + { + _id = value; + } + } + + public override void WriteXml( System.Xml.XmlWriter writer ) + { + if( _id != null ) + writer.WriteAttributeString( "Id", _id ); + if( !_showHeader ) + writer.WriteAttributeString( "ShowHeader", _showHeader.ToString() ); + + base.WriteXml( writer ); + } + + public override void ReadXml( System.Xml.XmlReader reader ) + { + if( reader.MoveToAttribute( "Id" ) ) + _id = reader.Value; + if( reader.MoveToAttribute( "ShowHeader" ) ) + _showHeader = bool.Parse( reader.Value ); + + + base.ReadXml( reader ); + } + + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( "DocumentPane()" ); + + foreach (LayoutElement child in Children) + child.ConsoleDump(tab + 1); + } +#endif + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPaneGroup.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPaneGroup.cs new file mode 100644 index 0000000..cd3bc85 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutDocumentPaneGroup.cs @@ -0,0 +1,89 @@ +/************************************************************************************* + + 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.Collections.ObjectModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Markup; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty("Children")] + [Serializable] + public class LayoutDocumentPaneGroup : LayoutPositionableGroup, ILayoutDocumentPane, ILayoutOrientableGroup + { + public LayoutDocumentPaneGroup() + { + } + + public LayoutDocumentPaneGroup(LayoutDocumentPane documentPane) + { + Children.Add(documentPane); + } + + #region Orientation + + private Orientation _orientation; + public Orientation Orientation + { + get { return _orientation; } + set + { + if (_orientation != value) + { + RaisePropertyChanging("Orientation"); + _orientation = value; + RaisePropertyChanged("Orientation"); + } + } + } + + #endregion + + protected override bool GetVisibility() + { + return true; + } + + public override void WriteXml(System.Xml.XmlWriter writer) + { + writer.WriteAttributeString("Orientation", Orientation.ToString()); + base.WriteXml(writer); + } + + public override void ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToAttribute("Orientation")) + Orientation = (Orientation)Enum.Parse(typeof(Orientation), reader.Value, true); + base.ReadXml(reader); + } + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( string.Format( "DocumentPaneGroup({0})", Orientation ) ); + + foreach (LayoutElement child in Children) + child.ConsoleDump(tab + 1); + } +#endif + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutElement.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutElement.cs new file mode 100644 index 0000000..8753bd1 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutElement.cs @@ -0,0 +1,138 @@ +/************************************************************************************* + + 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; +using System.ComponentModel; +using System.Xml.Serialization; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [Serializable] + public abstract class LayoutElement : DependencyObject, ILayoutElement + { + internal LayoutElement() + { } + + #region Parent + + [NonSerialized] + private ILayoutContainer _parent = null; + [NonSerialized] + private ILayoutRoot _root = null; + [XmlIgnore] + public ILayoutContainer Parent + { + get { return _parent; } + set + { + if (_parent != value) + { + ILayoutContainer oldValue = _parent; + ILayoutRoot oldRoot = _root; + RaisePropertyChanging("Parent"); + OnParentChanging(oldValue, value); + _parent = value; + OnParentChanged(oldValue, value); + + _root = Root; + if (oldRoot != _root) + OnRootChanged(oldRoot, _root); + + RaisePropertyChanged("Parent"); + + var root = Root as LayoutRoot; + if (root != null) + root.FireLayoutUpdated(); + } + } + } + + /// + /// Provides derived classes an opportunity to handle execute code before to the Parent property changes. + /// + protected virtual void OnParentChanging(ILayoutContainer oldValue, ILayoutContainer newValue) + { + } + + /// + /// Provides derived classes an opportunity to handle changes to the Parent property. + /// + protected virtual void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue) + { + + } + + + protected virtual void OnRootChanged(ILayoutRoot oldRoot, ILayoutRoot newRoot) + { + if (oldRoot != null) + ((LayoutRoot)oldRoot).OnLayoutElementRemoved(this); + if (newRoot != null) + ((LayoutRoot)newRoot).OnLayoutElementAdded(this); + } + + + #endregion + + [field: NonSerialized] + [field: XmlIgnore] + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void RaisePropertyChanged(string propertyName) + { + if (PropertyChanged != null) + PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + + [field: NonSerialized] + [field: XmlIgnore] + public event PropertyChangingEventHandler PropertyChanging; + + protected virtual void RaisePropertyChanging(string propertyName) + { + if (PropertyChanging != null) + PropertyChanging(this, new System.ComponentModel.PropertyChangingEventArgs(propertyName)); + } + + public ILayoutRoot Root + { + get + { + var parent = Parent; + + while (parent != null && (!(parent is ILayoutRoot))) + { + parent = parent.Parent; + } + + return parent as ILayoutRoot; + } + } + + +#if TRACE + public virtual void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new String( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( this.ToString() ); + } +#endif + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutElementEventArgs.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutElementEventArgs.cs new file mode 100644 index 0000000..17371e8 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutElementEventArgs.cs @@ -0,0 +1,38 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + public class LayoutElementEventArgs : EventArgs + { + public LayoutElementEventArgs(LayoutElement element) + { + Element = element; + } + + + public LayoutElement Element + { + get; + private set; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutFloatingWindow.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutFloatingWindow.cs new file mode 100644 index 0000000..b9df9d1 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutFloatingWindow.cs @@ -0,0 +1,52 @@ +/************************************************************************************* + + 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.Markup; +using System.Windows; +using System.Xml.Serialization; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [Serializable] + [XmlInclude(typeof(LayoutAnchorableFloatingWindow))] + [XmlInclude(typeof(LayoutDocumentFloatingWindow))] + public abstract class LayoutFloatingWindow : LayoutElement, ILayoutContainer + { + public LayoutFloatingWindow() + { + + } + + + public abstract IEnumerable Children { get; } + + public abstract void RemoveChild(ILayoutElement element); + + public abstract void ReplaceChild(ILayoutElement oldElement, ILayoutElement newElement); + + public abstract int ChildrenCount { get; } + + public abstract bool IsValid { get; } + + + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutGroup.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutGroup.cs new file mode 100644 index 0000000..99f1b32 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutGroup.cs @@ -0,0 +1,269 @@ +/************************************************************************************* + + 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.Collections.ObjectModel; +using System.Xml.Serialization; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [Serializable] + public abstract class LayoutGroup : LayoutGroupBase, ILayoutContainer, ILayoutGroup, IXmlSerializable where T : class, ILayoutElement + { + internal LayoutGroup() + { + _children.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_children_CollectionChanged); + } + + void _children_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.OldItems != null) + { + foreach (LayoutElement element in e.OldItems) + { + if (element.Parent == this) + element.Parent = null; + } + } + } + + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.NewItems != null) + { + foreach (LayoutElement element in e.NewItems) + { + if (element.Parent != this) + { + if (element.Parent != null) + element.Parent.RemoveChild(element); + element.Parent = this; + } + + } + } + } + + ComputeVisibility(); + OnChildrenCollectionChanged(); + NotifyChildrenTreeChanged(ChildrenTreeChange.DirectChildrenChanged); + RaisePropertyChanged("ChildrenCount"); + } + + ObservableCollection _children = new ObservableCollection(); + + public ObservableCollection Children + { + get { return _children; } + } + + IEnumerable ILayoutContainer.Children + { + get { return _children.Cast(); } + } + + + #region IsVisible + + private bool _isVisible = true; + public bool IsVisible + { + get { return _isVisible; } + protected set + { + if (_isVisible != value) + { + RaisePropertyChanging("IsVisible"); + _isVisible = value; + OnIsVisibleChanged(); + RaisePropertyChanged("IsVisible"); + } + } + } + + protected virtual void OnIsVisibleChanged() + { + UpdateParentVisibility(); + } + + void UpdateParentVisibility() + { + var parentPane = Parent as ILayoutElementWithVisibility; + if (parentPane != null) + parentPane.ComputeVisibility(); + } + + + public void ComputeVisibility() + { + IsVisible = GetVisibility(); + } + + protected abstract bool GetVisibility(); + + protected override void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue) + { + base.OnParentChanged(oldValue, newValue); + + ComputeVisibility(); + } + + #endregion + + + public void MoveChild(int oldIndex, int newIndex) + { + if (oldIndex == newIndex) + return; + _children.Move(oldIndex, newIndex); + ChildMoved(oldIndex, newIndex); + } + + protected virtual void ChildMoved(int oldIndex, int newIndex) + { + + } + + public void RemoveChildAt(int childIndex) + { + _children.RemoveAt(childIndex); + } + + public int IndexOfChild(ILayoutElement element) + { + return _children.Cast().ToList().IndexOf(element); + } + + public void InsertChildAt(int index, ILayoutElement element) + { + _children.Insert(index, (T)element); + } + + public void RemoveChild(ILayoutElement element) + { + _children.Remove((T)element); + } + + public void ReplaceChild(ILayoutElement oldElement, ILayoutElement newElement) + { + int index = _children.IndexOf((T)oldElement); + _children.Insert(index, (T)newElement); + _children.RemoveAt(index + 1); + } + + public int ChildrenCount + { + get { return _children.Count; } + } + + public void ReplaceChildAt(int index, ILayoutElement element) + { + _children[index] = (T)element; + } + + + public System.Xml.Schema.XmlSchema GetSchema() + { + return null; + } + + public virtual void ReadXml(System.Xml.XmlReader reader) + { + reader.MoveToContent(); + if (reader.IsEmptyElement) + { + reader.Read(); + ComputeVisibility(); + return; + } + string localName = reader.LocalName; + reader.Read(); + while (true) + { + if ( (reader.LocalName == localName ) && + ( reader.NodeType == System.Xml.XmlNodeType.EndElement) ) + { + break; + } + if( reader.NodeType == System.Xml.XmlNodeType.Whitespace ) + { + reader.Read(); + continue; + } + + XmlSerializer serializer = null; + if (reader.LocalName == "LayoutAnchorablePaneGroup") + serializer = new XmlSerializer(typeof(LayoutAnchorablePaneGroup)); + else if (reader.LocalName == "LayoutAnchorablePane") + serializer = new XmlSerializer(typeof(LayoutAnchorablePane)); + else if (reader.LocalName == "LayoutAnchorable") + serializer = new XmlSerializer(typeof(LayoutAnchorable)); + else if (reader.LocalName == "LayoutDocumentPaneGroup") + serializer = new XmlSerializer(typeof(LayoutDocumentPaneGroup)); + else if (reader.LocalName == "LayoutDocumentPane") + serializer = new XmlSerializer(typeof(LayoutDocumentPane)); + else if (reader.LocalName == "LayoutDocument") + serializer = new XmlSerializer(typeof(LayoutDocument)); + else if (reader.LocalName == "LayoutAnchorGroup") + serializer = new XmlSerializer(typeof(LayoutAnchorGroup)); + else if (reader.LocalName == "LayoutPanel") + serializer = new XmlSerializer(typeof(LayoutPanel)); + else + { + Type type = this.FindType( reader.LocalName ); + if( type == null ) + throw new ArgumentException( "AvalonDock.LayoutGroup doesn't know how to deserialize " + reader.LocalName ); + serializer = new XmlSerializer( type ); + } + + Children.Add((T)serializer.Deserialize(reader)); + } + + reader.ReadEndElement(); + } + + public virtual void WriteXml(System.Xml.XmlWriter writer) + { + foreach (var child in Children) + { + var type = child.GetType(); + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, child); + } + + } + + private Type FindType( string name ) + { + foreach( var a in AppDomain.CurrentDomain.GetAssemblies() ) + { + foreach( var t in a.GetTypes() ) + { + if( t.Name.Equals( name ) ) + return t; + } + } + return null; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutGroupBase.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutGroupBase.cs new file mode 100644 index 0000000..d62a6fe --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutGroupBase.cs @@ -0,0 +1,58 @@ +/************************************************************************************* + + 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.Xml.Serialization; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [Serializable] + public abstract class LayoutGroupBase : LayoutElement + { + [field: NonSerialized] + [field: XmlIgnore] + public event EventHandler ChildrenCollectionChanged; + + protected virtual void OnChildrenCollectionChanged() + { + if (ChildrenCollectionChanged != null) + ChildrenCollectionChanged(this, EventArgs.Empty); + } + + protected void NotifyChildrenTreeChanged(ChildrenTreeChange change) + { + OnChildrenTreeChanged(change); + var parentGroup = Parent as LayoutGroupBase; + if (parentGroup != null) + parentGroup.NotifyChildrenTreeChanged(ChildrenTreeChange.TreeChanged); + } + + [field: NonSerialized] + [field: XmlIgnore] + public event EventHandler ChildrenTreeChanged; + + protected virtual void OnChildrenTreeChanged(ChildrenTreeChange change) + { + if (ChildrenTreeChanged != null) + ChildrenTreeChanged(this, new ChildrenTreeChangedEventArgs(change)); + } + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutPanel.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutPanel.cs new file mode 100644 index 0000000..e58f6e9 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutPanel.cs @@ -0,0 +1,92 @@ +/************************************************************************************* + + 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.Markup; +using System.Collections.ObjectModel; +using System.Windows; +using System.Windows.Controls; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty("Children")] + [Serializable] + public class LayoutPanel : LayoutPositionableGroup, ILayoutPanelElement, ILayoutOrientableGroup + { + public LayoutPanel() + { + + } + + public LayoutPanel(ILayoutPanelElement firstChild) + { + Children.Add(firstChild); + } + + + #region Orientation + + private Orientation _orientation; + public Orientation Orientation + { + get { return _orientation; } + set + { + if (_orientation != value) + { + RaisePropertyChanging("Orientation"); + _orientation = value; + RaisePropertyChanged("Orientation"); + } + } + } + + #endregion + + + protected override bool GetVisibility() + { + return Children.Any(c => c.IsVisible); + } + + public override void WriteXml(System.Xml.XmlWriter writer) + { + writer.WriteAttributeString("Orientation", Orientation.ToString()); + base.WriteXml(writer); + } + + public override void ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToAttribute("Orientation")) + Orientation = (Orientation)Enum.Parse(typeof(Orientation), reader.Value, true); + base.ReadXml(reader); + } + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( string.Format( "Panel({0})", Orientation ) ); + + foreach (LayoutElement child in Children) + child.ConsoleDump(tab + 1); + } +#endif + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutPositionableGroup.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutPositionableGroup.cs new file mode 100644 index 0000000..54683b7 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutPositionableGroup.cs @@ -0,0 +1,322 @@ +/************************************************************************************* + + 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; +using System.Globalization; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [Serializable] + public abstract class LayoutPositionableGroup : LayoutGroup, ILayoutPositionableElement, ILayoutPositionableElementWithActualSize where T : class, ILayoutElement + { + public LayoutPositionableGroup() + { } + + GridLength _dockWidth = new GridLength(1.0, GridUnitType.Star); + public GridLength DockWidth + { + get + { + return _dockWidth; + } + set + { + if (DockWidth != value) + { + RaisePropertyChanging("DockWidth"); + _dockWidth = value; + RaisePropertyChanged("DockWidth"); + + OnDockWidthChanged(); + } + } + } + + + protected virtual void OnDockWidthChanged() + { + + } + + GridLength _dockHeight = new GridLength(1.0, GridUnitType.Star); + public GridLength DockHeight + { + get + { + return _dockHeight; + } + set + { + if (DockHeight != value) + { + RaisePropertyChanging("DockHeight"); + _dockHeight = value; + RaisePropertyChanged("DockHeight"); + + OnDockHeightChanged(); + } + } + } + + protected virtual void OnDockHeightChanged() + { + + } + + #region CanRepositionItems + + private bool _canRepositionItems = true; + public bool CanRepositionItems + { + get + { + return _canRepositionItems; + } + set + { + if( _canRepositionItems != value ) + { + RaisePropertyChanging( "CanRepositionItems" ); + _canRepositionItems = value; + RaisePropertyChanged( "CanRepositionItems" ); + } + } + } + + #endregion + + + #region DockMinWidth + + private double _dockMinWidth = 25.0; + public double DockMinWidth + { + get { return _dockMinWidth; } + set + { + if (_dockMinWidth != value) + { + MathHelper.AssertIsPositiveOrZero(value); + RaisePropertyChanging("DockMinWidth"); + _dockMinWidth = value; + RaisePropertyChanged("DockMinWidth"); + } + } + } + + #endregion + + #region DockMinHeight + + private double _dockMinHeight = 25.0; + public double DockMinHeight + { + get { return _dockMinHeight; } + set + { + if (_dockMinHeight != value) + { + MathHelper.AssertIsPositiveOrZero(value); + RaisePropertyChanging("DockMinHeight"); + _dockMinHeight = value; + RaisePropertyChanged("DockMinHeight"); + } + } + } + + #endregion + + #region FloatingWidth + + private double _floatingWidth = 0.0; + public double FloatingWidth + { + get { return _floatingWidth; } + set + { + if (_floatingWidth != value) + { + RaisePropertyChanging("FloatingWidth"); + _floatingWidth = value; + RaisePropertyChanged("FloatingWidth"); + } + } + } + + #endregion + + #region FloatingHeight + + private double _floatingHeight = 0.0; + public double FloatingHeight + { + get { return _floatingHeight; } + set + { + if (_floatingHeight != value) + { + RaisePropertyChanging("FloatingHeight"); + _floatingHeight = value; + RaisePropertyChanged("FloatingHeight"); + } + } + } + + #endregion + + #region FloatingLeft + + private double _floatingLeft = 0.0; + public double FloatingLeft + { + get { return _floatingLeft; } + set + { + if (_floatingLeft != value) + { + RaisePropertyChanging("FloatingLeft"); + _floatingLeft = value; + RaisePropertyChanged("FloatingLeft"); + } + } + } + + #endregion + + #region FloatingTop + + private double _floatingTop = 0.0; + public double FloatingTop + { + get { return _floatingTop; } + set + { + if (_floatingTop != value) + { + RaisePropertyChanging("FloatingTop"); + _floatingTop = value; + RaisePropertyChanged("FloatingTop"); + } + } + } + + #endregion + + #region IsMaximized + + private bool _isMaximized = false; + public bool IsMaximized + { + get { return _isMaximized; } + set + { + if (_isMaximized != value) + { + _isMaximized = value; + RaisePropertyChanged("IsMaximized"); + } + } + } + + #endregion + + + [NonSerialized] + double _actualWidth; + double ILayoutPositionableElementWithActualSize.ActualWidth + { + get + { + return _actualWidth; + } + set + { + _actualWidth = value; + } + } + + [NonSerialized] + double _actualHeight; + double ILayoutPositionableElementWithActualSize.ActualHeight + { + get + { + return _actualHeight; + } + set + { + _actualHeight = value; + } + } + + public override void WriteXml(System.Xml.XmlWriter writer) + { + if (DockWidth.Value != 1.0 || !DockWidth.IsStar) + writer.WriteAttributeString("DockWidth", _gridLengthConverter.ConvertToInvariantString(DockWidth)); + if (DockHeight.Value != 1.0 || !DockHeight.IsStar) + writer.WriteAttributeString("DockHeight", _gridLengthConverter.ConvertToInvariantString(DockHeight)); + + if (DockMinWidth != 25.0) + writer.WriteAttributeString("DocMinWidth", DockMinWidth.ToString(CultureInfo.InvariantCulture)); + if (DockMinHeight != 25.0) + writer.WriteAttributeString("DockMinHeight", DockMinHeight.ToString(CultureInfo.InvariantCulture)); + + if (FloatingWidth != 0.0) + writer.WriteAttributeString("FloatingWidth", FloatingWidth.ToString(CultureInfo.InvariantCulture)); + if (FloatingHeight != 0.0) + writer.WriteAttributeString("FloatingHeight", FloatingHeight.ToString(CultureInfo.InvariantCulture)); + if (FloatingLeft != 0.0) + writer.WriteAttributeString("FloatingLeft", FloatingLeft.ToString(CultureInfo.InvariantCulture)); + if (FloatingTop != 0.0) + writer.WriteAttributeString("FloatingTop", FloatingTop.ToString(CultureInfo.InvariantCulture)); + if( IsMaximized ) + writer.WriteAttributeString( "IsMaximized", IsMaximized.ToString() ); + + base.WriteXml(writer); + } + + static GridLengthConverter _gridLengthConverter = new GridLengthConverter(); + public override void ReadXml(System.Xml.XmlReader reader) + { + if (reader.MoveToAttribute("DockWidth")) + _dockWidth = (GridLength)_gridLengthConverter.ConvertFromInvariantString(reader.Value); + if (reader.MoveToAttribute("DockHeight")) + _dockHeight = (GridLength)_gridLengthConverter.ConvertFromInvariantString(reader.Value); + + if (reader.MoveToAttribute("DocMinWidth")) + _dockMinWidth = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("DocMinHeight")) + _dockMinHeight = double.Parse(reader.Value, CultureInfo.InvariantCulture); + + if (reader.MoveToAttribute("FloatingWidth")) + _floatingWidth = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("FloatingHeight")) + _floatingHeight = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("FloatingLeft")) + _floatingLeft = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if (reader.MoveToAttribute("FloatingTop")) + _floatingTop = double.Parse(reader.Value, CultureInfo.InvariantCulture); + if( reader.MoveToAttribute( "IsMaximized" ) ) + _isMaximized = bool.Parse( reader.Value ); + + base.ReadXml(reader); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs new file mode 100644 index 0000000..e618584 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs @@ -0,0 +1,689 @@ +/************************************************************************************* + + 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; +using System.Collections.ObjectModel; +using System.Windows.Markup; +using System.Xml.Serialization; +using Standard; + +namespace Xceed.Wpf.AvalonDock.Layout +{ + [ContentProperty("RootPanel")] + [Serializable] + public class LayoutRoot : LayoutElement, ILayoutContainer, ILayoutRoot + { + public LayoutRoot() + { + RightSide = new LayoutAnchorSide(); + LeftSide = new LayoutAnchorSide(); + TopSide = new LayoutAnchorSide(); + BottomSide = new LayoutAnchorSide(); + RootPanel = new LayoutPanel(new LayoutDocumentPane()); + } + + + #region RootPanel + + private LayoutPanel _rootPanel; + public LayoutPanel RootPanel + { + get { return _rootPanel; } + set + { + if (_rootPanel != value) + { + RaisePropertyChanging("RootPanel"); + if (_rootPanel != null && + _rootPanel.Parent == this) + _rootPanel.Parent = null; + _rootPanel = value; + + if (_rootPanel == null) + _rootPanel = new LayoutPanel(new LayoutDocumentPane()); + + if (_rootPanel != null) + _rootPanel.Parent = this; + RaisePropertyChanged("RootPanel"); + } + } + } + + #endregion + + #region TopSide + + private LayoutAnchorSide _topSide = null; + public LayoutAnchorSide TopSide + { + get { return _topSide; } + set + { + if (_topSide != value) + { + RaisePropertyChanging("TopSide"); + _topSide = value; + if (_topSide != null) + _topSide.Parent = this; + RaisePropertyChanged("TopSide"); + } + } + } + + #endregion + + #region RightSide + + private LayoutAnchorSide _rightSide; + public LayoutAnchorSide RightSide + { + get { return _rightSide; } + set + { + if (_rightSide != value) + { + RaisePropertyChanging("RightSide"); + _rightSide = value; + if (_rightSide != null) + _rightSide.Parent = this; + RaisePropertyChanged("RightSide"); + } + } + } + + #endregion + + #region LeftSide + + private LayoutAnchorSide _leftSide = null; + public LayoutAnchorSide LeftSide + { + get { return _leftSide; } + set + { + if (_leftSide != value) + { + RaisePropertyChanging("LeftSide"); + _leftSide = value; + if (_leftSide != null) + _leftSide.Parent = this; + RaisePropertyChanged("LeftSide"); + } + } + } + + #endregion + + #region BottomSide + + private LayoutAnchorSide _bottomSide = null; + public LayoutAnchorSide BottomSide + { + get { return _bottomSide; } + set + { + if (_bottomSide != value) + { + RaisePropertyChanging("BottomSide"); + _bottomSide = value; + if (_bottomSide != null) + _bottomSide.Parent = this; + RaisePropertyChanged("BottomSide"); + } + } + } + + #endregion + + #region FloatingWindows + ObservableCollection _floatingWindows = null; + + public ObservableCollection FloatingWindows + { + get + { + if (_floatingWindows == null) + { + _floatingWindows = new ObservableCollection(); + _floatingWindows.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_floatingWindows_CollectionChanged); + } + + return _floatingWindows; + } + } + + void _floatingWindows_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.OldItems != null && (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) + { + foreach (LayoutFloatingWindow element in e.OldItems) + { + if (element.Parent == this) + element.Parent = null; + } + } + + if (e.NewItems != null && (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) + { + foreach (LayoutFloatingWindow element in e.NewItems) + element.Parent = this; + } + } + #endregion + + #region HiddenAnchorables + + ObservableCollection _hiddenAnchorables = null; + + public ObservableCollection Hidden + { + get + { + if (_hiddenAnchorables == null) + { + _hiddenAnchorables = new ObservableCollection(); + _hiddenAnchorables.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_hiddenAnchorables_CollectionChanged); + } + + return _hiddenAnchorables; + } + } + + void _hiddenAnchorables_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.OldItems != null) + { + foreach (LayoutAnchorable element in e.OldItems) + { + if (element.Parent == this) + element.Parent = null; + } + } + } + + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) + { + if (e.NewItems != null) + { + foreach (LayoutAnchorable element in e.NewItems) + { + if (element.Parent != this) + { + if (element.Parent != null) + element.Parent.RemoveChild(element); + element.Parent = this; + } + + } + } + } + + + + } + + #endregion + + #region Children + public IEnumerable Children + { + get + { + if (RootPanel != null) + yield return RootPanel; + if (_floatingWindows != null) + { + foreach (var floatingWindow in _floatingWindows) + yield return floatingWindow; + } + if (TopSide != null) + yield return TopSide; + if (RightSide != null) + yield return RightSide; + if (BottomSide != null) + yield return BottomSide; + if (LeftSide != null) + yield return LeftSide; + if (_hiddenAnchorables != null) + { + foreach (var hiddenAnchorable in _hiddenAnchorables) + yield return hiddenAnchorable; + } + } + } + public void RemoveChild(ILayoutElement element) + { + if (element == RootPanel) + RootPanel = null; + else if (_floatingWindows != null && _floatingWindows.Contains(element)) + _floatingWindows.Remove(element as LayoutFloatingWindow); + else if (_hiddenAnchorables != null && _hiddenAnchorables.Contains(element)) + _hiddenAnchorables.Remove(element as LayoutAnchorable); + else if (element == TopSide) + TopSide = null; + else if (element == RightSide) + RightSide = null; + else if (element == BottomSide) + BottomSide = null; + else if (element == LeftSide) + LeftSide = null; + + } + + public void ReplaceChild(ILayoutElement oldElement, ILayoutElement newElement) + { + if (oldElement == RootPanel) + RootPanel = (LayoutPanel)newElement; + else if (_floatingWindows != null && _floatingWindows.Contains(oldElement)) + { + int index = _floatingWindows.IndexOf(oldElement as LayoutFloatingWindow); + _floatingWindows.Remove(oldElement as LayoutFloatingWindow); + _floatingWindows.Insert(index, newElement as LayoutFloatingWindow); + } + else if (_hiddenAnchorables != null && _hiddenAnchorables.Contains(oldElement)) + { + int index = _hiddenAnchorables.IndexOf(oldElement as LayoutAnchorable); + _hiddenAnchorables.Remove(oldElement as LayoutAnchorable); + _hiddenAnchorables.Insert(index, newElement as LayoutAnchorable); + } + else if (oldElement == TopSide) + TopSide = (LayoutAnchorSide)newElement; + else if (oldElement == RightSide) + RightSide = (LayoutAnchorSide)newElement; + else if (oldElement == BottomSide) + BottomSide = (LayoutAnchorSide)newElement; + else if (oldElement == LeftSide) + LeftSide = (LayoutAnchorSide)newElement; + } + + public int ChildrenCount + { + get + { + return 5 + + (_floatingWindows != null ? _floatingWindows.Count : 0) + + (_hiddenAnchorables != null ? _hiddenAnchorables.Count : 0); + } + } + #endregion + + #region ActiveContent + + [field:NonSerialized] + private WeakReference _activeContent = null; + private bool _activeContentSet = false; + + [XmlIgnore] + public LayoutContent ActiveContent + { + get { return _activeContent.GetValueOrDefault(); } + set + { + var currentValue = ActiveContent; + if (currentValue != value) + { + InternalSetActiveContent(currentValue, value); + } + } + } + + void InternalSetActiveContent(LayoutContent currentValue, LayoutContent newActiveContent) + { + RaisePropertyChanging("ActiveContent"); + if (currentValue != null) + currentValue.IsActive = false; + _activeContent = new WeakReference(newActiveContent); + currentValue = ActiveContent; + if (currentValue != null) + currentValue.IsActive = true; + RaisePropertyChanged("ActiveContent"); + _activeContentSet = currentValue != null; + if (currentValue != null) + { + if (currentValue.Parent is LayoutDocumentPane || currentValue is LayoutDocument) + LastFocusedDocument = currentValue; + } + else + LastFocusedDocument = null; + } + + void UpdateActiveContentProperty() + { + var activeContent = ActiveContent; + if (_activeContentSet && (activeContent == null || activeContent.Root != this)) + { + _activeContentSet = false; + InternalSetActiveContent(activeContent, null); + } + } + #endregion + + #region LastFocusedDocument + + [field: NonSerialized] + private WeakReference _lastFocusedDocument = null; + [field: NonSerialized] + private bool _lastFocusedDocumentSet = false; + + [XmlIgnore] + public LayoutContent LastFocusedDocument + { + get { return _lastFocusedDocument.GetValueOrDefault(); } + private set + { + var currentValue = LastFocusedDocument; + if (currentValue != value) + { + RaisePropertyChanging("LastFocusedDocument"); + if (currentValue != null) + currentValue.IsLastFocusedDocument = false; + _lastFocusedDocument = new WeakReference(value); + currentValue = LastFocusedDocument; + if (currentValue != null) + currentValue.IsLastFocusedDocument = true; + _lastFocusedDocumentSet = currentValue != null; + RaisePropertyChanged("LastFocusedDocument"); + } + } + } + + #endregion + + #region Manager + + + [NonSerialized] + private DockingManager _manager = null; + + [XmlIgnore] + public DockingManager Manager + { + get { return _manager; } + internal set + { + if (_manager != value) + { + RaisePropertyChanging("Manager"); + _manager = value; + RaisePropertyChanged("Manager"); + } + } + } + + #endregion + + #region CollectGarbage + + /// + /// Removes any empty container not directly referenced by other layout items + /// + public void CollectGarbage() + { + bool exitFlag = true; + + #region collect empty panes + do + { + exitFlag = true; + + //for each content that references via PreviousContainer a disconnected Pane set the property to null + foreach (var content in this.Descendents().OfType().Where(c => c.PreviousContainer != null && + (c.PreviousContainer.Parent == null || c.PreviousContainer.Parent.Root != this))) + { + content.PreviousContainer = null; + } + + //for each pane that is empty + foreach (var emptyPane in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) + { + //...set null any reference coming from contents not yet hosted in a floating window + foreach (var contentReferencingEmptyPane in this.Descendents().OfType() + .Where(c => ((ILayoutPreviousContainer)c).PreviousContainer == emptyPane && !c.IsFloating)) + { + if (contentReferencingEmptyPane is LayoutAnchorable && + !((LayoutAnchorable)contentReferencingEmptyPane).IsVisible) + continue; + + ((ILayoutPreviousContainer)contentReferencingEmptyPane).PreviousContainer = null; + contentReferencingEmptyPane.PreviousContainerIndex = -1; + } + + //...if this pane is the only documentpane present in the layout than skip it + if (emptyPane is LayoutDocumentPane && + this.Descendents().OfType().Count(c => c != emptyPane) == 0) + continue; + + //...if this empty panes is not referenced by anyone, than removes it from its parent container + if (!this.Descendents().OfType().Any(c => c.PreviousContainer == emptyPane)) + { + var parentGroup = emptyPane.Parent as ILayoutContainer; + parentGroup.RemoveChild(emptyPane); + exitFlag = false; + break; + } + } + + if (!exitFlag) + { + //removes any empty anchorable pane group + foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) + { + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + parentGroup.RemoveChild(emptyPaneGroup); + exitFlag = false; + break; + } + } + + if (!exitFlag) + { + //removes any empty layout panel + foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) + { + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + parentGroup.RemoveChild(emptyPaneGroup); + exitFlag = false; + break; + } + } + + if (!exitFlag) + { + //removes any empty floating window + foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) + { + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + parentGroup.RemoveChild(emptyPaneGroup); + exitFlag = false; + break; + } + } + + if (!exitFlag) + { + //removes any empty anchor group + foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) + { + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + parentGroup.RemoveChild(emptyPaneGroup); + exitFlag = false; + break; + } + } + + } + while (!exitFlag); + #endregion + + #region collapse single child anchorable pane groups + do + { + exitFlag = true; + //for each pane that is empty + foreach (var paneGroupToCollapse in this.Descendents().OfType().Where(p => p.ChildrenCount == 1 && p.Children[0] is LayoutAnchorablePaneGroup).ToArray()) + { + var singleChild = paneGroupToCollapse.Children[0] as LayoutAnchorablePaneGroup; + paneGroupToCollapse.Orientation = singleChild.Orientation; + paneGroupToCollapse.RemoveChild(singleChild); + while (singleChild.ChildrenCount > 0) + { + paneGroupToCollapse.InsertChildAt( + paneGroupToCollapse.ChildrenCount, singleChild.Children[0]); + } + + exitFlag = false; + break; + } + + } + while (!exitFlag); + + + + #endregion + + #region collapse single child document pane groups + do + { + exitFlag = true; + //for each pane that is empty + foreach (var paneGroupToCollapse in this.Descendents().OfType().Where(p => p.ChildrenCount == 1 && p.Children[0] is LayoutDocumentPaneGroup).ToArray()) + { + var singleChild = paneGroupToCollapse.Children[0] as LayoutDocumentPaneGroup; + paneGroupToCollapse.Orientation = singleChild.Orientation; + paneGroupToCollapse.RemoveChild(singleChild); + while (singleChild.ChildrenCount > 0) + { + paneGroupToCollapse.InsertChildAt( + paneGroupToCollapse.ChildrenCount, singleChild.Children[0]); + } + + exitFlag = false; + break; + } + + } + while (!exitFlag); + + + + #endregion + + //do + //{ + // exitFlag = true; + // //for each panel that has only one child + // foreach( var panelToCollapse in this.Descendents().OfType().Where( p => p.ChildrenCount == 1 && p.Children[ 0 ] is LayoutPanel ).ToArray() ) + // { + // var singleChild = panelToCollapse.Children[ 0 ] as LayoutPanel; + // panelToCollapse.Orientation = singleChild.Orientation; + // panelToCollapse.RemoveChild( singleChild ); + // ILayoutPanelElement[] singleChildChildren = new ILayoutPanelElement[ singleChild.ChildrenCount ]; + // singleChild.Children.CopyTo( singleChildChildren, 0 ); + // while( singleChild.ChildrenCount > 0 ) + // { + // panelToCollapse.InsertChildAt( + // panelToCollapse.ChildrenCount, singleChildChildren[ panelToCollapse.ChildrenCount ] ); + // } + + // exitFlag = false; + // break; + // } + + //} + //while( !exitFlag ); + + #region Update ActiveContent and LastFocusedDocument properties + UpdateActiveContentProperty(); + #endregion +#if DEBUG + System.Diagnostics.Debug.Assert( + !this.Descendents().OfType().Any(a => a.ChildrenCount == 0 && a.IsVisible)); +#if TRACE + RootPanel.ConsoleDump(4); +#endif +#endif + } + + #endregion + + public event EventHandler Updated; + + internal void FireLayoutUpdated() + { + if (Updated != null) + Updated(this, EventArgs.Empty); + } + + #region LayoutElement Added/Removed events + + internal void OnLayoutElementAdded(LayoutElement element) + { + if (ElementAdded != null) + ElementAdded(this, new LayoutElementEventArgs(element)); + } + + public event EventHandler ElementAdded; + + internal void OnLayoutElementRemoved(LayoutElement element) + { + if (element.Descendents().OfType().Any(c => c == LastFocusedDocument)) + LastFocusedDocument = null; + if (element.Descendents().OfType().Any(c => c == ActiveContent)) + ActiveContent = null; + if (ElementRemoved != null) + ElementRemoved(this, new LayoutElementEventArgs(element)); + } + + public event EventHandler ElementRemoved; + + #endregion + +#if TRACE + public override void ConsoleDump(int tab) + { + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( "RootPanel()" ); + + RootPanel.ConsoleDump(tab + 1); + + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( "FloatingWindows()" ); + + foreach (LayoutFloatingWindow fw in FloatingWindows) + fw.ConsoleDump(tab + 1); + + System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) ); + System.Diagnostics.Trace.WriteLine( "Hidden()" ); + + foreach (LayoutAnchorable hidden in Hidden) + hidden.ConsoleDump(tab + 1); + } +#endif + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/Serialization/LayoutSerializationCallbackEventArgs.cs b/Src/Xceed.Wpf.AvalonDock/Layout/Serialization/LayoutSerializationCallbackEventArgs.cs new file mode 100644 index 0000000..f428d4f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/Serialization/LayoutSerializationCallbackEventArgs.cs @@ -0,0 +1,38 @@ +/************************************************************************************* + + 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.ComponentModel; + +namespace Xceed.Wpf.AvalonDock.Layout.Serialization +{ + public class LayoutSerializationCallbackEventArgs : CancelEventArgs + { + public LayoutSerializationCallbackEventArgs(LayoutContent model, object previousContent) + { + Cancel = false; + Model = model; + Content = previousContent; + } + + public LayoutContent Model { get; private set; } + + public object Content { get; set; } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/Serialization/LayoutSerializer.cs b/Src/Xceed.Wpf.AvalonDock/Layout/Serialization/LayoutSerializer.cs new file mode 100644 index 0000000..f7a467b --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/Serialization/LayoutSerializer.cs @@ -0,0 +1,138 @@ +/************************************************************************************* + + 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.IO; +using Xceed.Wpf.AvalonDock.Controls; +using System.Windows; + +namespace Xceed.Wpf.AvalonDock.Layout.Serialization +{ + public abstract class LayoutSerializer + { + DockingManager _manager; + + public LayoutSerializer(DockingManager manager) + { + if (manager == null) + throw new ArgumentNullException("manager"); + + _manager = manager; + _previousAnchorables = _manager.Layout.Descendents().OfType().ToArray(); + _previousDocuments = _manager.Layout.Descendents().OfType().ToArray(); + } + + LayoutAnchorable[] _previousAnchorables = null; + LayoutDocument[] _previousDocuments = null; + + public DockingManager Manager + { + get { return _manager; } + } + + public event EventHandler LayoutSerializationCallback; + + protected virtual void FixupLayout(LayoutRoot layout) + { + //fix container panes + foreach (var lcToAttach in layout.Descendents().OfType().Where(lc => lc.PreviousContainerId != null)) + { + var paneContainerToAttach = layout.Descendents().OfType().FirstOrDefault(lps => lps.Id == lcToAttach.PreviousContainerId); + if (paneContainerToAttach == null) + throw new ArgumentException(string.Format("Unable to find a pane with id ='{0}'", lcToAttach.PreviousContainerId)); + + lcToAttach.PreviousContainer = paneContainerToAttach as ILayoutContainer; + } + + + //now fix the content of the layoutcontents + foreach (var lcToFix in layout.Descendents().OfType().Where(lc => lc.Content == null).ToArray()) + { + LayoutAnchorable previousAchorable = null; + if (lcToFix.ContentId != null) + { + //try find the content in replaced layout + previousAchorable = _previousAnchorables.FirstOrDefault(a => a.ContentId == lcToFix.ContentId); + } + + if (LayoutSerializationCallback != null) + { + var args = new LayoutSerializationCallbackEventArgs(lcToFix, previousAchorable != null ? previousAchorable.Content : null); + LayoutSerializationCallback(this, args); + if (args.Cancel) + lcToFix.Close(); + else if (args.Content != null) + lcToFix.Content = args.Content; + else if (args.Model.Content != null) + lcToFix.Hide(false); + } + else if (previousAchorable == null) + lcToFix.Hide(false); + else + { + lcToFix.Content = previousAchorable.Content; + lcToFix.IconSource = previousAchorable.IconSource; + } + } + + + foreach (var lcToFix in layout.Descendents().OfType().Where(lc => lc.Content == null).ToArray()) + { + LayoutDocument previousDocument = null; + if (lcToFix.ContentId != null) + { + //try find the content in replaced layout + previousDocument = _previousDocuments.FirstOrDefault(a => a.ContentId == lcToFix.ContentId); + } + + if (LayoutSerializationCallback != null) + { + var args = new LayoutSerializationCallbackEventArgs(lcToFix, previousDocument != null ? previousDocument.Content : null); + LayoutSerializationCallback(this, args); + + if (args.Cancel) + lcToFix.Close(); + else if (args.Content != null) + lcToFix.Content = args.Content; + else if (args.Model.Content != null) + lcToFix.Close(); + } + else if (previousDocument == null) + lcToFix.Close(); + else + lcToFix.Content = previousDocument.Content; + } + + + layout.CollectGarbage(); + } + + protected void StartDeserialization() + { + Manager.SuspendDocumentsSourceBinding = true; + Manager.SuspendAnchorablesSourceBinding = true; + } + + protected void EndDeserialization() + { + Manager.SuspendDocumentsSourceBinding = false; + Manager.SuspendAnchorablesSourceBinding = false; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Layout/Serialization/XmlLayoutSerializer.cs b/Src/Xceed.Wpf.AvalonDock/Layout/Serialization/XmlLayoutSerializer.cs new file mode 100644 index 0000000..1512133 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Layout/Serialization/XmlLayoutSerializer.cs @@ -0,0 +1,110 @@ +/************************************************************************************* + + 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.Xml.Serialization; +using System.IO; + +namespace Xceed.Wpf.AvalonDock.Layout.Serialization +{ + public class XmlLayoutSerializer : LayoutSerializer + { + public XmlLayoutSerializer(DockingManager manager) + : base(manager) + { + + } + + public void Serialize(System.Xml.XmlWriter writer) + { + var serializer = new XmlSerializer(typeof(LayoutRoot)); + serializer.Serialize(writer, Manager.Layout); + } + public void Serialize(System.IO.TextWriter writer) + { + var serializer = new XmlSerializer(typeof(LayoutRoot)); + serializer.Serialize(writer, Manager.Layout); + } + public void Serialize(System.IO.Stream stream) + { + var serializer = new XmlSerializer(typeof(LayoutRoot)); + serializer.Serialize(stream, Manager.Layout); + } + + public void Serialize(string filepath) + { + using (var stream = new StreamWriter(filepath)) + Serialize(stream); + } + + public void Deserialize(System.IO.Stream stream) + { + try + { + StartDeserialization(); + var serializer = new XmlSerializer(typeof(LayoutRoot)); + var layout = serializer.Deserialize(stream) as LayoutRoot; + FixupLayout(layout); + Manager.Layout = layout; + } + finally + { + EndDeserialization(); + } + } + + public void Deserialize(System.IO.TextReader reader) + { + try + { + StartDeserialization(); + var serializer = new XmlSerializer(typeof(LayoutRoot)); + var layout = serializer.Deserialize(reader) as LayoutRoot; + FixupLayout(layout); + Manager.Layout = layout; + } + finally + { + EndDeserialization(); + } + } + + public void Deserialize(System.Xml.XmlReader reader) + { + try + { + StartDeserialization(); + var serializer = new XmlSerializer(typeof(LayoutRoot)); + var layout = serializer.Deserialize(reader) as LayoutRoot; + FixupLayout(layout); + Manager.Layout = layout; + } + finally + { + EndDeserialization(); + } + } + + public void Deserialize(string filepath) + { + using (var stream = new StreamReader(filepath)) + Deserialize(stream); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/LayoutEventArgs.cs b/Src/Xceed.Wpf.AvalonDock/LayoutEventArgs.cs new file mode 100644 index 0000000..219b5e9 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/LayoutEventArgs.cs @@ -0,0 +1,38 @@ +/************************************************************************************* + + 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 Xceed.Wpf.AvalonDock.Layout; + +namespace Xceed.Wpf.AvalonDock +{ + class LayoutEventArgs : EventArgs + { + public LayoutEventArgs(LayoutRoot layoutRoot) + { + LayoutRoot = layoutRoot; + } + + public LayoutRoot LayoutRoot + { + get; + private set; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/MathHelper.cs b/Src/Xceed.Wpf.AvalonDock/MathHelper.cs new file mode 100644 index 0000000..dbe3e96 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/MathHelper.cs @@ -0,0 +1,45 @@ +/************************************************************************************* + + 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 + + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Xceed.Wpf.AvalonDock +{ + internal static class MathHelper + { + + public static double MinMax(double value, double min, double max) + { + if (min > max) + throw new ArgumentException("min>max"); + + if (value < min) + return min; + if (value > max) + return max; + + return value; + } + + public static void AssertIsPositiveOrZero(double value) + { + if (value < 0.0) + throw new ArgumentException("Invalid value, must be a positive number or equal to zero"); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/AssemblyInfo.cs b/Src/Xceed.Wpf.AvalonDock/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..450d70a --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/AssemblyInfo.cs @@ -0,0 +1,76 @@ +/************************************************************************************* + + 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.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Markup; +using System; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle( "Xceed Toolkit for WPF - AvalonDock" )] +[assembly: AssemblyDescription( "This assembly implements the Xceed.Wpf.AvalonDock namespace, a docking layout system for the Windows Presentation Framework." )] + +[assembly: AssemblyCompany( "Xceed Software Inc." )] +[assembly: AssemblyProduct( "Xceed Toolkit for WPF - AvalonDock" )] +[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2016" )] +[assembly: AssemblyCulture( "" )] + + + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] +[assembly: CLSCompliant( true )] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + +[assembly: XmlnsPrefix( "http://schemas.xceed.com/wpf/xaml/avalondock", "xcad" )] +[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/avalondock", "Xceed.Wpf.AvalonDock" )] +[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/avalondock", "Xceed.Wpf.AvalonDock.Controls" )] +[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/avalondock", "Xceed.Wpf.AvalonDock.Converters" )] +[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/avalondock", "Xceed.Wpf.AvalonDock.Layout" )] +[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/avalondock", "Xceed.Wpf.AvalonDock.Themes" )] + +#pragma warning disable 1699 +[assembly: AssemblyDelaySign( false )] +[assembly: AssemblyKeyFile( @"..\..\sn.snk" )] +[assembly: AssemblyKeyName( "" )] +#pragma warning restore 1699 + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.Designer.cs new file mode 100644 index 0000000..72ca068 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.Designer.cs @@ -0,0 +1,243 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Xceed.Wpf.AvalonDock.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xceed.Wpf.AvalonDock.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Auto Hide. + /// + public static string Anchorable_AutoHide { + get { + return ResourceManager.GetString("Anchorable_AutoHide", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Auto Hide. + /// + public static string Anchorable_BtnAutoHide_Hint { + get { + return ResourceManager.GetString("Anchorable_BtnAutoHide_Hint", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hide. + /// + public static string Anchorable_BtnClose_Hint { + get { + return ResourceManager.GetString("Anchorable_BtnClose_Hint", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Window Position. + /// + public static string Anchorable_CxMenu_Hint { + get { + return ResourceManager.GetString("Anchorable_CxMenu_Hint", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dock. + /// + public static string Anchorable_Dock { + get { + return ResourceManager.GetString("Anchorable_Dock", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dock as Tabbed Document. + /// + public static string Anchorable_DockAsDocument { + get { + return ResourceManager.GetString("Anchorable_DockAsDocument", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Float. + /// + public static string Anchorable_Float { + get { + return ResourceManager.GetString("Anchorable_Float", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hide. + /// + public static string Anchorable_Hide { + get { + return ResourceManager.GetString("Anchorable_Hide", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Close. + /// + public static string Document_Close { + get { + return ResourceManager.GetString("Document_Close", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Close All. + /// + public static string Document_CloseAll { + get { + return ResourceManager.GetString("Document_CloseAll", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Close All But This. + /// + public static string Document_CloseAllButThis { + get { + return ResourceManager.GetString("Document_CloseAllButThis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Window Position. + /// + public static string Document_CxMenu_Hint { + get { + return ResourceManager.GetString("Document_CxMenu_Hint", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dock as Tabbed Document. + /// + public static string Document_DockAsDocument { + get { + return ResourceManager.GetString("Document_DockAsDocument", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Float. + /// + public static string Document_Float { + get { + return ResourceManager.GetString("Document_Float", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move To Next Tab Group. + /// + public static string Document_MoveToNextTabGroup { + get { + return ResourceManager.GetString("Document_MoveToNextTabGroup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Move To Previous Tab Group. + /// + public static string Document_MoveToPreviousTabGroup { + get { + return ResourceManager.GetString("Document_MoveToPreviousTabGroup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New Horizontal Tab Group. + /// + public static string Document_NewHorizontalTabGroup { + get { + return ResourceManager.GetString("Document_NewHorizontalTabGroup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New Vertical Tab Group. + /// + public static string Document_NewVerticalTabGroup { + get { + return ResourceManager.GetString("Document_NewVerticalTabGroup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximize. + /// + public static string Window_Maximize { + get { + return ResourceManager.GetString("Window_Maximize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Restore. + /// + public static string Window_Restore { + get { + return ResourceManager.GetString("Window_Restore", resourceCulture); + } + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.de.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.de.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.de.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.de.resx new file mode 100644 index 0000000..b245dcc --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.de.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Automatisch im Hintergrund + + + Automatisch im Hintergrund + + + Schließen + + + Fensterposition + + + Andocken + + + Als Dokument im Registerkartenformat andocken + + + Verankerung aufheben + + + Schließen + + + Schließen + + + Schließen Sie alle + + + Alle ausser diesem schließen + + + Fensterposition + + + Als Dokument andocken + + + Verankerung aufheben + + + Zur nächsten Registerkartengruppe wechseln + + + Zur vorherigen Registerkartengruppe wechseln + + + Neue horizontale Registerkartengruppe + + + Neue vertikale Registerkartengruppe + + + Maximieren + + + Wiederherstellen + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.es.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.es.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.es.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.es.resx new file mode 100644 index 0000000..81fed85 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.es.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Esconder Automáticamente + + + Esconder Automáticamente + + + Esconder + + + Posición de Ventana + + + Anclar + + + Anclar como Documento en Ficha + + + Ventana Flotante + + + Esconder + + + Cerrar + + + Cerca de todo + + + Cerrar Todo, Pero Este + + + Posición de Ventana + + + Anclar como Documento en Ficha + + + Ventana Flotante + + + Mover al Grupo de Fichas Siguiente + + + Mover al Grupo de Fichas Anterior + + + Nuevo Grupo de Fichas Horizontal + + + Nuevo Grupo de Fichas Vertical + + + Maximizar + + + Restaurar + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.fr.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.fr.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.fr.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.fr.resx new file mode 100644 index 0000000..364f0c9 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.fr.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cacher Automatiquement + + + Cacher Automatiquement + + + Cacher + + + Position de la Fenêtre + + + Ancrer + + + Ancrer comme Onglet de Document + + + Flottante + + + Cacher + + + Fermer + + + Fermer tout + + + Fermer Tout Sauf Ceci + + + Position de la Fenêtre + + + Ancrer Comme Onglet de Document + + + Flottante + + + Déplacer Vers Le Groupe d'Onglets Suivant + + + Déplacer Vers Le Groupe d'Onglets Précédent + + + Nouveau Groupe d'Onglets Horizontal + + + Nouveau Groupe d'Onglets Vertical + + + Plein Écran + + + Restaurer + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.hu.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.hu.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.hu.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.hu.resx new file mode 100644 index 0000000..7bfdc07 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.hu.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Automatikus elrejtés + + + Automatikus elrejtés + + + Elrejtés + + + Elhelyezkedés + + + Dokkolás + + + Dokkolás dokumentumfülként + + + Lebegő + + + Elrejtés + + + Bezárás + + + Zárjon be minden + + + Ennek kivételével az összes bezárása + + + Elhelyezkedés + + + Dokkolás dokumentumfülként + + + Lebegő + + + Mozgatás a következő fülcsoportra + + + Mozgatás az előző fülcsoportra + + + Új vízszintes fülcsoport + + + Új függőleges fülcsoport + + + Teljes méret + + + Visszaállítás + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.it.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.it.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.it.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.it.resx new file mode 100644 index 0000000..c28be45 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.it.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Nascondi Automaticamente + + + Nascondi Automaticamente + + + Nascondi + + + Posizione della Finestra + + + Ancora + + + Ancora come Documento + + + Finestra Mobile + + + Nascondi + + + Chiudi + + + Chiudere tutte le + + + Chiudi Tutti Tranne Questo + + + Posizione della Finestra + + + Ancora come Documento + + + Finestra Mobile + + + Muovi al Gruppo Successivo + + + Muovi al Gruppo Precedente + + + Nuovo Gruppo Orizzontale + + + Nuovo Gruppo Verticale + + + Ingrandisci + + + Ripristina + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.pt-BR.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.pt-BR.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.pt-BR.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.pt-BR.resx new file mode 100644 index 0000000..10ca481 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.pt-BR.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Esconder Automaticamente + + + Esconder Automaticamente + + + Esconder + + + Posição da Janela + + + Ancorar + + + Ancorar Como Documento em Aba + + + Flutuar + + + Esconder + + + Fechar + + + Feche todos os + + + Fechar Todos Menos Este + + + Posição da Janela + + + Ancorar como Documento em Aba + + + Janela Flutuante + + + Mover para o Próximo Grupo de Documentos + + + Mover para o Grupo de Documentos Anterior + + + Novo Grupo de Documentos Horizontal + + + Novo Grupo de Documentos Vertical + + + Maximizar + + + Recuperar + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.resx new file mode 100644 index 0000000..ce93dc9 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Auto Hide + + + Auto Hide + + + Hide + + + Window Position + + + Dock + + + Dock as Tabbed Document + + + Float + + + Hide + + + Close + + + Close All + + + Close All But This + + + Window Position + + + Dock as Tabbed Document + + + Float + + + Move To Next Tab Group + + + Move To Previous Tab Group + + + New Horizontal Tab Group + + + New Vertical Tab Group + + + Maximize + + + Restore + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ro.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ro.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ro.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ro.resx new file mode 100644 index 0000000..87f93e5 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ro.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Ascunde automat + + + Ascunde automat + + + Ascunde + + + Poziția ferestrei + + + Dochează + + + Dochează ca și document + + + Plutește + + + Ascunde + + + Închide + + + Aproape toate + + + Închide tot fără documentul curent + + + Poziția ferestrei + + + Dochează ca și document + + + Plutește + + + Mută către grup de taburi următor + + + Mută către grup de taburi anterior + + + Grup nou de taburi orizontal + + + Grup nou de taburi vertical + + + Maximizează + + + Restaurează + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ru.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ru.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ru.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ru.resx new file mode 100644 index 0000000..52040d0 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.ru.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Скрывать Автоматически + + + Скрывать Автоматически + + + Скрыть + + + Положение Окна + + + Присоединить + + + Присоединить как Документ + + + Отсоединить + + + Скрыть + + + Закрыть + + + Закрыть все + + + Закрыть Все кроме Этого + + + Положение Окна + + + Присоединить как Документ + + + Отсоединить + + + Перейти к Следующей Группе Вкладок + + + Перейти к Предыдущей Группе Вкладок + + + Новая Горизонтальная Группа Вкладок + + + Новая Вертикальная Группа Вкладок + + + Развернуть + + + Восстановить + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.sv.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.sv.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.sv.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.sv.resx new file mode 100644 index 0000000..910384e --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.sv.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Dölj automatiskt + + + Dölj automatiskt + + + Dölj + + + Fönsterposition + + + Docka + + + Docka som tabbat dokument + + + Koppla loss + + + Dölj + + + Stäng + + + Stäng alla + + + Stäng alla andra + + + Fönsterposition + + + Docka som tabbat dokument + + + Koppla loss + + + Flytta till nästa tabgrupp + + + Flytta till föregående tabgrupp + + + Ny horisontell tabgrupp + + + Ny vertikal tabgrupp + + + Maximera + + + Återställ + + diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.zh-Hans.Designer.cs b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.zh-Hans.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/Properties/Resources.zh-Hans.resx b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.zh-Hans.resx new file mode 100644 index 0000000..655bfff --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Properties/Resources.zh-Hans.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 自动隐藏 + + + 自动隐藏 + + + 隐藏 + + + 窗口位置 + + + 停靠 + + + 停靠成标签式文档 + + + 漂浮 + + + 隐藏 + + + 关闭 + + + 關閉所有 + + + 留此,关闭其他 + + + 窗口位置 + + + 停靠成标签式文档 + + + 漂浮 + + + 移到下一标签组 + + + 移到上一标签组 + + + 新建水平标签组 + + + 新建垂直标签组 + + + 最大化 + + + 恢复 + + diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/DictionaryTheme.cs b/Src/Xceed.Wpf.AvalonDock/Themes/DictionaryTheme.cs new file mode 100644 index 0000000..f8ccc32 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Themes/DictionaryTheme.cs @@ -0,0 +1,43 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Themes +{ + public abstract class DictionaryTheme : Theme + { + public DictionaryTheme( ResourceDictionary themeResourceDictionary ) + { + this.ThemeResourceDictionary = themeResourceDictionary; + } + + public ResourceDictionary ThemeResourceDictionary + { + get; + private set; + } + + public override Uri GetResourceUri() + { + return null; + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockBottom.PNG b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockBottom.PNG new file mode 100644 index 0000000..cdc7c06 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockBottom.PNG differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockLeft.PNG b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockLeft.PNG new file mode 100644 index 0000000..88a086b Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockLeft.PNG differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockPane.PNG b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockPane.PNG new file mode 100644 index 0000000..0377b96 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockPane.PNG differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockPaneEmpty.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockPaneEmpty.png new file mode 100644 index 0000000..c3be321 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockPaneEmpty.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockRight.PNG b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockRight.PNG new file mode 100644 index 0000000..067b3f0 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockRight.PNG differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockTop.PNG b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockTop.PNG new file mode 100644 index 0000000..b14b818 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/DockTop.PNG differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/HTabGroup.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/HTabGroup.png new file mode 100644 index 0000000..4c50d26 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/HTabGroup.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneBottom.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneBottom.png new file mode 100644 index 0000000..a682de7 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneBottom.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneLeft.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneLeft.png new file mode 100644 index 0000000..705a490 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneLeft.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneRight.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneRight.png new file mode 100644 index 0000000..c08f50f Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneRight.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneTop.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneTop.png new file mode 100644 index 0000000..14197ef Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockDocPaneTop.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneBottom.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneBottom.png new file mode 100644 index 0000000..01be445 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneBottom.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneInside.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneInside.png new file mode 100644 index 0000000..a0b30b0 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneInside.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneLeft.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneLeft.png new file mode 100644 index 0000000..21dfb7b Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneLeft.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneRight.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneRight.png new file mode 100644 index 0000000..52438d8 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneRight.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneTop.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneTop.png new file mode 100644 index 0000000..852a56b Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/InnerDockPaneTop.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/Locked.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/Locked.png new file mode 100644 index 0000000..b8f6ced Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/Locked.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinAutoHide.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinAutoHide.png new file mode 100644 index 0000000..7a968a2 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinAutoHide.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinClose.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinClose.png new file mode 100644 index 0000000..1bd384e Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinClose.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinDocMenu.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinDocMenu.png new file mode 100644 index 0000000..35b3fef Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinDocMenu.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinMaximize.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinMaximize.png new file mode 100644 index 0000000..1913942 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinMaximize.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinMenu.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinMenu.png new file mode 100644 index 0000000..ebad71b Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinMenu.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinRestore.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinRestore.png new file mode 100644 index 0000000..c95bb93 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/PinRestore.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/VTabGroup.png b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/VTabGroup.png new file mode 100644 index 0000000..c3f279f Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/Themes/Generic/Images/VTabGroup.png differ diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/GenericTheme.cs b/Src/Xceed.Wpf.AvalonDock/Themes/GenericTheme.cs new file mode 100644 index 0000000..20a6677 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Themes/GenericTheme.cs @@ -0,0 +1,33 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Themes +{ + public class GenericTheme : Theme + { + public override Uri GetResourceUri() + { + return new Uri( + "/Xceed.Wpf.AvalonDock;component/Themes/generic.xaml", + UriKind.Relative ); + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/Theme.cs b/Src/Xceed.Wpf.AvalonDock/Themes/Theme.cs new file mode 100644 index 0000000..0e15406 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Themes/Theme.cs @@ -0,0 +1,36 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.AvalonDock.Themes +{ + public abstract class Theme : DependencyObject + { + public Theme() + { + + } + + public abstract Uri GetResourceUri(); + + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Themes/generic.xaml b/Src/Xceed.Wpf.AvalonDock/Themes/generic.xaml new file mode 100644 index 0000000..cad0993 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Themes/generic.xaml @@ -0,0 +1,1080 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Src/Xceed.Wpf.AvalonDock/Win32Helper.cs b/Src/Xceed.Wpf.AvalonDock/Win32Helper.cs new file mode 100644 index 0000000..22ff5ff --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Win32Helper.cs @@ -0,0 +1,461 @@ +/************************************************************************************* + + 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.Runtime.InteropServices; +using System.Windows; + +namespace Xceed.Wpf.AvalonDock +{ + internal static class Win32Helper + { + [DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)] + internal static extern IntPtr CreateWindowEx(int dwExStyle, + string lpszClassName, + string lpszWindowName, + int style, + int x, int y, + int width, int height, + IntPtr hwndParent, + IntPtr hMenu, + IntPtr hInst, + [MarshalAs(UnmanagedType.AsAny)] object pvParam); + internal const int + WS_CHILD = 0x40000000, + WS_VISIBLE = 0x10000000, + WS_VSCROLL = 0x00200000, + WS_BORDER = 0x00800000, + WS_CLIPSIBLINGS = 0x04000000, + WS_CLIPCHILDREN = 0x02000000, + WS_TABSTOP = 0x00010000, + WS_GROUP = 0x00020000; + + + /// + /// SetWindowPos Flags + /// + [Flags()] + internal enum SetWindowPosFlags : uint + { + /// If the calling thread and the thread that owns the window are attached to different input queues, + /// the system posts the request to the thread that owns the window. This prevents the calling thread from + /// blocking its execution while other threads process the request. + /// SWP_ASYNCWINDOWPOS + SynchronousWindowPosition = 0x4000, + /// Prevents generation of the WM_SYNCPAINT message. + /// SWP_DEFERERASE + DeferErase = 0x2000, + /// Draws a frame (defined in the window's class description) around the window. + /// SWP_DRAWFRAME + DrawFrame = 0x0020, + /// Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to + /// the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE + /// is sent only when the window's size is being changed. + /// SWP_FRAMECHANGED + FrameChanged = 0x0020, + /// Hides the window. + /// SWP_HIDEWINDOW + HideWindow = 0x0080, + /// Does not activate the window. If this flag is not set, the window is activated and moved to the + /// top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter + /// parameter). + /// SWP_NOACTIVATE + DoNotActivate = 0x0010, + /// Discards the entire contents of the client area. If this flag is not specified, the valid + /// contents of the client area are saved and copied back into the client area after the window is sized or + /// repositioned. + /// SWP_NOCOPYBITS + DoNotCopyBits = 0x0100, + /// Retains the current position (ignores X and Y parameters). + /// SWP_NOMOVE + IgnoreMove = 0x0002, + /// Does not change the owner window's position in the Z order. + /// SWP_NOOWNERZORDER + DoNotChangeOwnerZOrder = 0x0200, + /// Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to + /// the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent + /// window uncovered as a result of the window being moved. When this flag is set, the application must + /// explicitly invalidate or redraw any parts of the window and parent window that need redrawing. + /// SWP_NOREDRAW + DoNotRedraw = 0x0008, + /// Same as the SWP_NOOWNERZORDER flag. + /// SWP_NOREPOSITION + DoNotReposition = 0x0200, + /// Prevents the window from receiving the WM_WINDOWPOSCHANGING message. + /// SWP_NOSENDCHANGING + DoNotSendChangingEvent = 0x0400, + /// Retains the current size (ignores the cx and cy parameters). + /// SWP_NOSIZE + IgnoreResize = 0x0001, + /// Retains the current Z order (ignores the hWndInsertAfter parameter). + /// SWP_NOZORDER + IgnoreZOrder = 0x0004, + /// Displays the window. + /// SWP_SHOWWINDOW + ShowWindow = 0x0040, + } + + /// + /// Special window handles + /// + internal static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); + internal static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); + internal static readonly IntPtr HWND_TOP = new IntPtr(0); + internal static readonly IntPtr HWND_BOTTOM = new IntPtr(1); + + [StructLayout(LayoutKind.Sequential)] + internal class WINDOWPOS + { + public IntPtr hwnd; + public IntPtr hwndInsertAfter; + public int x; + public int y; + public int cx; + public int cy; + public int flags; + }; + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags); + + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] + internal static extern bool IsChild(IntPtr hWndParent, IntPtr hwnd); + + [DllImport("user32.dll")] + internal static extern IntPtr SetFocus(IntPtr hWnd); + + internal const int WM_WINDOWPOSCHANGED = 0x0047; + internal const int WM_WINDOWPOSCHANGING = 0x0046; + internal const int WM_NCMOUSEMOVE = 0xa0; + internal const int WM_NCLBUTTONDOWN = 0xA1; + internal const int WM_NCLBUTTONUP = 0xA2; + internal const int WM_NCLBUTTONDBLCLK = 0xA3; + internal const int WM_NCRBUTTONDOWN = 0xA4; + internal const int WM_NCRBUTTONUP = 0xA5; + internal const int WM_CAPTURECHANGED = 0x0215; + internal const int WM_EXITSIZEMOVE = 0x0232; + internal const int WM_ENTERSIZEMOVE = 0x0231; + internal const int WM_MOVE = 0x0003; + internal const int WM_MOVING = 0x0216; + internal const int WM_KILLFOCUS = 0x0008; + internal const int WM_SETFOCUS = 0x0007; + internal const int WM_ACTIVATE = 0x0006; + internal const int WM_NCHITTEST = 0x0084; + internal const int WM_INITMENUPOPUP = 0x0117; + internal const int WM_KEYDOWN = 0x0100; + internal const int WM_KEYUP = 0x0101; + + internal const int WA_INACTIVE = 0x0000; + + internal const int WM_SYSCOMMAND = 0x0112; + // These are the wParam of WM_SYSCOMMAND + internal const int SC_MAXIMIZE = 0xF030; + internal const int SC_RESTORE = 0xF120; + + internal const int + WM_CREATE = 0x0001; + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr SetActiveWindow(IntPtr hWnd); + + [DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)] + internal static extern bool DestroyWindow(IntPtr hwnd); + + internal const int HT_CAPTION = 0x2; + + [DllImportAttribute("user32.dll")] + internal static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); + [DllImportAttribute("user32.dll")] + internal static extern int PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); + + + [DllImport("user32.dll")] + static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect); + [DllImport("user32.dll")] + internal static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); + + // Hook Types + public enum HookType : int + { + WH_JOURNALRECORD = 0, + WH_JOURNALPLAYBACK = 1, + WH_KEYBOARD = 2, + WH_GETMESSAGE = 3, + WH_CALLWNDPROC = 4, + WH_CBT = 5, + WH_SYSMSGFILTER = 6, + WH_MOUSE = 7, + WH_HARDWARE = 8, + WH_DEBUG = 9, + WH_SHELL = 10, + WH_FOREGROUNDIDLE = 11, + WH_CALLWNDPROCRET = 12, + WH_KEYBOARD_LL = 13, + WH_MOUSE_LL = 14 + } + + public const int HCBT_SETFOCUS = 9; + public const int HCBT_ACTIVATE = 5; + + [DllImport("kernel32.dll")] + public static extern uint GetCurrentThreadId(); + + public delegate int HookProc(int code, IntPtr wParam, + IntPtr lParam); + + [DllImport("user32.dll")] + public static extern IntPtr SetWindowsHookEx(HookType code, + HookProc func, + IntPtr hInstance, + int threadID); + [DllImport("user32.dll")] + public static extern int UnhookWindowsHookEx(IntPtr hhook); + [DllImport("user32.dll")] + public static extern int CallNextHookEx(IntPtr hhook, + int code, IntPtr wParam, IntPtr lParam); + + [Serializable, StructLayout(LayoutKind.Sequential)] + internal struct RECT + { + public int Left; + public int Top; + public int Right; + public int Bottom; + public RECT(int left_, int top_, int right_, int bottom_) + { + Left = left_; Top = top_; Right = right_; Bottom = bottom_; + } + + public int Height + { + get { return Bottom - Top; } + } + + public int Width + { + get { return Right - Left; } + } + public Size Size { get { return new Size(Width, Height); } } + public Point Location { get { return new Point(Left, Top); } } + // Handy method for converting to a System.Drawing.Rectangle + public Rect ToRectangle() { return new Rect(Left, Top, Right, Bottom); } + public static RECT FromRectangle(Rect rectangle) + { return new Rect(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); } + public override int GetHashCode() + { return Left ^ ((Top << 13) | (Top >> 0x13)) ^ ((Width << 0x1a) | (Width >> 6)) ^ ((Height << 7) | (Height >> 0x19)); } + + #region Operator overloads + public static implicit operator Rect(RECT rect) { return rect.ToRectangle(); } public static implicit operator RECT(Rect rect) { return FromRectangle(rect); } + #endregion + } + + internal static RECT GetClientRect(IntPtr hWnd) + { + RECT result = new RECT(); + GetClientRect(hWnd, out result); + return result; + } + internal static RECT GetWindowRect(IntPtr hWnd) + { + RECT result = new RECT(); + GetWindowRect(hWnd, out result); + return result; + } + + [DllImport("user32.dll")] + internal static extern IntPtr GetTopWindow(IntPtr hWnd); + + internal const uint GW_HWNDNEXT = 2; + internal const uint GW_HWNDPREV = 3; + + + [DllImport("user32.dll", SetLastError = true)] + internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); + + internal enum GetWindow_Cmd : uint + { + GW_HWNDFIRST = 0, + GW_HWNDLAST = 1, + GW_HWNDNEXT = 2, + GW_HWNDPREV = 3, + GW_OWNER = 4, + GW_CHILD = 5, + GW_ENABLEDPOPUP = 6 + } + + internal static int MakeLParam(int LoWord, int HiWord) + { + return (int) ((HiWord << 16) | (LoWord & 0xffff)); + } + + + internal const int WM_MOUSEMOVE = 0x200; + internal const int WM_LBUTTONDOWN = 0x201; + internal const int WM_LBUTTONUP = 0x202; + internal const int WM_LBUTTONDBLCLK = 0x203; + internal const int WM_RBUTTONDOWN = 0x204; + internal const int WM_RBUTTONUP = 0x205; + internal const int WM_RBUTTONDBLCLK = 0x206; + internal const int WM_MBUTTONDOWN = 0x207; + internal const int WM_MBUTTONUP = 0x208; + internal const int WM_MBUTTONDBLCLK = 0x209; + internal const int WM_MOUSEWHEEL = 0x20A; + internal const int WM_MOUSEHWHEEL = 0x20E; + + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool GetCursorPos(ref Win32Point pt); + + [StructLayout(LayoutKind.Sequential)] + internal struct Win32Point + { + public Int32 X; + public Int32 Y; + }; + internal static Point GetMousePosition() + { + Win32Point w32Mouse = new Win32Point(); + GetCursorPos(ref w32Mouse); + return new Point(w32Mouse.X, w32Mouse.Y); + } + + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool IsWindowVisible(IntPtr hWnd); + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool IsWindowEnabled(IntPtr hWnd); + + [DllImport("user32.dll")] + internal static extern IntPtr GetFocus(); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool BringWindowToTop(IntPtr hWnd); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); + + [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] + internal static extern IntPtr GetParent(IntPtr hWnd); + + /// + /// Changes an attribute of the specified window. The function also sets the 32-bit (long) value at the specified offset into the extra window memory. + /// + /// A handle to the window and, indirectly, the class to which the window belongs.. + /// The zero-based offset to the value to be set. Valid values are in the range zero through the number of bytes of extra window memory, minus the size of an integer. To set any other value, specify one of the following values: GWL_EXSTYLE, GWL_HINSTANCE, GWL_ID, GWL_STYLE, GWL_USERDATA, GWL_WNDPROC + /// The replacement value. + /// If the function succeeds, the return value is the previous value of the specified 32-bit integer. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + [DllImport("user32.dll")] + static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + [DllImport("user32.dll", SetLastError = true)] + static extern int GetWindowLong(IntPtr hWnd, int nIndex); + + public static void SetOwner(IntPtr childHandle, IntPtr ownerHandle) + { + SetWindowLong( + childHandle, + -8, // GWL_HWNDPARENT + ownerHandle.ToInt32()); + } + + public static IntPtr GetOwner(IntPtr childHandle) + { + return new IntPtr(GetWindowLong(childHandle, -8)); + } + + + //Monitor Patch #13440 + + /// + /// The MonitorFromRect function retrieves a handle to the display monitor that + /// has the largest area of intersection with a specified rectangle. + /// + /// Pointer to a RECT structure that specifies the rectangle of interest in + /// virtual-screen coordinates + /// Determines the function's return value if the rectangle does not intersect + /// any display monitor + /// + /// If the rectangle intersects one or more display monitor rectangles, the return value + /// is an HMONITOR handle to the display monitor that has the largest area of intersection with the rectangle. + /// If the rectangle does not intersect a display monitor, the return value depends on the value of dwFlags. + /// + [DllImport("user32.dll")] + public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); + + /// + /// The MonitorFromWindow function retrieves a handle to the display monitor that has the largest area of intersection with the bounding rectangle of a specified window. + /// + /// A handle to the window of interest. + /// Determines the function's return value if the window does not intersect any display monitor. + /// If the window intersects one or more display monitor rectangles, the return value is an HMONITOR handle to the display monitor that has the largest area of intersection with the window. + /// If the window does not intersect a display monitor, the return value depends on the value of dwFlags. + /// + [DllImport("user32.dll")] + public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); + + + /// + /// The MONITORINFO structure contains information about a display monitor. + /// + [StructLayout(LayoutKind.Sequential)] + public class MonitorInfo + { + /// + /// The size of the structure, in bytes. + /// + public int Size = Marshal.SizeOf(typeof(MonitorInfo)); + /// + /// A RECT structure that specifies the display monitor rectangle, expressed + /// in virtual-screen coordinates. + /// Note that if the monitor is not the primary display monitor, + /// some of the rectangle's coordinates may be negative values. + /// + public RECT Monitor; + /// + /// A RECT structure that specifies the work area rectangle of the display monitor, + /// expressed in virtual-screen coordinates. Note that if the monitor is not the primary + /// display monitor, some of the rectangle's coordinates may be negative values. + /// + public RECT Work; + /// + /// A set of flags that represent attributes of the display monitor. + /// + public uint Flags; + } + + /// + /// The GetMonitorInfo function retrieves information about a display monitor. + /// + /// Handle to the display monitor of interest. + /// Pointer to a MONITORINFO or MONITORINFOEX structure that receives + /// information about the specified display monitor + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetMonitorInfo(IntPtr hMonitor, [In, Out] MonitorInfo lpmi); + + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/WindowHelper.cs b/Src/Xceed.Wpf.AvalonDock/WindowHelper.cs new file mode 100644 index 0000000..8323fad --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/WindowHelper.cs @@ -0,0 +1,80 @@ +/************************************************************************************* + + 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.Media; +using System.Windows; +using System.Windows.Interop; + +namespace Xceed.Wpf.AvalonDock +{ + static class WindowHelper + { + public static bool IsAttachedToPresentationSource(this Visual element) + { + return PresentationSource.FromVisual(element as Visual) != null; + } + + public static void SetParentToMainWindowOf(this Window window, Visual element) + { + var wndParent = Window.GetWindow(element); + if (wndParent != null) + window.Owner = wndParent; + else + { + IntPtr parentHwnd; + if (GetParentWindowHandle(element, out parentHwnd)) + Win32Helper.SetOwner(new WindowInteropHelper(window).Handle, parentHwnd); + } + } + + public static IntPtr GetParentWindowHandle(this Window window) + { + if (window.Owner != null) + return new WindowInteropHelper(window.Owner).Handle; + else + return Win32Helper.GetOwner(new WindowInteropHelper(window).Handle); + } + + + public static bool GetParentWindowHandle(this Visual element, out IntPtr hwnd) + { + hwnd = IntPtr.Zero; + HwndSource wpfHandle = PresentationSource.FromVisual(element) as HwndSource; + + if (wpfHandle == null) + return false; + + hwnd = Win32Helper.GetParent(wpfHandle.Handle); + if (hwnd == IntPtr.Zero) + hwnd = wpfHandle.Handle; + return true; + } + + public static void SetParentWindowToNull(this Window window) + { + if (window.Owner != null) + window.Owner = null; + else + { + Win32Helper.SetOwner(new WindowInteropHelper(window).Handle, IntPtr.Zero); + } + } + } +} diff --git a/Src/Xceed.Wpf.AvalonDock/Xceed.Wpf.AvalonDock.csproj b/Src/Xceed.Wpf.AvalonDock/Xceed.Wpf.AvalonDock.csproj new file mode 100644 index 0000000..9aca8b5 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/Xceed.Wpf.AvalonDock.csproj @@ -0,0 +1,365 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {DB81988F-E0F2-45A0-A1FD-8C37F3D35244} + library + Properties + Xceed.Wpf.AvalonDock + Xceed.Wpf.AvalonDock + v4.6.1 + + + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + true + full + false + bin\Debug\ + DEBUG + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + false + + + false + + + + + + + + + + + + + + + 4.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + True + True + Resources.de.resx + + + True + True + Resources.resx + + + True + True + Resources.es.resx + + + True + True + Resources.fr.resx + + + True + True + Resources.hu.resx + + + True + True + Resources.it.resx + + + True + True + Resources.pt-BR.resx + + + True + True + Resources.ro.resx + + + True + True + Resources.ru.resx + + + True + True + Resources.sv.resx + + + True + True + Resources.zh-Hans.resx + + + + + + + + PublicResXFileCodeGenerator + Resources.hu.Designer.cs + Designer + + + PublicResXFileCodeGenerator + Resources.Designer.cs + Designer + + + PublicResXFileCodeGenerator + Resources.it.Designer.cs + Designer + + + PublicResXFileCodeGenerator + Resources.fr.Designer.cs + Designer + + + PublicResXFileCodeGenerator + Resources.es.Designer.cs + + + Designer + PublicResXFileCodeGenerator + Resources.pt-BR.Designer.cs + + + Designer + PublicResXFileCodeGenerator + Resources.ru.Designer.cs + + + Designer + PublicResXFileCodeGenerator + Resources.de.Designer.cs + + + Designer + PublicResXFileCodeGenerator + Resources.sv.Designer.cs + + + Designer + PublicResXFileCodeGenerator + Resources.zh-Hans.Designer.cs + + + PublicResXFileCodeGenerator + Resources.ro.Designer.cs + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + MSBuild:Compile + + + + + + \ No newline at end of file diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/Xceed.Wpf.AvalonDock.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/Xceed.Wpf.AvalonDock.dll new file mode 100644 index 0000000..6e3030f Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/Xceed.Wpf.AvalonDock.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/Xceed.Wpf.AvalonDock.pdb b/Src/Xceed.Wpf.AvalonDock/bin/Debug/Xceed.Wpf.AvalonDock.pdb new file mode 100644 index 0000000..1137d94 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/Xceed.Wpf.AvalonDock.pdb differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/de/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/de/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..ddc5930 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/de/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/es/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/es/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..7937992 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/es/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/fr/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/fr/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..5618534 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/fr/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/hu/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/hu/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..0cdeaf6 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/hu/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/it/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/it/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..fb7b8f0 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/it/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/pt-BR/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/pt-BR/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..0997d39 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/pt-BR/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/ro/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/ro/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..11c267d Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/ro/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/ru/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/ru/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..6138876 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/ru/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/sv/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/sv/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..77ce29d Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/sv/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/bin/Debug/zh-Hans/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/bin/Debug/zh-Hans/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..8807381 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/bin/Debug/zh-Hans/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/Src/Xceed.Wpf.AvalonDock/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..01f0258 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.cs b/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.cs new file mode 100644 index 0000000..c65238f --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.cs @@ -0,0 +1,2 @@ + + diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.i.cs b/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.i.cs new file mode 100644 index 0000000..136dd1b --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.i.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XamlGeneratedNamespace { + + + /// + /// GeneratedInternalTypeHelper + /// + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public sealed class GeneratedInternalTypeHelper : System.Windows.Markup.InternalTypeHelper { + + /// + /// CreateInstance + /// + protected override object CreateInstance(System.Type type, System.Globalization.CultureInfo culture) { + return System.Activator.CreateInstance(type, ((System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic) + | (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.CreateInstance)), null, null, culture); + } + + /// + /// GetPropertyValue + /// + protected override object GetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, System.Globalization.CultureInfo culture) { + return propertyInfo.GetValue(target, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// SetPropertyValue + /// + protected override void SetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, object value, System.Globalization.CultureInfo culture) { + propertyInfo.SetValue(target, value, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// CreateDelegate + /// + protected override System.Delegate CreateDelegate(System.Type delegateType, object target, string handler) { + return ((System.Delegate)(target.GetType().InvokeMember("_CreateDelegate", (System.Reflection.BindingFlags.InvokeMethod + | (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)), null, target, new object[] { + delegateType, + handler}, null))); + } + + /// + /// AddEventHandler + /// + protected override void AddEventHandler(System.Reflection.EventInfo eventInfo, object target, System.Delegate handler) { + eventInfo.AddEventHandler(target, handler); + } + } +} + diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.Designer.cs.dll new file mode 100644 index 0000000..d70b74e Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.de.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.de.Designer.cs.dll new file mode 100644 index 0000000..493623e Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.de.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.es.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.es.Designer.cs.dll new file mode 100644 index 0000000..a6b26da Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.es.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.fr.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.fr.Designer.cs.dll new file mode 100644 index 0000000..d2d7efe Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.fr.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.hu.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.hu.Designer.cs.dll new file mode 100644 index 0000000..481d8b6 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.hu.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.it.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.it.Designer.cs.dll new file mode 100644 index 0000000..08943a2 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.it.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.pt-BR.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.pt-BR.Designer.cs.dll new file mode 100644 index 0000000..d385962 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.pt-BR.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.ro.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.ro.Designer.cs.dll new file mode 100644 index 0000000..2c7c181 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.ro.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.ru.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.ru.Designer.cs.dll new file mode 100644 index 0000000..4e525f2 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.ru.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.sv.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.sv.Designer.cs.dll new file mode 100644 index 0000000..4b290a1 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.sv.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.zh-Hans.Designer.cs.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.zh-Hans.Designer.cs.dll new file mode 100644 index 0000000..65eaf66 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TempPE/Properties.Resources.zh-Hans.Designer.cs.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs b/Src/Xceed.Wpf.AvalonDock/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs new file mode 100644 index 0000000..e69de29 diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Themes/generic.baml b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Themes/generic.baml new file mode 100644 index 0000000..4597cb1 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Themes/generic.baml differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.de.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.de.resources new file mode 100644 index 0000000..2d06a70 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.de.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.es.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.es.resources new file mode 100644 index 0000000..f0a2627 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.es.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources new file mode 100644 index 0000000..a624b88 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources new file mode 100644 index 0000000..5e49fd0 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.it.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.it.resources new file mode 100644 index 0000000..77d9552 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.it.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources new file mode 100644 index 0000000..b92e312 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.resources new file mode 100644 index 0000000..7aaab51 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources new file mode 100644 index 0000000..de13996 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources new file mode 100644 index 0000000..5980151 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources new file mode 100644 index 0000000..49c6105 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources new file mode 100644 index 0000000..b102a44 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csproj.FileListAbsolute.txt b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..4f120f3 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csproj.FileListAbsolute.txt @@ -0,0 +1,84 @@ +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\Xceed.Wpf.AvalonDock.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\Xceed.Wpf.AvalonDock.pdb +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.csprojResolveAssemblyReference.cache +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\GeneratedInternalTypeHelper.g.cs +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock_MarkupCompile.cache +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock_MarkupCompile.lref +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Themes\generic.baml +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.g.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.it.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.es.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.de.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.csproj.GenerateResource.Cache +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.dll +C:\download\WPFToolkit\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.pdb +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\Xceed.Wpf.AvalonDock.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\Xceed.Wpf.AvalonDock.pdb +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\bin\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.csprojResolveAssemblyReference.cache +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\GeneratedInternalTypeHelper.g.cs +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock_MarkupCompile.cache +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock_MarkupCompile.lref +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Themes\generic.baml +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.g.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.it.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.es.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.de.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.csproj.GenerateResource.Cache +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.dll +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.pdb diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csproj.GenerateResource.Cache b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csproj.GenerateResource.Cache new file mode 100644 index 0000000..eaca1e0 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csproj.GenerateResource.Cache differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csprojResolveAssemblyReference.cache b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csprojResolveAssemblyReference.cache new file mode 100644 index 0000000..69656e9 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csprojResolveAssemblyReference.cache differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.dll new file mode 100644 index 0000000..6e3030f Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.g.resources b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.g.resources new file mode 100644 index 0000000..112be62 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.g.resources differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.pdb b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.pdb new file mode 100644 index 0000000..1137d94 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.pdb differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.cache b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.cache new file mode 100644 index 0000000..33659fc --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.cache @@ -0,0 +1,20 @@ +Xceed.Wpf.AvalonDock + + +library +C# +.cs +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\ +Xceed.Wpf.AvalonDock +none +false +DEBUG + +1692892633 + +1541800582208 +12-354110402 +Themes\generic.xaml; + +False + diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.i.cache b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.i.cache new file mode 100644 index 0000000..6cf2c38 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.i.cache @@ -0,0 +1,20 @@ +Xceed.Wpf.AvalonDock + + +library +C# +.cs +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\ +Xceed.Wpf.AvalonDock +none +false +DEBUG + +1692892633 + +158-775779578 +12-354110402 +Themes\generic.xaml; + +True + diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.i.lref b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.i.lref new file mode 100644 index 0000000..f974dc7 --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.i.lref @@ -0,0 +1,4 @@ +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\GeneratedInternalTypeHelper.g.i.cs + +FC:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\Themes\generic.xaml;; + diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.lref b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.lref new file mode 100644 index 0000000..9a9709c --- /dev/null +++ b/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.lref @@ -0,0 +1,4 @@ +C:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\obj\Debug\GeneratedInternalTypeHelper.g.cs + +FC:\boneyard\WPFToolkit\Src\Xceed.Wpf.AvalonDock\Themes\generic.xaml;; + diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/de/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/de/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..ddc5930 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/de/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/es/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/es/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..7937992 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/es/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/fr/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/fr/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..5618534 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/fr/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/hu/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/hu/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..0cdeaf6 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/hu/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/it/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/it/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..fb7b8f0 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/it/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/pt-BR/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/pt-BR/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..0997d39 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/pt-BR/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/ro/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/ro/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..11c267d Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/ro/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/ru/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/ru/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..6138876 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/ru/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/sv/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/sv/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..77ce29d Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/sv/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/obj/Debug/zh-Hans/Xceed.Wpf.AvalonDock.resources.dll b/Src/Xceed.Wpf.AvalonDock/obj/Debug/zh-Hans/Xceed.Wpf.AvalonDock.resources.dll new file mode 100644 index 0000000..8807381 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/obj/Debug/zh-Hans/Xceed.Wpf.AvalonDock.resources.dll differ diff --git a/Src/Xceed.Wpf.AvalonDock/sn.snk b/Src/Xceed.Wpf.AvalonDock/sn.snk new file mode 100644 index 0000000..1bdc912 Binary files /dev/null and b/Src/Xceed.Wpf.AvalonDock/sn.snk differ diff --git a/Src/Xceed.Wpf.Toolkit/AssemblyVersionInfo.cs b/Src/Xceed.Wpf.Toolkit/AssemblyVersionInfo.cs new file mode 100644 index 0000000..e67c8f8 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/AssemblyVersionInfo.cs @@ -0,0 +1,32 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +#pragma warning disable 0436 +[assembly: System.Reflection.AssemblyVersion( _XceedVersionInfo.Version )] +#pragma warning restore 0436 + +internal static class _XceedVersionInfo +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string BaseVersion = "3.1"; + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string Version = BaseVersion + + ".0.0"; + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string PublicKeyToken = "ba83ff368b7563c6"; + + +} diff --git a/Src/Xceed.Wpf.Toolkit/AssemblyVersionInfoCommon.cs b/Src/Xceed.Wpf.Toolkit/AssemblyVersionInfoCommon.cs new file mode 100644 index 0000000..49ee168 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/AssemblyVersionInfoCommon.cs @@ -0,0 +1,22 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +internal static class _XceedVersionInfoCommon +{ +[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] + public const string Build = ".*"; + +} diff --git a/Src/Xceed.Wpf.Toolkit/AutoSelectTextBox/Implementation/AutoSelectBehaviorEnum.cs b/Src/Xceed.Wpf.Toolkit/AutoSelectTextBox/Implementation/AutoSelectBehaviorEnum.cs new file mode 100644 index 0000000..1a99643 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/AutoSelectTextBox/Implementation/AutoSelectBehaviorEnum.cs @@ -0,0 +1,28 @@ +/************************************************************************************* + + 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.Text; + +namespace Xceed.Wpf.Toolkit +{ + public enum AutoSelectBehavior + { + Never, + OnFocus + } +} diff --git a/Src/Xceed.Wpf.Toolkit/AutoSelectTextBox/Implementation/AutoSelectTextBox.cs b/Src/Xceed.Wpf.Toolkit/AutoSelectTextBox/Implementation/AutoSelectTextBox.cs new file mode 100644 index 0000000..f4e7975 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/AutoSelectTextBox/Implementation/AutoSelectTextBox.cs @@ -0,0 +1,300 @@ +/************************************************************************************* + + 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.Windows.Controls; +using System.Windows.Input; +using System.Windows; +using System.Windows.Automation; +using Xceed.Wpf.Toolkit.Core.Utilities; + +namespace Xceed.Wpf.Toolkit +{ + public class AutoSelectTextBox : TextBox + { + static AutoSelectTextBox() + { + AutomationProperties.AutomationIdProperty.OverrideMetadata( typeof( AutoSelectTextBox ), new UIPropertyMetadata( "AutoSelectTextBox" ) ); + } + + #region AutoSelectBehavior PROPERTY + + public AutoSelectBehavior AutoSelectBehavior + { + get + { + return ( AutoSelectBehavior )GetValue( AutoSelectBehaviorProperty ); + } + set + { + SetValue( AutoSelectBehaviorProperty, value ); + } + } + + public static readonly DependencyProperty AutoSelectBehaviorProperty = + DependencyProperty.Register( "AutoSelectBehavior", typeof( AutoSelectBehavior ), typeof( AutoSelectTextBox ), + new UIPropertyMetadata( AutoSelectBehavior.Never ) ); + + #endregion AutoSelectBehavior PROPERTY + + #region AutoMoveFocus PROPERTY + + public bool AutoMoveFocus + { + get + { + return ( bool )GetValue( AutoMoveFocusProperty ); + } + set + { + SetValue( AutoMoveFocusProperty, value ); + } + } + + public static readonly DependencyProperty AutoMoveFocusProperty = + DependencyProperty.Register( "AutoMoveFocus", typeof( bool ), typeof( AutoSelectTextBox ), new UIPropertyMetadata( false ) ); + + #endregion AutoMoveFocus PROPERTY + + #region QueryMoveFocus EVENT + + public static readonly RoutedEvent QueryMoveFocusEvent = EventManager.RegisterRoutedEvent( "QueryMoveFocus", + RoutingStrategy.Bubble, + typeof( QueryMoveFocusEventHandler ), + typeof( AutoSelectTextBox ) ); + #endregion QueryMoveFocus EVENT + + protected override void OnPreviewKeyDown( KeyEventArgs e ) + { + if( !this.AutoMoveFocus ) + { + base.OnPreviewKeyDown( e ); + return; + } + + if( ( e.Key == Key.Left ) + && ( ( Keyboard.Modifiers == ModifierKeys.None ) + || ( Keyboard.Modifiers == ModifierKeys.Control ) ) ) + { + e.Handled = this.MoveFocusLeft(); + } + + if( ( e.Key == Key.Right ) + && ( ( Keyboard.Modifiers == ModifierKeys.None ) + || ( Keyboard.Modifiers == ModifierKeys.Control ) ) ) + { + e.Handled = this.MoveFocusRight(); + } + + if( ( ( e.Key == Key.Up ) || ( e.Key == Key.PageUp ) ) + && ( ( Keyboard.Modifiers == ModifierKeys.None ) + || ( Keyboard.Modifiers == ModifierKeys.Control ) ) ) + { + e.Handled = this.MoveFocusUp(); + } + + if( ( ( e.Key == Key.Down ) || ( e.Key == Key.PageDown ) ) + && ( ( Keyboard.Modifiers == ModifierKeys.None ) + || ( Keyboard.Modifiers == ModifierKeys.Control ) ) ) + { + e.Handled = this.MoveFocusDown(); + } + + base.OnPreviewKeyDown( e ); + } + + protected override void OnPreviewGotKeyboardFocus( KeyboardFocusChangedEventArgs e ) + { + base.OnPreviewGotKeyboardFocus( e ); + + if( this.AutoSelectBehavior == AutoSelectBehavior.OnFocus ) + { + // If the focus was not in one of our child ( or popup ), we select all the text. + if( !TreeHelper.IsDescendantOf( e.OldFocus as DependencyObject, this ) ) + { + this.SelectAll(); + } + } + } + + protected override void OnPreviewMouseLeftButtonDown( MouseButtonEventArgs e ) + { + base.OnPreviewMouseLeftButtonDown( e ); + + if( this.AutoSelectBehavior == AutoSelectBehavior.Never ) + return; + + if( this.IsKeyboardFocusWithin == false ) + { + this.Focus(); + e.Handled = true; //prevent from removing the selection + } + } + + protected override void OnTextChanged( TextChangedEventArgs e ) + { + base.OnTextChanged( e ); + + if( !this.AutoMoveFocus ) + return; + + if( ( this.Text.Length != 0 ) + && ( this.Text.Length == this.MaxLength ) + && ( this.CaretIndex == this.MaxLength ) ) + { + if( this.CanMoveFocus( FocusNavigationDirection.Right, true ) == true ) + { + FocusNavigationDirection direction = ( this.FlowDirection == FlowDirection.LeftToRight ) + ? FocusNavigationDirection.Right + : FocusNavigationDirection.Left; + + this.MoveFocus( new TraversalRequest( direction ) ); + } + } + } + + private bool CanMoveFocus( FocusNavigationDirection direction, bool reachedMax ) + { + QueryMoveFocusEventArgs e = new QueryMoveFocusEventArgs( direction, reachedMax ); + this.RaiseEvent( e ); + return e.CanMoveFocus; + } + + private bool MoveFocusLeft() + { + if( this.FlowDirection == FlowDirection.LeftToRight ) + { + //occurs only if the cursor is at the beginning of the text + if( ( this.CaretIndex == 0 ) && ( this.SelectionLength == 0 ) ) + { + if( ComponentCommands.MoveFocusBack.CanExecute( null, this ) ) + { + ComponentCommands.MoveFocusBack.Execute( null, this ); + return true; + } + else if( this.CanMoveFocus( FocusNavigationDirection.Left, false ) ) + { + this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Left ) ); + return true; + } + } + } + else + { + //occurs only if the cursor is at the end of the text + if( ( this.CaretIndex == this.Text.Length ) && ( this.SelectionLength == 0 ) ) + { + if( ComponentCommands.MoveFocusBack.CanExecute( null, this ) ) + { + ComponentCommands.MoveFocusBack.Execute( null, this ); + return true; + } + else if( this.CanMoveFocus( FocusNavigationDirection.Left, false ) ) + { + this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Left ) ); + return true; + } + } + } + + return false; + } + + private bool MoveFocusRight() + { + if( this.FlowDirection == FlowDirection.LeftToRight ) + { + //occurs only if the cursor is at the beginning of the text + if( ( this.CaretIndex == this.Text.Length ) && ( this.SelectionLength == 0 ) ) + { + if( ComponentCommands.MoveFocusForward.CanExecute( null, this ) ) + { + ComponentCommands.MoveFocusForward.Execute( null, this ); + return true; + } + else if( this.CanMoveFocus( FocusNavigationDirection.Right, false ) ) + { + this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Right ) ); + return true; + } + } + } + else + { + //occurs only if the cursor is at the end of the text + if( ( this.CaretIndex == 0 ) && ( this.SelectionLength == 0 ) ) + { + if( ComponentCommands.MoveFocusForward.CanExecute( null, this ) ) + { + ComponentCommands.MoveFocusForward.Execute( null, this ); + return true; + } + else if( this.CanMoveFocus( FocusNavigationDirection.Right, false ) ) + { + this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Right ) ); + return true; + } + } + } + + return false; + } + + private bool MoveFocusUp() + { + int lineNumber = this.GetLineIndexFromCharacterIndex( this.SelectionStart ); + + //occurs only if the cursor is on the first line + if( lineNumber == 0 ) + { + if( ComponentCommands.MoveFocusUp.CanExecute( null, this ) ) + { + ComponentCommands.MoveFocusUp.Execute( null, this ); + return true; + } + else if( this.CanMoveFocus( FocusNavigationDirection.Up, false ) ) + { + this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Up ) ); + return true; + } + } + + return false; + } + + private bool MoveFocusDown() + { + int lineNumber = this.GetLineIndexFromCharacterIndex( this.SelectionStart ); + + //occurs only if the cursor is on the first line + if( lineNumber == ( this.LineCount - 1 ) ) + { + if( ComponentCommands.MoveFocusDown.CanExecute( null, this ) ) + { + ComponentCommands.MoveFocusDown.Execute( null, this ); + return true; + } + else if( this.CanMoveFocus( FocusNavigationDirection.Down, false ) ) + { + this.MoveFocus( new TraversalRequest( FocusNavigationDirection.Down ) ); + return true; + } + } + + return false; + } + } +} + diff --git a/Src/Xceed.Wpf.Toolkit/AutoSelectTextBox/Implementation/QueryMoveFocusEventArgs.cs b/Src/Xceed.Wpf.Toolkit/AutoSelectTextBox/Implementation/QueryMoveFocusEventArgs.cs new file mode 100644 index 0000000..6c5251d --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/AutoSelectTextBox/Implementation/QueryMoveFocusEventArgs.cs @@ -0,0 +1,73 @@ +/************************************************************************************* + + 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.Windows; +using System.Windows.Input; + +namespace Xceed.Wpf.Toolkit +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA1003:UseGenericEventHandlerInstances" )] + public delegate void QueryMoveFocusEventHandler( object sender, QueryMoveFocusEventArgs e ); + + public class QueryMoveFocusEventArgs : RoutedEventArgs + { + //default CTOR private to prevent its usage. + private QueryMoveFocusEventArgs() + { + } + + //internal to prevent anybody from building this type of event. + internal QueryMoveFocusEventArgs( FocusNavigationDirection direction, bool reachedMaxLength ) + : base( AutoSelectTextBox.QueryMoveFocusEvent ) + { + m_navigationDirection = direction; + m_reachedMaxLength = reachedMaxLength; + } + + public FocusNavigationDirection FocusNavigationDirection + { + get + { + return m_navigationDirection; + } + } + + public bool ReachedMaxLength + { + get + { + return m_reachedMaxLength; + } + } + + public bool CanMoveFocus + { + get + { + return m_canMove; + } + set + { + m_canMove = value; + } + } + + private FocusNavigationDirection m_navigationDirection; + private bool m_reachedMaxLength; + private bool m_canMove = true; //defaults to true... if nobody does nothing, then its capable of moving focus. + + } +} diff --git a/Src/Xceed.Wpf.Toolkit/BusyIndicator/Implementation/BusyIndicator.cs b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Implementation/BusyIndicator.cs new file mode 100644 index 0000000..557e596 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Implementation/BusyIndicator.cs @@ -0,0 +1,359 @@ +/************************************************************************************* + + 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.Windows; +using System.Windows.Controls; +using System.Windows.Shapes; +using System.Windows.Threading; + +namespace Xceed.Wpf.Toolkit +{ + /// + /// A control to provide a visual indicator when an application is busy. + /// + [TemplateVisualState( Name = VisualStates.StateIdle, GroupName = VisualStates.GroupBusyStatus )] + [TemplateVisualState( Name = VisualStates.StateBusy, GroupName = VisualStates.GroupBusyStatus )] + [TemplateVisualState( Name = VisualStates.StateVisible, GroupName = VisualStates.GroupVisibility )] + [TemplateVisualState( Name = VisualStates.StateHidden, GroupName = VisualStates.GroupVisibility )] + [StyleTypedProperty( Property = "OverlayStyle", StyleTargetType = typeof( Rectangle ) )] + [StyleTypedProperty( Property = "ProgressBarStyle", StyleTargetType = typeof( ProgressBar ) )] + public class BusyIndicator : ContentControl + { + #region Private Members + + /// + /// Timer used to delay the initial display and avoid flickering. + /// + private DispatcherTimer _displayAfterTimer = new DispatcherTimer(); + + #endregion //Private Members + + #region Constructors + + static BusyIndicator() + { + DefaultStyleKeyProperty.OverrideMetadata( typeof( BusyIndicator ), new FrameworkPropertyMetadata( typeof( BusyIndicator ) ) ); + } + + public BusyIndicator() + { + _displayAfterTimer.Tick += DisplayAfterTimerElapsed; + } + + #endregion //Constructors + + #region Base Class Overrides + + /// + /// Overrides the OnApplyTemplate method. + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + ChangeVisualState( false ); + } + + #endregion //Base Class Overrides + + #region Properties + + /// + /// Gets or sets a value indicating whether the BusyContent is visible. + /// + protected bool IsContentVisible + { + get; + set; + } + + #endregion //Properties + + #region Dependency Properties + + #region IsBusy + + /// + /// Identifies the IsBusy dependency property. + /// + public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register( + "IsBusy", + typeof( bool ), + typeof( BusyIndicator ), + new PropertyMetadata( false, new PropertyChangedCallback( OnIsBusyChanged ) ) ); + + /// + /// Gets or sets a value indicating whether the busy indicator should show. + /// + public bool IsBusy + { + get + { + return ( bool )GetValue( IsBusyProperty ); + } + set + { + SetValue( IsBusyProperty, value ); + } + } + + /// + /// IsBusyProperty property changed handler. + /// + /// BusyIndicator that changed its IsBusy. + /// Event arguments. + private static void OnIsBusyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( BusyIndicator )d ).OnIsBusyChanged( e ); + } + + /// + /// IsBusyProperty property changed handler. + /// + /// Event arguments. + protected virtual void OnIsBusyChanged( DependencyPropertyChangedEventArgs e ) + { + if( IsBusy ) + { + if( DisplayAfter.Equals( TimeSpan.Zero ) ) + { + // Go visible now + IsContentVisible = true; + } + else + { + // Set a timer to go visible + _displayAfterTimer.Interval = DisplayAfter; + _displayAfterTimer.Start(); + } + } + else + { + // No longer visible + _displayAfterTimer.Stop(); + IsContentVisible = false; + + if( this.FocusAfterBusy != null ) + { + this.FocusAfterBusy.Dispatcher.BeginInvoke( DispatcherPriority.Input, new Action( () => + { + this.FocusAfterBusy.Focus(); + } + ) ); + } + } + + ChangeVisualState( true ); + } + + #endregion //IsBusy + + #region Busy Content + + /// + /// Identifies the BusyContent dependency property. + /// + public static readonly DependencyProperty BusyContentProperty = DependencyProperty.Register( + "BusyContent", + typeof( object ), + typeof( BusyIndicator ), + new PropertyMetadata( null ) ); + + /// + /// Gets or sets a value indicating the busy content to display to the user. + /// + public object BusyContent + { + get + { + return ( object )GetValue( BusyContentProperty ); + } + set + { + SetValue( BusyContentProperty, value ); + } + } + + #endregion //Busy Content + + #region Busy Content Template + + /// + /// Identifies the BusyTemplate dependency property. + /// + public static readonly DependencyProperty BusyContentTemplateProperty = DependencyProperty.Register( + "BusyContentTemplate", + typeof( DataTemplate ), + typeof( BusyIndicator ), + new PropertyMetadata( null ) ); + + /// + /// Gets or sets a value indicating the template to use for displaying the busy content to the user. + /// + public DataTemplate BusyContentTemplate + { + get + { + return ( DataTemplate )GetValue( BusyContentTemplateProperty ); + } + set + { + SetValue( BusyContentTemplateProperty, value ); + } + } + + #endregion //Busy Content Template + + #region Display After + + /// + /// Identifies the DisplayAfter dependency property. + /// + public static readonly DependencyProperty DisplayAfterProperty = DependencyProperty.Register( + "DisplayAfter", + typeof( TimeSpan ), + typeof( BusyIndicator ), + new PropertyMetadata( TimeSpan.FromSeconds( 0.1 ) ) ); + + /// + /// Gets or sets a value indicating how long to delay before displaying the busy content. + /// + public TimeSpan DisplayAfter + { + get + { + return ( TimeSpan )GetValue( DisplayAfterProperty ); + } + set + { + SetValue( DisplayAfterProperty, value ); + } + } + + #endregion //Display After + + #region FocusAfterBusy + + /// + /// Identifies the FocusAfterBusy dependency property. + /// + public static readonly DependencyProperty FocusAfterBusyProperty = DependencyProperty.Register( + "FocusAfterBusy", + typeof( Control ), + typeof( BusyIndicator ), + new PropertyMetadata( null ) ); + + /// + /// Gets or sets a Control that should get focus when the busy indicator disapears. + /// + public Control FocusAfterBusy + { + get + { + return ( Control )GetValue( FocusAfterBusyProperty ); + } + set + { + SetValue( FocusAfterBusyProperty, value ); + } + } + + #endregion //FocusAfterBusy + + #region Overlay Style + + /// + /// Identifies the OverlayStyle dependency property. + /// + public static readonly DependencyProperty OverlayStyleProperty = DependencyProperty.Register( + "OverlayStyle", + typeof( Style ), + typeof( BusyIndicator ), + new PropertyMetadata( null ) ); + + /// + /// Gets or sets a value indicating the style to use for the overlay. + /// + public Style OverlayStyle + { + get + { + return ( Style )GetValue( OverlayStyleProperty ); + } + set + { + SetValue( OverlayStyleProperty, value ); + } + } + #endregion //Overlay Style + + #region ProgressBar Style + + /// + /// Identifies the ProgressBarStyle dependency property. + /// + public static readonly DependencyProperty ProgressBarStyleProperty = DependencyProperty.Register( + "ProgressBarStyle", + typeof( Style ), + typeof( BusyIndicator ), + new PropertyMetadata( null ) ); + + /// + /// Gets or sets a value indicating the style to use for the progress bar. + /// + public Style ProgressBarStyle + { + get + { + return ( Style )GetValue( ProgressBarStyleProperty ); + } + set + { + SetValue( ProgressBarStyleProperty, value ); + } + } + + #endregion //ProgressBar Style + + #endregion //Dependency Properties + + #region Methods + + /// + /// Handler for the DisplayAfterTimer. + /// + /// Event sender. + /// Event arguments. + private void DisplayAfterTimerElapsed( object sender, EventArgs e ) + { + _displayAfterTimer.Stop(); + IsContentVisible = true; + ChangeVisualState( true ); + } + + /// + /// Changes the control's visual state(s). + /// + /// True if state transitions should be used. + protected virtual void ChangeVisualState( bool useTransitions ) + { + VisualStateManager.GoToState( this, IsBusy ? VisualStates.StateBusy : VisualStates.StateIdle, useTransitions ); + VisualStateManager.GoToState( this, IsContentVisible ? VisualStates.StateVisible : VisualStates.StateHidden, useTransitions ); + } + + #endregion //Methods + } +} diff --git a/Src/Xceed.Wpf.Toolkit/BusyIndicator/Implementation/Converters/ProgressBarWidthConverter.cs b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Implementation/Converters/ProgressBarWidthConverter.cs new file mode 100644 index 0000000..e53acbc --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Implementation/Converters/ProgressBarWidthConverter.cs @@ -0,0 +1,41 @@ +/************************************************************************************* + + 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.Globalization; +using System.Linq; +using System.Text; +using System.Windows.Data; + +namespace Xceed.Wpf.Toolkit.Converters +{ + public class ProgressBarWidthConverter : IMultiValueConverter + { + public object Convert( object[] values, Type targetType, object parameter, CultureInfo culture ) + { + var contentWidth = ( double )values[ 0 ]; + var parentMinWidth = ( double )values[ 1 ]; + + return Math.Max( contentWidth, parentMinWidth ); + } + + public object[] ConvertBack( object value, Type[] targetTypes, object parameter, CultureInfo culture ) + { + throw new NotImplementedException(); + } + } +} diff --git a/Src/Xceed.Wpf.Toolkit/BusyIndicator/Implementation/VisualStates.BusyIndicator.cs b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Implementation/VisualStates.BusyIndicator.cs new file mode 100644 index 0000000..5e1c41f --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Implementation/VisualStates.BusyIndicator.cs @@ -0,0 +1,51 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +namespace Xceed.Wpf.Toolkit +{ + internal static partial class VisualStates + { + /// + /// Busyness group name. + /// + public const string GroupBusyStatus = "BusyStatusStates"; + + /// + /// Busy state for BusyIndicator. + /// + public const string StateBusy = "Busy"; + + /// + /// Idle state for BusyIndicator. + /// + public const string StateIdle = "Idle"; + + /// + /// BusyDisplay group. + /// + public const string GroupVisibility = "VisibilityStates"; + + /// + /// Visible state name for BusyIndicator. + /// + public const string StateVisible = "Visible"; + + /// + /// Hidden state name for BusyIndicator. + /// + public const string StateHidden = "Hidden"; + } +} diff --git a/Src/Xceed.Wpf.Toolkit/BusyIndicator/Themes/Aero2.NormalColor.xaml b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Themes/Aero2.NormalColor.xaml new file mode 100644 index 0000000..39c7121 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Themes/Aero2.NormalColor.xaml @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + Collapsed + + + + + + + Collapsed + + + + + + + + + + + Visible + + + + + + + Visible + + + + + + + + + + + + + True + + + + + + + + + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Src/Xceed.Wpf.Toolkit/BusyIndicator/Themes/Generic.xaml b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Themes/Generic.xaml new file mode 100644 index 0000000..c87385a --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/BusyIndicator/Themes/Generic.xaml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Collapsed + + + + + + + Collapsed + + + + + + + + + + + Visible + + + + + + + Visible + + + + + + + + + + + + + True + + + + + + + + + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/ButtonSpinner.cs b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/ButtonSpinner.cs new file mode 100644 index 0000000..4d083e1 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/ButtonSpinner.cs @@ -0,0 +1,366 @@ +/************************************************************************************* + + 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.Windows; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Markup; + +namespace Xceed.Wpf.Toolkit +{ + public enum Location + { + Left, + Right + } + + /// + /// Represents a spinner control that includes two Buttons. + /// + [TemplatePart( Name = PART_IncreaseButton, Type = typeof( ButtonBase ) )] + [TemplatePart( Name = PART_DecreaseButton, Type = typeof( ButtonBase ) )] + [ContentProperty( "Content" )] + public class ButtonSpinner : Spinner + { + private const string PART_IncreaseButton = "PART_IncreaseButton"; + private const string PART_DecreaseButton = "PART_DecreaseButton"; + + #region Properties + + #region AllowSpin + + public static readonly DependencyProperty AllowSpinProperty = DependencyProperty.Register( "AllowSpin", typeof( bool ), typeof( ButtonSpinner ), new UIPropertyMetadata( true, AllowSpinPropertyChanged ) ); + public bool AllowSpin + { + get + { + return ( bool )GetValue( AllowSpinProperty ); + } + set + { + SetValue( AllowSpinProperty, value ); + } + } + + private static void AllowSpinPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ButtonSpinner source = d as ButtonSpinner; + source.OnAllowSpinChanged( (bool)e.OldValue, (bool)e.NewValue ); + } + + #endregion //AllowSpin + + #region ButtonSpinnerLocation + + public static readonly DependencyProperty ButtonSpinnerLocationProperty = DependencyProperty.Register( "ButtonSpinnerLocation", typeof( Location ), typeof( ButtonSpinner ), new UIPropertyMetadata( Location.Right ) ); + public Location ButtonSpinnerLocation + { + get + { + return ( Location )GetValue( ButtonSpinnerLocationProperty ); + } + set + { + SetValue( ButtonSpinnerLocationProperty, value ); + } + } + + #endregion //ButtonSpinnerLocation + + #region Content + + /// + /// Identifies the Content dependency property. + /// + public static readonly DependencyProperty ContentProperty = DependencyProperty.Register( "Content", typeof( object ), typeof( ButtonSpinner ), new PropertyMetadata( null, OnContentPropertyChanged ) ); + public object Content + { + get + { + return GetValue( ContentProperty ) as object; + } + set + { + SetValue( ContentProperty, value ); + } + } + + /// + /// ContentProperty property changed handler. + /// + /// ButtonSpinner that changed its Content. + /// Event arguments. + private static void OnContentPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ButtonSpinner source = d as ButtonSpinner; + source.OnContentChanged( e.OldValue, e.NewValue ); + } + + #endregion //Content + + #region DecreaseButton + + private ButtonBase _decreaseButton; + /// + /// Gets or sets the DecreaseButton template part. + /// + private ButtonBase DecreaseButton + { + get + { + return _decreaseButton; + } + set + { + if( _decreaseButton != null ) + { + _decreaseButton.Click -= OnButtonClick; + } + + _decreaseButton = value; + + if( _decreaseButton != null ) + { + _decreaseButton.Click += OnButtonClick; + } + } + } + + #endregion //DecreaseButton + + #region IncreaseButton + + private ButtonBase _increaseButton; + /// + /// Gets or sets the IncreaseButton template part. + /// + private ButtonBase IncreaseButton + { + get + { + return _increaseButton; + } + set + { + if( _increaseButton != null ) + { + _increaseButton.Click -= OnButtonClick; + } + + _increaseButton = value; + + if( _increaseButton != null ) + { + _increaseButton.Click += OnButtonClick; + } + } + } + + #endregion //IncreaseButton + + #region ShowButtonSpinner + + public static readonly DependencyProperty ShowButtonSpinnerProperty = DependencyProperty.Register( "ShowButtonSpinner", typeof( bool ), typeof( ButtonSpinner ), new UIPropertyMetadata( true ) ); + public bool ShowButtonSpinner + { + get + { + return ( bool )GetValue( ShowButtonSpinnerProperty ); + } + set + { + SetValue( ShowButtonSpinnerProperty, value ); + } + } + + #endregion //ShowButtonSpinner + + #endregion //Properties + + #region Constructors + + static ButtonSpinner() + { + DefaultStyleKeyProperty.OverrideMetadata( typeof( ButtonSpinner ), new FrameworkPropertyMetadata( typeof( ButtonSpinner ) ) ); + } + + #endregion //Constructors + + #region Base Class Overrides + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + IncreaseButton = GetTemplateChild( PART_IncreaseButton ) as ButtonBase; + DecreaseButton = GetTemplateChild( PART_DecreaseButton ) as ButtonBase; + + SetButtonUsage(); + } + + /// + /// Cancel LeftMouseButtonUp events originating from a button that has + /// been changed to disabled. + /// + /// The data for the event. + protected override void OnMouseLeftButtonUp( MouseButtonEventArgs e ) + { + base.OnMouseLeftButtonUp( e ); + + Point mousePosition; + if( IncreaseButton != null && IncreaseButton.IsEnabled == false ) + { + mousePosition = e.GetPosition( IncreaseButton ); + if( mousePosition.X > 0 && mousePosition.X < IncreaseButton.ActualWidth && + mousePosition.Y > 0 && mousePosition.Y < IncreaseButton.ActualHeight ) + { + e.Handled = true; + } + } + + if( DecreaseButton != null && DecreaseButton.IsEnabled == false ) + { + mousePosition = e.GetPosition( DecreaseButton ); + if( mousePosition.X > 0 && mousePosition.X < DecreaseButton.ActualWidth && + mousePosition.Y > 0 && mousePosition.Y < DecreaseButton.ActualHeight ) + { + e.Handled = true; + } + } + } + + protected override void OnPreviewKeyDown( KeyEventArgs e ) + { + switch( e.Key ) + { + case Key.Up: + { + if( this.AllowSpin ) + { + this.OnSpin( new SpinEventArgs( SpinDirection.Increase ) ); + e.Handled = true; + } + + break; + } + case Key.Down: + { + if( this.AllowSpin ) + { + this.OnSpin( new SpinEventArgs( SpinDirection.Decrease ) ); + e.Handled = true; + } + + break; + } + case Key.Enter: + { + //Do not Spin on enter Key when spinners have focus + if( this.IncreaseButton.IsFocused || this.DecreaseButton.IsFocused ) + { + e.Handled = true; + } + break; + } + } + } + + protected override void OnMouseWheel( MouseWheelEventArgs e ) + { + base.OnMouseWheel( e ); + + if( this.IsKeyboardFocusWithin && !e.Handled && this.AllowSpin ) + { + if( e.Delta < 0 ) + { + this.OnSpin( new SpinEventArgs( SpinDirection.Decrease, true ) ); + } + else if( 0 < e.Delta ) + { + this.OnSpin( new SpinEventArgs( SpinDirection.Increase, true ) ); + } + + e.Handled = true; + } + } + + /// + /// Called when valid spin direction changed. + /// + /// The old value. + /// The new value. + protected override void OnValidSpinDirectionChanged( ValidSpinDirections oldValue, ValidSpinDirections newValue ) + { + SetButtonUsage(); + } + + #endregion //Base Class Overrides + + #region Event Handlers + + /// + /// Handle click event of IncreaseButton and DecreaseButton template parts, + /// translating Click to appropriate Spin event. + /// + /// Event sender, should be either IncreaseButton or DecreaseButton template part. + /// Event args. + private void OnButtonClick( object sender, RoutedEventArgs e ) + { + if( AllowSpin ) + { + SpinDirection direction = sender == IncreaseButton ? SpinDirection.Increase : SpinDirection.Decrease; + OnSpin( new SpinEventArgs( direction ) ); + } + } + + #endregion //Event Handlers + + #region Methods + + /// + /// Occurs when the Content property value changed. + /// + /// The old value of the Content property. + /// The new value of the Content property. + protected virtual void OnContentChanged( object oldValue, object newValue ) + { + } + + protected virtual void OnAllowSpinChanged( bool oldValue, bool newValue ) + { + SetButtonUsage(); + } + + /// + /// Disables or enables the buttons based on the valid spin direction. + /// + private void SetButtonUsage() + { + // buttonspinner adds buttons that spin, so disable accordingly. + if( IncreaseButton != null ) + { + IncreaseButton.IsEnabled = AllowSpin && ( ( ValidSpinDirection & ValidSpinDirections.Increase ) == ValidSpinDirections.Increase ); + } + + if( DecreaseButton != null ) + { + DecreaseButton.IsEnabled = AllowSpin && ( ( ValidSpinDirection & ValidSpinDirections.Decrease ) == ValidSpinDirections.Decrease ); + } + } + + #endregion //Methods + } +} diff --git a/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/SpinDirection.cs b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/SpinDirection.cs new file mode 100644 index 0000000..4e962dc --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/SpinDirection.cs @@ -0,0 +1,35 @@ +/************************************************************************************* + + 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 + + ***********************************************************************************/ + +namespace Xceed.Wpf.Toolkit +{ + /// + /// Represents spin directions that could be initiated by the end-user. + /// + /// Preview + public enum SpinDirection + { + /// + /// Represents a spin initiated by the end-user in order to Increase a value. + /// + Increase = 0, + + /// + /// Represents a spin initiated by the end-user in order to Decrease a value. + /// + Decrease = 1 + } +} diff --git a/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/SpinEventArgs.cs b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/SpinEventArgs.cs new file mode 100644 index 0000000..0510e18 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/SpinEventArgs.cs @@ -0,0 +1,63 @@ +/************************************************************************************* + + 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.Windows; + +namespace Xceed.Wpf.Toolkit +{ + /// + /// Provides data for the Spinner.Spin event. + /// + /// Preview + public class SpinEventArgs : RoutedEventArgs + { + /// + /// Gets the SpinDirection for the spin that has been initiated by the + /// end-user. + /// + public SpinDirection Direction + { + get; + private set; + } + + /// + /// Get or set whheter the spin event originated from a mouse wheel event. + /// + public bool UsingMouseWheel + { + get; + private set; + } + + /// + /// Initializes a new instance of the SpinEventArgs class. + /// + /// Spin direction. + public SpinEventArgs( SpinDirection direction ) + : base() + { + Direction = direction; + } + + public SpinEventArgs( SpinDirection direction, bool usingMouseWheel ) + : base() + { + Direction = direction; + UsingMouseWheel = usingMouseWheel; + } + } +} diff --git a/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/Spinner.cs b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/Spinner.cs new file mode 100644 index 0000000..2fdf609 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/Spinner.cs @@ -0,0 +1,101 @@ +/************************************************************************************* + + 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.Windows; +using System.Windows.Controls; + +namespace Xceed.Wpf.Toolkit +{ + /// + /// Base class for controls that represents controls that can spin. + /// + public abstract class Spinner : Control + { + #region Properties + + /// + /// Identifies the ValidSpinDirection dependency property. + /// + public static readonly DependencyProperty ValidSpinDirectionProperty = DependencyProperty.Register( "ValidSpinDirection", typeof( ValidSpinDirections ), typeof( Spinner ), new PropertyMetadata( ValidSpinDirections.Increase | ValidSpinDirections.Decrease, OnValidSpinDirectionPropertyChanged ) ); + public ValidSpinDirections ValidSpinDirection + { + get + { + return ( ValidSpinDirections )GetValue( ValidSpinDirectionProperty ); + } + set + { + SetValue( ValidSpinDirectionProperty, value ); + } + } + + /// + /// ValidSpinDirectionProperty property changed handler. + /// + /// ButtonSpinner that changed its ValidSpinDirection. + /// Event arguments. + private static void OnValidSpinDirectionPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + Spinner source = ( Spinner )d; + ValidSpinDirections oldvalue = ( ValidSpinDirections )e.OldValue; + ValidSpinDirections newvalue = ( ValidSpinDirections )e.NewValue; + source.OnValidSpinDirectionChanged( oldvalue, newvalue ); + } + + #endregion //Properties + + /// + /// Occurs when spinning is initiated by the end-user. + /// + public event EventHandler Spin; + + /// + /// Initializes a new instance of the Spinner class. + /// + protected Spinner() + { + } + + /// + /// Raises the OnSpin event when spinning is initiated by the end-user. + /// + /// Spin event args. + protected virtual void OnSpin( SpinEventArgs e ) + { + ValidSpinDirections valid = e.Direction == SpinDirection.Increase ? ValidSpinDirections.Increase : ValidSpinDirections.Decrease; + + //Only raise the event if spin is allowed. + if( ( ValidSpinDirection & valid ) == valid ) + { + EventHandler handler = Spin; + if( handler != null ) + { + handler( this, e ); + } + } + } + + /// + /// Called when valid spin direction changed. + /// + /// The old value. + /// The new value. + protected virtual void OnValidSpinDirectionChanged( ValidSpinDirections oldValue, ValidSpinDirections newValue ) + { + } + } +} diff --git a/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/ValidSpinDirections.cs b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/ValidSpinDirections.cs new file mode 100644 index 0000000..ecd4786 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Implementation/ValidSpinDirections.cs @@ -0,0 +1,42 @@ +/************************************************************************************* + + 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; + +namespace Xceed.Wpf.Toolkit +{ + /// + /// Represents spin directions that are valid. + /// + [Flags] + public enum ValidSpinDirections + { + /// + /// Can not increase nor decrease. + /// + None = 0, + + /// + /// Can increase. + /// + Increase = 1, + + /// + /// Can decrease. + /// + Decrease = 2 + } +} diff --git a/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Themes/Aero2.NormalColor.xaml b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Themes/Aero2.NormalColor.xaml new file mode 100644 index 0000000..e5a3586 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Themes/Aero2.NormalColor.xaml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + diff --git a/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Themes/Generic.xaml b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Themes/Generic.xaml new file mode 100644 index 0000000..611510b --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/ButtonSpinner/Themes/Generic.xaml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + diff --git a/Src/Xceed.Wpf.Toolkit/Calculator/Implementation/Calculator.cs b/Src/Xceed.Wpf.Toolkit/Calculator/Implementation/Calculator.cs new file mode 100644 index 0000000..5994ebe --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/Calculator/Implementation/Calculator.cs @@ -0,0 +1,578 @@ +/************************************************************************************* + + 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.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Threading; +using Xceed.Wpf.Toolkit.Core.Utilities; + +namespace Xceed.Wpf.Toolkit +{ + [TemplatePart( Name = PART_CalculatorButtonPanel, Type = typeof( ContentControl ) )] + public class Calculator : Control + { + private const string PART_CalculatorButtonPanel = "PART_CalculatorButtonPanel"; + + #region Members + + private ContentControl _buttonPanel; + private bool _showNewNumber = true; + private decimal _previousValue; + private Operation _lastOperation = Operation.None; + private readonly Dictionary _timers = new Dictionary(); + + #endregion //Members + + #region Enumerations + + public enum CalculatorButtonType + { + Add, + Back, + Cancel, + Clear, + Decimal, + Divide, + Eight, + Equal, + Five, + Four, + Fraction, + MAdd, + MC, + MR, + MS, + MSub, + Multiply, + Negate, + Nine, + None, + One, + Percent, + Seven, + Six, + Sqrt, + Subtract, + Three, + Two, + Zero + } + + public enum Operation + { + Add, + Subtract, + Divide, + Multiply, + Percent, + Sqrt, + Fraction, + None, + Clear, + Negate + } + + #endregion //Enumerations + + #region Properties + + #region CalculatorButtonPanelTemplate + + public static readonly DependencyProperty CalculatorButtonPanelTemplateProperty = DependencyProperty.Register( "CalculatorButtonPanelTemplate" + , typeof( ControlTemplate ), typeof( Calculator ), new UIPropertyMetadata( null ) ); + public ControlTemplate CalculatorButtonPanelTemplate + { + get + { + return (ControlTemplate)GetValue( CalculatorButtonPanelTemplateProperty ); + } + set + { + SetValue( CalculatorButtonPanelTemplateProperty, value ); + } + } + + #endregion //CalculatorButtonPanelTemplate + + #region CalculatorButtonType + + public static readonly DependencyProperty CalculatorButtonTypeProperty = DependencyProperty.RegisterAttached( "CalculatorButtonType", typeof( CalculatorButtonType ), typeof( Calculator ), new UIPropertyMetadata( CalculatorButtonType.None, OnCalculatorButtonTypeChanged ) ); + public static CalculatorButtonType GetCalculatorButtonType( DependencyObject target ) + { + return ( CalculatorButtonType )target.GetValue( CalculatorButtonTypeProperty ); + } + public static void SetCalculatorButtonType( DependencyObject target, CalculatorButtonType value ) + { + target.SetValue( CalculatorButtonTypeProperty, value ); + } + private static void OnCalculatorButtonTypeChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) + { + OnCalculatorButtonTypeChanged( o, ( CalculatorButtonType )e.OldValue, ( CalculatorButtonType )e.NewValue ); + } + private static void OnCalculatorButtonTypeChanged( DependencyObject o, CalculatorButtonType oldValue, CalculatorButtonType newValue ) + { + Button button = o as Button; + button.CommandParameter = newValue; + if( button.Content == null ) + { + button.Content = CalculatorUtilities.GetCalculatorButtonContent( newValue ); + } + } + + #endregion //CalculatorButtonType + + #region DisplayText + + public static readonly DependencyProperty DisplayTextProperty = DependencyProperty.Register( "DisplayText", typeof( string ), typeof( Calculator ), new UIPropertyMetadata( "0", OnDisplayTextChanged ) ); + public string DisplayText + { + get + { + return ( string )GetValue( DisplayTextProperty ); + } + set + { + SetValue( DisplayTextProperty, value ); + } + } + + private static void OnDisplayTextChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) + { + Calculator calculator = o as Calculator; + if( calculator != null ) + calculator.OnDisplayTextChanged( ( string )e.OldValue, ( string )e.NewValue ); + } + + protected virtual void OnDisplayTextChanged( string oldValue, string newValue ) + { + // TODO: Add your property changed side-effects. Descendants can override as well. + } + + #endregion //DisplayText + + #region Memory + + public static readonly DependencyProperty MemoryProperty = DependencyProperty.Register( "Memory", typeof( decimal ), typeof( Calculator ), new UIPropertyMetadata( default( decimal ) ) ); + public decimal Memory + { + get + { + return ( decimal )GetValue( MemoryProperty ); + } + set + { + SetValue( MemoryProperty, value ); + } + } + + #endregion //Memory + + #region Precision + + public static readonly DependencyProperty PrecisionProperty = DependencyProperty.Register( "Precision", typeof( int ), typeof( Calculator ), new UIPropertyMetadata( 6 ) ); + public int Precision + { + get + { + return ( int )GetValue( PrecisionProperty ); + } + set + { + SetValue( PrecisionProperty, value ); + } + } + + #endregion //Precision + + #region Value + + public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof( decimal? ), typeof( Calculator ), new FrameworkPropertyMetadata( default( decimal ), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValueChanged ) ); + public decimal? Value + { + get + { + return ( decimal? )GetValue( ValueProperty ); + } + set + { + SetValue( ValueProperty, value ); + } + } + + private static void OnValueChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) + { + Calculator calculator = o as Calculator; + if( calculator != null ) + calculator.OnValueChanged( ( decimal? )e.OldValue, ( decimal? )e.NewValue ); + } + + protected virtual void OnValueChanged( decimal? oldValue, decimal? newValue ) + { + SetDisplayText( newValue ); + + RoutedPropertyChangedEventArgs args = new RoutedPropertyChangedEventArgs( oldValue, newValue ); + args.RoutedEvent = ValueChangedEvent; + RaiseEvent( args ); + } + + #endregion //Value + + #endregion //Properties + + #region Constructors + + static Calculator() + { + DefaultStyleKeyProperty.OverrideMetadata( typeof( Calculator ), new FrameworkPropertyMetadata( typeof( Calculator ) ) ); + } + + public Calculator() + { + CommandBindings.Add( new CommandBinding( CalculatorCommands.CalculatorButtonClick, ExecuteCalculatorButtonClick ) ); + AddHandler( MouseDownEvent, new MouseButtonEventHandler( Calculator_OnMouseDown ), true ); + } + + #endregion //Constructors + + #region Base Class Overrides + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _buttonPanel = GetTemplateChild( PART_CalculatorButtonPanel ) as ContentControl; + } + + protected override void OnTextInput( TextCompositionEventArgs e ) + { + var buttonType = CalculatorUtilities.GetCalculatorButtonTypeFromText( e.Text ); + if( buttonType != CalculatorButtonType.None ) + { + SimulateCalculatorButtonClick( buttonType ); + ProcessCalculatorButton( buttonType ); + } + } + + #endregion //Base Class Overrides + + #region Event Handlers + + private void Calculator_OnMouseDown( object sender, MouseButtonEventArgs e ) + { + if( !IsFocused ) + { + Focus(); + e.Handled = true; + } + } + + void Timer_Tick( object sender, EventArgs e ) + { + DispatcherTimer timer = ( DispatcherTimer )sender; + timer.Stop(); + timer.Tick -= Timer_Tick; + + if( _timers.ContainsValue( timer ) ) + { + var button = _timers.Where( x => x.Value == timer ).Select( x => x.Key ).FirstOrDefault(); + if( button != null ) + { + VisualStateManager.GoToState( button, button.IsMouseOver ? "MouseOver" : "Normal", true ); + _timers.Remove( button ); + } + } + } + + #endregion //Event Handlers + + #region Methods + + internal void InitializeToValue(decimal? value) + { + _previousValue = 0; + _lastOperation = Operation.None; + _showNewNumber = true; + Value = value; + // Since the display text may be out of sync + // with "Value", this call will force the + // text update if Value was already equal to + // the value parameter. + this.SetDisplayText( value ); + } + + private void Calculate() + { + if( _lastOperation == Operation.None ) + return; + + try + { + Value = Decimal.Round( CalculateValue( _lastOperation ), Precision ); + SetDisplayText( Value ); //Set DisplayText even when Value doesn't change + } + catch + { + Value = null; + DisplayText = "ERROR"; + } + } + + private void SetDisplayText( decimal? newValue ) + { + if( newValue.HasValue && ( newValue.Value != 0 ) ) + DisplayText = newValue.ToString(); + else + DisplayText = "0"; + } + + private void Calculate( Operation newOperation ) + { + if( !_showNewNumber ) + Calculate(); + + _lastOperation = newOperation; + } + + private void Calculate( Operation currentOperation, Operation newOperation ) + { + _lastOperation = currentOperation; + Calculate(); + _lastOperation = newOperation; + } + + private decimal CalculateValue( Operation operation ) + { + decimal newValue = decimal.Zero; + decimal currentValue = CalculatorUtilities.ParseDecimal( DisplayText ); + + switch( operation ) + { + case Operation.Add: + newValue = CalculatorUtilities.Add( _previousValue, currentValue ); + break; + case Operation.Subtract: + newValue = CalculatorUtilities.Subtract( _previousValue, currentValue ); + break; + case Operation.Multiply: + newValue = CalculatorUtilities.Multiply( _previousValue, currentValue ); + break; + case Operation.Divide: + newValue = CalculatorUtilities.Divide( _previousValue, currentValue ); + break; + //case Operation.Percent: + // newValue = CalculatorUtilities.Percent(_previousValue, currentValue); + // break; + case Operation.Sqrt: + newValue = CalculatorUtilities.SquareRoot( currentValue ); + break; + case Operation.Fraction: + newValue = CalculatorUtilities.Fraction( currentValue ); + break; + case Operation.Negate: + newValue = CalculatorUtilities.Negate( currentValue ); + break; + default: + newValue = decimal.Zero; + break; + } + + return newValue; + } + + void ProcessBackKey() + { + string displayText; + if( DisplayText.Length > 1 && !( DisplayText.Length == 2 && DisplayText[ 0 ] == '-' ) ) + { + displayText = DisplayText.Remove( DisplayText.Length - 1, 1 ); + } + else + { + displayText = "0"; + _showNewNumber = true; + } + + DisplayText = displayText; + } + + private void ProcessCalculatorButton( CalculatorButtonType buttonType ) + { + if( CalculatorUtilities.IsDigit( buttonType ) ) + ProcessDigitKey( buttonType ); + else if( ( CalculatorUtilities.IsMemory( buttonType ) ) ) + ProcessMemoryKey( buttonType ); + else + ProcessOperationKey( buttonType ); + } + + private void ProcessDigitKey( CalculatorButtonType buttonType ) + { + if( _showNewNumber ) + DisplayText = CalculatorUtilities.GetCalculatorButtonContent( buttonType ); + else + DisplayText += CalculatorUtilities.GetCalculatorButtonContent( buttonType ); + + _showNewNumber = false; + } + + private void ProcessMemoryKey( Calculator.CalculatorButtonType buttonType ) + { + decimal currentValue = CalculatorUtilities.ParseDecimal( DisplayText ); + + _showNewNumber = true; + + switch( buttonType ) + { + case Calculator.CalculatorButtonType.MAdd: + Memory += currentValue; + break; + case Calculator.CalculatorButtonType.MC: + Memory = decimal.Zero; + break; + case Calculator.CalculatorButtonType.MR: + DisplayText = Memory.ToString(); + _showNewNumber = false; + break; + case Calculator.CalculatorButtonType.MS: + Memory = currentValue; + break; + case Calculator.CalculatorButtonType.MSub: + Memory -= currentValue; + break; + default: + break; + } + } + + private void ProcessOperationKey( CalculatorButtonType buttonType ) + { + switch( buttonType ) + { + case CalculatorButtonType.Add: + Calculate( Operation.Add ); + break; + case CalculatorButtonType.Subtract: + Calculate( Operation.Subtract ); + break; + case CalculatorButtonType.Multiply: + Calculate( Operation.Multiply ); + break; + case CalculatorButtonType.Divide: + Calculate( Operation.Divide ); + break; + case CalculatorButtonType.Percent: + if( _lastOperation != Operation.None ) + { + decimal currentValue = CalculatorUtilities.ParseDecimal( DisplayText ); + decimal newValue = CalculatorUtilities.Percent( _previousValue, currentValue ); + DisplayText = newValue.ToString(); + } + else + { + DisplayText = "0"; + _showNewNumber = true; + } + return; + case CalculatorButtonType.Sqrt: + Calculate( Operation.Sqrt, Operation.None ); + break; + case CalculatorButtonType.Fraction: + Calculate( Operation.Fraction, Operation.None ); + break; + case CalculatorButtonType.Negate: + Calculate( Operation.Negate, Operation.None ); + break; + case CalculatorButtonType.Equal: + Calculate( Operation.None ); + break; + case CalculatorButtonType.Clear: + Calculate( Operation.Clear, Operation.None ); + break; + case CalculatorButtonType.Cancel: + DisplayText = _previousValue.ToString(); + _lastOperation = Operation.None; + _showNewNumber = true; + return; + case CalculatorButtonType.Back: + ProcessBackKey(); + return; + default: + break; + } + + Decimal.TryParse( DisplayText, out _previousValue ); + _showNewNumber = true; + } + + private void SimulateCalculatorButtonClick( CalculatorButtonType buttonType ) + { + var button = CalculatorUtilities.FindButtonByCalculatorButtonType( _buttonPanel, buttonType ); + if( button != null ) + { + VisualStateManager.GoToState( button, "Pressed", true ); + DispatcherTimer timer; + if( _timers.ContainsKey( button ) ) + { + timer = _timers[ button ]; + timer.Stop(); + } + else + { + timer = new DispatcherTimer(); + timer.Interval = TimeSpan.FromMilliseconds( 100 ); + timer.Tick += Timer_Tick; + _timers.Add( button, timer ); + } + + timer.Start(); + } + } + + #endregion //Methods + + #region Events + + //Due to a bug in Visual Studio, you cannot create event handlers for nullable args in XAML, so I have to use object instead. + public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent( "ValueChanged", RoutingStrategy.Bubble, typeof( RoutedPropertyChangedEventHandler ), typeof( Calculator ) ); + public event RoutedPropertyChangedEventHandler ValueChanged + { + add + { + AddHandler( ValueChangedEvent, value ); + } + remove + { + RemoveHandler( ValueChangedEvent, value ); + } + } + + #endregion //Events + + #region Commands + + private void ExecuteCalculatorButtonClick( object sender, ExecutedRoutedEventArgs e ) + { + var buttonType = ( CalculatorButtonType )e.Parameter; + ProcessCalculatorButton( buttonType ); + } + + #endregion //Commands + } +} diff --git a/Src/Xceed.Wpf.Toolkit/Calculator/Implementation/CalculatorCommands.cs b/Src/Xceed.Wpf.Toolkit/Calculator/Implementation/CalculatorCommands.cs new file mode 100644 index 0000000..df187c3 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/Calculator/Implementation/CalculatorCommands.cs @@ -0,0 +1,33 @@ +/************************************************************************************* + + 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.Windows.Input; + +namespace Xceed.Wpf.Toolkit +{ + public static class CalculatorCommands + { + private static RoutedCommand _calculatorButtonClickCommand = new RoutedCommand(); + + public static RoutedCommand CalculatorButtonClick + { + get + { + return _calculatorButtonClickCommand; + } + } + } +} diff --git a/Src/Xceed.Wpf.Toolkit/Calculator/Themes/Aero2.NormalColor.xaml b/Src/Xceed.Wpf.Toolkit/Calculator/Themes/Aero2.NormalColor.xaml new file mode 100644 index 0000000..82f5a99 --- /dev/null +++ b/Src/Xceed.Wpf.Toolkit/Calculator/Themes/Aero2.NormalColor.xaml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +