mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-03-03 00:00:57 +08:00
项目结构调整
This commit is contained in:
22
Others/Dragablz/.gitattributes
vendored
Normal file
22
Others/Dragablz/.gitattributes
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
*.sln merge=union
|
||||
*.csproj merge=union
|
||||
*.vbproj merge=union
|
||||
*.fsproj merge=union
|
||||
*.dbproj merge=union
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
234
Others/Dragablz/.gitignore
vendored
Normal file
234
Others/Dragablz/.gitignore
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
build/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Visual Studio 2015+ cache/options directory
|
||||
.vs/
|
||||
|
||||
# Roslyn cache directories
|
||||
*.ide/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
#NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding addin-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# If using the old MSBuild-Integrated Package Restore, uncomment this:
|
||||
#!**/packages/repositories.config
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# =========================
|
||||
# Operating System Files
|
||||
# =========================
|
||||
|
||||
# OSX
|
||||
# =========================
|
||||
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear on external disk
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# Windows
|
||||
# =========================
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
105
Others/Dragablz/Dragablz.Test/Core/CollectionTeaserFixtures.cs
Normal file
105
Others/Dragablz/Dragablz.Test/Core/CollectionTeaserFixtures.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using NUnit.Framework;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using FakeItEasy;
|
||||
|
||||
namespace Dragablz.Core.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class CollectionTeaserFixture
|
||||
{
|
||||
[Test]
|
||||
public void WillCreateForList()
|
||||
{
|
||||
var myList = new ArrayList();
|
||||
|
||||
CollectionTeaser collectionTeaser;
|
||||
var result = CollectionTeaser.TryCreate(myList, out collectionTeaser);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.IsNotNull(collectionTeaser);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WillCreateForGenericCollection()
|
||||
{
|
||||
var myList = A.Fake<ICollection<string>>();
|
||||
|
||||
CollectionTeaser collectionTeaser;
|
||||
var result = CollectionTeaser.TryCreate(myList, out collectionTeaser);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.IsNotNull(collectionTeaser);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WillCreateForCollection()
|
||||
{
|
||||
var myList = A.Fake<ICollection>();
|
||||
|
||||
CollectionTeaser collectionTeaser;
|
||||
var result = CollectionTeaser.TryCreate(myList, out collectionTeaser);
|
||||
|
||||
Assert.IsFalse(result);
|
||||
Assert.IsNull(collectionTeaser);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WillAddForList()
|
||||
{
|
||||
var myList = new ArrayList();
|
||||
CollectionTeaser collectionTeaser;
|
||||
Assert.IsTrue(CollectionTeaser.TryCreate(myList, out collectionTeaser));
|
||||
|
||||
collectionTeaser.Add("i am going to type this in, manually, twice.");
|
||||
|
||||
CollectionAssert.AreEquivalent(new[] { "i am going to type this in, manually, twice." }, myList);
|
||||
//i didnt really. i copied and pasted it.
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WillRemoveForList()
|
||||
{
|
||||
var myList = new ArrayList
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
};
|
||||
CollectionTeaser collectionTeaser;
|
||||
Assert.IsTrue(CollectionTeaser.TryCreate(myList, out collectionTeaser));
|
||||
|
||||
collectionTeaser.Remove(3);
|
||||
|
||||
CollectionAssert.AreEquivalent(new[] { 1, 2, 4, 5 }, myList);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WillAddForGenericCollection()
|
||||
{
|
||||
var myList = A.Fake<ICollection<string>>();
|
||||
CollectionTeaser collectionTeaser;
|
||||
Assert.IsTrue(CollectionTeaser.TryCreate(myList, out collectionTeaser));
|
||||
|
||||
collectionTeaser.Add("hello");
|
||||
|
||||
A.CallTo(() => myList.Add("hello")).MustHaveHappened();
|
||||
A.CallTo(() => myList.Remove("hello")).MustNotHaveHappened();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WillRemoveForGenericCollection()
|
||||
{
|
||||
var myList = A.Fake<ICollection<string>>();
|
||||
CollectionTeaser collectionTeaser;
|
||||
Assert.IsTrue(CollectionTeaser.TryCreate(myList, out collectionTeaser));
|
||||
|
||||
collectionTeaser.Remove("bye");
|
||||
|
||||
A.CallTo(() => myList.Remove("bye")).MustHaveHappened();
|
||||
A.CallTo(() => myList.Add("bye")).MustNotHaveHappened();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using NUnit.Framework;
|
||||
namespace Dragablz.Dockablz.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TilerCalculatorFixture
|
||||
{
|
||||
[TestCase(0, new int[0])]
|
||||
[TestCase(1, new[] { 1 })]
|
||||
[TestCase(2, new[] { 1, 1 })]
|
||||
[TestCase(3, new[] { 1, 2 })]
|
||||
[TestCase(4, new[] { 2, 2 })]
|
||||
[TestCase(5, new[] { 2, 3 })]
|
||||
[TestCase(6, new[] { 3, 3 })]
|
||||
[TestCase(7, new[] { 2, 2, 3 })]
|
||||
[TestCase(9, new[] { 3, 3, 3 })]
|
||||
[TestCase(10, new[] { 3, 3, 4 })]
|
||||
[TestCase(25, new[] { 5, 5, 5, 5, 5 })]
|
||||
[TestCase(26, new[] { 5, 5, 5, 5, 6 })]
|
||||
[TestCase(29, new[] { 5, 6, 6, 6, 6 })]
|
||||
[TestCase(30, new[] { 6, 6, 6, 6, 6 })]
|
||||
public void WillCalculateCellsPerColumn(int totalCells, int[] expectedCellsPerColumn)
|
||||
{
|
||||
var result = TilerCalculator.GetCellCountPerColumn(totalCells);
|
||||
|
||||
CollectionAssert.AreEqual(expectedCellsPerColumn, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Others/Dragablz/Dragablz.Test/Dragablz.Test.csproj
Normal file
24
Others/Dragablz/Dragablz.Test/Dragablz.Test.csproj
Normal file
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp3.0;net45;net40</TargetFrameworks>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="1.1.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FakeItEasy" Version="5.4.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dragablz\Dragablz.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
65
Others/Dragablz/Dragablz.sln
Normal file
65
Others/Dragablz/Dragablz.sln
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29424.173
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dragablz", "Dragablz\Dragablz.csproj", "{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DragablzDemo", "DragablzDemo\DragablzDemo.csproj", "{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dragablz.Test", "Dragablz.Test\Dragablz.Test.csproj", "{F8636090-2153-401A-A00F-C5ADB66EF612}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C4D2C8A3-2B3A-46C6-83D3-6DCC83B34646}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2B28B8D0-67E7-461C-97C8-8A2ECA6C9314}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F8636090-2153-401A-A00F-C5ADB66EF612}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {AD581326-677F-4EEB-8B87-71546D0AAF5C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
2
Others/Dragablz/Dragablz.sln.DotSettings
Normal file
2
Others/Dragablz/Dragablz.sln.DotSettings
Normal file
@@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=DragablzDemo_002EAnnotations/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
72
Others/Dragablz/Dragablz/CanvasOrganiser.cs
Normal file
72
Others/Dragablz/Dragablz/CanvasOrganiser.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class CanvasOrganiser : IItemsOrganiser
|
||||
{
|
||||
public virtual void Organise(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> items)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void Organise(DragablzItemsControl requestor, Size measureBounds, IOrderedEnumerable<DragablzItem> items)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OrganiseOnMouseDownWithin(DragablzItemsControl requestor, Size measureBounds, List<DragablzItem> siblingItems, DragablzItem dragablzItem)
|
||||
{
|
||||
var zIndex = int.MaxValue;
|
||||
foreach (var source in siblingItems.OrderByDescending(Panel.GetZIndex))
|
||||
{
|
||||
Panel.SetZIndex(source, --zIndex);
|
||||
|
||||
}
|
||||
Panel.SetZIndex(dragablzItem, int.MaxValue);
|
||||
}
|
||||
|
||||
public virtual void OrganiseOnDragStarted(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OrganiseOnDrag(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OrganiseOnDragCompleted(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual Point ConstrainLocation(DragablzItemsControl requestor, Size measureBounds, Point itemCurrentLocation, Size itemCurrentSize, Point itemDesiredLocation, Size itemDesiredSize)
|
||||
{
|
||||
//we will stop it pushing beyond the bounds...unless it's already beyond...
|
||||
var reduceBoundsWidth = itemCurrentLocation.X + itemCurrentSize.Width > measureBounds.Width
|
||||
? 0
|
||||
: itemDesiredSize.Width;
|
||||
var reduceBoundsHeight = itemCurrentLocation.Y + itemCurrentSize.Height > measureBounds.Height
|
||||
? 0
|
||||
: itemDesiredSize.Height;
|
||||
|
||||
return new Point(
|
||||
Math.Min(Math.Max(itemDesiredLocation.X, 0), measureBounds.Width - reduceBoundsWidth),
|
||||
Math.Min(Math.Max(itemDesiredLocation.Y, 0), measureBounds.Height - reduceBoundsHeight));
|
||||
}
|
||||
|
||||
public virtual Size Measure(DragablzItemsControl requestor, Size availableSize, IEnumerable<DragablzItem> items)
|
||||
{
|
||||
return availableSize;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<DragablzItem> Sort(IEnumerable<DragablzItem> items)
|
||||
{
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Others/Dragablz/Dragablz/ContainerCustomisations.cs
Normal file
34
Others/Dragablz/Dragablz/ContainerCustomisations.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
internal class ContainerCustomisations
|
||||
{
|
||||
private readonly Func<DragablzItem> _getContainerForItemOverride;
|
||||
private readonly Action<DependencyObject, object> _prepareContainerForItemOverride;
|
||||
private readonly Action<DependencyObject, object> _clearingContainerForItemOverride;
|
||||
|
||||
public ContainerCustomisations(Func<DragablzItem> getContainerForItemOverride = null, Action<DependencyObject, object> prepareContainerForItemOverride = null, Action<DependencyObject, object> clearingContainerForItemOverride = null)
|
||||
{
|
||||
_getContainerForItemOverride = getContainerForItemOverride;
|
||||
_prepareContainerForItemOverride = prepareContainerForItemOverride;
|
||||
_clearingContainerForItemOverride = clearingContainerForItemOverride;
|
||||
}
|
||||
|
||||
public Func<DragablzItem> GetContainerForItemOverride
|
||||
{
|
||||
get { return _getContainerForItemOverride; }
|
||||
}
|
||||
|
||||
public Action<DependencyObject, object> PrepareContainerForItemOverride
|
||||
{
|
||||
get { return _prepareContainerForItemOverride; }
|
||||
}
|
||||
|
||||
public Action<DependencyObject, object> ClearingContainerForItemOverride
|
||||
{
|
||||
get { return _clearingContainerForItemOverride; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Dragablz.Converters
|
||||
{
|
||||
public class BooleanAndToVisibilityConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (values == null)
|
||||
return Visibility.Collapsed;
|
||||
|
||||
return values.Select(GetBool).All(b => b)
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool GetBool(object value)
|
||||
{
|
||||
if (value is bool)
|
||||
{
|
||||
return (bool)value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Dragablz.Converters
|
||||
{
|
||||
public class EqualityToBooleanConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Equals(value, parameter);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Binding.DoNothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Dragablz.Converters
|
||||
{
|
||||
public class EqualityToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Equals(value, parameter)
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Binding.DoNothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Dragablz.Converters
|
||||
{
|
||||
public class ShowDefaultCloseButtonConverter : IMultiValueConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// [0] is owning tabcontrol ShowDefaultCloseButton value.
|
||||
/// [1] is owning tabcontrol FixedHeaderCount value.
|
||||
/// [2] is item LogicalIndex
|
||||
/// </summary>
|
||||
/// <param name="values"></param>
|
||||
/// <param name="targetType"></param>
|
||||
/// <param name="parameter"></param>
|
||||
/// <param name="culture"></param>
|
||||
/// <returns></returns>
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return ((values[0] == DependencyProperty.UnsetValue ? false : (bool)values[0]) &&
|
||||
(values[2] == DependencyProperty.UnsetValue ? 0 : (int)values[2]) >=
|
||||
(values[1] == DependencyProperty.UnsetValue ? 0 : (int)values[1])) ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
65
Others/Dragablz/Dragablz/Core/CollectionTeaser.cs
Normal file
65
Others/Dragablz/Dragablz/Core/CollectionTeaser.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
internal class CollectionTeaser
|
||||
{
|
||||
private readonly Action<object> _addMethod;
|
||||
private readonly Action<object> _removeMethod;
|
||||
|
||||
private CollectionTeaser(Action<object> addMethod, Action<object> removeMethod)
|
||||
{
|
||||
_addMethod = addMethod;
|
||||
_removeMethod = removeMethod;
|
||||
}
|
||||
|
||||
public static bool TryCreate(object items, out CollectionTeaser collectionTeaser)
|
||||
{
|
||||
collectionTeaser = null;
|
||||
|
||||
var list = items as IList;
|
||||
if (list != null)
|
||||
{
|
||||
collectionTeaser = new CollectionTeaser(i => list.Add(i), list.Remove);
|
||||
}
|
||||
else if (items != null)
|
||||
{
|
||||
var itemsType = items.GetType();
|
||||
var genericCollectionType = typeof (ICollection<>);
|
||||
|
||||
//TODO, *IF* we really wanted to we could get the consumer to inform us of the correct type
|
||||
//if there are multiple impls. havent got time for this edge case right now though
|
||||
var collectionImplType = itemsType.GetInterfaces().SingleOrDefault(x =>
|
||||
x.IsGenericType &&
|
||||
x.GetGenericTypeDefinition() == genericCollectionType);
|
||||
|
||||
if (collectionImplType != null)
|
||||
{
|
||||
var genericArgType = collectionImplType.GetGenericArguments().First();
|
||||
|
||||
var addMethodInfo = collectionImplType.GetMethod("Add", new[] {genericArgType});
|
||||
var removeMethodInfo = collectionImplType.GetMethod("Remove", new[] { genericArgType });
|
||||
|
||||
collectionTeaser = new CollectionTeaser(
|
||||
i => addMethodInfo.Invoke(items, new[] {i}),
|
||||
i => removeMethodInfo.Invoke(items, new[] {i}));
|
||||
}
|
||||
}
|
||||
|
||||
return collectionTeaser != null;
|
||||
}
|
||||
|
||||
public void Add(object item)
|
||||
{
|
||||
_addMethod(item);
|
||||
}
|
||||
|
||||
public void Remove(object item)
|
||||
{
|
||||
_removeMethod(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Others/Dragablz/Dragablz/Core/Extensions.cs
Normal file
127
Others/Dragablz/Dragablz/Core/Extensions.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
#if NET40
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
#endif
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
internal static class Extensions
|
||||
{
|
||||
public static IEnumerable<TContainer> Containers<TContainer>(this ItemsControl itemsControl) where TContainer : class
|
||||
{
|
||||
#if NET40
|
||||
var fieldInfo = typeof(ItemContainerGenerator).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var list = (IList)fieldInfo.GetValue(itemsControl.ItemContainerGenerator);
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
#else
|
||||
for (var i = 0; i < itemsControl.ItemContainerGenerator.Items.Count; i++)
|
||||
#endif
|
||||
{
|
||||
var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as TContainer;
|
||||
if (container != null)
|
||||
yield return container;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TObject> Except<TObject>(this IEnumerable<TObject> first, params TObject[] second)
|
||||
{
|
||||
return first.Except((IEnumerable<TObject>)second);
|
||||
}
|
||||
|
||||
public static IEnumerable<object> LogicalTreeDepthFirstTraversal(this DependencyObject node)
|
||||
{
|
||||
if (node == null) yield break;
|
||||
yield return node;
|
||||
|
||||
foreach (var child in LogicalTreeHelper.GetChildren(node).OfType<DependencyObject>()
|
||||
.SelectMany(depObj => depObj.LogicalTreeDepthFirstTraversal()))
|
||||
yield return child;
|
||||
}
|
||||
|
||||
public static IEnumerable<object> VisualTreeDepthFirstTraversal(this DependencyObject node)
|
||||
{
|
||||
if (node == null) yield break;
|
||||
yield return node;
|
||||
|
||||
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(node, i);
|
||||
foreach (var d in child.VisualTreeDepthFirstTraversal())
|
||||
{
|
||||
yield return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Yields the visual ancestory (including the starting point).
|
||||
/// </summary>
|
||||
/// <param name="dependencyObject"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<DependencyObject> VisualTreeAncestory(this DependencyObject dependencyObject)
|
||||
{
|
||||
if (dependencyObject == null) throw new ArgumentNullException("dependencyObject");
|
||||
|
||||
while (dependencyObject != null)
|
||||
{
|
||||
yield return dependencyObject;
|
||||
dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Yields the logical ancestory (including the starting point).
|
||||
/// </summary>
|
||||
/// <param name="dependencyObject"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<DependencyObject> LogicalTreeAncestory(this DependencyObject dependencyObject)
|
||||
{
|
||||
if (dependencyObject == null) throw new ArgumentNullException("dependencyObject");
|
||||
|
||||
while (dependencyObject != null)
|
||||
{
|
||||
yield return dependencyObject;
|
||||
dependencyObject = LogicalTreeHelper.GetParent(dependencyObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the actual Left of the Window independently from the WindowState
|
||||
/// </summary>
|
||||
/// <param name="window"></param>
|
||||
/// <returns></returns>
|
||||
public static double GetActualLeft(this Window window)
|
||||
{
|
||||
if (window.WindowState == WindowState.Maximized)
|
||||
{
|
||||
var leftField = typeof(Window).GetField("_actualLeft", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
return leftField?.GetValue(window) as double? ?? 0;
|
||||
}
|
||||
|
||||
return window.Left;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the actual Top of the Window independently from the WindowState
|
||||
/// </summary>
|
||||
/// <param name="window"></param>
|
||||
/// <returns></returns>
|
||||
public static double GetActualTop(this Window window)
|
||||
{
|
||||
if (window.WindowState == WindowState.Maximized)
|
||||
{
|
||||
var topField = typeof(Window).GetField("_actualTop", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
return topField?.GetValue(window) as double? ?? 0;
|
||||
}
|
||||
|
||||
return window.Top;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
22
Others/Dragablz/Dragablz/Core/FuncComparer.cs
Normal file
22
Others/Dragablz/Dragablz/Core/FuncComparer.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
internal class FuncComparer<TObject> : IComparer<TObject>
|
||||
{
|
||||
private readonly Func<TObject, TObject, int> _comparer;
|
||||
|
||||
public FuncComparer(Func<TObject, TObject, int> comparer)
|
||||
{
|
||||
if (comparer == null) throw new ArgumentNullException("comparer");
|
||||
|
||||
_comparer = comparer;
|
||||
}
|
||||
|
||||
public int Compare(TObject x, TObject y)
|
||||
{
|
||||
return _comparer(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Others/Dragablz/Dragablz/Core/HitTest.cs
Normal file
33
Others/Dragablz/Dragablz/Core/HitTest.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Non-client hit test values, HT*
|
||||
/// </summary>
|
||||
internal enum HitTest
|
||||
{
|
||||
HT_ERROR = -2,
|
||||
HT_TRANSPARENT = -1,
|
||||
HT_NOWHERE = 0,
|
||||
HT_CLIENT = 1,
|
||||
HT_CAPTION = 2,
|
||||
HT_SYSMENU = 3,
|
||||
HT_GROWBOX = 4,
|
||||
HT_MENU = 5,
|
||||
HT_HSCROLL = 6,
|
||||
HT_VSCROLL = 7,
|
||||
HT_MINBUTTON = 8,
|
||||
HT_MAXBUTTON = 9,
|
||||
HT_LEFT = 10,
|
||||
HT_RIGHT = 11,
|
||||
HT_TOP = 12,
|
||||
HT_TOPLEFT = 13,
|
||||
HT_TOPRIGHT = 14,
|
||||
HT_BOTTOM = 15,
|
||||
HT_BOTTOMLEFT = 16,
|
||||
HT_BOTTOMRIGHT = 17,
|
||||
HT_BORDER = 18,
|
||||
HT_OBJECT = 19,
|
||||
HT_CLOSE = 20,
|
||||
HT_HELP = 21
|
||||
}
|
||||
}
|
||||
112
Others/Dragablz/Dragablz/Core/InterTabTransfer.cs
Normal file
112
Others/Dragablz/Dragablz/Core/InterTabTransfer.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Dragablz.Dockablz;
|
||||
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
internal enum InterTabTransferReason
|
||||
{
|
||||
Breach,
|
||||
Reentry
|
||||
}
|
||||
|
||||
internal class InterTabTransfer
|
||||
{
|
||||
private readonly object _item;
|
||||
private readonly DragablzItem _originatorContainer;
|
||||
private readonly Orientation _breachOrientation;
|
||||
private readonly Point _dragStartWindowOffset;
|
||||
private readonly Point _dragStartItemOffset;
|
||||
private readonly Point _itemPositionWithinHeader;
|
||||
private readonly Size _itemSize;
|
||||
private readonly IList<FloatingItemSnapShot> _floatingItemSnapShots;
|
||||
private readonly bool _isTransposing;
|
||||
private readonly InterTabTransferReason _transferReason;
|
||||
|
||||
public InterTabTransfer(object item, DragablzItem originatorContainer, Orientation breachOrientation, Point dragStartWindowOffset, Point dragStartItemOffset, Point itemPositionWithinHeader, Size itemSize, IList<FloatingItemSnapShot> floatingItemSnapShots, bool isTransposing)
|
||||
{
|
||||
if (item == null) throw new ArgumentNullException("item");
|
||||
if (originatorContainer == null) throw new ArgumentNullException("originatorContainer");
|
||||
if (floatingItemSnapShots == null) throw new ArgumentNullException("floatingItemSnapShots");
|
||||
|
||||
_transferReason = InterTabTransferReason.Breach;
|
||||
|
||||
_item = item;
|
||||
_originatorContainer = originatorContainer;
|
||||
_breachOrientation = breachOrientation;
|
||||
_dragStartWindowOffset = dragStartWindowOffset;
|
||||
_dragStartItemOffset = dragStartItemOffset;
|
||||
_itemPositionWithinHeader = itemPositionWithinHeader;
|
||||
_itemSize = itemSize;
|
||||
_floatingItemSnapShots = floatingItemSnapShots;
|
||||
_isTransposing = isTransposing;
|
||||
}
|
||||
|
||||
public InterTabTransfer(object item, DragablzItem originatorContainer, Point dragStartItemOffset,
|
||||
IList<FloatingItemSnapShot> floatingItemSnapShots)
|
||||
{
|
||||
if (item == null) throw new ArgumentNullException("item");
|
||||
if (originatorContainer == null) throw new ArgumentNullException("originatorContainer");
|
||||
if (floatingItemSnapShots == null) throw new ArgumentNullException("floatingItemSnapShots");
|
||||
|
||||
_transferReason = InterTabTransferReason.Reentry;
|
||||
|
||||
_item = item;
|
||||
_originatorContainer = originatorContainer;
|
||||
_dragStartItemOffset = dragStartItemOffset;
|
||||
_floatingItemSnapShots = floatingItemSnapShots;
|
||||
}
|
||||
|
||||
public Orientation BreachOrientation
|
||||
{
|
||||
get { return _breachOrientation; }
|
||||
}
|
||||
|
||||
public Point DragStartWindowOffset
|
||||
{
|
||||
get { return _dragStartWindowOffset; }
|
||||
}
|
||||
|
||||
public object Item
|
||||
{
|
||||
get { return _item; }
|
||||
}
|
||||
|
||||
public DragablzItem OriginatorContainer
|
||||
{
|
||||
get { return _originatorContainer; }
|
||||
}
|
||||
|
||||
public InterTabTransferReason TransferReason
|
||||
{
|
||||
get { return _transferReason; }
|
||||
}
|
||||
|
||||
public Point DragStartItemOffset
|
||||
{
|
||||
get { return _dragStartItemOffset; }
|
||||
}
|
||||
|
||||
public Point ItemPositionWithinHeader
|
||||
{
|
||||
get { return _itemPositionWithinHeader; }
|
||||
}
|
||||
|
||||
public Size ItemSize
|
||||
{
|
||||
get { return _itemSize; }
|
||||
}
|
||||
|
||||
public IList<FloatingItemSnapShot> FloatingItemSnapShots
|
||||
{
|
||||
get { return _floatingItemSnapShots; }
|
||||
}
|
||||
|
||||
public bool IsTransposing
|
||||
{
|
||||
get { return _isTransposing; }
|
||||
}
|
||||
}
|
||||
}
|
||||
77
Others/Dragablz/Dragablz/Core/MultiComparer.cs
Normal file
77
Others/Dragablz/Dragablz/Core/MultiComparer.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
internal class MultiComparer<TObject> : IComparer<TObject>
|
||||
{
|
||||
private readonly IList<FuncComparer<TObject>> _attributeComparers;
|
||||
|
||||
private MultiComparer(FuncComparer<TObject> firstComparer)
|
||||
{
|
||||
_attributeComparers = new List<FuncComparer<TObject>>
|
||||
{
|
||||
firstComparer
|
||||
};
|
||||
}
|
||||
|
||||
public static MultiComparer<TObject> Ascending<TAttribute>(Func<TObject, TAttribute> accessor)
|
||||
where TAttribute : IComparable
|
||||
{
|
||||
if (accessor == null) throw new ArgumentNullException("accessor");
|
||||
|
||||
return new MultiComparer<TObject>(BuildAscendingComparer(accessor));
|
||||
}
|
||||
|
||||
public static MultiComparer<TObject> Descending<TAttribute>(Func<TObject, TAttribute> accessor)
|
||||
where TAttribute : IComparable
|
||||
{
|
||||
if (accessor == null) throw new ArgumentNullException("accessor");
|
||||
|
||||
return new MultiComparer<TObject>(BuildDescendingComparer(accessor));
|
||||
}
|
||||
|
||||
public MultiComparer<TObject> ThenAscending<TAttribute>(Func<TObject, TAttribute> accessor)
|
||||
where TAttribute : IComparable
|
||||
{
|
||||
if (accessor == null) throw new ArgumentNullException("accessor");
|
||||
|
||||
_attributeComparers.Add(BuildAscendingComparer(accessor));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MultiComparer<TObject> ThenDescending<TAttribute>(Func<TObject, TAttribute> accessor)
|
||||
where TAttribute : IComparable
|
||||
{
|
||||
if (accessor == null) throw new ArgumentNullException("accessor");
|
||||
|
||||
_attributeComparers.Add(BuildDescendingComparer(accessor));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int Compare(TObject x, TObject y)
|
||||
{
|
||||
var nonEqual = _attributeComparers.Select(c => new {result = c.Compare(x, y)}).FirstOrDefault(a => a.result != 0);
|
||||
|
||||
return nonEqual == null ? 0 : nonEqual.result;
|
||||
}
|
||||
|
||||
private static FuncComparer<TObject> BuildAscendingComparer<TAttribute>(Func<TObject, TAttribute> accessor)
|
||||
where TAttribute : IComparable
|
||||
{
|
||||
//TODO handle ref types better
|
||||
return new FuncComparer<TObject>((x, y) => accessor(x).CompareTo(accessor(y)));
|
||||
|
||||
}
|
||||
|
||||
private static FuncComparer<TObject> BuildDescendingComparer<TAttribute>(Func<TObject, TAttribute> accessor)
|
||||
where TAttribute : IComparable
|
||||
{
|
||||
//TODO handle ref types better
|
||||
return new FuncComparer<TObject>((x, y) => accessor(y).CompareTo(accessor(x)));
|
||||
}
|
||||
}
|
||||
}
|
||||
131
Others/Dragablz/Dragablz/Core/Native.cs
Normal file
131
Others/Dragablz/Dragablz/Core/Native.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
internal static class Native
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct POINT
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
|
||||
public static implicit operator Point(POINT point)
|
||||
{
|
||||
return new Point(point.X, point.Y);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int left;
|
||||
public int top;
|
||||
public int right;
|
||||
public int bottom;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetCursorPos(out POINT lpPoint);
|
||||
|
||||
public static POINT GetRawCursorPos()
|
||||
{
|
||||
POINT lpPoint;
|
||||
GetCursorPos(out lpPoint);
|
||||
return lpPoint;
|
||||
}
|
||||
|
||||
public static Point GetCursorPos()
|
||||
{
|
||||
POINT lpPoint;
|
||||
GetCursorPos(out lpPoint);
|
||||
return lpPoint;
|
||||
}
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
private static extern IntPtr GetDC(IntPtr hwnd);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||
|
||||
public static Point ToWpf(this Point pixelPoint)
|
||||
{
|
||||
var desktop = GetDC(IntPtr.Zero);
|
||||
var dpi = GetDeviceCaps(desktop, 88);
|
||||
ReleaseDC(IntPtr.Zero, desktop);
|
||||
|
||||
var physicalUnitSize = 96d / dpi ;
|
||||
var wpfPoint = new Point(physicalUnitSize * pixelPoint.X, physicalUnitSize * pixelPoint.Y);
|
||||
|
||||
return wpfPoint;
|
||||
}
|
||||
|
||||
public static IEnumerable<Window> SortWindowsTopToBottom(IEnumerable<Window> windows)
|
||||
{
|
||||
var windowsByHandle = windows.Select(window =>
|
||||
{
|
||||
var hwndSource = PresentationSource.FromVisual(window) as HwndSource;
|
||||
var handle = hwndSource != null ? hwndSource.Handle : IntPtr.Zero;
|
||||
return new {window, handle};
|
||||
}).Where(x => x.handle != IntPtr.Zero)
|
||||
.ToDictionary(x => x.handle, x => x.window);
|
||||
|
||||
for (var hWnd = GetTopWindow(IntPtr.Zero); hWnd != IntPtr.Zero; hWnd = GetWindow(hWnd, GW_HWNDNEXT))
|
||||
if (windowsByHandle.ContainsKey((hWnd)))
|
||||
yield return windowsByHandle[hWnd];
|
||||
}
|
||||
|
||||
public const int SW_SHOWNORMAL = 1;
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
|
||||
|
||||
private const uint GW_HWNDNEXT = 2;
|
||||
[DllImport("User32")]
|
||||
public static extern IntPtr GetTopWindow(IntPtr hWnd);
|
||||
|
||||
[DllImport("User32")]
|
||||
public static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd);
|
||||
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDOWPLACEMENT
|
||||
{
|
||||
public int length;
|
||||
public int flags;
|
||||
public int showCmd;
|
||||
public POINT minPosition;
|
||||
public POINT maxPosition;
|
||||
public RECT normalPosition;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
internal static extern IntPtr SendMessage(IntPtr hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam);
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
internal static extern IntPtr PostMessage(IntPtr hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
|
||||
[DllImport("dwmapi.dll", EntryPoint = "#127")]
|
||||
internal static extern void DwmGetColorizationParameters(ref DWMCOLORIZATIONPARAMS dp);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct DWMCOLORIZATIONPARAMS
|
||||
{
|
||||
public UInt32 ColorizationColor;
|
||||
public UInt32 ColorizationAfterglow;
|
||||
public UInt32 ColorizationColorBalance;
|
||||
public UInt32 ColorizationAfterglowBalance;
|
||||
public UInt32 ColorizationBlurBalance;
|
||||
public UInt32 ColorizationGlassReflectionIntensity;
|
||||
public UInt32 ColorizationOpaqueBlend;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
26
Others/Dragablz/Dragablz/Core/SystemCommand.cs
Normal file
26
Others/Dragablz/Dragablz/Core/SystemCommand.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
internal enum SystemCommand
|
||||
{
|
||||
SC_CLOSE = 0xF060,
|
||||
SC_CONTEXTHELP = 0xF180,
|
||||
SC_DEFAULT = 0xF160,
|
||||
SC_HOTKEY = 0xF150,
|
||||
SC_HSCROLL = 0xF080,
|
||||
SCF_ISSECURE = 0x00000001,
|
||||
SC_KEYMENU = 0xF100,
|
||||
SC_MAXIMIZE = 0xF030,
|
||||
SC_MINIMIZE = 0xF020,
|
||||
SC_MONITORPOWER = 0xF170,
|
||||
SC_MOUSEMENU = 0xF090,
|
||||
SC_MOVE = 0xF010,
|
||||
SC_MOUSEMOVE = 0xF012,
|
||||
SC_NEXTWINDOW = 0xF040,
|
||||
SC_PREVWINDOW = 0xF050,
|
||||
SC_RESTORE = 0xF120,
|
||||
SC_SCREENSAVE = 0xF140,
|
||||
SC_SIZE = 0xF000,
|
||||
SC_TASKLIST = 0xF130,
|
||||
SC_VSCROLL = 0xF070
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
internal class TabHeaderDragStartInformation
|
||||
{
|
||||
private readonly DragablzItem _dragItem;
|
||||
private readonly double _dragablzItemsControlHorizontalOffset;
|
||||
private readonly double _dragablzItemControlVerticalOffset;
|
||||
private readonly double _dragablzItemHorizontalOffset;
|
||||
private readonly double _dragablzItemVerticalOffset;
|
||||
|
||||
public TabHeaderDragStartInformation(
|
||||
DragablzItem dragItem,
|
||||
double dragablzItemsControlHorizontalOffset, double dragablzItemControlVerticalOffset, double dragablzItemHorizontalOffset, double dragablzItemVerticalOffset)
|
||||
{
|
||||
if (dragItem == null) throw new ArgumentNullException("dragItem");
|
||||
|
||||
_dragItem = dragItem;
|
||||
_dragablzItemsControlHorizontalOffset = dragablzItemsControlHorizontalOffset;
|
||||
_dragablzItemControlVerticalOffset = dragablzItemControlVerticalOffset;
|
||||
_dragablzItemHorizontalOffset = dragablzItemHorizontalOffset;
|
||||
_dragablzItemVerticalOffset = dragablzItemVerticalOffset;
|
||||
}
|
||||
|
||||
public double DragablzItemsControlHorizontalOffset
|
||||
{
|
||||
get { return _dragablzItemsControlHorizontalOffset; }
|
||||
}
|
||||
|
||||
public double DragablzItemControlVerticalOffset
|
||||
{
|
||||
get { return _dragablzItemControlVerticalOffset; }
|
||||
}
|
||||
|
||||
public double DragablzItemHorizontalOffset
|
||||
{
|
||||
get { return _dragablzItemHorizontalOffset; }
|
||||
}
|
||||
|
||||
public double DragablzItemVerticalOffset
|
||||
{
|
||||
get { return _dragablzItemVerticalOffset; }
|
||||
}
|
||||
|
||||
public DragablzItem DragItem
|
||||
{
|
||||
get { return _dragItem; }
|
||||
}
|
||||
}
|
||||
}
|
||||
245
Others/Dragablz/Dragablz/Core/WindowMessage.cs
Normal file
245
Others/Dragablz/Dragablz/Core/WindowMessage.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
namespace Dragablz.Core
|
||||
{
|
||||
internal enum WindowMessage
|
||||
{
|
||||
WM_NULL = 0,
|
||||
WM_CREATE = 1,
|
||||
WM_DESTROY = 2,
|
||||
WM_MOVE = 3,
|
||||
WM_SIZE = 5,
|
||||
WM_ACTIVATE = 6,
|
||||
WM_SETFOCUS = 7,
|
||||
WM_KILLFOCUS = 8,
|
||||
WM_ENABLE = 10,
|
||||
WM_SETREDRAW = 11,
|
||||
WM_SETTEXT = 12,
|
||||
WM_GETTEXT = 13,
|
||||
WM_GETTEXTLENGTH = 14,
|
||||
WM_PAINT = 15,
|
||||
WM_CLOSE = 16,
|
||||
WM_QUERYENDSESSION = 17,
|
||||
WM_QUIT = 18,
|
||||
WM_QUERYOPEN = 19,
|
||||
WM_ERASEBKGND = 20,
|
||||
WM_SYSCOLORCHANGE = 21,
|
||||
WM_ENDSESSION = 22,
|
||||
WM_SHOWWINDOW = 24,
|
||||
WM_CTLCOLOR = 25,
|
||||
WM_SETTINGCHANGE = 26,
|
||||
WM_WININICHANGE = 26,
|
||||
WM_DEVMODECHANGE = 27,
|
||||
WM_ACTIVATEAPP = 28,
|
||||
WM_FONTCHANGE = 29,
|
||||
WM_TIMECHANGE = 30,
|
||||
WM_CANCELMODE = 31,
|
||||
WM_SETCURSOR = 32,
|
||||
WM_TABLET_MAXOFFSET = 32,
|
||||
WM_MOUSEACTIVATE = 33,
|
||||
WM_CHILDACTIVATE = 34,
|
||||
WM_QUEUESYNC = 35,
|
||||
WM_GETMINMAXINFO = 36,
|
||||
WM_PAINTICON = 38,
|
||||
WM_ICONERASEBKGND = 39,
|
||||
WM_NEXTDLGCTL = 40,
|
||||
WM_SPOOLERSTATUS = 42,
|
||||
WM_DRAWITEM = 43,
|
||||
WM_MEASUREITEM = 44,
|
||||
WM_DELETEITEM = 45,
|
||||
WM_VKEYTOITEM = 46,
|
||||
WM_CHARTOITEM = 47,
|
||||
WM_SETFONT = 48,
|
||||
WM_GETFONT = 49,
|
||||
WM_SETHOTKEY = 50,
|
||||
WM_GETHOTKEY = 51,
|
||||
WM_QUERYDRAGICON = 55,
|
||||
WM_COMPAREITEM = 57,
|
||||
WM_GETOBJECT = 61,
|
||||
WM_COMPACTING = 65,
|
||||
WM_COMMNOTIFY = 68,
|
||||
WM_WINDOWPOSCHANGING = 70,
|
||||
WM_WINDOWPOSCHANGED = 71,
|
||||
WM_POWER = 72,
|
||||
WM_COPYDATA = 74,
|
||||
WM_CANCELJOURNAL = 75,
|
||||
WM_NOTIFY = 78,
|
||||
WM_INPUTLANGCHANGEREQUEST = 80,
|
||||
WM_INPUTLANGCHANGE = 81,
|
||||
WM_TCARD = 82,
|
||||
WM_HELP = 83,
|
||||
WM_USERCHANGED = 84,
|
||||
WM_NOTIFYFORMAT = 85,
|
||||
WM_CONTEXTMENU = 123,
|
||||
WM_STYLECHANGING = 124,
|
||||
WM_STYLECHANGED = 125,
|
||||
WM_DISPLAYCHANGE = 126,
|
||||
WM_GETICON = 127,
|
||||
WM_SETICON = 128,
|
||||
WM_NCCREATE = 129,
|
||||
WM_NCDESTROY = 130,
|
||||
WM_NCCALCSIZE = 131,
|
||||
WM_NCHITTEST = 132,
|
||||
WM_NCPAINT = 133,
|
||||
WM_NCACTIVATE = 134,
|
||||
WM_GETDLGCODE = 135,
|
||||
WM_SYNCPAINT = 136,
|
||||
WM_MOUSEQUERY = 155,
|
||||
WM_NCMOUSEMOVE = 160,
|
||||
WM_NCLBUTTONDOWN = 161,
|
||||
WM_NCLBUTTONUP = 162,
|
||||
WM_NCLBUTTONDBLCLK = 163,
|
||||
WM_NCRBUTTONDOWN = 164,
|
||||
WM_NCRBUTTONUP = 165,
|
||||
WM_NCRBUTTONDBLCLK = 166,
|
||||
WM_NCMBUTTONDOWN = 167,
|
||||
WM_NCMBUTTONUP = 168,
|
||||
WM_NCMBUTTONDBLCLK = 169,
|
||||
WM_NCXBUTTONDOWN = 171,
|
||||
WM_NCXBUTTONUP = 172,
|
||||
WM_NCXBUTTONDBLCLK = 173,
|
||||
WM_INPUT = 255,
|
||||
WM_KEYDOWN = 256,
|
||||
WM_KEYFIRST = 256,
|
||||
WM_KEYUP = 257,
|
||||
WM_CHAR = 258,
|
||||
WM_DEADCHAR = 259,
|
||||
WM_SYSKEYDOWN = 260,
|
||||
WM_SYSKEYUP = 261,
|
||||
WM_SYSCHAR = 262,
|
||||
WM_SYSDEADCHAR = 263,
|
||||
WM_KEYLAST = 264,
|
||||
WM_IME_STARTCOMPOSITION = 269,
|
||||
WM_IME_ENDCOMPOSITION = 270,
|
||||
WM_IME_COMPOSITION = 271,
|
||||
WM_IME_KEYLAST = 271,
|
||||
WM_INITDIALOG = 272,
|
||||
WM_COMMAND = 273,
|
||||
WM_SYSCOMMAND = 274,
|
||||
WM_TIMER = 275,
|
||||
WM_HSCROLL = 276,
|
||||
WM_VSCROLL = 277,
|
||||
WM_INITMENU = 278,
|
||||
WM_INITMENUPOPUP = 279,
|
||||
WM_MENUSELECT = 287,
|
||||
WM_MENUCHAR = 288,
|
||||
WM_ENTERIDLE = 289,
|
||||
WM_UNINITMENUPOPUP = 293,
|
||||
WM_CHANGEUISTATE = 295,
|
||||
WM_UPDATEUISTATE = 296,
|
||||
WM_QUERYUISTATE = 297,
|
||||
WM_CTLCOLORMSGBOX = 306,
|
||||
WM_CTLCOLOREDIT = 307,
|
||||
WM_CTLCOLORLISTBOX = 308,
|
||||
WM_CTLCOLORBTN = 309,
|
||||
WM_CTLCOLORDLG = 310,
|
||||
WM_CTLCOLORSCROLLBAR = 311,
|
||||
WM_CTLCOLORSTATIC = 312,
|
||||
WM_MOUSEFIRST = 512,
|
||||
WM_MOUSEMOVE = 512,
|
||||
WM_LBUTTONDOWN = 513,
|
||||
WM_LBUTTONUP = 514,
|
||||
WM_LBUTTONDBLCLK = 515,
|
||||
WM_RBUTTONDOWN = 516,
|
||||
WM_RBUTTONUP = 517,
|
||||
WM_RBUTTONDBLCLK = 518,
|
||||
WM_MBUTTONDOWN = 519,
|
||||
WM_MBUTTONUP = 520,
|
||||
WM_MBUTTONDBLCLK = 521,
|
||||
WM_MOUSEWHEEL = 522,
|
||||
WM_XBUTTONDOWN = 523,
|
||||
WM_XBUTTONUP = 524,
|
||||
WM_XBUTTONDBLCLK = 525,
|
||||
WM_MOUSEHWHEEL = 526,
|
||||
WM_MOUSELAST = 526,
|
||||
WM_PARENTNOTIFY = 528,
|
||||
WM_ENTERMENULOOP = 529,
|
||||
WM_EXITMENULOOP = 530,
|
||||
WM_NEXTMENU = 531,
|
||||
WM_SIZING = 532,
|
||||
WM_CAPTURECHANGED = 533,
|
||||
WM_MOVING = 534,
|
||||
WM_POWERBROADCAST = 536,
|
||||
WM_DEVICECHANGE = 537,
|
||||
WM_MDICREATE = 544,
|
||||
WM_MDIDESTROY = 545,
|
||||
WM_MDIACTIVATE = 546,
|
||||
WM_MDIRESTORE = 547,
|
||||
WM_MDINEXT = 548,
|
||||
WM_MDIMAXIMIZE = 549,
|
||||
WM_MDITILE = 550,
|
||||
WM_MDICASCADE = 551,
|
||||
WM_MDIICONARRANGE = 552,
|
||||
WM_MDIGETACTIVE = 553,
|
||||
WM_MDISETMENU = 560,
|
||||
WM_ENTERSIZEMOVE = 561,
|
||||
WM_EXITSIZEMOVE = 562,
|
||||
WM_DROPFILES = 563,
|
||||
WM_MDIREFRESHMENU = 564,
|
||||
WM_IME_SETCONTEXT = 641,
|
||||
WM_IME_NOTIFY = 642,
|
||||
WM_IME_CONTROL = 643,
|
||||
WM_IME_COMPOSITIONFULL = 644,
|
||||
WM_IME_SELECT = 645,
|
||||
WM_IME_CHAR = 646,
|
||||
WM_IME_REQUEST = 648,
|
||||
WM_IME_KEYDOWN = 656,
|
||||
WM_IME_KEYUP = 657,
|
||||
WM_MOUSEHOVER = 673,
|
||||
WM_NCMOUSELEAVE = 674,
|
||||
WM_MOUSELEAVE = 675,
|
||||
WM_WTSSESSION_CHANGE = 689,
|
||||
WM_TABLET_DEFBASE = 704,
|
||||
WM_TABLET_ADDED = 712,
|
||||
WM_TABLET_DELETED = 713,
|
||||
WM_TABLET_FLICK = 715,
|
||||
WM_TABLET_QUERYSYSTEMGESTURESTATUS = 716,
|
||||
WM_CUT = 768,
|
||||
WM_COPY = 769,
|
||||
WM_PASTE = 770,
|
||||
WM_CLEAR = 771,
|
||||
WM_UNDO = 772,
|
||||
WM_RENDERFORMAT = 773,
|
||||
WM_RENDERALLFORMATS = 774,
|
||||
WM_DESTROYCLIPBOARD = 775,
|
||||
WM_DRAWCLIPBOARD = 776,
|
||||
WM_PAINTCLIPBOARD = 777,
|
||||
WM_VSCROLLCLIPBOARD = 778,
|
||||
WM_SIZECLIPBOARD = 779,
|
||||
WM_ASKCBFORMATNAME = 780,
|
||||
WM_CHANGECBCHAIN = 781,
|
||||
WM_HSCROLLCLIPBOARD = 782,
|
||||
WM_QUERYNEWPALETTE = 783,
|
||||
WM_PALETTEISCHANGING = 784,
|
||||
WM_PALETTECHANGED = 785,
|
||||
WM_HOTKEY = 786,
|
||||
WM_PRINT = 791,
|
||||
WM_PRINTCLIENT = 792,
|
||||
WM_APPCOMMAND = 793,
|
||||
WM_THEMECHANGED = 794,
|
||||
WM_DWMCOMPOSITIONCHANGED = 798,
|
||||
WM_DWMNCRENDERINGCHANGED = 799,
|
||||
WM_DWMCOLORIZATIONCOLORCHANGED = 800,
|
||||
WM_DWMWINDOWMAXIMIZEDCHANGE = 801,
|
||||
WM_DWMSENDICONICTHUMBNAIL = 803,
|
||||
WM_DWMSENDICONICLIVEPREVIEWBITMAP = 806,
|
||||
WM_HANDHELDFIRST = 856,
|
||||
WM_HANDHELDLAST = 863,
|
||||
WM_AFXFIRST = 864,
|
||||
WM_AFXLAST = 895,
|
||||
WM_PENWINFIRST = 896,
|
||||
WM_PENWINLAST = 911,
|
||||
WM_USER = 1024,
|
||||
WM_APP = 32768,
|
||||
}
|
||||
|
||||
public enum WindowSizingMessage
|
||||
{
|
||||
WMSZ_BOTTOM = 6,
|
||||
WMSZ_BOTTOMLEFT = 7,
|
||||
WMSZ_BOTTOMRIGHT = 8,
|
||||
WMSZ_LEFT = 1,
|
||||
WMSZ_RIGHT = 2,
|
||||
WMSZ_TOP = 3,
|
||||
WMSZ_TOPLEFT = 4,
|
||||
WMSZ_TOPRIGHT = 5,
|
||||
}
|
||||
}
|
||||
48
Others/Dragablz/Dragablz/DefaultInterLayoutClient.cs
Normal file
48
Others/Dragablz/Dragablz/DefaultInterLayoutClient.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a simple implementation of <see cref="IInterLayoutClient"/>, but only really useful if
|
||||
/// <see cref="TabItem"/> instances are specified in XAML. If you are binding via ItemsSource then
|
||||
/// you most likely want to create your own implementation of <see cref="IInterLayoutClient"/>.
|
||||
/// </summary>
|
||||
public class DefaultInterLayoutClient : IInterLayoutClient
|
||||
{
|
||||
public INewTabHost<UIElement> GetNewHost(object partition, TabablzControl source)
|
||||
{
|
||||
var tabablzControl = new TabablzControl {DataContext = source.DataContext};
|
||||
|
||||
Clone(source, tabablzControl);
|
||||
|
||||
if (source.InterTabController == null)
|
||||
throw new InvalidOperationException("Source tab does not have an InterTabCOntroller set. Ensure this is set on initial, and subsequently generated tab controls.");
|
||||
|
||||
var newInterTabController = new InterTabController
|
||||
{
|
||||
Partition = source.InterTabController.Partition
|
||||
};
|
||||
Clone(source.InterTabController, newInterTabController);
|
||||
tabablzControl.SetCurrentValue(TabablzControl.InterTabControllerProperty, newInterTabController);
|
||||
|
||||
return new NewTabHost<UIElement>(tabablzControl, tabablzControl);
|
||||
}
|
||||
|
||||
private static void Clone(DependencyObject from, DependencyObject to)
|
||||
{
|
||||
var localValueEnumerator = from.GetLocalValueEnumerator();
|
||||
while (localValueEnumerator.MoveNext())
|
||||
{
|
||||
if (localValueEnumerator.Current.Property.ReadOnly ||
|
||||
localValueEnumerator.Current.Value is FrameworkElement) continue;
|
||||
|
||||
if (!(localValueEnumerator.Current.Value is BindingExpressionBase))
|
||||
to.SetCurrentValue(localValueEnumerator.Current.Property, localValueEnumerator.Current.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Others/Dragablz/Dragablz/DefaultInterTabClient.cs
Normal file
34
Others/Dragablz/Dragablz/DefaultInterTabClient.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using Dragablz.Core;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class DefaultInterTabClient : IInterTabClient
|
||||
{
|
||||
public virtual INewTabHost<Window> GetNewHost(IInterTabClient interTabClient, object partition, TabablzControl source)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
var sourceWindow = Window.GetWindow(source);
|
||||
if (sourceWindow == null) throw new ApplicationException("Unable to ascertain source window.");
|
||||
var newWindow = (Window)Activator.CreateInstance(sourceWindow.GetType());
|
||||
|
||||
newWindow.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.DataBind);
|
||||
|
||||
var newTabablzControl = newWindow.LogicalTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();
|
||||
if (newTabablzControl == null) throw new ApplicationException("Unable to ascertain tab control.");
|
||||
|
||||
if (newTabablzControl.ItemsSource == null)
|
||||
newTabablzControl.Items.Clear();
|
||||
|
||||
return new NewTabHost<Window>(newWindow, newTabablzControl);
|
||||
}
|
||||
|
||||
public virtual TabEmptiedResponse TabEmptiedHandler(TabablzControl tabControl, Window window)
|
||||
{
|
||||
return TabEmptiedResponse.CloseWindowOrLayoutBranch;
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Others/Dragablz/Dragablz/Dockablz/Branch.cs
Normal file
98
Others/Dragablz/Dragablz/Dockablz/Branch.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
[TemplatePart(Name = FirstContentPresenterPartName, Type=typeof(ContentPresenter))]
|
||||
[TemplatePart(Name = SecondContentPresenterPartName, Type = typeof(ContentPresenter))]
|
||||
public class Branch : Control
|
||||
{
|
||||
private const string FirstContentPresenterPartName = "PART_FirstContentPresenter";
|
||||
private const string SecondContentPresenterPartName = "PART_SecondContentPresenter";
|
||||
|
||||
static Branch()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Branch), new FrameworkPropertyMetadata(typeof(Branch)));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof (Orientation), typeof (Branch), new PropertyMetadata(default(Orientation)));
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get { return (Orientation) GetValue(OrientationProperty); }
|
||||
set { SetValue(OrientationProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FirstItemProperty = DependencyProperty.Register(
|
||||
"FirstItem", typeof(object), typeof(Branch), new PropertyMetadata(default(object)));
|
||||
|
||||
public object FirstItem
|
||||
{
|
||||
get { return GetValue(FirstItemProperty); }
|
||||
set { SetValue(FirstItemProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FirstItemLengthProperty = DependencyProperty.Register(
|
||||
"FirstItemLength", typeof (GridLength), typeof (Branch), new FrameworkPropertyMetadata(new GridLength(0.49999, GridUnitType.Star), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
|
||||
public GridLength FirstItemLength
|
||||
{
|
||||
get { return (GridLength) GetValue(FirstItemLengthProperty); }
|
||||
set { SetValue(FirstItemLengthProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SecondItemProperty = DependencyProperty.Register(
|
||||
"SecondItem", typeof(object), typeof(Branch), new PropertyMetadata(default(object)));
|
||||
|
||||
public object SecondItem
|
||||
{
|
||||
get { return GetValue(SecondItemProperty); }
|
||||
set { SetValue(SecondItemProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SecondItemLengthProperty = DependencyProperty.Register(
|
||||
"SecondItemLength", typeof(GridLength), typeof(Branch), new FrameworkPropertyMetadata(new GridLength(0.50001, GridUnitType.Star), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
|
||||
public GridLength SecondItemLength
|
||||
{
|
||||
get { return (GridLength) GetValue(SecondItemLengthProperty); }
|
||||
set { SetValue(SecondItemLengthProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the proportional size of the first item, between 0 and 1, where 1 would represent the entire size of the branch.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double GetFirstProportion()
|
||||
{
|
||||
return (1/(FirstItemLength.Value + SecondItemLength.Value))*FirstItemLength.Value;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
FirstContentPresenter = GetTemplateChild(FirstContentPresenterPartName) as ContentPresenter;
|
||||
SecondContentPresenter = GetTemplateChild(SecondContentPresenterPartName) as ContentPresenter;
|
||||
}
|
||||
|
||||
internal ContentPresenter FirstContentPresenter { get; private set; }
|
||||
internal ContentPresenter SecondContentPresenter { get; private set; }
|
||||
}
|
||||
}
|
||||
129
Others/Dragablz/Dragablz/Dockablz/BranchAccessor.cs
Normal file
129
Others/Dragablz/Dragablz/Dockablz/BranchAccessor.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Dragablz.Core;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
public class BranchAccessor
|
||||
{
|
||||
private readonly Branch _branch;
|
||||
private readonly BranchAccessor _firstItemBranchAccessor;
|
||||
private readonly BranchAccessor _secondItemBranchAccessor;
|
||||
private readonly TabablzControl _firstItemTabablzControl;
|
||||
private readonly TabablzControl _secondItemTabablzControl;
|
||||
|
||||
public BranchAccessor(Branch branch)
|
||||
{
|
||||
if (branch == null) throw new ArgumentNullException("branch");
|
||||
|
||||
_branch = branch;
|
||||
|
||||
var firstChildBranch = branch.FirstItem as Branch;
|
||||
if (firstChildBranch != null)
|
||||
_firstItemBranchAccessor = new BranchAccessor(firstChildBranch);
|
||||
else
|
||||
_firstItemTabablzControl = FindTabablzControl(branch.FirstItem, branch.FirstContentPresenter);
|
||||
|
||||
var secondChildBranch = branch.SecondItem as Branch;
|
||||
if (secondChildBranch != null)
|
||||
_secondItemBranchAccessor = new BranchAccessor(secondChildBranch);
|
||||
else
|
||||
_secondItemTabablzControl = FindTabablzControl(branch.SecondItem, branch.SecondContentPresenter);
|
||||
}
|
||||
|
||||
private static TabablzControl FindTabablzControl(object item, DependencyObject contentPresenter)
|
||||
{
|
||||
var result = item as TabablzControl;
|
||||
return result ?? contentPresenter.VisualTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();
|
||||
}
|
||||
|
||||
public Branch Branch
|
||||
{
|
||||
get { return _branch; }
|
||||
}
|
||||
|
||||
public BranchAccessor FirstItemBranchAccessor
|
||||
{
|
||||
get { return _firstItemBranchAccessor; }
|
||||
}
|
||||
|
||||
public BranchAccessor SecondItemBranchAccessor
|
||||
{
|
||||
get { return _secondItemBranchAccessor; }
|
||||
}
|
||||
|
||||
public TabablzControl FirstItemTabablzControl
|
||||
{
|
||||
get { return _firstItemTabablzControl; }
|
||||
}
|
||||
|
||||
public TabablzControl SecondItemTabablzControl
|
||||
{
|
||||
get { return _secondItemTabablzControl; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visits the content of the first or second side of a branch, according to its content type. No more than one of the provided <see cref="Action"/>
|
||||
/// callbacks will be called.
|
||||
/// </summary>
|
||||
/// <param name="childItem"></param>
|
||||
/// <param name="childBranchVisitor"></param>
|
||||
/// <param name="childTabablzControlVisitor"></param>
|
||||
/// <param name="childContentVisitor"></param>
|
||||
/// <returns></returns>
|
||||
public BranchAccessor Visit(BranchItem childItem,
|
||||
Action<BranchAccessor> childBranchVisitor = null,
|
||||
Action<TabablzControl> childTabablzControlVisitor = null,
|
||||
Action<object> childContentVisitor = null)
|
||||
{
|
||||
Func<BranchAccessor> branchGetter;
|
||||
Func<TabablzControl> tabGetter;
|
||||
Func<object> contentGetter;
|
||||
|
||||
switch (childItem)
|
||||
{
|
||||
case BranchItem.First:
|
||||
branchGetter = () => _firstItemBranchAccessor;
|
||||
tabGetter = () => _firstItemTabablzControl;
|
||||
contentGetter = () => _branch.FirstItem;
|
||||
break;
|
||||
case BranchItem.Second:
|
||||
branchGetter = () => _secondItemBranchAccessor;
|
||||
tabGetter = () => _secondItemTabablzControl;
|
||||
contentGetter = () => _branch.SecondItem;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("childItem");
|
||||
}
|
||||
|
||||
var branchDescription = branchGetter();
|
||||
if (branchDescription != null)
|
||||
{
|
||||
if (childBranchVisitor != null)
|
||||
childBranchVisitor(branchDescription);
|
||||
return this;
|
||||
}
|
||||
|
||||
var tabablzControl = tabGetter();
|
||||
if (tabablzControl != null)
|
||||
{
|
||||
if (childTabablzControlVisitor != null)
|
||||
childTabablzControlVisitor(tabablzControl);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
if (childContentVisitor == null) return this;
|
||||
|
||||
var content = contentGetter();
|
||||
if (content != null)
|
||||
childContentVisitor(content);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Others/Dragablz/Dragablz/Dockablz/BranchItem.cs
Normal file
8
Others/Dragablz/Dragablz/Dockablz/BranchItem.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
public enum BranchItem
|
||||
{
|
||||
First,
|
||||
Second
|
||||
}
|
||||
}
|
||||
35
Others/Dragablz/Dragablz/Dockablz/BranchResult.cs
Normal file
35
Others/Dragablz/Dragablz/Dockablz/BranchResult.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
public class BranchResult
|
||||
{
|
||||
private readonly Branch _branch;
|
||||
private readonly TabablzControl _tabablzControl;
|
||||
|
||||
public BranchResult(Branch branch, TabablzControl tabablzControl)
|
||||
{
|
||||
if (branch == null) throw new ArgumentNullException("branch");
|
||||
if (tabablzControl == null) throw new ArgumentNullException("tabablzControl");
|
||||
|
||||
_branch = branch;
|
||||
_tabablzControl = tabablzControl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The new branch.
|
||||
/// </summary>
|
||||
public Branch Branch
|
||||
{
|
||||
get { return _branch; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The new tab control.
|
||||
/// </summary>
|
||||
public TabablzControl TabablzControl
|
||||
{
|
||||
get { return _tabablzControl; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
public class CouldBeHeaderedStyleSelector : StyleSelector
|
||||
{
|
||||
public Style NonHeaderedStyle { get; set; }
|
||||
|
||||
public Style HeaderedStyle { get; set; }
|
||||
|
||||
public override Style SelectStyle(object item, DependencyObject container)
|
||||
{
|
||||
return container is HeaderedDragablzItem || container is HeaderedContentControl
|
||||
? HeaderedStyle
|
||||
: NonHeaderedStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Others/Dragablz/Dragablz/Dockablz/DropZone.cs
Normal file
37
Others/Dragablz/Dragablz/Dockablz/DropZone.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
public class DropZone : Control
|
||||
{
|
||||
static DropZone()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(DropZone), new FrameworkPropertyMetadata(typeof(DropZone)));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(
|
||||
"Location", typeof (DropZoneLocation), typeof (DropZone), new PropertyMetadata(default(DropZoneLocation)));
|
||||
|
||||
public DropZoneLocation Location
|
||||
{
|
||||
get { return (DropZoneLocation) GetValue(LocationProperty); }
|
||||
set { SetValue(LocationProperty, value); }
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey IsOfferedPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"IsOffered", typeof (bool), typeof (DropZone),
|
||||
new PropertyMetadata(default(bool)));
|
||||
|
||||
public static readonly DependencyProperty IsOfferedProperty =
|
||||
IsOfferedPropertyKey.DependencyProperty;
|
||||
|
||||
public bool IsOffered
|
||||
{
|
||||
get { return (bool) GetValue(IsOfferedProperty); }
|
||||
internal set { SetValue(IsOfferedPropertyKey, value); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Others/Dragablz/Dragablz/Dockablz/DropZoneLocation.cs
Normal file
11
Others/Dragablz/Dragablz/Dockablz/DropZoneLocation.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
public enum DropZoneLocation
|
||||
{
|
||||
Top,
|
||||
Right,
|
||||
Bottom,
|
||||
Left,
|
||||
Floating
|
||||
}
|
||||
}
|
||||
86
Others/Dragablz/Dragablz/Dockablz/Extensions.cs
Normal file
86
Others/Dragablz/Dragablz/Dockablz/Extensions.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Begin a query of layout content, returning an accessor for examining the children.
|
||||
/// </summary>
|
||||
/// <param name="layout"></param>
|
||||
/// <returns></returns>
|
||||
public static LayoutAccessor Query(this Layout layout)
|
||||
{
|
||||
if (layout == null) throw new ArgumentNullException("layout");
|
||||
|
||||
return new LayoutAccessor(layout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method for <see cref="LayoutAccessor.Visit"/> which allows a context to be passed through.
|
||||
/// </summary>
|
||||
/// <typeparam name="TContext"></typeparam>
|
||||
/// <param name="layoutAccessor"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="branchVisitor"></param>
|
||||
/// <param name="tabablzControlVisitor"></param>
|
||||
/// <param name="contentVisitor"></param>
|
||||
/// <returns></returns>
|
||||
public static LayoutAccessor Visit<TContext>(
|
||||
this LayoutAccessor layoutAccessor,
|
||||
TContext context,
|
||||
Action<TContext, BranchAccessor> branchVisitor = null,
|
||||
Action<TContext, TabablzControl> tabablzControlVisitor = null,
|
||||
Action<TContext, object> contentVisitor = null)
|
||||
{
|
||||
if (layoutAccessor == null) throw new ArgumentNullException("layoutAccessor");
|
||||
|
||||
layoutAccessor.Visit(
|
||||
WrapVisitor(context, branchVisitor),
|
||||
WrapVisitor(context, tabablzControlVisitor),
|
||||
WrapVisitor(context, contentVisitor)
|
||||
);
|
||||
|
||||
return layoutAccessor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method for <see cref="BranchAccessor.Visit"/> which allows a context to be passed through.
|
||||
/// </summary>
|
||||
/// <typeparam name="TContext"></typeparam>
|
||||
/// <param name="branchAccessor"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="childItem"></param>
|
||||
/// <param name="branchVisitor"></param>
|
||||
/// <param name="tabablzControlVisitor"></param>
|
||||
/// <param name="contentVisitor"></param>
|
||||
/// <returns></returns>
|
||||
public static BranchAccessor Visit<TContext>(
|
||||
this BranchAccessor branchAccessor,
|
||||
TContext context,
|
||||
BranchItem childItem,
|
||||
Action<TContext, BranchAccessor> branchVisitor = null,
|
||||
Action<TContext, TabablzControl> tabablzControlVisitor = null,
|
||||
Action<TContext, object> contentVisitor = null)
|
||||
{
|
||||
if (branchAccessor == null) throw new ArgumentNullException("branchAccessor");
|
||||
|
||||
branchAccessor.Visit(
|
||||
childItem,
|
||||
WrapVisitor(context, branchVisitor),
|
||||
WrapVisitor(context, tabablzControlVisitor),
|
||||
WrapVisitor(context, contentVisitor)
|
||||
);
|
||||
|
||||
return branchAccessor;
|
||||
}
|
||||
|
||||
private static Action<TVisitArg> WrapVisitor<TContext, TVisitArg>(TContext context, Action<TContext, TVisitArg> visitor)
|
||||
{
|
||||
if (visitor == null) return null;
|
||||
|
||||
return a => visitor(context, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Others/Dragablz/Dragablz/Dockablz/Finder.cs
Normal file
53
Others/Dragablz/Dragablz/Dockablz/Finder.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
internal static class Finder
|
||||
{
|
||||
internal static LocationReport Find(TabablzControl tabablzControl)
|
||||
{
|
||||
if (tabablzControl == null) throw new ArgumentNullException("tabablzControl");
|
||||
|
||||
var locationReportBuilder = new LocationReportBuilder(tabablzControl);
|
||||
|
||||
foreach (var loadedInstance in Layout.GetLoadedInstances())
|
||||
{
|
||||
locationReportBuilder.CurrentLayout = loadedInstance;
|
||||
|
||||
loadedInstance.Query().Visit(
|
||||
locationReportBuilder,
|
||||
BranchVisitor,
|
||||
TabablzControlVisitor
|
||||
);
|
||||
|
||||
if (locationReportBuilder.IsFound)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!locationReportBuilder.IsFound)
|
||||
throw new LocationReportException("Instance not within any layout.");
|
||||
|
||||
return locationReportBuilder.ToLocationReport();
|
||||
}
|
||||
|
||||
private static void BranchVisitor(LocationReportBuilder locationReportBuilder, BranchAccessor branchAccessor)
|
||||
{
|
||||
if (Equals(branchAccessor.FirstItemTabablzControl, locationReportBuilder.TargetTabablzControl))
|
||||
locationReportBuilder.MarkFound(branchAccessor.Branch, false);
|
||||
else if (Equals(branchAccessor.SecondItemTabablzControl, locationReportBuilder.TargetTabablzControl))
|
||||
locationReportBuilder.MarkFound(branchAccessor.Branch, true);
|
||||
else
|
||||
{
|
||||
branchAccessor.Visit(BranchItem.First, ba => BranchVisitor(locationReportBuilder, ba));
|
||||
if (locationReportBuilder.IsFound) return;
|
||||
branchAccessor.Visit(BranchItem.Second, ba => BranchVisitor(locationReportBuilder, ba));
|
||||
}
|
||||
}
|
||||
|
||||
private static void TabablzControlVisitor(LocationReportBuilder locationReportBuilder, TabablzControl tabablzControl)
|
||||
{
|
||||
if (Equals(tabablzControl, locationReportBuilder.TargetTabablzControl))
|
||||
locationReportBuilder.MarkFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Others/Dragablz/Dragablz/Dockablz/FloatRequestedEvent.cs
Normal file
22
Others/Dragablz/Dragablz/Dockablz/FloatRequestedEvent.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
public delegate void FloatRequestedEventHandler(object sender, FloatRequestedEventArgs e);
|
||||
|
||||
public class FloatRequestedEventArgs : DragablzItemEventArgs
|
||||
{
|
||||
public FloatRequestedEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem)
|
||||
: base(routedEvent, source, dragablzItem)
|
||||
{ }
|
||||
|
||||
public FloatRequestedEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem)
|
||||
: base(routedEvent, dragablzItem)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
46
Others/Dragablz/Dragablz/Dockablz/FloatTransfer.cs
Normal file
46
Others/Dragablz/Dragablz/Dockablz/FloatTransfer.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
internal class FloatTransfer
|
||||
{
|
||||
private readonly double _width;
|
||||
private readonly double _height;
|
||||
private readonly object _content;
|
||||
|
||||
public FloatTransfer(double width, double height, object content)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_content = content;
|
||||
}
|
||||
|
||||
public static FloatTransfer TakeSnapshot(DragablzItem dragablzItem, TabablzControl sourceTabControl)
|
||||
{
|
||||
if (dragablzItem == null) throw new ArgumentNullException("dragablzItem");
|
||||
|
||||
return new FloatTransfer(sourceTabControl.ActualWidth, sourceTabControl.ActualHeight, dragablzItem.UnderlyingContent ?? dragablzItem.Content ?? dragablzItem);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
//TODO width and height transfer obsolete
|
||||
public double Width
|
||||
{
|
||||
get { return _width; }
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
//TODO width and height transfer obsolete
|
||||
public double Height
|
||||
{
|
||||
get { return _height; }
|
||||
}
|
||||
|
||||
public object Content
|
||||
{
|
||||
get { return _content; }
|
||||
}
|
||||
}
|
||||
}
|
||||
74
Others/Dragablz/Dragablz/Dockablz/FloatingItemSnapShot.cs
Normal file
74
Others/Dragablz/Dragablz/Dockablz/FloatingItemSnapShot.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
/// <summary>
|
||||
/// experimentational. might have to puish this back to mvvm only
|
||||
/// </summary>
|
||||
internal class FloatingItemSnapShot
|
||||
{
|
||||
private readonly object _content;
|
||||
private readonly Rect _location;
|
||||
private readonly int _zIndex;
|
||||
private readonly WindowState _state;
|
||||
|
||||
public FloatingItemSnapShot(object content, Rect location, int zIndex, WindowState state)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
|
||||
_content = content;
|
||||
_location = location;
|
||||
_zIndex = zIndex;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
public static FloatingItemSnapShot Take(DragablzItem dragablzItem)
|
||||
{
|
||||
if (dragablzItem == null) throw new ArgumentNullException("dragablzItem");
|
||||
|
||||
return new FloatingItemSnapShot(
|
||||
dragablzItem.Content,
|
||||
new Rect(dragablzItem.X, dragablzItem.Y, dragablzItem.ActualWidth, dragablzItem.ActualHeight),
|
||||
Panel.GetZIndex(dragablzItem),
|
||||
Layout.GetFloatingItemState(dragablzItem));
|
||||
}
|
||||
|
||||
public void Apply(DragablzItem dragablzItem)
|
||||
{
|
||||
if (dragablzItem == null) throw new ArgumentNullException("dragablzItem");
|
||||
|
||||
dragablzItem.SetCurrentValue(DragablzItem.XProperty, Location.Left);
|
||||
dragablzItem.SetCurrentValue(DragablzItem.YProperty, Location.Top);
|
||||
dragablzItem.SetCurrentValue(FrameworkElement.WidthProperty, Location.Width);
|
||||
dragablzItem.SetCurrentValue(FrameworkElement.HeightProperty, Location.Height);
|
||||
Layout.SetFloatingItemState(dragablzItem, State);
|
||||
Panel.SetZIndex(dragablzItem, ZIndex);
|
||||
}
|
||||
|
||||
public object Content
|
||||
{
|
||||
get { return _content; }
|
||||
}
|
||||
|
||||
public Rect Location
|
||||
{
|
||||
get { return _location; }
|
||||
}
|
||||
|
||||
public int ZIndex
|
||||
{
|
||||
get { return _zIndex; }
|
||||
}
|
||||
|
||||
public WindowState State
|
||||
{
|
||||
get { return _state; }
|
||||
}
|
||||
}
|
||||
}
|
||||
986
Others/Dragablz/Dragablz/Dockablz/Layout.cs
Normal file
986
Others/Dragablz/Dragablz/Dockablz/Layout.cs
Normal file
@@ -0,0 +1,986 @@
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using Dragablz.Core;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
public delegate void ClosingFloatingItemCallback(ItemActionCallbackArgs<Layout> args);
|
||||
|
||||
[TemplatePart(Name = TopDropZonePartName, Type = typeof(DropZone))]
|
||||
[TemplatePart(Name = RightDropZonePartName, Type = typeof(DropZone))]
|
||||
[TemplatePart(Name = BottomDropZonePartName, Type = typeof(DropZone))]
|
||||
[TemplatePart(Name = LeftDropZonePartName, Type = typeof(DropZone))]
|
||||
[TemplatePart(Name = FloatingDropZonePartName, Type = typeof(DropZone))]
|
||||
[TemplatePart(Name = FloatingContentPresenterPartName, Type = typeof(ContentPresenter))]
|
||||
public class Layout : ContentControl
|
||||
{
|
||||
private static readonly HashSet<Layout> LoadedLayouts = new HashSet<Layout>();
|
||||
private const string TopDropZonePartName = "PART_TopDropZone";
|
||||
private const string RightDropZonePartName = "PART_RightDropZone";
|
||||
private const string BottomDropZonePartName = "PART_BottomDropZone";
|
||||
private const string LeftDropZonePartName = "PART_LeftDropZone";
|
||||
private const string FloatingDropZonePartName = "PART_FloatDropZone";
|
||||
private const string FloatingContentPresenterPartName = "PART_FloatContentPresenter";
|
||||
|
||||
private readonly IDictionary<DropZoneLocation, DropZone> _dropZones = new Dictionary<DropZoneLocation, DropZone>();
|
||||
private static Tuple<Layout, DropZone> _currentlyOfferedDropZone;
|
||||
|
||||
public static RoutedCommand UnfloatItemCommand = new RoutedCommand();
|
||||
public static RoutedCommand MaximiseFloatingItem = new RoutedCommand();
|
||||
public static RoutedCommand RestoreFloatingItem = new RoutedCommand();
|
||||
public static RoutedCommand CloseFloatingItem = new RoutedCommand();
|
||||
public static RoutedCommand TileFloatingItemsCommand = new RoutedCommand();
|
||||
public static RoutedCommand TileFloatingItemsVerticallyCommand = new RoutedCommand();
|
||||
public static RoutedCommand TileFloatingItemsHorizontallyCommand = new RoutedCommand();
|
||||
|
||||
private readonly DragablzItemsControl _floatingItems;
|
||||
private static bool _isDragOpWireUpPending;
|
||||
private FloatTransfer _floatTransfer;
|
||||
|
||||
static Layout()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Layout), new FrameworkPropertyMetadata(typeof(Layout)));
|
||||
|
||||
EventManager.RegisterClassHandler(typeof(DragablzItem), DragablzItem.DragStarted, new DragablzDragStartedEventHandler(ItemDragStarted));
|
||||
EventManager.RegisterClassHandler(typeof(DragablzItem), DragablzItem.PreviewDragDelta, new DragablzDragDeltaEventHandler(PreviewItemDragDelta), true);
|
||||
EventManager.RegisterClassHandler(typeof(DragablzItem), DragablzItem.DragCompleted, new DragablzDragCompletedEventHandler(ItemDragCompleted));
|
||||
}
|
||||
|
||||
public Layout()
|
||||
{
|
||||
Loaded += (sender, args) =>
|
||||
{
|
||||
LoadedLayouts.Add(this);
|
||||
MarkTopLeftItem(this);
|
||||
};
|
||||
Unloaded += (sender, args) => LoadedLayouts.Remove(this);
|
||||
|
||||
CommandBindings.Add(new CommandBinding(UnfloatItemCommand, UnfloatExecuted, CanExecuteUnfloat));
|
||||
CommandBindings.Add(new CommandBinding(MaximiseFloatingItem, MaximiseFloatingItemExecuted, CanExecuteMaximiseFloatingItem));
|
||||
CommandBindings.Add(new CommandBinding(CloseFloatingItem, CloseFloatingItemExecuted, CanExecuteCloseFloatingItem));
|
||||
CommandBindings.Add(new CommandBinding(RestoreFloatingItem, RestoreFloatingItemExecuted, CanExecuteRestoreFloatingItem));
|
||||
CommandBindings.Add(new CommandBinding(TileFloatingItemsCommand, TileFloatingItemsExecuted));
|
||||
CommandBindings.Add(new CommandBinding(TileFloatingItemsCommand, TileFloatingItemsExecuted));
|
||||
CommandBindings.Add(new CommandBinding(TileFloatingItemsVerticallyCommand, TileFloatingItemsVerticallyExecuted));
|
||||
CommandBindings.Add(new CommandBinding(TileFloatingItemsHorizontallyCommand, TileFloatingItemsHorizontallyExecuted));
|
||||
|
||||
//TODO bad bad behaviour. Pick up this from the template.
|
||||
_floatingItems = new DragablzItemsControl
|
||||
{
|
||||
ContainerCustomisations = new ContainerCustomisations(
|
||||
GetFloatingContainerForItemOverride,
|
||||
PrepareFloatingContainerForItemOverride,
|
||||
ClearingFloatingContainerForItemOverride)
|
||||
};
|
||||
|
||||
var floatingItemsSourceBinding = new Binding("FloatingItemsSource") { Source = this };
|
||||
_floatingItems.SetBinding(ItemsControl.ItemsSourceProperty, floatingItemsSourceBinding);
|
||||
var floatingItemsControlStyleBinding = new Binding("FloatingItemsControlStyle") { Source = this };
|
||||
_floatingItems.SetBinding(StyleProperty, floatingItemsControlStyleBinding);
|
||||
var floatingItemTemplateBinding = new Binding("FloatingItemTemplate") { Source = this };
|
||||
_floatingItems.SetBinding(ItemsControl.ItemTemplateProperty, floatingItemTemplateBinding);
|
||||
var floatingItemTemplateSelectorBinding = new Binding("FloatingItemTemplateSelector") { Source = this };
|
||||
_floatingItems.SetBinding(ItemsControl.ItemTemplateSelectorProperty, floatingItemTemplateSelectorBinding);
|
||||
var floatingItemContainerStyeBinding = new Binding("FloatingItemContainerStyle") { Source = this };
|
||||
_floatingItems.SetBinding(ItemsControl.ItemContainerStyleProperty, floatingItemContainerStyeBinding);
|
||||
var floatingItemContainerStyleSelectorBinding = new Binding("FloatingItemContainerStyleSelector") { Source = this };
|
||||
_floatingItems.SetBinding(ItemsControl.ItemContainerStyleSelectorProperty, floatingItemContainerStyleSelectorBinding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to get all the currently loaded layouts.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Layout> GetLoadedInstances()
|
||||
{
|
||||
return LoadedLayouts.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the location of a tab control withing a layout.
|
||||
/// </summary>
|
||||
/// <param name="tabablzControl"></param>
|
||||
/// <returns></returns>
|
||||
public static LocationReport Find(TabablzControl tabablzControl)
|
||||
{
|
||||
if (tabablzControl == null) throw new ArgumentNullException("tabablzControl");
|
||||
|
||||
return Finder.Find(tabablzControl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a split in a layout, at the location of a specified <see cref="TabablzControl"/>.
|
||||
/// </summary>
|
||||
/// <para></para>
|
||||
/// <param name="tabablzControl">Tab control to be split.</param>
|
||||
/// <param name="orientation">Direction of split.</param>
|
||||
/// <param name="makeSecond">Set to <c>true</c> to make the current tab control push into the right hand or bottom of the split.</param>
|
||||
/// <remarks>The tab control to be split must be hosted in a layout control.</remarks>
|
||||
public static BranchResult Branch(TabablzControl tabablzControl, Orientation orientation, bool makeSecond)
|
||||
{
|
||||
return Branch(tabablzControl, orientation, makeSecond, .5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a split in a layout, at the location of a specified <see cref="TabablzControl"/>.
|
||||
/// </summary>
|
||||
/// <para></para>
|
||||
/// <param name="tabablzControl">Tab control to be split.</param>
|
||||
/// <param name="orientation">Direction of split.</param>
|
||||
/// <param name="makeSecond">Set to <c>true</c> to make the current tab control push into the right hand or bottom of the split.</param>
|
||||
/// <param name="firstItemProportion">Sets the proportion of the first tab control, with 0.5 being 50% of available space.</param>
|
||||
/// <remarks>The tab control to be split must be hosted in a layout control. <see cref="Layout.BranchTemplate" /> should be set (typically via XAML).</remarks>
|
||||
public static BranchResult Branch(TabablzControl tabablzControl, Orientation orientation, bool makeSecond, double firstItemProportion)
|
||||
{
|
||||
return Branch(tabablzControl, null, orientation, makeSecond, firstItemProportion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a split in a layout, at the location of a specified <see cref="TabablzControl"/>.
|
||||
/// </summary>
|
||||
/// <para></para>
|
||||
/// <param name="tabablzControl">Tab control to be split.</param>
|
||||
/// <param name="newSiblingTabablzControl">New sibling tab control (otherwise <see cref="Layout.BranchTemplate"/> will be used).</param>
|
||||
/// <param name="orientation">Direction of split.</param>
|
||||
/// <param name="makeCurrentSecond">Set to <c>true</c> to make the current tab control push into the right hand or bottom of the split.</param>
|
||||
/// <param name="firstItemProportion">Sets the proportion of the first tab control, with 0.5 being 50% of available space.</param>
|
||||
/// <remarks>The tab control to be split must be hosted in a layout control. </remarks>
|
||||
public static BranchResult Branch(TabablzControl tabablzControl, TabablzControl newSiblingTabablzControl, Orientation orientation, bool makeCurrentSecond,
|
||||
double firstItemProportion)
|
||||
{
|
||||
if (firstItemProportion < 0.0 || firstItemProportion > 1.0) throw new ArgumentOutOfRangeException("firstItemProportion", "Must be >= 0.0 and <= 1.0");
|
||||
|
||||
var locationReport = Find(tabablzControl);
|
||||
|
||||
Action<Branch> applier;
|
||||
object existingContent;
|
||||
if (!locationReport.IsLeaf)
|
||||
{
|
||||
existingContent = locationReport.RootLayout.Content;
|
||||
applier = branch => locationReport.RootLayout.Content = branch;
|
||||
}
|
||||
else if (!locationReport.IsSecondLeaf)
|
||||
{
|
||||
existingContent = locationReport.ParentBranch.FirstItem;
|
||||
applier = branch => locationReport.ParentBranch.FirstItem = branch;
|
||||
}
|
||||
else
|
||||
{
|
||||
existingContent = locationReport.ParentBranch.SecondItem;
|
||||
applier = branch => locationReport.ParentBranch.SecondItem = branch;
|
||||
}
|
||||
|
||||
var selectedItem = tabablzControl.SelectedItem;
|
||||
var branchResult = Branch(orientation, firstItemProportion, makeCurrentSecond, locationReport.RootLayout.BranchTemplate, newSiblingTabablzControl, existingContent, applier);
|
||||
tabablzControl.SelectedItem = selectedItem;
|
||||
tabablzControl.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
tabablzControl.SetCurrentValue(Selector.SelectedItemProperty, selectedItem);
|
||||
MarkTopLeftItem(locationReport.RootLayout);
|
||||
}),
|
||||
DispatcherPriority.Loaded);
|
||||
|
||||
return branchResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use in conjuction with the <see cref="InterTabController.Partition"/> on a <see cref="TabablzControl"/>
|
||||
/// to isolate drag and drop spaces/control instances.
|
||||
/// </summary>
|
||||
public string Partition { get; set; }
|
||||
|
||||
public static readonly DependencyProperty InterLayoutClientProperty = DependencyProperty.Register(
|
||||
"InterLayoutClient", typeof (IInterLayoutClient), typeof (Layout), new PropertyMetadata(new DefaultInterLayoutClient()));
|
||||
|
||||
public IInterLayoutClient InterLayoutClient
|
||||
{
|
||||
get { return (IInterLayoutClient) GetValue(InterLayoutClientProperty); }
|
||||
set { SetValue(InterLayoutClientProperty, value); }
|
||||
}
|
||||
|
||||
internal static bool IsContainedWithinBranch(DependencyObject dependencyObject)
|
||||
{
|
||||
do
|
||||
{
|
||||
dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
|
||||
if (dependencyObject is Branch)
|
||||
return true;
|
||||
} while (dependencyObject != null);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey IsParticipatingInDragPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"IsParticipatingInDrag", typeof (bool), typeof (Layout),
|
||||
new PropertyMetadata(default(bool)));
|
||||
|
||||
public static readonly DependencyProperty IsParticipatingInDragProperty =
|
||||
IsParticipatingInDragPropertyKey.DependencyProperty;
|
||||
|
||||
public bool IsParticipatingInDrag
|
||||
{
|
||||
get { return (bool) GetValue(IsParticipatingInDragProperty); }
|
||||
private set { SetValue(IsParticipatingInDragPropertyKey, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BranchTemplateProperty = DependencyProperty.Register(
|
||||
"BranchTemplate", typeof (DataTemplate), typeof (Layout), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public DataTemplate BranchTemplate
|
||||
{
|
||||
get { return (DataTemplate) GetValue(BranchTemplateProperty); }
|
||||
set { SetValue(BranchTemplateProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsFloatDropZoneEnabledProperty = DependencyProperty.Register(
|
||||
"IsFloatDropZoneEnabled", typeof (bool), typeof (Layout), new PropertyMetadata(default(bool)));
|
||||
|
||||
public bool IsFloatDropZoneEnabled
|
||||
{
|
||||
get { return (bool) GetValue(IsFloatDropZoneEnabledProperty); }
|
||||
set { SetValue(IsFloatDropZoneEnabledProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a margin for the container which hosts all floating items.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty FloatingItemsContainerMarginProperty = DependencyProperty.Register(
|
||||
"FloatingItemsContainerMargin", typeof (Thickness), typeof (Layout), new PropertyMetadata(default(Thickness)));
|
||||
|
||||
/// <summary>
|
||||
/// Defines a margin for the container which hosts all floating items.
|
||||
/// </summary>
|
||||
public Thickness FloatingItemsContainerMargin
|
||||
{
|
||||
get { return (Thickness) GetValue(FloatingItemsContainerMarginProperty); }
|
||||
set { SetValue(FloatingItemsContainerMarginProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Floating items, such as tool/MDI windows, which will sit above the <see cref="Content"/>.
|
||||
/// </summary>
|
||||
public ItemCollection FloatingItems
|
||||
{
|
||||
get { return _floatingItems.Items; }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FloatingItemsSourceProperty = DependencyProperty.Register(
|
||||
"FloatingItemsSource", typeof (IEnumerable), typeof (Layout), new PropertyMetadata(default(IEnumerable)));
|
||||
|
||||
/// <summary>
|
||||
/// Floating items, such as tool/MDI windows, which will sit above the <see cref="Content"/>.
|
||||
/// </summary>
|
||||
public IEnumerable FloatingItemsSource
|
||||
{
|
||||
get { return (IEnumerable) GetValue(FloatingItemsSourceProperty); }
|
||||
set { SetValue(FloatingItemsSourceProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FloatingItemsControlStyleProperty = DependencyProperty.Register(
|
||||
"FloatingItemsControlStyle", typeof (Style), typeof (Layout), new PropertyMetadata((Style)null));
|
||||
|
||||
/// <summary>
|
||||
/// The style to be applied to the <see cref="DragablzItemsControl"/> which is used to display floating items.
|
||||
/// In most scenarios it should be OK to leave this to that applied by the default style.
|
||||
/// </summary>
|
||||
public Style FloatingItemsControlStyle
|
||||
{
|
||||
get { return (Style) GetValue(FloatingItemsControlStyleProperty); }
|
||||
set { SetValue(FloatingItemsControlStyleProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FloatingItemContainerStyleProperty = DependencyProperty.Register(
|
||||
"FloatingItemContainerStyle", typeof (Style), typeof (Layout), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style FloatingItemContainerStyle
|
||||
{
|
||||
get { return (Style) GetValue(FloatingItemContainerStyleProperty); }
|
||||
set { SetValue(FloatingItemContainerStyleProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FloatingItemContainerStyleSelectorProperty = DependencyProperty.Register(
|
||||
"FloatingItemContainerStyleSelector", typeof (StyleSelector), typeof (Layout), new PropertyMetadata(new CouldBeHeaderedStyleSelector()));
|
||||
|
||||
public StyleSelector FloatingItemContainerStyleSelector
|
||||
{
|
||||
get { return (StyleSelector) GetValue(FloatingItemContainerStyleSelectorProperty); }
|
||||
set { SetValue(FloatingItemContainerStyleSelectorProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FloatingItemTemplateProperty = DependencyProperty.Register(
|
||||
"FloatingItemTemplate", typeof (DataTemplate), typeof (Layout), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public DataTemplate FloatingItemTemplate
|
||||
{
|
||||
get { return (DataTemplate) GetValue(FloatingItemTemplateProperty); }
|
||||
set { SetValue(FloatingItemTemplateProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FloatingItemTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"FloatingItemTemplateSelector", typeof (DataTemplateSelector), typeof (Layout), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
|
||||
public DataTemplateSelector FloatingItemTemplateSelector
|
||||
{
|
||||
get { return (DataTemplateSelector) GetValue(FloatingItemTemplateSelectorProperty); }
|
||||
set { SetValue(FloatingItemTemplateSelectorProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FloatingItemHeaderMemberPathProperty = DependencyProperty.Register(
|
||||
"FloatingItemHeaderMemberPath", typeof (string), typeof (Layout), new PropertyMetadata(default(string)));
|
||||
|
||||
public string FloatingItemHeaderMemberPath
|
||||
{
|
||||
get { return (string) GetValue(FloatingItemHeaderMemberPathProperty); }
|
||||
set { SetValue(FloatingItemHeaderMemberPathProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FloatingItemDisplayMemberPathProperty = DependencyProperty.Register(
|
||||
"FloatingItemDisplayMemberPath", typeof (string), typeof (Layout), new PropertyMetadata(default(string)));
|
||||
|
||||
public string FloatingItemDisplayMemberPath
|
||||
{
|
||||
get { return (string) GetValue(FloatingItemDisplayMemberPathProperty); }
|
||||
set { SetValue(FloatingItemDisplayMemberPathProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ClosingFloatingItemCallbackProperty = DependencyProperty.Register(
|
||||
"ClosingFloatingItemCallback", typeof (ClosingFloatingItemCallback), typeof (Layout), new PropertyMetadata(default(ClosingFloatingItemCallback)));
|
||||
|
||||
public ClosingFloatingItemCallback ClosingFloatingItemCallback
|
||||
{
|
||||
get { return (ClosingFloatingItemCallback) GetValue(ClosingFloatingItemCallbackProperty); }
|
||||
set { SetValue(ClosingFloatingItemCallbackProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey KeyIsFloatingInLayoutPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
||||
"IsFloatingInLayout", typeof (bool), typeof (Layout), new PropertyMetadata(default(bool)));
|
||||
|
||||
private static void SetIsFloatingInLayout(DependencyObject element, bool value)
|
||||
{
|
||||
element.SetValue(KeyIsFloatingInLayoutPropertyKey, value);
|
||||
}
|
||||
|
||||
public static bool GetIsFloatingInLayout(DependencyObject element)
|
||||
{
|
||||
return (bool)element.GetValue(KeyIsFloatingInLayoutPropertyKey.DependencyProperty);
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey IsTopLeftItemPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"IsTopLeftItem", typeof(bool), typeof(Layout),
|
||||
new PropertyMetadata(default(bool)));
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if an item/tab control within a layout is contained at the top most and left most branch item.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsTopLeftItemProperty = IsTopLeftItemPropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if an item/tab control within a layout is contained at the top most and left most branch item.
|
||||
/// </summary>
|
||||
private static void SetIsTopLeftItem(DependencyObject element, bool value)
|
||||
{
|
||||
element.SetValue(IsTopLeftItemPropertyKey, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if an item/tab control within a layout is contained at the top most and left most branch item.
|
||||
/// </summary>
|
||||
public static bool GetIsTopLeftItem(DependencyObject element)
|
||||
{
|
||||
return (bool)element.GetValue(IsTopLeftItemProperty);
|
||||
}
|
||||
|
||||
/// <summary>When overridden in a derived class, is invoked whenever application code or internal processes call <see cref="M:System.Windows.FrameworkElement.ApplyTemplate" />.</summary>
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var floatingItemsContentPresenter = GetTemplateChild(FloatingContentPresenterPartName) as ContentPresenter;
|
||||
if (floatingItemsContentPresenter != null)
|
||||
floatingItemsContentPresenter.Content = _floatingItems;
|
||||
|
||||
_dropZones[DropZoneLocation.Top] = GetTemplateChild(TopDropZonePartName) as DropZone;
|
||||
_dropZones[DropZoneLocation.Right] = GetTemplateChild(RightDropZonePartName) as DropZone;
|
||||
_dropZones[DropZoneLocation.Bottom] = GetTemplateChild(BottomDropZonePartName) as DropZone;
|
||||
_dropZones[DropZoneLocation.Left] = GetTemplateChild(LeftDropZonePartName) as DropZone;
|
||||
_dropZones[DropZoneLocation.Floating] = GetTemplateChild(FloatingDropZonePartName) as DropZone;
|
||||
}
|
||||
|
||||
internal IEnumerable<DragablzItem> FloatingDragablzItems()
|
||||
{
|
||||
return _floatingItems.DragablzItems();
|
||||
}
|
||||
|
||||
internal static void RestoreFloatingItemSnapShots(DependencyObject ancestor, IEnumerable<FloatingItemSnapShot> floatingItemSnapShots)
|
||||
{
|
||||
var layouts = ancestor.VisualTreeDepthFirstTraversal().OfType<Layout>().ToList();
|
||||
foreach (var floatingDragablzItem in layouts.SelectMany(l => l.FloatingDragablzItems()))
|
||||
{
|
||||
var itemSnapShots = floatingItemSnapShots as FloatingItemSnapShot[] ?? floatingItemSnapShots.ToArray();
|
||||
var floatingItemSnapShot = itemSnapShots.FirstOrDefault(
|
||||
ss => ss.Content == floatingDragablzItem.Content);
|
||||
if (floatingItemSnapShot != null)
|
||||
floatingItemSnapShot.Apply(floatingDragablzItem);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ItemDragStarted(object sender, DragablzDragStartedEventArgs e)
|
||||
{
|
||||
//we wait until drag is in full flow so we know the partition has been setup by the owning tab control
|
||||
_isDragOpWireUpPending = true;
|
||||
}
|
||||
|
||||
private static void SetupParticipatingLayouts(DragablzItem dragablzItem)
|
||||
{
|
||||
var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(dragablzItem) as DragablzItemsControl;
|
||||
if (sourceOfDragItemsControl == null || sourceOfDragItemsControl.Items.Count != 1) return;
|
||||
|
||||
var draggingWindow = Window.GetWindow(dragablzItem);
|
||||
if (draggingWindow == null) return;
|
||||
|
||||
foreach (var loadedLayout in LoadedLayouts.Where(l =>
|
||||
l.Partition == dragablzItem.PartitionAtDragStart &&
|
||||
!Equals(Window.GetWindow(l), draggingWindow)))
|
||||
|
||||
{
|
||||
loadedLayout.IsParticipatingInDrag = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void MonitorDropZones(Point cursorPos)
|
||||
{
|
||||
var myWindow = Window.GetWindow(this);
|
||||
if (myWindow == null) return;
|
||||
|
||||
foreach (var dropZone in _dropZones.Values.Where(dz => dz != null))
|
||||
{
|
||||
var pointFromScreen = myWindow.PointFromScreen(cursorPos);
|
||||
var pointRelativeToDropZone = myWindow.TranslatePoint(pointFromScreen, dropZone);
|
||||
var inputHitTest = dropZone.InputHitTest(pointRelativeToDropZone);
|
||||
//TODO better halding when windows are layered over each other
|
||||
if (inputHitTest != null)
|
||||
{
|
||||
if (_currentlyOfferedDropZone != null)
|
||||
_currentlyOfferedDropZone.Item2.IsOffered = false;
|
||||
dropZone.IsOffered = true;
|
||||
_currentlyOfferedDropZone = new Tuple<Layout, DropZone>(this, dropZone);
|
||||
}
|
||||
else
|
||||
{
|
||||
dropZone.IsOffered = false;
|
||||
if (_currentlyOfferedDropZone != null && _currentlyOfferedDropZone.Item2 == dropZone)
|
||||
_currentlyOfferedDropZone = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetSourceTabControl(DragablzItem dragablzItem, out TabablzControl tabablzControl)
|
||||
{
|
||||
var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(dragablzItem) as DragablzItemsControl;
|
||||
if (sourceOfDragItemsControl == null) throw new ApplicationException("Unable to determine source items control.");
|
||||
|
||||
tabablzControl = TabablzControl.GetOwnerOfHeaderItems(sourceOfDragItemsControl);
|
||||
|
||||
return tabablzControl != null;
|
||||
}
|
||||
|
||||
private void Branch(DropZoneLocation location, DragablzItem sourceDragablzItem)
|
||||
{
|
||||
if (InterLayoutClient == null)
|
||||
throw new InvalidOperationException("InterLayoutClient is not set.");
|
||||
|
||||
var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(sourceDragablzItem) as DragablzItemsControl;
|
||||
if (sourceOfDragItemsControl == null) throw new ApplicationException("Unable to determin source items control.");
|
||||
|
||||
var sourceTabControl = TabablzControl.GetOwnerOfHeaderItems(sourceOfDragItemsControl);
|
||||
if (sourceTabControl == null) throw new ApplicationException("Unable to determin source tab control.");
|
||||
|
||||
var floatingItemSnapShots = sourceTabControl.VisualTreeDepthFirstTraversal()
|
||||
.OfType<Layout>()
|
||||
.SelectMany(l => l.FloatingDragablzItems().Select(FloatingItemSnapShot.Take))
|
||||
.ToList();
|
||||
|
||||
var sourceItem = sourceOfDragItemsControl.ItemContainerGenerator.ItemFromContainer(sourceDragablzItem);
|
||||
sourceTabControl.RemoveItem(sourceDragablzItem);
|
||||
|
||||
var branchItem = new Branch
|
||||
{
|
||||
Orientation = (location == DropZoneLocation.Right || location == DropZoneLocation.Left) ? Orientation.Horizontal : Orientation.Vertical
|
||||
};
|
||||
|
||||
object newContent;
|
||||
if (BranchTemplate == null)
|
||||
{
|
||||
var newTabHost = InterLayoutClient.GetNewHost(Partition, sourceTabControl);
|
||||
if (newTabHost == null)
|
||||
throw new ApplicationException("InterLayoutClient did not provide a new tab host.");
|
||||
newTabHost.TabablzControl.AddToSource(sourceItem);
|
||||
newTabHost.TabablzControl.SelectedItem = sourceItem;
|
||||
newContent = newTabHost.Container;
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() => RestoreFloatingItemSnapShots(newTabHost.TabablzControl, floatingItemSnapShots)), DispatcherPriority.Loaded);
|
||||
}
|
||||
else
|
||||
{
|
||||
newContent = new ContentControl
|
||||
{
|
||||
Content = new object(),
|
||||
ContentTemplate = BranchTemplate,
|
||||
};
|
||||
((ContentControl) newContent).Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
//TODO might need to improve this a bit, make it a bit more declarative for complex trees
|
||||
var newTabControl = ((ContentControl)newContent).VisualTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();
|
||||
if (newTabControl == null) return;
|
||||
|
||||
newTabControl.DataContext = sourceTabControl.DataContext;
|
||||
newTabControl.AddToSource(sourceItem);
|
||||
newTabControl.SelectedItem = sourceItem;
|
||||
Dispatcher.BeginInvoke(new Action(() => RestoreFloatingItemSnapShots(newTabControl, floatingItemSnapShots)), DispatcherPriority.Loaded);
|
||||
}), DispatcherPriority.Loaded);
|
||||
}
|
||||
|
||||
if (location == DropZoneLocation.Right || location == DropZoneLocation.Bottom)
|
||||
{
|
||||
branchItem.FirstItem = Content;
|
||||
branchItem.SecondItem = newContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
branchItem.FirstItem = newContent;
|
||||
branchItem.SecondItem = Content;
|
||||
}
|
||||
|
||||
SetCurrentValue(ContentProperty, branchItem);
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() => MarkTopLeftItem(this)), DispatcherPriority.Loaded);
|
||||
}
|
||||
|
||||
internal static bool ConsolidateBranch(DependencyObject redundantNode)
|
||||
{
|
||||
bool isSecondLineageWhenOwnerIsBranch;
|
||||
var ownerBranch = FindLayoutOrBranchOwner(redundantNode, out isSecondLineageWhenOwnerIsBranch) as Branch;
|
||||
if (ownerBranch == null) return false;
|
||||
|
||||
var survivingItem = isSecondLineageWhenOwnerIsBranch ? ownerBranch.FirstItem : ownerBranch.SecondItem;
|
||||
|
||||
var grandParent = FindLayoutOrBranchOwner(ownerBranch, out isSecondLineageWhenOwnerIsBranch);
|
||||
if (grandParent == null) throw new ApplicationException("Unexpected structure, grandparent Layout or Branch not found");
|
||||
|
||||
var layout = grandParent as Layout;
|
||||
if (layout != null)
|
||||
{
|
||||
layout.Content = survivingItem;
|
||||
MarkTopLeftItem(layout);
|
||||
return true;
|
||||
}
|
||||
|
||||
var branch = (Branch) grandParent;
|
||||
if (isSecondLineageWhenOwnerIsBranch)
|
||||
branch.SecondItem = survivingItem;
|
||||
else
|
||||
branch.FirstItem = survivingItem;
|
||||
var rootLayout = branch.VisualTreeAncestory().OfType<Layout>().FirstOrDefault();
|
||||
if (rootLayout != null)
|
||||
MarkTopLeftItem(rootLayout);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static object FindLayoutOrBranchOwner(DependencyObject node, out bool isSecondLineageWhenOwnerIsBranch)
|
||||
{
|
||||
isSecondLineageWhenOwnerIsBranch = false;
|
||||
|
||||
var ancestoryStack = new Stack<DependencyObject>();
|
||||
do
|
||||
{
|
||||
ancestoryStack.Push(node);
|
||||
node = VisualTreeHelper.GetParent(node);
|
||||
if (node is Layout)
|
||||
return node;
|
||||
|
||||
var branch = node as Branch;
|
||||
if (branch == null) continue;
|
||||
|
||||
isSecondLineageWhenOwnerIsBranch = ancestoryStack.Contains(branch.SecondContentPresenter);
|
||||
return branch;
|
||||
|
||||
} while (node != null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static BranchResult Branch(Orientation orientation, double proportion, bool makeSecond, DataTemplate branchTemplate, TabablzControl newSibling, object existingContent, Action<Branch> applier)
|
||||
{
|
||||
var branchItem = new Branch
|
||||
{
|
||||
Orientation = orientation
|
||||
};
|
||||
|
||||
var newContent = new ContentControl
|
||||
{
|
||||
Content = newSibling ?? new object(),
|
||||
ContentTemplate = branchTemplate,
|
||||
};
|
||||
|
||||
if (!makeSecond)
|
||||
{
|
||||
branchItem.FirstItem = existingContent;
|
||||
branchItem.SecondItem = newContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
branchItem.FirstItem = newContent;
|
||||
branchItem.SecondItem = existingContent;
|
||||
}
|
||||
|
||||
branchItem.SetCurrentValue(Dockablz.Branch.FirstItemLengthProperty, new GridLength(proportion, GridUnitType.Star));
|
||||
branchItem.SetCurrentValue(Dockablz.Branch.SecondItemLengthProperty, new GridLength(1-proportion, GridUnitType.Star));
|
||||
|
||||
applier(branchItem);
|
||||
|
||||
newContent.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.Loaded);
|
||||
var newTabablzControl = newContent.VisualTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();
|
||||
if (newTabablzControl != null) return new BranchResult(branchItem, newTabablzControl);
|
||||
|
||||
//let#s be kinf and give WPF an extra change to gen the controls
|
||||
newContent.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.Background);
|
||||
newTabablzControl = newContent.VisualTreeDepthFirstTraversal().OfType<TabablzControl>().FirstOrDefault();
|
||||
|
||||
if (newTabablzControl == null)
|
||||
throw new ApplicationException("New TabablzControl was not generated inside branch.");
|
||||
|
||||
return new BranchResult(branchItem, newTabablzControl);
|
||||
}
|
||||
|
||||
private static void ItemDragCompleted(object sender, DragablzDragCompletedEventArgs e)
|
||||
{
|
||||
_isDragOpWireUpPending = false;
|
||||
|
||||
foreach (var loadedLayout in LoadedLayouts)
|
||||
loadedLayout.IsParticipatingInDrag = false;
|
||||
|
||||
if (_currentlyOfferedDropZone == null || e.DragablzItem.IsDropTargetFound) return;
|
||||
|
||||
TabablzControl tabablzControl;
|
||||
if (TryGetSourceTabControl(e.DragablzItem, out tabablzControl))
|
||||
{
|
||||
if (tabablzControl.Items.Count > 1) return;
|
||||
|
||||
if (_currentlyOfferedDropZone.Item2.Location == DropZoneLocation.Floating)
|
||||
Float(_currentlyOfferedDropZone.Item1, e.DragablzItem);
|
||||
else
|
||||
_currentlyOfferedDropZone.Item1.Branch(_currentlyOfferedDropZone.Item2.Location, e.DragablzItem);
|
||||
}
|
||||
|
||||
_currentlyOfferedDropZone = null;
|
||||
}
|
||||
|
||||
private static void Float(Layout layout, DragablzItem dragablzItem)
|
||||
{
|
||||
//TODO we need eq of IManualInterTabClient here, so consumer can control this op'.
|
||||
|
||||
//remove from source
|
||||
var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(dragablzItem) as DragablzItemsControl;
|
||||
if (sourceOfDragItemsControl == null) throw new ApplicationException("Unable to determin source items control.");
|
||||
var sourceTabControl = TabablzControl.GetOwnerOfHeaderItems(sourceOfDragItemsControl);
|
||||
layout._floatTransfer = FloatTransfer.TakeSnapshot(dragablzItem, sourceTabControl);
|
||||
var floatingItemSnapShots = sourceTabControl.VisualTreeDepthFirstTraversal()
|
||||
.OfType<Layout>()
|
||||
.SelectMany(l => l.FloatingDragablzItems().Select(FloatingItemSnapShot.Take))
|
||||
.ToList();
|
||||
if (sourceTabControl == null) throw new ApplicationException("Unable to determin source tab control.");
|
||||
sourceTabControl.RemoveItem(dragablzItem);
|
||||
|
||||
//add to float layer
|
||||
CollectionTeaser collectionTeaser;
|
||||
if (CollectionTeaser.TryCreate(layout.FloatingItemsSource, out collectionTeaser))
|
||||
collectionTeaser.Add(layout._floatTransfer.Content);
|
||||
else
|
||||
layout.FloatingItems.Add(layout._floatTransfer.Content);
|
||||
|
||||
layout.Dispatcher.BeginInvoke(new Action(() => RestoreFloatingItemSnapShots(layout, floatingItemSnapShots)), DispatcherPriority.Loaded);
|
||||
}
|
||||
|
||||
private static void PreviewItemDragDelta(object sender, DragablzDragDeltaEventArgs e)
|
||||
{
|
||||
if (e.Cancel) return;
|
||||
|
||||
if (_isDragOpWireUpPending)
|
||||
{
|
||||
SetupParticipatingLayouts(e.DragablzItem);
|
||||
_isDragOpWireUpPending = false;
|
||||
}
|
||||
|
||||
foreach (var layout in LoadedLayouts.Where(l => l.IsParticipatingInDrag))
|
||||
{
|
||||
var cursorPos = Native.GetCursorPos();
|
||||
layout.MonitorDropZones(cursorPos);
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareFloatingContainerForItemOverride(DependencyObject dependencyObject, object o)
|
||||
{
|
||||
var headeredDragablzItem = dependencyObject as HeaderedDragablzItem;
|
||||
if (headeredDragablzItem == null) return;
|
||||
|
||||
SetIsFloatingInLayout(dependencyObject, true);
|
||||
|
||||
var headerBinding = new Binding(FloatingItemHeaderMemberPath) {Source = o};
|
||||
headeredDragablzItem.SetBinding(HeaderedDragablzItem.HeaderContentProperty, headerBinding);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(FloatingItemDisplayMemberPath))
|
||||
{
|
||||
var contentBinding = new Binding(FloatingItemDisplayMemberPath) {Source = o};
|
||||
headeredDragablzItem.SetBinding(ContentProperty, contentBinding);
|
||||
}
|
||||
|
||||
if (_floatTransfer == null || (o != _floatTransfer.Content && dependencyObject != _floatTransfer.Content))
|
||||
return;
|
||||
|
||||
var dragablzItem = (DragablzItem) dependencyObject;
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
//TODO might be nice to allow user a bit of control over sizing...especially the .75 thing i have handily hard coded. shoot me.
|
||||
dragablzItem.Measure(new Size(_floatingItems.ActualWidth, _floatingItems.ActualHeight));
|
||||
var newWidth = Math.Min(_floatingItems.ActualWidth*.75, dragablzItem.DesiredSize.Width);
|
||||
var newHeight = Math.Min(_floatingItems.ActualHeight * .75, dragablzItem.DesiredSize.Height);
|
||||
dragablzItem.SetCurrentValue(DragablzItem.XProperty, _floatingItems.ActualWidth/2 - newWidth/2);
|
||||
dragablzItem.SetCurrentValue(DragablzItem.YProperty, _floatingItems.ActualHeight/2 - newHeight/2);
|
||||
dragablzItem.SetCurrentValue(WidthProperty, newWidth);
|
||||
dragablzItem.SetCurrentValue(HeightProperty, newHeight);
|
||||
}), DispatcherPriority.Loaded);
|
||||
|
||||
_floatTransfer = null;
|
||||
}
|
||||
|
||||
private DragablzItem GetFloatingContainerForItemOverride()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(FloatingItemHeaderMemberPath))
|
||||
return new DragablzItem();
|
||||
|
||||
return new HeaderedDragablzItem();
|
||||
}
|
||||
|
||||
private static void ClearingFloatingContainerForItemOverride(DependencyObject dependencyObject, object o)
|
||||
{
|
||||
SetIsFloatingInLayout(dependencyObject, false);
|
||||
}
|
||||
|
||||
private void TileFloatingItemsExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
|
||||
{
|
||||
var dragablzItems = _floatingItems.DragablzItems();
|
||||
Tiler.Tile(dragablzItems, new Size(_floatingItems.ActualWidth, _floatingItems.ActualHeight));
|
||||
}
|
||||
|
||||
private void TileFloatingItemsHorizontallyExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
var dragablzItems = _floatingItems.DragablzItems();
|
||||
Tiler.TileHorizontally(dragablzItems, new Size(_floatingItems.ActualWidth, _floatingItems.ActualHeight));
|
||||
}
|
||||
|
||||
private void TileFloatingItemsVerticallyExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
var dragablzItems = _floatingItems.DragablzItems();
|
||||
Tiler.TileVertically(dragablzItems, new Size(_floatingItems.ActualWidth, _floatingItems.ActualHeight));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FloatingItemStateProperty = DependencyProperty.RegisterAttached(
|
||||
"FloatingItemState", typeof (WindowState), typeof (Layout), new PropertyMetadata(default(WindowState)));
|
||||
|
||||
public static void SetFloatingItemState(DependencyObject element, WindowState value)
|
||||
{
|
||||
element.SetValue(FloatingItemStateProperty, value);
|
||||
}
|
||||
|
||||
public static WindowState GetFloatingItemState(DependencyObject element)
|
||||
{
|
||||
return (WindowState) element.GetValue(FloatingItemStateProperty);
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty LocationSnapShotProperty = DependencyProperty.RegisterAttached(
|
||||
"LocationSnapShot", typeof (LocationSnapShot), typeof (Layout), new PropertyMetadata(default(LocationSnapShot)));
|
||||
|
||||
internal static void SetLocationSnapShot(FrameworkElement element, LocationSnapShot value)
|
||||
{
|
||||
element.SetValue(LocationSnapShotProperty, value);
|
||||
}
|
||||
|
||||
internal static LocationSnapShot GetLocationSnapShot(FrameworkElement element)
|
||||
{
|
||||
return (LocationSnapShot) element.GetValue(LocationSnapShotProperty);
|
||||
}
|
||||
|
||||
private static void CanExecuteMaximiseFloatingItem(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)
|
||||
{
|
||||
canExecuteRoutedEventArgs.CanExecute = false;
|
||||
canExecuteRoutedEventArgs.Handled = true;
|
||||
|
||||
var dragablzItem = canExecuteRoutedEventArgs.Parameter as DragablzItem;
|
||||
if (dragablzItem != null)
|
||||
{
|
||||
canExecuteRoutedEventArgs.CanExecute = new[] {WindowState.Normal, WindowState.Minimized}.Contains(GetFloatingItemState(dragablzItem));
|
||||
}
|
||||
}
|
||||
|
||||
private static void CanExecuteRestoreFloatingItem(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)
|
||||
{
|
||||
canExecuteRoutedEventArgs.CanExecute = false;
|
||||
canExecuteRoutedEventArgs.Handled = true;
|
||||
|
||||
var dragablzItem = canExecuteRoutedEventArgs.Parameter as DragablzItem;
|
||||
if (dragablzItem != null)
|
||||
{
|
||||
canExecuteRoutedEventArgs.CanExecute = new[] { WindowState.Maximized, WindowState.Minimized }.Contains(GetFloatingItemState(dragablzItem));
|
||||
}
|
||||
}
|
||||
|
||||
private static void CanExecuteCloseFloatingItem(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)
|
||||
{
|
||||
canExecuteRoutedEventArgs.CanExecute = true;
|
||||
canExecuteRoutedEventArgs.Handled = true;
|
||||
}
|
||||
|
||||
private void CloseFloatingItemExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
|
||||
{
|
||||
var dragablzItem = executedRoutedEventArgs.Parameter as DragablzItem;
|
||||
if (dragablzItem == null) throw new ApplicationException("Parameter must be a DragablzItem");
|
||||
|
||||
var cancel = false;
|
||||
if (ClosingFloatingItemCallback != null)
|
||||
{
|
||||
var callbackArgs = new ItemActionCallbackArgs<Layout>(Window.GetWindow(this), this, dragablzItem);
|
||||
ClosingFloatingItemCallback(callbackArgs);
|
||||
cancel = callbackArgs.IsCancelled;
|
||||
}
|
||||
|
||||
if (cancel) return;
|
||||
|
||||
//TODO ...need a similar tp manual inter tab controlller here for the extra hook
|
||||
|
||||
var item = _floatingItems.ItemContainerGenerator.ItemFromContainer(dragablzItem);
|
||||
|
||||
CollectionTeaser collectionTeaser;
|
||||
if (CollectionTeaser.TryCreate(_floatingItems.ItemsSource, out collectionTeaser))
|
||||
collectionTeaser.Remove(item);
|
||||
else
|
||||
_floatingItems.Items.Remove(item);
|
||||
}
|
||||
|
||||
private static void MaximiseFloatingItemExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
var dragablzItem = e.Parameter as DragablzItem;
|
||||
if (dragablzItem == null) return;
|
||||
|
||||
SetLocationSnapShot(dragablzItem, LocationSnapShot.Take(dragablzItem));
|
||||
SetFloatingItemState(dragablzItem, WindowState.Maximized);
|
||||
}
|
||||
|
||||
private static void RestoreFloatingItemExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
var dragablzItem = e.Parameter as DragablzItem;
|
||||
if (dragablzItem == null) return;
|
||||
|
||||
SetFloatingItemState(dragablzItem, WindowState.Normal);
|
||||
var locationSnapShot = GetLocationSnapShot(dragablzItem);
|
||||
if (locationSnapShot != null)
|
||||
locationSnapShot.Apply(dragablzItem);
|
||||
}
|
||||
|
||||
private bool IsHostingTab()
|
||||
{
|
||||
return this.VisualTreeDepthFirstTraversal().OfType<TabablzControl>()
|
||||
.FirstOrDefault(t => t.InterTabController != null && t.InterTabController.Partition == Partition)
|
||||
!= null;
|
||||
}
|
||||
|
||||
private static void MarkTopLeftItem(Layout layout)
|
||||
{
|
||||
var layoutAccessor = layout.Query();
|
||||
if (layoutAccessor.TabablzControl != null)
|
||||
{
|
||||
SetIsTopLeftItem(layoutAccessor.TabablzControl, true);
|
||||
return;
|
||||
}
|
||||
var branchAccessor = layoutAccessor.BranchAccessor;
|
||||
while (branchAccessor != null && branchAccessor.FirstItemTabablzControl == null)
|
||||
{
|
||||
branchAccessor = branchAccessor.FirstItemBranchAccessor;
|
||||
}
|
||||
|
||||
foreach (var tabablzControl in layoutAccessor.TabablzControls())
|
||||
{
|
||||
SetIsTopLeftItem(tabablzControl, branchAccessor != null && Equals(tabablzControl, branchAccessor.FirstItemTabablzControl));
|
||||
}
|
||||
}
|
||||
|
||||
private void CanExecuteUnfloat(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)
|
||||
{
|
||||
canExecuteRoutedEventArgs.CanExecute = IsHostingTab();
|
||||
canExecuteRoutedEventArgs.ContinueRouting = false;
|
||||
canExecuteRoutedEventArgs.Handled = true;
|
||||
}
|
||||
|
||||
private void UnfloatExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
|
||||
{
|
||||
var dragablzItem = executedRoutedEventArgs.Parameter as DragablzItem;
|
||||
if (dragablzItem == null) return;
|
||||
|
||||
var exemplarTabControl = this.VisualTreeDepthFirstTraversal().OfType<TabablzControl>()
|
||||
.FirstOrDefault(t => t.InterTabController != null && t.InterTabController.Partition == Partition);
|
||||
|
||||
if (exemplarTabControl == null) return;
|
||||
|
||||
//TODO passing the exemplar tab in here isnt ideal, as strictly speaking there isnt one.
|
||||
var newTabHost = exemplarTabControl.InterTabController.InterTabClient.GetNewHost(exemplarTabControl.InterTabController.InterTabClient,
|
||||
exemplarTabControl.InterTabController.Partition, exemplarTabControl);
|
||||
if (newTabHost == null || newTabHost.TabablzControl == null || newTabHost.Container == null)
|
||||
throw new ApplicationException("New tab host was not correctly provided");
|
||||
|
||||
var floatingItemSnapShots = dragablzItem.VisualTreeDepthFirstTraversal()
|
||||
.OfType<Layout>()
|
||||
.SelectMany(l => l.FloatingDragablzItems().Select(FloatingItemSnapShot.Take))
|
||||
.ToList();
|
||||
|
||||
var content = dragablzItem.Content ?? dragablzItem;
|
||||
|
||||
//remove from source
|
||||
CollectionTeaser collectionTeaser;
|
||||
if (CollectionTeaser.TryCreate(FloatingItemsSource, out collectionTeaser))
|
||||
collectionTeaser.Remove(content);
|
||||
else
|
||||
FloatingItems.Remove(content);
|
||||
|
||||
var myWindow = Window.GetWindow(this);
|
||||
if (myWindow == null) throw new ApplicationException("Unable to find owning window.");
|
||||
newTabHost.Container.Width = myWindow.RestoreBounds.Width;
|
||||
newTabHost.Container.Height = myWindow.RestoreBounds.Height;
|
||||
|
||||
newTabHost.Container.Left = myWindow.Left + 20;
|
||||
newTabHost.Container.Top = myWindow.Top + 20;
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
newTabHost.TabablzControl.AddToSource(content);
|
||||
newTabHost.TabablzControl.SelectedItem = content;
|
||||
newTabHost.Container.Show();
|
||||
newTabHost.Container.Activate();
|
||||
|
||||
Dispatcher.BeginInvoke(
|
||||
new Action(() => RestoreFloatingItemSnapShots(newTabHost.TabablzControl, floatingItemSnapShots)));
|
||||
}), DispatcherPriority.DataBind);
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Others/Dragablz/Dragablz/Dockablz/LayoutAccessor.cs
Normal file
110
Others/Dragablz/Dragablz/Dockablz/LayoutAccessor.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides information about the <see cref="Layout"/> instance.
|
||||
/// </summary>
|
||||
public class LayoutAccessor
|
||||
{
|
||||
private readonly Layout _layout;
|
||||
private readonly BranchAccessor _branchAccessor;
|
||||
private readonly TabablzControl _tabablzControl;
|
||||
|
||||
public LayoutAccessor(Layout layout)
|
||||
{
|
||||
if (layout == null) throw new ArgumentNullException("layout");
|
||||
|
||||
_layout = layout;
|
||||
|
||||
var branch = Layout.Content as Branch;
|
||||
if (branch != null)
|
||||
_branchAccessor = new BranchAccessor(branch);
|
||||
else
|
||||
_tabablzControl = Layout.Content as TabablzControl;
|
||||
}
|
||||
|
||||
public Layout Layout
|
||||
{
|
||||
get { return _layout; }
|
||||
}
|
||||
|
||||
public IEnumerable<DragablzItem> FloatingItems
|
||||
{
|
||||
get { return _layout.FloatingDragablzItems(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="BranchAccessor"/> and <see cref="TabablzControl"/> are mutually exclusive, according to whether the layout has been split, or just contains a tab control.
|
||||
/// </summary>
|
||||
public BranchAccessor BranchAccessor
|
||||
{
|
||||
get { return _branchAccessor; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="BranchAccessor"/> and <see cref="TabablzControl"/> are mutually exclusive, according to whether the layout has been split, or just contains a tab control.
|
||||
/// </summary>
|
||||
public TabablzControl TabablzControl
|
||||
{
|
||||
get { return _tabablzControl; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visits the content of the layout, according to its content type. No more than one of the provided <see cref="Action"/>
|
||||
/// callbacks will be called.
|
||||
/// </summary>
|
||||
public LayoutAccessor Visit(
|
||||
Action<BranchAccessor> branchVisitor = null,
|
||||
Action<TabablzControl> tabablzControlVisitor = null,
|
||||
Action<object> contentVisitor = null)
|
||||
{
|
||||
if (_branchAccessor != null)
|
||||
{
|
||||
if (branchVisitor != null)
|
||||
{
|
||||
branchVisitor(_branchAccessor);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
if (_tabablzControl != null)
|
||||
{
|
||||
if (tabablzControlVisitor != null)
|
||||
tabablzControlVisitor(_tabablzControl);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
if (_layout.Content != null && contentVisitor != null)
|
||||
contentVisitor(_layout.Content);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the Tabablz controls in a Layout, regardless of location.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<TabablzControl> TabablzControls()
|
||||
{
|
||||
var tabablzControls = new List<TabablzControl>();
|
||||
this.Visit(tabablzControls, BranchAccessorVisitor, TabablzControlVisitor);
|
||||
return tabablzControls;
|
||||
}
|
||||
|
||||
private static void TabablzControlVisitor(IList<TabablzControl> resultSet, TabablzControl tabablzControl)
|
||||
{
|
||||
resultSet.Add(tabablzControl);
|
||||
}
|
||||
|
||||
private static void BranchAccessorVisitor(IList<TabablzControl> resultSet, BranchAccessor branchAccessor)
|
||||
{
|
||||
branchAccessor
|
||||
.Visit(resultSet, BranchItem.First, BranchAccessorVisitor, TabablzControlVisitor)
|
||||
.Visit(resultSet, BranchItem.Second, BranchAccessorVisitor, TabablzControlVisitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
Others/Dragablz/Dragablz/Dockablz/LocationReport.cs
Normal file
65
Others/Dragablz/Dragablz/Dockablz/LocationReport.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides information about where a tab control is withing a layout structure.
|
||||
/// </summary>
|
||||
public class LocationReport
|
||||
{
|
||||
private readonly TabablzControl _tabablzControl;
|
||||
private readonly Layout _rootLayout;
|
||||
private readonly Branch _parentBranch;
|
||||
private readonly bool _isLeaf;
|
||||
private readonly bool _isSecondLeaf;
|
||||
|
||||
//TODO I've internalised constructor for now, so I can come back and add Window without breaking.
|
||||
|
||||
internal LocationReport(TabablzControl tabablzControl, Layout rootLayout)
|
||||
: this(tabablzControl, rootLayout, null, false)
|
||||
{ }
|
||||
|
||||
internal LocationReport(TabablzControl tabablzControl, Layout rootLayout, Branch parentBranch, bool isSecondLeaf)
|
||||
{
|
||||
if (tabablzControl == null) throw new ArgumentNullException("tabablzControl");
|
||||
if (rootLayout == null) throw new ArgumentNullException("rootLayout");
|
||||
|
||||
_tabablzControl = tabablzControl;
|
||||
_rootLayout = rootLayout;
|
||||
_parentBranch = parentBranch;
|
||||
_isLeaf = _parentBranch != null;
|
||||
_isSecondLeaf = isSecondLeaf;
|
||||
}
|
||||
|
||||
public TabablzControl TabablzControl
|
||||
{
|
||||
get { return _tabablzControl; }
|
||||
}
|
||||
|
||||
public Layout RootLayout
|
||||
{
|
||||
get { return _rootLayout; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent branch if this is a leaf. If the <see cref="TabablzControl"/> is directly under the <see cref="RootLayout"/> will be <c>null</c>.
|
||||
/// </summary>
|
||||
public Branch ParentBranch
|
||||
{
|
||||
get { return _parentBranch; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Idicates if this is a leaf in a branch. <c>True</c> if <see cref="ParentBranch"/> is not null.
|
||||
/// </summary>
|
||||
public bool IsLeaf
|
||||
{
|
||||
get { return _isLeaf; }
|
||||
}
|
||||
|
||||
public bool IsSecondLeaf
|
||||
{
|
||||
get { return _isSecondLeaf; }
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Others/Dragablz/Dragablz/Dockablz/LocationReportBuilder.cs
Normal file
54
Others/Dragablz/Dragablz/Dockablz/LocationReportBuilder.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
internal class LocationReportBuilder
|
||||
{
|
||||
private readonly TabablzControl _targetTabablzControl;
|
||||
private Branch _branch;
|
||||
private bool _isSecondLeaf;
|
||||
private Layout _layout;
|
||||
|
||||
public LocationReportBuilder(TabablzControl targetTabablzControl)
|
||||
{
|
||||
_targetTabablzControl = targetTabablzControl;
|
||||
}
|
||||
|
||||
public TabablzControl TargetTabablzControl
|
||||
{
|
||||
get { return _targetTabablzControl; }
|
||||
}
|
||||
|
||||
public bool IsFound { get; private set; }
|
||||
|
||||
public void MarkFound()
|
||||
{
|
||||
if (IsFound)
|
||||
throw new InvalidOperationException("Already found.");
|
||||
|
||||
IsFound = true;
|
||||
|
||||
_layout = CurrentLayout;
|
||||
}
|
||||
|
||||
public void MarkFound(Branch branch, bool isSecondLeaf)
|
||||
{
|
||||
if (branch == null) throw new ArgumentNullException("branch");
|
||||
if (IsFound)
|
||||
throw new InvalidOperationException("Already found.");
|
||||
|
||||
IsFound = true;
|
||||
|
||||
_layout = CurrentLayout;
|
||||
_branch = branch;
|
||||
_isSecondLeaf = isSecondLeaf;
|
||||
}
|
||||
|
||||
public Layout CurrentLayout { get; set; }
|
||||
|
||||
public LocationReport ToLocationReport()
|
||||
{
|
||||
return new LocationReport(_targetTabablzControl, _layout, _branch, _isSecondLeaf);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Others/Dragablz/Dragablz/Dockablz/LocationReportException.cs
Normal file
22
Others/Dragablz/Dragablz/Dockablz/LocationReportException.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class LocationReportException : Exception
|
||||
{
|
||||
public LocationReportException()
|
||||
{
|
||||
}
|
||||
|
||||
public LocationReportException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public LocationReportException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Others/Dragablz/Dragablz/Dockablz/LocationSnapShot.cs
Normal file
38
Others/Dragablz/Dragablz/Dockablz/LocationSnapShot.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Navigation;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Initially needed to restore MDI dragablz items styles after a max then restore,
|
||||
/// as the trigger which binds the item width to the canvas width sets the Width back to the default
|
||||
/// (e.g double.NaN) when the trigger is unset. so we need to re-apply sizes manually
|
||||
/// </summary>
|
||||
internal class LocationSnapShot
|
||||
{
|
||||
private readonly double _width;
|
||||
private readonly double _height;
|
||||
|
||||
public static LocationSnapShot Take(FrameworkElement frameworkElement)
|
||||
{
|
||||
if (frameworkElement == null) throw new ArgumentNullException("frameworkElement");
|
||||
|
||||
return new LocationSnapShot(frameworkElement.Width, frameworkElement.Height);
|
||||
}
|
||||
|
||||
private LocationSnapShot(double width, double height)
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
public void Apply(FrameworkElement frameworkElement)
|
||||
{
|
||||
if (frameworkElement == null) throw new ArgumentNullException("frameworkElement");
|
||||
|
||||
frameworkElement.SetCurrentValue(FrameworkElement.WidthProperty, _width);
|
||||
frameworkElement.SetCurrentValue(FrameworkElement.HeightProperty, _height);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
Others/Dragablz/Dragablz/Dockablz/Tiler.cs
Normal file
83
Others/Dragablz/Dragablz/Dockablz/Tiler.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
internal class Tiler
|
||||
{
|
||||
public static void Tile(IEnumerable<DragablzItem> dragablzItems, Size bounds)
|
||||
{
|
||||
if (dragablzItems == null) throw new ArgumentNullException("dragablzItems");
|
||||
|
||||
var items = new Queue<DragablzItem>(dragablzItems.OrderBy(Panel.GetZIndex));
|
||||
|
||||
var cellCountPerColumn = TilerCalculator.GetCellCountPerColumn(items.Count());
|
||||
var x = 0d;
|
||||
var cellWidth = bounds.Width / cellCountPerColumn.Length;
|
||||
foreach (var cellCount in cellCountPerColumn)
|
||||
{
|
||||
var y = 0d;
|
||||
var cellHeight = bounds.Height / cellCount;
|
||||
for (var cell = 0; cell < cellCount; cell++)
|
||||
{
|
||||
var item = items.Dequeue();
|
||||
Layout.SetFloatingItemState(item, WindowState.Normal);
|
||||
item.SetCurrentValue(DragablzItem.XProperty, x);
|
||||
item.SetCurrentValue(DragablzItem.YProperty, y);
|
||||
item.SetCurrentValue(FrameworkElement.WidthProperty, cellWidth);
|
||||
item.SetCurrentValue(FrameworkElement.HeightProperty, cellHeight);
|
||||
|
||||
y += cellHeight;
|
||||
}
|
||||
|
||||
x += cellWidth;
|
||||
}
|
||||
}
|
||||
|
||||
public static void TileHorizontally(IEnumerable<DragablzItem> dragablzItems, Size bounds)
|
||||
{
|
||||
if (dragablzItems == null) throw new ArgumentNullException("dragablzItems");
|
||||
|
||||
var items = dragablzItems.ToList();
|
||||
|
||||
var x = 0.0;
|
||||
var width = bounds.Width/items.Count;
|
||||
foreach (var dragablzItem in items)
|
||||
{
|
||||
Layout.SetFloatingItemState(dragablzItem, WindowState.Normal);
|
||||
dragablzItem.SetCurrentValue(DragablzItem.XProperty, x);
|
||||
dragablzItem.SetCurrentValue(DragablzItem.YProperty, 0d);
|
||||
x += width;
|
||||
dragablzItem.SetCurrentValue(FrameworkElement.WidthProperty, width);
|
||||
dragablzItem.SetCurrentValue(FrameworkElement.HeightProperty, bounds.Height);
|
||||
}
|
||||
}
|
||||
|
||||
public static void TileVertically(IEnumerable<DragablzItem> dragablzItems, Size bounds)
|
||||
{
|
||||
if (dragablzItems == null) throw new ArgumentNullException("dragablzItems");
|
||||
|
||||
var items = dragablzItems.ToList();
|
||||
|
||||
var y = 0.0;
|
||||
var height = bounds.Height / items.Count;
|
||||
foreach (var dragablzItem in items)
|
||||
{
|
||||
Layout.SetFloatingItemState(dragablzItem, WindowState.Normal);
|
||||
dragablzItem.SetCurrentValue(DragablzItem.YProperty, y);
|
||||
dragablzItem.SetCurrentValue(DragablzItem.XProperty, 0d);
|
||||
y += height;
|
||||
dragablzItem.SetCurrentValue(FrameworkElement.HeightProperty, height);
|
||||
dragablzItem.SetCurrentValue(FrameworkElement.WidthProperty, bounds.Width);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
29
Others/Dragablz/Dragablz/Dockablz/TilerCalculator.cs
Normal file
29
Others/Dragablz/Dragablz/Dockablz/TilerCalculator.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Dragablz.Dockablz
|
||||
{
|
||||
internal static class TilerCalculator
|
||||
{
|
||||
public static int[] GetCellCountPerColumn(int totalCells)
|
||||
{
|
||||
if (totalCells == 2)
|
||||
return new[] {1, 1};
|
||||
|
||||
var sqrt = Math.Sqrt(totalCells);
|
||||
|
||||
if (unchecked(sqrt == (int) sqrt))
|
||||
return Enumerable.Repeat((int) sqrt, (int) sqrt).ToArray();
|
||||
|
||||
var columns = (int)Math.Round(sqrt, MidpointRounding.AwayFromZero);
|
||||
var minimumCellsPerColumns = (int)Math.Floor(sqrt);
|
||||
var result = Enumerable.Repeat(minimumCellsPerColumns, columns).ToArray();
|
||||
|
||||
for (var i = columns - 1; result.Aggregate((current, next) => current + next) < totalCells; i--)
|
||||
result[i]+=1;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Others/Dragablz/Dragablz/Dragablz.csproj
Normal file
33
Others/Dragablz/Dragablz/Dragablz.csproj
Normal file
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp3.1;net45;net40</TargetFrameworks>
|
||||
<UseWPF>true</UseWPF>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<PackageIconUrl>https://raw.githubusercontent.com/ButchersBoy/Dragablz/master/Resources/D32.png</PackageIconUrl>
|
||||
<PackageLicenseExpression></PackageLicenseExpression>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageProjectUrl>http://dragablz.net</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/ButchersBoy/Dragablz</RepositoryUrl>
|
||||
<PackageTags>WPF TabControl Tab Tearable</PackageTags>
|
||||
<PackageReleaseNotes>Support for .Net Core 3.0</PackageReleaseNotes>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<DocumentationFile>..\bin\Release\Dragablz.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<OutputPath>..\bin\Debug</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<OutputPath>..\bin\Release</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
32
Others/Dragablz/Dragablz/Dragablz.nuspec
Normal file
32
Others/Dragablz/Dragablz/Dragablz.nuspec
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0"?>
|
||||
<package >
|
||||
<metadata>
|
||||
<id>Dragablz</id>
|
||||
<version>0.0.0.0</version>
|
||||
<title>Dragablz - Dragable and tearable tab control for WPF</title>
|
||||
<authors>James Willock</authors>
|
||||
<owners>James Willock</owners>
|
||||
<iconUrl>https://raw.githubusercontent.com/ButchersBoy/Dragablz/master/Resources/D32.png</iconUrl>
|
||||
<licenseUrl>https://raw.githubusercontent.com/ButchersBoy/Dragablz/master/LICENSE</licenseUrl>
|
||||
<projectUrl>http://dragablz.net</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Dragable and tearable tab control for WPF</description>
|
||||
<releaseNotes>Support for .NET Core 3.0</releaseNotes>
|
||||
<copyright>Copyright 2014-20 James Willock/Mulholland Software Ltd</copyright>
|
||||
<tags>WPF TabControl Tab Tearable</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\bin\Release\netcoreapp3.0\Dragablz.dll" target="lib\netcoreapp3.0" />
|
||||
<file src="..\bin\Release\netcoreapp3.0\Dragablz.pdb" target="lib\netcoreapp3.0" />
|
||||
<file src="..\bin\Release\netcoreapp3.0\Dragablz.xml" target="lib\netcoreapp3.0" />
|
||||
<file src="..\bin\Release\net45\Dragablz.dll" target="lib\net45" />
|
||||
<file src="..\bin\Release\net45\Dragablz.pdb" target="lib\net45" />
|
||||
<file src="..\bin\Release\net45\Dragablz.xml" target="lib\net45" />
|
||||
<file src="..\bin\Release\net40\Dragablz.dll" target="lib\net40" />
|
||||
<file src="..\bin\Release\net40\Dragablz.pdb" target="lib\net40" />
|
||||
<file src="..\bin\Release\net40\Dragablz.xml" target="lib\net40" />
|
||||
<file src="..\Dragablz\**\*.cs" target="src\netcoreapp3.0" />
|
||||
<file src="..\Dragablz\**\*.cs" target="src\net45" />
|
||||
<file src="..\Dragablz\**\*.cs" target="src\net40" />
|
||||
</files>
|
||||
</package>
|
||||
74
Others/Dragablz/Dragablz/DragablzColors.cs
Normal file
74
Others/Dragablz/Dragablz/DragablzColors.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Dragablz.Core;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In supporting .Net 4.0 we don't have access to SystemParameters.WindowGlassBrush, and even then
|
||||
/// the opacity is not provided, so this class wraps up a few issues around here.
|
||||
/// </remarks>
|
||||
public static class DragablzColors
|
||||
{
|
||||
//TODO listen to changes from the OS to provide updates
|
||||
public static Color WindowBaseColor = Color.FromRgb(217, 217, 217);
|
||||
public static Brush WindowGlassBrush = GetWindowGlassBrush();
|
||||
public static Brush WindowGlassBalancedBrush = GetBalancedWindowGlassBrush();
|
||||
public static Brush WindowInactiveBrush = GetWindowInactiveBrush();
|
||||
|
||||
private static Brush GetWindowGlassBrush()
|
||||
{
|
||||
var colorizationParams = new Native.DWMCOLORIZATIONPARAMS();
|
||||
Native.DwmGetColorizationParameters(ref colorizationParams);
|
||||
var frameColor = ToColor(colorizationParams.ColorizationColor);
|
||||
|
||||
return new SolidColorBrush(frameColor);
|
||||
}
|
||||
|
||||
|
||||
private static Brush GetBalancedWindowGlassBrush()
|
||||
{
|
||||
var colorizationParams = new Native.DWMCOLORIZATIONPARAMS();
|
||||
Native.DwmGetColorizationParameters(ref colorizationParams);
|
||||
var frameColor = ToColor(colorizationParams.ColorizationColor);
|
||||
var blendedColor = BlendColor(frameColor, WindowBaseColor, 100f - colorizationParams.ColorizationColorBalance);
|
||||
|
||||
return new SolidColorBrush(blendedColor);
|
||||
}
|
||||
|
||||
private static Brush GetWindowInactiveBrush()
|
||||
{
|
||||
return new SolidColorBrush(SystemColors.MenuBarColor);
|
||||
}
|
||||
|
||||
private static Color ToColor(UInt32 value)
|
||||
{
|
||||
return Color.FromArgb(255,
|
||||
(byte)(value >> 16),
|
||||
(byte)(value >> 8),
|
||||
(byte)value
|
||||
);
|
||||
}
|
||||
|
||||
private static Color BlendColor(Color color1, Color color2, double percentage)
|
||||
{
|
||||
percentage = Math.Min(100, Math.Max(0, percentage));
|
||||
|
||||
return Color.FromRgb(
|
||||
BlendColorChannel(color1.R, color2.R, percentage),
|
||||
BlendColorChannel(color1.G, color2.G, percentage),
|
||||
BlendColorChannel(color1.B, color2.B, percentage));
|
||||
}
|
||||
|
||||
private static byte BlendColorChannel(double channel1, double channel2, double channel2Percentage)
|
||||
{
|
||||
var buff = channel1 + (channel2 - channel1) * channel2Percentage / 100D;
|
||||
return Math.Min((byte)Math.Round(buff), (byte)255);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
54
Others/Dragablz/Dragablz/DragablzDragCompletedEventArgs.cs
Normal file
54
Others/Dragablz/Dragablz/DragablzDragCompletedEventArgs.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public delegate void DragablzDragCompletedEventHandler(object sender, DragablzDragCompletedEventArgs e);
|
||||
|
||||
public class DragablzDragCompletedEventArgs : RoutedEventArgs
|
||||
{
|
||||
private readonly DragablzItem _dragablzItem;
|
||||
private readonly bool _isDropTargetFound;
|
||||
private readonly DragCompletedEventArgs _dragCompletedEventArgs;
|
||||
|
||||
public DragablzDragCompletedEventArgs(DragablzItem dragablzItem, DragCompletedEventArgs dragCompletedEventArgs)
|
||||
{
|
||||
if (dragablzItem == null) throw new ArgumentNullException("dragablzItem");
|
||||
if (dragCompletedEventArgs == null) throw new ArgumentNullException("dragCompletedEventArgs");
|
||||
|
||||
_dragablzItem = dragablzItem;
|
||||
_dragCompletedEventArgs = dragCompletedEventArgs;
|
||||
}
|
||||
|
||||
public DragablzDragCompletedEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem, DragCompletedEventArgs dragCompletedEventArgs)
|
||||
: base(routedEvent)
|
||||
{
|
||||
if (dragablzItem == null) throw new ArgumentNullException("dragablzItem");
|
||||
if (dragCompletedEventArgs == null) throw new ArgumentNullException("dragCompletedEventArgs");
|
||||
|
||||
_dragablzItem = dragablzItem;
|
||||
_dragCompletedEventArgs = dragCompletedEventArgs;
|
||||
}
|
||||
|
||||
public DragablzDragCompletedEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem, DragCompletedEventArgs dragCompletedEventArgs)
|
||||
: base(routedEvent, source)
|
||||
{
|
||||
if (dragablzItem == null) throw new ArgumentNullException("dragablzItem");
|
||||
if (dragCompletedEventArgs == null) throw new ArgumentNullException("dragCompletedEventArgs");
|
||||
|
||||
_dragablzItem = dragablzItem;
|
||||
_dragCompletedEventArgs = dragCompletedEventArgs;
|
||||
}
|
||||
|
||||
public DragablzItem DragablzItem
|
||||
{
|
||||
get { return _dragablzItem; }
|
||||
}
|
||||
|
||||
public DragCompletedEventArgs DragCompletedEventArgs
|
||||
{
|
||||
get { return _dragCompletedEventArgs; }
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Others/Dragablz/Dragablz/DragablzDragDeltaEventArgs.cs
Normal file
44
Others/Dragablz/Dragablz/DragablzDragDeltaEventArgs.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public delegate void DragablzDragDeltaEventHandler(object sender, DragablzDragDeltaEventArgs e);
|
||||
|
||||
public class DragablzDragDeltaEventArgs : DragablzItemEventArgs
|
||||
{
|
||||
private readonly DragDeltaEventArgs _dragDeltaEventArgs;
|
||||
|
||||
public DragablzDragDeltaEventArgs(DragablzItem dragablzItem, DragDeltaEventArgs dragDeltaEventArgs)
|
||||
: base(dragablzItem)
|
||||
{
|
||||
if (dragDeltaEventArgs == null) throw new ArgumentNullException("dragDeltaEventArgs");
|
||||
|
||||
_dragDeltaEventArgs = dragDeltaEventArgs;
|
||||
}
|
||||
|
||||
public DragablzDragDeltaEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem, DragDeltaEventArgs dragDeltaEventArgs)
|
||||
: base(routedEvent, dragablzItem)
|
||||
{
|
||||
if (dragDeltaEventArgs == null) throw new ArgumentNullException("dragDeltaEventArgs");
|
||||
|
||||
_dragDeltaEventArgs = dragDeltaEventArgs;
|
||||
}
|
||||
|
||||
public DragablzDragDeltaEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem, DragDeltaEventArgs dragDeltaEventArgs)
|
||||
: base(routedEvent, source, dragablzItem)
|
||||
{
|
||||
if (dragDeltaEventArgs == null) throw new ArgumentNullException("dragDeltaEventArgs");
|
||||
|
||||
_dragDeltaEventArgs = dragDeltaEventArgs;
|
||||
}
|
||||
|
||||
public DragDeltaEventArgs DragDeltaEventArgs
|
||||
{
|
||||
get { return _dragDeltaEventArgs; }
|
||||
}
|
||||
|
||||
public bool Cancel { get; set; }
|
||||
}
|
||||
}
|
||||
38
Others/Dragablz/Dragablz/DragablzDragStartedEventArgs.cs
Normal file
38
Others/Dragablz/Dragablz/DragablzDragStartedEventArgs.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public delegate void DragablzDragStartedEventHandler(object sender, DragablzDragStartedEventArgs e);
|
||||
|
||||
public class DragablzDragStartedEventArgs : DragablzItemEventArgs
|
||||
{
|
||||
private readonly DragStartedEventArgs _dragStartedEventArgs;
|
||||
|
||||
public DragablzDragStartedEventArgs(DragablzItem dragablzItem, DragStartedEventArgs dragStartedEventArgs)
|
||||
: base(dragablzItem)
|
||||
{
|
||||
if (dragStartedEventArgs == null) throw new ArgumentNullException("dragStartedEventArgs");
|
||||
|
||||
_dragStartedEventArgs = dragStartedEventArgs;
|
||||
}
|
||||
|
||||
public DragablzDragStartedEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem, DragStartedEventArgs dragStartedEventArgs)
|
||||
: base(routedEvent, dragablzItem)
|
||||
{
|
||||
_dragStartedEventArgs = dragStartedEventArgs;
|
||||
}
|
||||
|
||||
public DragablzDragStartedEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem, DragStartedEventArgs dragStartedEventArgs)
|
||||
: base(routedEvent, source, dragablzItem)
|
||||
{
|
||||
_dragStartedEventArgs = dragStartedEventArgs;
|
||||
}
|
||||
|
||||
public DragStartedEventArgs DragStartedEventArgs
|
||||
{
|
||||
get { return _dragStartedEventArgs; }
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Others/Dragablz/Dragablz/DragablzIcon.cs
Normal file
25
Others/Dragablz/Dragablz/DragablzIcon.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class DragablzIcon : Control
|
||||
{
|
||||
static DragablzIcon()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(DragablzIcon), new FrameworkPropertyMetadata(typeof(DragablzIcon)));
|
||||
}
|
||||
}
|
||||
}
|
||||
616
Others/Dragablz/Dragablz/DragablzItem.cs
Normal file
616
Others/Dragablz/Dragablz/DragablzItem.cs
Normal file
@@ -0,0 +1,616 @@
|
||||
using System;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using Dragablz.Core;
|
||||
using Dragablz.Referenceless;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public enum SizeGrip
|
||||
{
|
||||
NotApplicable,
|
||||
Left,
|
||||
TopLeft,
|
||||
Top,
|
||||
TopRight,
|
||||
Right,
|
||||
BottomRight,
|
||||
Bottom,
|
||||
BottomLeft
|
||||
}
|
||||
|
||||
[TemplatePart(Name = ThumbPartName, Type = typeof(Thumb))]
|
||||
public class DragablzItem : ContentControl
|
||||
{
|
||||
public const string ThumbPartName = "PART_Thumb";
|
||||
|
||||
private readonly SerialDisposable _templateSubscriptions = new SerialDisposable();
|
||||
private readonly SerialDisposable _rightMouseUpCleanUpDisposable = new SerialDisposable();
|
||||
|
||||
private Thumb _customThumb;
|
||||
private Thumb _thumb;
|
||||
private bool _seizeDragWithTemplate;
|
||||
private Action<DragablzItem> _dragSeizedContinuation;
|
||||
|
||||
static DragablzItem()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(DragablzItem), new FrameworkPropertyMetadata(typeof(DragablzItem)));
|
||||
}
|
||||
|
||||
public DragablzItem()
|
||||
{
|
||||
AddHandler(MouseDownEvent, new RoutedEventHandler(MouseDownHandler), true);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty XProperty = DependencyProperty.Register(
|
||||
"X", typeof (double), typeof (DragablzItem), new PropertyMetadata(default(double), OnXChanged));
|
||||
|
||||
public double X
|
||||
{
|
||||
get { return (double) GetValue(XProperty); }
|
||||
set { SetValue(XProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent XChangedEvent =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"XChanged",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof(RoutedPropertyChangedEventHandler<double>),
|
||||
typeof(DragablzItem));
|
||||
|
||||
public event RoutedPropertyChangedEventHandler<double> XChanged
|
||||
{
|
||||
add { AddHandler(XChangedEvent, value); }
|
||||
remove { RemoveHandler(IsDraggingChangedEvent, value); }
|
||||
}
|
||||
|
||||
private static void OnXChanged(
|
||||
DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var instance = (DragablzItem)d;
|
||||
var args = new RoutedPropertyChangedEventArgs<double>(
|
||||
(double)e.OldValue,
|
||||
(double)e.NewValue)
|
||||
{
|
||||
RoutedEvent = XChangedEvent
|
||||
};
|
||||
instance.RaiseEvent(args);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty YProperty = DependencyProperty.Register(
|
||||
"Y", typeof (double), typeof (DragablzItem), new PropertyMetadata(default(double), OnYChanged));
|
||||
|
||||
public double Y
|
||||
{
|
||||
get { return (double) GetValue(YProperty); }
|
||||
set { SetValue(YProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent YChangedEvent =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"YChanged",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof(RoutedPropertyChangedEventHandler<double>),
|
||||
typeof(DragablzItem));
|
||||
|
||||
public event RoutedPropertyChangedEventHandler<double> YChanged
|
||||
{
|
||||
add { AddHandler(YChangedEvent, value); }
|
||||
remove { RemoveHandler(IsDraggingChangedEvent, value); }
|
||||
}
|
||||
|
||||
private static void OnYChanged(
|
||||
DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var instance = (DragablzItem)d;
|
||||
var args = new RoutedPropertyChangedEventArgs<double>(
|
||||
(double)e.OldValue,
|
||||
(double)e.NewValue)
|
||||
{
|
||||
RoutedEvent = YChangedEvent
|
||||
};
|
||||
instance.RaiseEvent(args);
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey LogicalIndexPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"LogicalIndex", typeof (int), typeof (DragablzItem),
|
||||
new PropertyMetadata(default(int), OnLogicalIndexChanged));
|
||||
|
||||
public static readonly DependencyProperty LogicalIndexProperty =
|
||||
LogicalIndexPropertyKey.DependencyProperty;
|
||||
|
||||
public int LogicalIndex
|
||||
{
|
||||
get { return (int) GetValue(LogicalIndexProperty); }
|
||||
internal set { SetValue(LogicalIndexPropertyKey, value); }
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent LogicalIndexChangedEvent =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"LogicalIndexChanged",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof (RoutedPropertyChangedEventHandler<int>),
|
||||
typeof (DragablzItem));
|
||||
|
||||
public event RoutedPropertyChangedEventHandler<int> LogicalIndexChanged
|
||||
{
|
||||
add { AddHandler(LogicalIndexChangedEvent, value); }
|
||||
remove { RemoveHandler(LogicalIndexChangedEvent, value); }
|
||||
}
|
||||
|
||||
private static void OnLogicalIndexChanged(
|
||||
DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var instance = (DragablzItem) d;
|
||||
var args = new RoutedPropertyChangedEventArgs<int>(
|
||||
(int) e.OldValue,
|
||||
(int) e.NewValue)
|
||||
{
|
||||
RoutedEvent = DragablzItem.LogicalIndexChangedEvent
|
||||
};
|
||||
instance.RaiseEvent(args);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SizeGripProperty = DependencyProperty.RegisterAttached(
|
||||
"SizeGrip", typeof (SizeGrip), typeof (DragablzItem), new PropertyMetadata(default(SizeGrip), SizeGripPropertyChangedCallback));
|
||||
|
||||
private static void SizeGripPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
||||
{
|
||||
var thumb = (dependencyObject as Thumb);
|
||||
if (thumb == null) return;
|
||||
thumb.DragDelta += SizeThumbOnDragDelta;
|
||||
}
|
||||
|
||||
private static void SizeThumbOnDragDelta(object sender, DragDeltaEventArgs dragDeltaEventArgs)
|
||||
{
|
||||
var thumb = ((Thumb) sender);
|
||||
var dragablzItem = thumb.VisualTreeAncestory().OfType<DragablzItem>().FirstOrDefault();
|
||||
if (dragablzItem == null) return;
|
||||
|
||||
var sizeGrip = (SizeGrip) thumb.GetValue(SizeGripProperty);
|
||||
var width = dragablzItem.ActualWidth;
|
||||
var height = dragablzItem.ActualHeight;
|
||||
var x = dragablzItem.X;
|
||||
var y = dragablzItem.Y;
|
||||
switch (sizeGrip)
|
||||
{
|
||||
case SizeGrip.NotApplicable:
|
||||
break;
|
||||
case SizeGrip.Left:
|
||||
width += -dragDeltaEventArgs.HorizontalChange;
|
||||
x += dragDeltaEventArgs.HorizontalChange;
|
||||
break;
|
||||
case SizeGrip.TopLeft:
|
||||
width += -dragDeltaEventArgs.HorizontalChange;
|
||||
height += -dragDeltaEventArgs.VerticalChange;
|
||||
x += dragDeltaEventArgs.HorizontalChange;
|
||||
y += dragDeltaEventArgs.VerticalChange;
|
||||
break;
|
||||
case SizeGrip.Top:
|
||||
height += -dragDeltaEventArgs.VerticalChange;
|
||||
y += dragDeltaEventArgs.VerticalChange;
|
||||
break;
|
||||
case SizeGrip.TopRight:
|
||||
height += -dragDeltaEventArgs.VerticalChange;
|
||||
width += dragDeltaEventArgs.HorizontalChange;
|
||||
y += dragDeltaEventArgs.VerticalChange;
|
||||
break;
|
||||
case SizeGrip.Right:
|
||||
width += dragDeltaEventArgs.HorizontalChange;
|
||||
break;
|
||||
case SizeGrip.BottomRight:
|
||||
width += dragDeltaEventArgs.HorizontalChange;
|
||||
height += dragDeltaEventArgs.VerticalChange;
|
||||
break;
|
||||
case SizeGrip.Bottom:
|
||||
height += dragDeltaEventArgs.VerticalChange;
|
||||
break;
|
||||
case SizeGrip.BottomLeft:
|
||||
height += dragDeltaEventArgs.VerticalChange;
|
||||
width += -dragDeltaEventArgs.HorizontalChange;
|
||||
x += dragDeltaEventArgs.HorizontalChange;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
dragablzItem.SetCurrentValue(XProperty, x);
|
||||
dragablzItem.SetCurrentValue(YProperty, y);
|
||||
dragablzItem.SetCurrentValue(WidthProperty, Math.Max(width, thumb.DesiredSize.Width));
|
||||
dragablzItem.SetCurrentValue(HeightProperty, Math.Max(height, thumb.DesiredSize.Height));
|
||||
}
|
||||
|
||||
public static void SetSizeGrip(DependencyObject element, SizeGrip value)
|
||||
{
|
||||
element.SetValue(SizeGripProperty, value);
|
||||
}
|
||||
|
||||
public static SizeGrip GetSizeGrip(DependencyObject element)
|
||||
{
|
||||
return (SizeGrip) element.GetValue(SizeGripProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows item content to be rotated (in suppported templates), typically for use in a vertical/side tab.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ContentRotateTransformAngleProperty = DependencyProperty.RegisterAttached(
|
||||
"ContentRotateTransformAngle", typeof (double), typeof (DragablzItem), new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
/// <summary>
|
||||
/// Allows item content to be rotated (in suppported templates), typically for use in a vertical/side tab.
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void SetContentRotateTransformAngle(DependencyObject element, double value)
|
||||
{
|
||||
element.SetValue(ContentRotateTransformAngleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows item content to be rotated (in suppported templates), typically for use in a vertical/side tab.
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
/// <returns></returns>
|
||||
public static double GetContentRotateTransformAngle(DependencyObject element)
|
||||
{
|
||||
return (double) element.GetValue(ContentRotateTransformAngleProperty);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
|
||||
"IsSelected", typeof(bool), typeof(DragablzItem), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.AffectsParentMeasure));
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get { return (bool) GetValue(IsSelectedProperty); }
|
||||
set { SetValue(IsSelectedProperty, value); }
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey IsDraggingPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"IsDragging", typeof (bool), typeof (DragablzItem),
|
||||
new PropertyMetadata(default(bool), OnIsDraggingChanged));
|
||||
|
||||
public static readonly DependencyProperty IsDraggingProperty =
|
||||
IsDraggingPropertyKey.DependencyProperty;
|
||||
|
||||
public bool IsDragging
|
||||
{
|
||||
get { return (bool) GetValue(IsDraggingProperty); }
|
||||
internal set { SetValue(IsDraggingPropertyKey, value); }
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent IsDraggingChangedEvent =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"IsDraggingChanged",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof (RoutedPropertyChangedEventHandler<bool>),
|
||||
typeof (DragablzItem));
|
||||
|
||||
public event RoutedPropertyChangedEventHandler<bool> IsDraggingChanged
|
||||
{
|
||||
add { AddHandler(IsDraggingChangedEvent, value); }
|
||||
remove { RemoveHandler(IsDraggingChangedEvent, value); }
|
||||
}
|
||||
|
||||
internal object UnderlyingContent { get; set; }
|
||||
|
||||
private static void OnIsDraggingChanged(
|
||||
DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var instance = (DragablzItem)d;
|
||||
var args = new RoutedPropertyChangedEventArgs<bool>(
|
||||
(bool)e.OldValue,
|
||||
(bool)e.NewValue) { RoutedEvent = IsDraggingChangedEvent };
|
||||
instance.RaiseEvent(args);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent MouseDownWithinEvent =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"MouseDownWithin",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof(DragablzItemEventHandler),
|
||||
typeof (DragablzItem));
|
||||
|
||||
private static void OnMouseDownWithin(DependencyObject d)
|
||||
{
|
||||
var instance = (DragablzItem)d;
|
||||
instance.RaiseEvent(new DragablzItemEventArgs(MouseDownWithinEvent, instance));
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey IsSiblingDraggingPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"IsSiblingDragging", typeof (bool), typeof (DragablzItem),
|
||||
new PropertyMetadata(default(bool), OnIsSiblingDraggingChanged));
|
||||
|
||||
public static readonly DependencyProperty IsSiblingDraggingProperty =
|
||||
IsSiblingDraggingPropertyKey.DependencyProperty;
|
||||
|
||||
public bool IsSiblingDragging
|
||||
{
|
||||
get { return (bool) GetValue(IsSiblingDraggingProperty); }
|
||||
internal set { SetValue(IsSiblingDraggingPropertyKey, value); }
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent IsSiblingDraggingChangedEvent =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"IsSiblingDraggingChanged",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof (RoutedPropertyChangedEventHandler<bool>),
|
||||
typeof (DragablzItem));
|
||||
|
||||
public event RoutedPropertyChangedEventHandler<bool> IsSiblingDraggingChanged
|
||||
{
|
||||
add { AddHandler(IsSiblingDraggingChangedEvent, value); }
|
||||
remove { RemoveHandler(IsSiblingDraggingChangedEvent, value); }
|
||||
}
|
||||
|
||||
private static void OnIsSiblingDraggingChanged(
|
||||
DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var instance = (DragablzItem) d;
|
||||
var args = new RoutedPropertyChangedEventArgs<bool>(
|
||||
(bool) e.OldValue,
|
||||
(bool) e.NewValue)
|
||||
{
|
||||
RoutedEvent = IsSiblingDraggingChangedEvent
|
||||
};
|
||||
instance.RaiseEvent(args);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent DragStarted =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"DragStarted",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof(DragablzDragStartedEventHandler),
|
||||
typeof(DragablzItem));
|
||||
|
||||
protected void OnDragStarted(DragablzDragStartedEventArgs e)
|
||||
{
|
||||
RaiseEvent(e);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent DragDelta =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"DragDelta",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof (DragablzDragDeltaEventHandler),
|
||||
typeof (DragablzItem));
|
||||
|
||||
protected void OnDragDelta(DragablzDragDeltaEventArgs e)
|
||||
{
|
||||
RaiseEvent(e);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent PreviewDragDelta =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"PreviewDragDelta",
|
||||
RoutingStrategy.Tunnel,
|
||||
typeof(DragablzDragDeltaEventHandler),
|
||||
typeof(DragablzItem));
|
||||
|
||||
protected void OnPreviewDragDelta(DragablzDragDeltaEventArgs e)
|
||||
{
|
||||
RaiseEvent(e);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent DragCompleted =
|
||||
EventManager.RegisterRoutedEvent(
|
||||
"DragCompleted",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof(DragablzDragCompletedEventHandler),
|
||||
typeof(DragablzItem));
|
||||
|
||||
protected void OnDragCompleted(DragCompletedEventArgs e)
|
||||
{
|
||||
var args = new DragablzDragCompletedEventArgs(DragCompleted, this, e);
|
||||
RaiseEvent(args);
|
||||
|
||||
//OK, this is a cheeky bit. A completed drag may have occured after a tab as been pushed
|
||||
//intom a new window, which means we may have reverted to the template thumb. So, let's
|
||||
//refresh the thumb in case the user has a custom one
|
||||
_customThumb = FindCustomThumb();
|
||||
_templateSubscriptions.Disposable = SelectAndSubscribeToThumb().Item2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="DragablzItem" /> templates contain a thumb, which is used to drag the item around.
|
||||
/// For most scenarios this is fine, but by setting this flag to <value>true</value> you can define
|
||||
/// a custom thumb in your content, without having to override the template. This can be useful if you
|
||||
/// have extra content; such as a custom button that you want the user to be able to interact with (as usually
|
||||
/// the default thumb will handle mouse interaction).
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsCustomThumbProperty = DependencyProperty.RegisterAttached(
|
||||
"IsCustomThumb", typeof (bool), typeof (DragablzItem), new PropertyMetadata(default(bool), IsCustomThumbPropertyChangedCallback));
|
||||
|
||||
private static void IsCustomThumbPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
||||
{
|
||||
var thumb = dependencyObject as Thumb;
|
||||
if (thumb == null) throw new ApplicationException("IsCustomThumb can only be applied to a thumb");
|
||||
|
||||
if (thumb.IsLoaded)
|
||||
ApplyCustomThumbSetting(thumb);
|
||||
else
|
||||
thumb.Loaded += CustomThumbOnLoaded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="DragablzItem" /> templates contain a thumb, which is used to drag the item around.
|
||||
/// For most scenarios this is fine, but by setting this flag to <value>true</value> you can define
|
||||
/// a custom thumb in your content, without having to override the template. This can be useful if you
|
||||
/// have extra content; such as a custom button that you want the user to be able to interact with (as usually
|
||||
/// the default thumb will handle mouse interaction).
|
||||
/// </summary>
|
||||
public static void SetIsCustomThumb(Thumb element, bool value)
|
||||
{
|
||||
element.SetValue(IsCustomThumbProperty, value);
|
||||
}
|
||||
|
||||
public static bool GetIsCustomThumb(Thumb element)
|
||||
{
|
||||
return (bool) element.GetValue(IsCustomThumbProperty);
|
||||
}
|
||||
|
||||
private bool _isTemplateThumbWithMouseAfterSeize = false;
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var thumbAndSubscription = SelectAndSubscribeToThumb();
|
||||
_templateSubscriptions.Disposable = thumbAndSubscription.Item2;
|
||||
|
||||
if (_seizeDragWithTemplate && thumbAndSubscription.Item1 != null)
|
||||
{
|
||||
_isTemplateThumbWithMouseAfterSeize = true;
|
||||
Mouse.AddLostMouseCaptureHandler(this, LostMouseAfterSeizeHandler);
|
||||
if (_dragSeizedContinuation != null)
|
||||
_dragSeizedContinuation(this);
|
||||
_dragSeizedContinuation = null;
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() => thumbAndSubscription.Item1.RaiseEvent(new MouseButtonEventArgs(InputManager.Current.PrimaryMouseDevice,
|
||||
0,
|
||||
MouseButton.Left) {RoutedEvent = MouseLeftButtonDownEvent})));
|
||||
}
|
||||
_seizeDragWithTemplate = false;
|
||||
}
|
||||
|
||||
protected override void OnPreviewMouseRightButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
if (_thumb != null)
|
||||
{
|
||||
var currentThumbIsHitTestVisible = _thumb.IsHitTestVisible;
|
||||
_thumb.SetCurrentValue(IsHitTestVisibleProperty, false);
|
||||
_rightMouseUpCleanUpDisposable.Disposable = Disposable.Create(() =>
|
||||
{
|
||||
_thumb.SetCurrentValue(IsHitTestVisibleProperty, currentThumbIsHitTestVisible);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_rightMouseUpCleanUpDisposable.Disposable = Disposable.Empty;
|
||||
}
|
||||
|
||||
base.OnPreviewMouseRightButtonDown(e);
|
||||
}
|
||||
|
||||
protected override void OnPreviewMouseRightButtonUp(MouseButtonEventArgs e)
|
||||
{
|
||||
_rightMouseUpCleanUpDisposable.Disposable = Disposable.Empty;
|
||||
base.OnPreviewMouseRightButtonUp(e);
|
||||
}
|
||||
|
||||
private void LostMouseAfterSeizeHandler(object sender, MouseEventArgs mouseEventArgs)
|
||||
{
|
||||
_isTemplateThumbWithMouseAfterSeize = false;
|
||||
Mouse.RemoveLostMouseCaptureHandler(this, LostMouseAfterSeizeHandler);
|
||||
}
|
||||
|
||||
internal void InstigateDrag(Action<DragablzItem> continuation)
|
||||
{
|
||||
_dragSeizedContinuation = continuation;
|
||||
var thumb = GetTemplateChild(ThumbPartName) as Thumb;
|
||||
if (thumb != null)
|
||||
{
|
||||
thumb.CaptureMouse();
|
||||
}
|
||||
else
|
||||
_seizeDragWithTemplate = true;
|
||||
}
|
||||
|
||||
internal Point MouseAtDragStart { get; set; }
|
||||
|
||||
internal string PartitionAtDragStart { get; set; }
|
||||
|
||||
internal bool IsDropTargetFound { get; set; }
|
||||
|
||||
private void ThumbOnDragCompleted(object sender, DragCompletedEventArgs dragCompletedEventArgs)
|
||||
{
|
||||
OnDragCompleted(dragCompletedEventArgs);
|
||||
MouseAtDragStart = new Point();
|
||||
}
|
||||
|
||||
private void ThumbOnDragDelta(object sender, DragDeltaEventArgs dragDeltaEventArgs)
|
||||
{
|
||||
var thumb = (Thumb) sender;
|
||||
|
||||
var previewEventArgs = new DragablzDragDeltaEventArgs(PreviewDragDelta, this, dragDeltaEventArgs);
|
||||
OnPreviewDragDelta(previewEventArgs);
|
||||
if (previewEventArgs.Cancel)
|
||||
thumb.CancelDrag();
|
||||
if (!previewEventArgs.Handled)
|
||||
{
|
||||
var eventArgs = new DragablzDragDeltaEventArgs(DragDelta, this, dragDeltaEventArgs);
|
||||
OnDragDelta(eventArgs);
|
||||
if (eventArgs.Cancel)
|
||||
thumb.CancelDrag();
|
||||
}
|
||||
}
|
||||
|
||||
private void ThumbOnDragStarted(object sender, DragStartedEventArgs dragStartedEventArgs)
|
||||
{
|
||||
MouseAtDragStart = Mouse.GetPosition(this);
|
||||
OnDragStarted(new DragablzDragStartedEventArgs(DragStarted, this, dragStartedEventArgs));
|
||||
}
|
||||
|
||||
private void MouseDownHandler(object sender, RoutedEventArgs routedEventArgs)
|
||||
{
|
||||
OnMouseDownWithin(this);
|
||||
}
|
||||
|
||||
private static void CustomThumbOnLoaded(object sender, RoutedEventArgs routedEventArgs)
|
||||
{
|
||||
var thumb = (Thumb)sender;
|
||||
thumb.Loaded -= CustomThumbOnLoaded;
|
||||
ApplyCustomThumbSetting(thumb);
|
||||
}
|
||||
|
||||
private Thumb FindCustomThumb()
|
||||
{
|
||||
return this.VisualTreeDepthFirstTraversal().OfType<Thumb>().FirstOrDefault(GetIsCustomThumb);
|
||||
}
|
||||
|
||||
private static void ApplyCustomThumbSetting(Thumb thumb)
|
||||
{
|
||||
var dragablzItem = thumb.VisualTreeAncestory().OfType<DragablzItem>().FirstOrDefault();
|
||||
if (dragablzItem == null) throw new ApplicationException("Cannot find parent DragablzItem for custom thumb");
|
||||
|
||||
var enableCustomThumb = (bool)thumb.GetValue(IsCustomThumbProperty);
|
||||
dragablzItem._customThumb = enableCustomThumb ? thumb : null;
|
||||
dragablzItem._templateSubscriptions.Disposable = dragablzItem.SelectAndSubscribeToThumb().Item2;
|
||||
|
||||
if (dragablzItem._customThumb != null && dragablzItem._isTemplateThumbWithMouseAfterSeize)
|
||||
dragablzItem.Dispatcher.BeginInvoke(new Action(() => dragablzItem._customThumb.RaiseEvent(new MouseButtonEventArgs(InputManager.Current.PrimaryMouseDevice,
|
||||
0,
|
||||
MouseButton.Left) { RoutedEvent = MouseLeftButtonDownEvent })));
|
||||
}
|
||||
|
||||
private Tuple<Thumb, IDisposable> SelectAndSubscribeToThumb()
|
||||
{
|
||||
var templateThumb = GetTemplateChild(ThumbPartName) as Thumb;
|
||||
templateThumb?.SetCurrentValue(IsHitTestVisibleProperty, _customThumb == null);
|
||||
|
||||
_thumb = _customThumb ?? templateThumb;
|
||||
if (_thumb != null)
|
||||
{
|
||||
_thumb.DragStarted += ThumbOnDragStarted;
|
||||
_thumb.DragDelta += ThumbOnDragDelta;
|
||||
_thumb.DragCompleted += ThumbOnDragCompleted;
|
||||
}
|
||||
|
||||
var tidyUpThumb = _thumb;
|
||||
var disposable = Disposable.Create(() =>
|
||||
{
|
||||
if (tidyUpThumb == null) return;
|
||||
tidyUpThumb.DragStarted -= ThumbOnDragStarted;
|
||||
tidyUpThumb.DragDelta -= ThumbOnDragDelta;
|
||||
tidyUpThumb.DragCompleted -= ThumbOnDragCompleted;
|
||||
});
|
||||
|
||||
return new Tuple<Thumb, IDisposable>(_thumb, disposable);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Others/Dragablz/Dragablz/DragablzItemEventArgs.cs
Normal file
37
Others/Dragablz/Dragablz/DragablzItemEventArgs.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public delegate void DragablzItemEventHandler(object sender, DragablzItemEventArgs e);
|
||||
|
||||
public class DragablzItemEventArgs : RoutedEventArgs
|
||||
{
|
||||
private readonly DragablzItem _dragablzItem;
|
||||
|
||||
public DragablzItemEventArgs(DragablzItem dragablzItem)
|
||||
{
|
||||
if (dragablzItem == null) throw new ArgumentNullException("dragablzItem");
|
||||
|
||||
_dragablzItem = dragablzItem;
|
||||
}
|
||||
|
||||
public DragablzItemEventArgs(RoutedEvent routedEvent, DragablzItem dragablzItem)
|
||||
: base(routedEvent)
|
||||
{
|
||||
_dragablzItem = dragablzItem;
|
||||
}
|
||||
|
||||
public DragablzItemEventArgs(RoutedEvent routedEvent, object source, DragablzItem dragablzItem)
|
||||
: base(routedEvent, source)
|
||||
{
|
||||
_dragablzItem = dragablzItem;
|
||||
}
|
||||
|
||||
public DragablzItem DragablzItem
|
||||
{
|
||||
get { return _dragablzItem; }
|
||||
}
|
||||
}
|
||||
}
|
||||
401
Others/Dragablz/Dragablz/DragablzItemsControl.cs
Normal file
401
Others/Dragablz/Dragablz/DragablzItemsControl.cs
Normal file
@@ -0,0 +1,401 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Threading;
|
||||
using Dragablz.Core;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Items control which typically uses a canvas and
|
||||
/// </summary>
|
||||
public class DragablzItemsControl : ItemsControl
|
||||
{
|
||||
private object[] _previousSortQueryResult;
|
||||
|
||||
static DragablzItemsControl()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(DragablzItemsControl), new FrameworkPropertyMetadata(typeof(DragablzItemsControl)));
|
||||
}
|
||||
|
||||
public DragablzItemsControl()
|
||||
{
|
||||
ItemContainerGenerator.StatusChanged += ItemContainerGeneratorOnStatusChanged;
|
||||
ItemContainerGenerator.ItemsChanged += ItemContainerGeneratorOnItemsChanged;
|
||||
AddHandler(DragablzItem.XChangedEvent, new RoutedPropertyChangedEventHandler<double>(ItemXChanged));
|
||||
AddHandler(DragablzItem.YChangedEvent, new RoutedPropertyChangedEventHandler<double>(ItemYChanged));
|
||||
AddHandler(DragablzItem.DragDelta, new DragablzDragDeltaEventHandler(ItemDragDelta));
|
||||
AddHandler(DragablzItem.DragCompleted, new DragablzDragCompletedEventHandler(ItemDragCompleted));
|
||||
AddHandler(DragablzItem.DragStarted, new DragablzDragStartedEventHandler(ItemDragStarted));
|
||||
AddHandler(DragablzItem.MouseDownWithinEvent, new DragablzItemEventHandler(ItemMouseDownWithinHandlerTarget));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FixedItemCountProperty = DependencyProperty.Register(
|
||||
"FixedItemCount", typeof (int), typeof (DragablzItemsControl), new PropertyMetadata(default(int)));
|
||||
|
||||
public int FixedItemCount
|
||||
{
|
||||
get { return (int) GetValue(FixedItemCountProperty); }
|
||||
set { SetValue(FixedItemCountProperty, value); }
|
||||
}
|
||||
|
||||
private void ItemContainerGeneratorOnItemsChanged(object sender, ItemsChangedEventArgs itemsChangedEventArgs)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void ClearContainerForItemOverride(DependencyObject element, object item)
|
||||
{
|
||||
if (ContainerCustomisations != null && ContainerCustomisations.ClearingContainerForItemOverride != null)
|
||||
ContainerCustomisations.ClearingContainerForItemOverride(element, item);
|
||||
|
||||
base.ClearContainerForItemOverride(element, item);
|
||||
|
||||
((DragablzItem)element).SizeChanged -= ItemSizeChangedEventHandler;
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
var dragablzItems = DragablzItems().ToList();
|
||||
if (ItemsOrganiser == null) return;
|
||||
ItemsOrganiser.Organise(this, new Size(ItemsPresenterWidth, ItemsPresenterHeight), dragablzItems);
|
||||
var measure = ItemsOrganiser.Measure(this, new Size(ActualWidth, ActualHeight), dragablzItems);
|
||||
ItemsPresenterWidth = measure.Width;
|
||||
ItemsPresenterHeight = measure.Height;
|
||||
}), DispatcherPriority.Input);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemsOrganiserProperty = DependencyProperty.Register(
|
||||
"ItemsOrganiser", typeof (IItemsOrganiser), typeof (DragablzItemsControl), new PropertyMetadata(default(IItemsOrganiser)));
|
||||
|
||||
public IItemsOrganiser ItemsOrganiser
|
||||
{
|
||||
get { return (IItemsOrganiser) GetValue(ItemsOrganiserProperty); }
|
||||
set { SetValue(ItemsOrganiserProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PositionMonitorProperty = DependencyProperty.Register(
|
||||
"PositionMonitor", typeof (PositionMonitor), typeof (DragablzItemsControl), new PropertyMetadata(default(PositionMonitor)));
|
||||
|
||||
public PositionMonitor PositionMonitor
|
||||
{
|
||||
get { return (PositionMonitor) GetValue(PositionMonitorProperty); }
|
||||
set { SetValue(PositionMonitorProperty, value); }
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey ItemsPresenterWidthPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"ItemsPresenterWidth", typeof(double), typeof (DragablzItemsControl),
|
||||
new PropertyMetadata(default(double)));
|
||||
|
||||
public static readonly DependencyProperty ItemsPresenterWidthProperty =
|
||||
ItemsPresenterWidthPropertyKey.DependencyProperty;
|
||||
|
||||
public double ItemsPresenterWidth
|
||||
{
|
||||
get { return (double) GetValue(ItemsPresenterWidthProperty); }
|
||||
private set { SetValue(ItemsPresenterWidthPropertyKey, value); }
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey ItemsPresenterHeightPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"ItemsPresenterHeight", typeof (double), typeof (DragablzItemsControl),
|
||||
new PropertyMetadata(default(double)));
|
||||
|
||||
public static readonly DependencyProperty ItemsPresenterHeightProperty =
|
||||
ItemsPresenterHeightPropertyKey.DependencyProperty;
|
||||
|
||||
public double ItemsPresenterHeight
|
||||
{
|
||||
get { return (double) GetValue(ItemsPresenterHeightProperty); }
|
||||
private set { SetValue(ItemsPresenterHeightPropertyKey, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the underlying source, displaying in a specific position in rendered control.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="addLocationHint"></param>
|
||||
public void AddToSource(object item, AddLocationHint addLocationHint)
|
||||
{
|
||||
AddToSource(item, null, addLocationHint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the underlying source, displaying in a specific position in rendered control.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="nearItem"></param>
|
||||
/// <param name="addLocationHint"></param>
|
||||
public void AddToSource(object item, object nearItem, AddLocationHint addLocationHint)
|
||||
{
|
||||
CollectionTeaser collectionTeaser;
|
||||
if (CollectionTeaser.TryCreate(ItemsSource, out collectionTeaser))
|
||||
collectionTeaser.Add(item);
|
||||
else
|
||||
Items.Add(item);
|
||||
MoveItem(new MoveItemRequest(item, nearItem, addLocationHint));
|
||||
}
|
||||
|
||||
internal ContainerCustomisations ContainerCustomisations { get; set; }
|
||||
|
||||
private void ItemContainerGeneratorOnStatusChanged(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) return;
|
||||
|
||||
InvalidateMeasure();
|
||||
//extra kick
|
||||
Dispatcher.BeginInvoke(new Action(InvalidateMeasure), DispatcherPriority.Loaded);
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item)
|
||||
{
|
||||
var dragablzItem = item as DragablzItem;
|
||||
if (dragablzItem == null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride()
|
||||
{
|
||||
var result = ContainerCustomisations != null && ContainerCustomisations.GetContainerForItemOverride != null
|
||||
? ContainerCustomisations.GetContainerForItemOverride()
|
||||
: new DragablzItem();
|
||||
|
||||
result.SizeChanged += ItemSizeChangedEventHandler;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
|
||||
{
|
||||
if (ContainerCustomisations != null && ContainerCustomisations.PrepareContainerForItemOverride != null)
|
||||
ContainerCustomisations.PrepareContainerForItemOverride(element, item);
|
||||
|
||||
base.PrepareContainerForItemOverride(element, item);
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
if (ItemsOrganiser == null) return base.MeasureOverride(constraint);
|
||||
|
||||
if (LockedMeasure.HasValue)
|
||||
{
|
||||
ItemsPresenterWidth = LockedMeasure.Value.Width;
|
||||
ItemsPresenterHeight = LockedMeasure.Value.Height;
|
||||
return LockedMeasure.Value;
|
||||
}
|
||||
|
||||
var dragablzItems = DragablzItems().ToList();
|
||||
var maxConstraint = new Size(double.PositiveInfinity, double.PositiveInfinity);
|
||||
|
||||
ItemsOrganiser.Organise(this, maxConstraint, dragablzItems);
|
||||
var measure = ItemsOrganiser.Measure(this, new Size(ActualWidth, ActualHeight), dragablzItems);
|
||||
|
||||
ItemsPresenterWidth = measure.Width;
|
||||
ItemsPresenterHeight = measure.Height;
|
||||
|
||||
var width = double.IsInfinity(constraint.Width) ? measure.Width : constraint.Width;
|
||||
var height = double.IsInfinity(constraint.Height) ? measure.Height : constraint.Height;
|
||||
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
internal void InstigateDrag(object item, Action<DragablzItem> continuation)
|
||||
{
|
||||
var dragablzItem = (DragablzItem)ItemContainerGenerator.ContainerFromItem(item);
|
||||
dragablzItem.InstigateDrag(continuation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move an item in the rendered layout.
|
||||
/// </summary>
|
||||
/// <param name="moveItemRequest"></param>
|
||||
public void MoveItem(MoveItemRequest moveItemRequest)
|
||||
{
|
||||
if (moveItemRequest == null) throw new ArgumentNullException("moveItemRequest");
|
||||
|
||||
if (ItemsOrganiser == null) return;
|
||||
|
||||
var dragablzItem = moveItemRequest.Item as DragablzItem ??
|
||||
ItemContainerGenerator.ContainerFromItem(
|
||||
moveItemRequest.Item) as DragablzItem;
|
||||
var contextDragablzItem = moveItemRequest.Context as DragablzItem ??
|
||||
ItemContainerGenerator.ContainerFromItem(
|
||||
moveItemRequest.Context) as DragablzItem;
|
||||
|
||||
if (dragablzItem == null) return;
|
||||
|
||||
var sortedItems = DragablzItems().OrderBy(di => di.LogicalIndex).ToList();
|
||||
sortedItems.Remove(dragablzItem);
|
||||
|
||||
switch (moveItemRequest.AddLocationHint)
|
||||
{
|
||||
case AddLocationHint.First:
|
||||
sortedItems.Insert(0, dragablzItem);
|
||||
break;
|
||||
case AddLocationHint.Last:
|
||||
sortedItems.Add(dragablzItem);
|
||||
break;
|
||||
case AddLocationHint.Prior:
|
||||
case AddLocationHint.After:
|
||||
if (contextDragablzItem == null)
|
||||
return;
|
||||
|
||||
var contextIndex = sortedItems.IndexOf(contextDragablzItem);
|
||||
sortedItems.Insert(moveItemRequest.AddLocationHint == AddLocationHint.Prior ? contextIndex : contextIndex + 1, dragablzItem);
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
//TODO might not be too great for perf on larger lists
|
||||
var orderedEnumerable = sortedItems.OrderBy(di => sortedItems.IndexOf(di));
|
||||
|
||||
ItemsOrganiser.Organise(this, new Size(ItemsPresenterWidth, ItemsPresenterHeight), orderedEnumerable);
|
||||
}
|
||||
|
||||
internal IEnumerable<DragablzItem> DragablzItems()
|
||||
{
|
||||
return this.Containers<DragablzItem>().ToList();
|
||||
}
|
||||
|
||||
internal Size? LockedMeasure { get; set; }
|
||||
|
||||
private void ItemDragStarted(object sender, DragablzDragStartedEventArgs eventArgs)
|
||||
{
|
||||
if (ItemsOrganiser != null)
|
||||
{
|
||||
var bounds = new Size(ActualWidth, ActualHeight);
|
||||
ItemsOrganiser.OrganiseOnDragStarted(this, bounds,
|
||||
DragablzItems().Except(new[] { eventArgs.DragablzItem }).ToList(),
|
||||
eventArgs.DragablzItem);
|
||||
}
|
||||
|
||||
eventArgs.Handled = true;
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(InvalidateMeasure), DispatcherPriority.Loaded);
|
||||
}
|
||||
|
||||
private void ItemDragCompleted(object sender, DragablzDragCompletedEventArgs eventArgs)
|
||||
{
|
||||
var dragablzItems = DragablzItems()
|
||||
.Select(i =>
|
||||
{
|
||||
i.IsDragging = false;
|
||||
i.IsSiblingDragging = false;
|
||||
return i;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (ItemsOrganiser != null)
|
||||
{
|
||||
var bounds = new Size(ActualWidth, ActualHeight);
|
||||
ItemsOrganiser.OrganiseOnDragCompleted(this, bounds,
|
||||
dragablzItems.Except(eventArgs.DragablzItem),
|
||||
eventArgs.DragablzItem);
|
||||
}
|
||||
|
||||
eventArgs.Handled = true;
|
||||
|
||||
//wowsers
|
||||
Dispatcher.BeginInvoke(new Action(InvalidateMeasure));
|
||||
Dispatcher.BeginInvoke(new Action(InvalidateMeasure), DispatcherPriority.Loaded);
|
||||
}
|
||||
|
||||
private void ItemDragDelta(object sender, DragablzDragDeltaEventArgs eventArgs)
|
||||
{
|
||||
var bounds = new Size(ItemsPresenterWidth, ItemsPresenterHeight);
|
||||
var desiredLocation = new Point(
|
||||
eventArgs.DragablzItem.X + eventArgs.DragDeltaEventArgs.HorizontalChange,
|
||||
eventArgs.DragablzItem.Y + eventArgs.DragDeltaEventArgs.VerticalChange
|
||||
);
|
||||
if (ItemsOrganiser != null)
|
||||
{
|
||||
if (FixedItemCount > 0 &&
|
||||
ItemsOrganiser.Sort(DragablzItems()).Take(FixedItemCount).Contains(eventArgs.DragablzItem))
|
||||
{
|
||||
eventArgs.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
desiredLocation = ItemsOrganiser.ConstrainLocation(this, bounds,
|
||||
new Point(eventArgs.DragablzItem.X, eventArgs.DragablzItem.Y),
|
||||
new Size(eventArgs.DragablzItem.ActualWidth, eventArgs.DragablzItem.ActualHeight),
|
||||
desiredLocation, eventArgs.DragablzItem.DesiredSize);
|
||||
}
|
||||
|
||||
foreach (var dragableItem in DragablzItems()
|
||||
.Except(new[] { eventArgs.DragablzItem })) // how about Linq.Where() ?
|
||||
{
|
||||
dragableItem.IsSiblingDragging = true;
|
||||
}
|
||||
eventArgs.DragablzItem.IsDragging = true;
|
||||
|
||||
eventArgs.DragablzItem.X = desiredLocation.X;
|
||||
eventArgs.DragablzItem.Y = desiredLocation.Y;
|
||||
|
||||
if (ItemsOrganiser != null)
|
||||
ItemsOrganiser.OrganiseOnDrag(
|
||||
this,
|
||||
bounds,
|
||||
DragablzItems().Except(new[] {eventArgs.DragablzItem}), eventArgs.DragablzItem);
|
||||
|
||||
eventArgs.DragablzItem.BringIntoView();
|
||||
|
||||
eventArgs.Handled = true;
|
||||
}
|
||||
|
||||
private void ItemXChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
|
||||
{
|
||||
UpdateMonitor(routedPropertyChangedEventArgs);
|
||||
}
|
||||
|
||||
private void ItemYChanged(object sender, RoutedPropertyChangedEventArgs<double> routedPropertyChangedEventArgs)
|
||||
{
|
||||
UpdateMonitor(routedPropertyChangedEventArgs);
|
||||
}
|
||||
|
||||
private void UpdateMonitor(RoutedEventArgs routedPropertyChangedEventArgs)
|
||||
{
|
||||
if (PositionMonitor == null) return;
|
||||
|
||||
var dragablzItem = (DragablzItem) routedPropertyChangedEventArgs.OriginalSource;
|
||||
|
||||
if (!Equals(ItemsControlFromItemContainer(dragablzItem), this)) return;
|
||||
|
||||
PositionMonitor.OnLocationChanged(new LocationChangedEventArgs(dragablzItem.Content, new Point(dragablzItem.X, dragablzItem.Y)));
|
||||
|
||||
var linearPositionMonitor = PositionMonitor as StackPositionMonitor;
|
||||
if (linearPositionMonitor == null) return;
|
||||
|
||||
var sortedItems = linearPositionMonitor.Sort(this.Containers<DragablzItem>()).Select(di => di.Content).ToArray();
|
||||
if (_previousSortQueryResult == null || !_previousSortQueryResult.SequenceEqual(sortedItems))
|
||||
linearPositionMonitor.OnOrderChanged(new OrderChangedEventArgs(_previousSortQueryResult, sortedItems));
|
||||
|
||||
_previousSortQueryResult = sortedItems;
|
||||
}
|
||||
|
||||
private void ItemMouseDownWithinHandlerTarget(object sender, DragablzItemEventArgs e)
|
||||
{
|
||||
if (ItemsOrganiser == null) return;
|
||||
|
||||
var bounds = new Size(ActualWidth, ActualHeight);
|
||||
ItemsOrganiser.OrganiseOnMouseDownWithin(this, bounds,
|
||||
DragablzItems().Except(e.DragablzItem).ToList(),
|
||||
e.DragablzItem);
|
||||
}
|
||||
|
||||
private void ItemSizeChangedEventHandler(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
InvalidateMeasure();
|
||||
//extra kick
|
||||
Dispatcher.BeginInvoke(new Action(InvalidateMeasure), DispatcherPriority.Loaded);
|
||||
}
|
||||
}
|
||||
}
|
||||
370
Others/Dragablz/Dragablz/DragablzWindow.cs
Normal file
370
Others/Dragablz/Dragablz/DragablzWindow.cs
Normal file
@@ -0,0 +1,370 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using Dragablz.Core;
|
||||
using Dragablz.Dockablz;
|
||||
using Dragablz.Referenceless;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// It is not necessary to use a <see cref="DragablzWindow"/> to gain tab dragging features.
|
||||
/// What this Window does is allow a quick way to remove the Window border, and support transparency whilst
|
||||
/// dragging.
|
||||
/// </summary>
|
||||
[TemplatePart(Name = WindowSurfaceGridPartName, Type = typeof(Grid))]
|
||||
[TemplatePart(Name = WindowRestoreThumbPartName, Type = typeof(Thumb))]
|
||||
[TemplatePart(Name = WindowResizeThumbPartName, Type = typeof(Thumb))]
|
||||
public class DragablzWindow : Window
|
||||
{
|
||||
public const string WindowSurfaceGridPartName = "PART_WindowSurface";
|
||||
public const string WindowRestoreThumbPartName = "PART_WindowRestoreThumb";
|
||||
public const string WindowResizeThumbPartName = "PART_WindowResizeThumb";
|
||||
private readonly SerialDisposable _templateSubscription = new SerialDisposable();
|
||||
|
||||
public static RoutedCommand CloseWindowCommand = new RoutedCommand();
|
||||
public static RoutedCommand RestoreWindowCommand = new RoutedCommand();
|
||||
public static RoutedCommand MaximizeWindowCommand = new RoutedCommand();
|
||||
public static RoutedCommand MinimizeWindowCommand = new RoutedCommand();
|
||||
|
||||
private const int ResizeMargin = 4;
|
||||
private Size _sizeWhenResizeBegan;
|
||||
private Point _screenMousePointWhenResizeBegan;
|
||||
private Point _windowLocationPointWhenResizeBegan;
|
||||
private SizeGrip _resizeType;
|
||||
|
||||
private static SizeGrip[] _leftMode = new[] { SizeGrip.TopLeft, SizeGrip.Left, SizeGrip.BottomLeft };
|
||||
private static SizeGrip[] _rightMode = new[] { SizeGrip.TopRight, SizeGrip.Right, SizeGrip.BottomRight };
|
||||
private static SizeGrip[] _topMode = new[] { SizeGrip.TopLeft, SizeGrip.Top, SizeGrip.TopRight };
|
||||
private static SizeGrip[] _bottomMode = new[] { SizeGrip.BottomLeft, SizeGrip.Bottom, SizeGrip.BottomRight };
|
||||
|
||||
private static double _xScale = 1;
|
||||
private static double _yScale = 1;
|
||||
private static bool _dpiInitialized = false;
|
||||
|
||||
static DragablzWindow()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(DragablzWindow), new FrameworkPropertyMetadata(typeof(DragablzWindow)));
|
||||
}
|
||||
|
||||
public DragablzWindow()
|
||||
{
|
||||
AddHandler(DragablzItem.DragStarted, new DragablzDragStartedEventHandler(ItemDragStarted), true);
|
||||
AddHandler(DragablzItem.DragCompleted, new DragablzDragCompletedEventHandler(ItemDragCompleted), true);
|
||||
CommandBindings.Add(new CommandBinding(CloseWindowCommand, CloseWindowExecuted));
|
||||
CommandBindings.Add(new CommandBinding(MaximizeWindowCommand, MaximizeWindowExecuted));
|
||||
CommandBindings.Add(new CommandBinding(MinimizeWindowCommand, MinimizeWindowExecuted));
|
||||
CommandBindings.Add(new CommandBinding(RestoreWindowCommand, RestoreWindowExecuted));
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey IsWindowBeingDraggedByTabPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"IsBeingDraggedByTab", typeof (bool), typeof (DragablzWindow),
|
||||
new PropertyMetadata(default(bool)));
|
||||
|
||||
public static readonly DependencyProperty IsBeingDraggedByTabProperty =
|
||||
IsWindowBeingDraggedByTabPropertyKey.DependencyProperty;
|
||||
|
||||
public bool IsBeingDraggedByTab
|
||||
{
|
||||
get { return (bool) GetValue(IsBeingDraggedByTabProperty); }
|
||||
private set { SetValue(IsWindowBeingDraggedByTabPropertyKey, value); }
|
||||
}
|
||||
|
||||
private void ItemDragCompleted(object sender, DragablzDragCompletedEventArgs e)
|
||||
{
|
||||
IsBeingDraggedByTab = false;
|
||||
}
|
||||
|
||||
private void ItemDragStarted(object sender, DragablzDragStartedEventArgs e)
|
||||
{
|
||||
var sourceOfDragItemsControl = ItemsControl.ItemsControlFromItemContainer(e.DragablzItem) as DragablzItemsControl;
|
||||
if (sourceOfDragItemsControl == null) return;
|
||||
|
||||
var sourceTab = TabablzControl.GetOwnerOfHeaderItems(sourceOfDragItemsControl);
|
||||
if (sourceTab == null) return;
|
||||
|
||||
if (sourceOfDragItemsControl.Items.Count != 1
|
||||
|| (sourceTab.InterTabController != null && !sourceTab.InterTabController.MoveWindowWithSolitaryTabs)
|
||||
|| Layout.IsContainedWithinBranch(sourceOfDragItemsControl))
|
||||
return;
|
||||
|
||||
IsBeingDraggedByTab = true;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
var windowSurfaceGrid = GetTemplateChild(WindowSurfaceGridPartName) as Grid;
|
||||
var windowRestoreThumb = GetTemplateChild(WindowRestoreThumbPartName) as Thumb;
|
||||
var windowResizeThumb = GetTemplateChild(WindowResizeThumbPartName) as Thumb;
|
||||
|
||||
_templateSubscription.Disposable = Disposable.Create(() =>
|
||||
{
|
||||
if (windowSurfaceGrid != null)
|
||||
{
|
||||
windowSurfaceGrid.MouseLeftButtonDown -= WindowSurfaceGridOnMouseLeftButtonDown;
|
||||
}
|
||||
|
||||
if (windowRestoreThumb != null)
|
||||
{
|
||||
windowRestoreThumb.DragDelta -= WindowMoveThumbOnDragDelta;
|
||||
windowRestoreThumb.MouseDoubleClick -= WindowRestoreThumbOnMouseDoubleClick;
|
||||
}
|
||||
|
||||
if (windowResizeThumb == null) return;
|
||||
|
||||
windowResizeThumb.MouseMove -= WindowResizeThumbOnMouseMove;
|
||||
windowResizeThumb.DragStarted -= WindowResizeThumbOnDragStarted;
|
||||
windowResizeThumb.DragDelta -= WindowResizeThumbOnDragDelta;
|
||||
windowResizeThumb.DragCompleted -= WindowResizeThumbOnDragCompleted;
|
||||
});
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (windowSurfaceGrid != null)
|
||||
{
|
||||
windowSurfaceGrid.MouseLeftButtonDown += WindowSurfaceGridOnMouseLeftButtonDown;
|
||||
}
|
||||
|
||||
if (windowRestoreThumb != null)
|
||||
{
|
||||
windowRestoreThumb.DragDelta += WindowMoveThumbOnDragDelta;
|
||||
windowRestoreThumb.MouseDoubleClick += WindowRestoreThumbOnMouseDoubleClick;
|
||||
}
|
||||
|
||||
if (windowResizeThumb == null) return;
|
||||
|
||||
windowResizeThumb.MouseMove += WindowResizeThumbOnMouseMove;
|
||||
windowResizeThumb.DragStarted += WindowResizeThumbOnDragStarted;
|
||||
windowResizeThumb.DragDelta += WindowResizeThumbOnDragDelta;
|
||||
windowResizeThumb.DragCompleted += WindowResizeThumbOnDragCompleted;
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
var resizeThumb = GetTemplateChild(WindowResizeThumbPartName) as Thumb;
|
||||
if (resizeThumb != null)
|
||||
{
|
||||
var outerRectangleGeometry = new RectangleGeometry(new Rect(sizeInfo.NewSize));
|
||||
var innerRectangleGeometry =
|
||||
new RectangleGeometry(new Rect(ResizeMargin, ResizeMargin, sizeInfo.NewSize.Width - ResizeMargin * 2, sizeInfo.NewSize.Height - ResizeMargin*2));
|
||||
resizeThumb.Clip = new CombinedGeometry(GeometryCombineMode.Exclude, outerRectangleGeometry,
|
||||
innerRectangleGeometry);
|
||||
}
|
||||
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
}
|
||||
|
||||
protected IntPtr CriticalHandle
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = typeof (Window).GetProperty("CriticalHandle", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.GetValue(this, new object[0]);
|
||||
return (IntPtr) value;
|
||||
}
|
||||
}
|
||||
|
||||
private void WindowSurfaceGridOnMouseLeftButtonDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
|
||||
{
|
||||
if (mouseButtonEventArgs.ChangedButton != MouseButton.Left) return;
|
||||
if (mouseButtonEventArgs.ClickCount == 1)
|
||||
DragMove();
|
||||
if (mouseButtonEventArgs.ClickCount == 2)
|
||||
WindowState = WindowState.Maximized;
|
||||
}
|
||||
|
||||
private static void WindowResizeThumbOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
|
||||
{
|
||||
var thumb = (Thumb)sender;
|
||||
var mousePositionInThumb = Mouse.GetPosition(thumb);
|
||||
thumb.Cursor = SelectCursor(SelectSizingMode(mousePositionInThumb, thumb.RenderSize));
|
||||
}
|
||||
|
||||
private void WindowRestoreThumbOnMouseDoubleClick(object sender, MouseButtonEventArgs mouseButtonEventArgs)
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
private void WindowResizeThumbOnDragCompleted(object sender, DragCompletedEventArgs dragCompletedEventArgs)
|
||||
{
|
||||
Cursor = Cursors.Arrow;
|
||||
}
|
||||
|
||||
private void WindowResizeThumbOnDragDelta(object sender, DragDeltaEventArgs dragDeltaEventArgs)
|
||||
{
|
||||
var mousePositionInWindow = Mouse.GetPosition(this);
|
||||
var currentScreenMousePoint = PointToScreen(mousePositionInWindow);
|
||||
|
||||
var width = _sizeWhenResizeBegan.Width;
|
||||
var height = _sizeWhenResizeBegan.Height;
|
||||
var left = _windowLocationPointWhenResizeBegan.X;
|
||||
var top = _windowLocationPointWhenResizeBegan.Y;
|
||||
|
||||
if (_leftMode.Contains(_resizeType))
|
||||
{
|
||||
var diff = currentScreenMousePoint.X - _screenMousePointWhenResizeBegan.X;
|
||||
diff /= _xScale;
|
||||
var suggestedWidth = width + -diff;
|
||||
left += diff;
|
||||
width = suggestedWidth;
|
||||
}
|
||||
if (_rightMode.Contains(_resizeType))
|
||||
{
|
||||
var diff = currentScreenMousePoint.X - _screenMousePointWhenResizeBegan.X;
|
||||
diff /= _xScale;
|
||||
width += diff;
|
||||
}
|
||||
if (_topMode.Contains(_resizeType))
|
||||
{
|
||||
var diff = currentScreenMousePoint.Y - _screenMousePointWhenResizeBegan.Y;
|
||||
diff /= _yScale;
|
||||
height += -diff;
|
||||
top += diff;
|
||||
}
|
||||
if (_bottomMode.Contains(_resizeType))
|
||||
{
|
||||
var diff = currentScreenMousePoint.Y - _screenMousePointWhenResizeBegan.Y;
|
||||
diff /= _yScale;
|
||||
height += diff;
|
||||
}
|
||||
|
||||
width = Math.Max(MinWidth, width);
|
||||
height = Math.Max(MinHeight, height);
|
||||
//TODO must try harder.
|
||||
left = Math.Min(left, _windowLocationPointWhenResizeBegan.X + _sizeWhenResizeBegan.Width - ResizeMargin*4);
|
||||
//TODO must try harder.
|
||||
top = Math.Min(top, _windowLocationPointWhenResizeBegan.Y + _sizeWhenResizeBegan.Height - ResizeMargin * 4);
|
||||
SetCurrentValue(WidthProperty, width);
|
||||
SetCurrentValue(HeightProperty, height);
|
||||
SetCurrentValue(LeftProperty, left);
|
||||
SetCurrentValue(TopProperty, top);
|
||||
}
|
||||
|
||||
private void GetDPI()
|
||||
{
|
||||
if (_dpiInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
|
||||
_xScale = m.M11;
|
||||
_yScale = m.M22;
|
||||
_dpiInitialized = true;
|
||||
}
|
||||
|
||||
private void WindowResizeThumbOnDragStarted(object sender, DragStartedEventArgs dragStartedEventArgs)
|
||||
{
|
||||
_sizeWhenResizeBegan = new Size(ActualWidth, ActualHeight);
|
||||
_windowLocationPointWhenResizeBegan = new Point(Left, Top);
|
||||
var mousePositionInWindow = Mouse.GetPosition(this);
|
||||
_screenMousePointWhenResizeBegan = PointToScreen(mousePositionInWindow);
|
||||
|
||||
var thumb = (Thumb)sender;
|
||||
var mousePositionInThumb = Mouse.GetPosition(thumb);
|
||||
_resizeType = SelectSizingMode(mousePositionInThumb, thumb.RenderSize);
|
||||
|
||||
GetDPI();
|
||||
}
|
||||
|
||||
private static SizeGrip SelectSizingMode(Point mousePositionInThumb, Size thumbSize)
|
||||
{
|
||||
if (mousePositionInThumb.X <= ResizeMargin)
|
||||
{
|
||||
if (mousePositionInThumb.Y <= ResizeMargin)
|
||||
return SizeGrip.TopLeft;
|
||||
if (mousePositionInThumb.Y >= thumbSize.Height - ResizeMargin)
|
||||
return SizeGrip.BottomLeft;
|
||||
return SizeGrip.Left;
|
||||
}
|
||||
|
||||
if (mousePositionInThumb.X >= thumbSize.Width - ResizeMargin)
|
||||
{
|
||||
if (mousePositionInThumb.Y <= ResizeMargin)
|
||||
return SizeGrip.TopRight;
|
||||
if (mousePositionInThumb.Y >= thumbSize.Height - ResizeMargin)
|
||||
return SizeGrip.BottomRight;
|
||||
return SizeGrip.Right;
|
||||
}
|
||||
|
||||
if (mousePositionInThumb.Y <= ResizeMargin)
|
||||
return SizeGrip.Top;
|
||||
|
||||
return SizeGrip.Bottom;
|
||||
}
|
||||
|
||||
private static Cursor SelectCursor(SizeGrip sizeGrip)
|
||||
{
|
||||
switch (sizeGrip)
|
||||
{
|
||||
case SizeGrip.Left:
|
||||
return Cursors.SizeWE;
|
||||
case SizeGrip.TopLeft:
|
||||
return Cursors.SizeNWSE;
|
||||
case SizeGrip.Top:
|
||||
return Cursors.SizeNS;
|
||||
case SizeGrip.TopRight:
|
||||
return Cursors.SizeNESW;
|
||||
case SizeGrip.Right:
|
||||
return Cursors.SizeWE;
|
||||
case SizeGrip.BottomRight:
|
||||
return Cursors.SizeNWSE;
|
||||
case SizeGrip.Bottom:
|
||||
return Cursors.SizeNS;
|
||||
case SizeGrip.BottomLeft:
|
||||
return Cursors.SizeNESW;
|
||||
default:
|
||||
return Cursors.Arrow;
|
||||
}
|
||||
}
|
||||
|
||||
private void WindowMoveThumbOnDragDelta(object sender, DragDeltaEventArgs dragDeltaEventArgs)
|
||||
{
|
||||
if (WindowState != WindowState.Maximized ||
|
||||
(!(Math.Abs(dragDeltaEventArgs.HorizontalChange) > 2) &&
|
||||
!(Math.Abs(dragDeltaEventArgs.VerticalChange) > 2))) return;
|
||||
|
||||
var cursorPos = Native.GetRawCursorPos();
|
||||
WindowState = WindowState.Normal;
|
||||
|
||||
GetDPI();
|
||||
|
||||
Top = cursorPos.Y / _yScale - 2;
|
||||
Left = cursorPos.X / _xScale - RestoreBounds.Width / 2;
|
||||
|
||||
var lParam = (int)(uint)cursorPos.X | (cursorPos.Y << 16);
|
||||
Native.SendMessage(CriticalHandle, WindowMessage.WM_LBUTTONUP, (IntPtr)HitTest.HT_CAPTION,
|
||||
(IntPtr)lParam);
|
||||
Native.SendMessage(CriticalHandle, WindowMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_MOUSEMOVE,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
|
||||
private void RestoreWindowExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
Native.PostMessage(new WindowInteropHelper(this).Handle, WindowMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_RESTORE, IntPtr.Zero);
|
||||
}
|
||||
|
||||
private void MinimizeWindowExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
Native.PostMessage(new WindowInteropHelper(this).Handle, WindowMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_MINIMIZE, IntPtr.Zero);
|
||||
}
|
||||
|
||||
private void MaximizeWindowExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
Native.PostMessage(new WindowInteropHelper(this).Handle, WindowMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_MAXIMIZE, IntPtr.Zero);
|
||||
}
|
||||
|
||||
private void CloseWindowExecuted(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
|
||||
{
|
||||
Native.PostMessage(new WindowInteropHelper(this).Handle, WindowMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Others/Dragablz/Dragablz/EmptyHeaderSizingHint.cs
Normal file
22
Others/Dragablz/Dragablz/EmptyHeaderSizingHint.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide a hint for how the header should size itself if there are no tabs left (and a Window is still open).
|
||||
/// </summary>
|
||||
public enum EmptyHeaderSizingHint
|
||||
{
|
||||
/// <summary>
|
||||
/// The header size collapses to zero along the correct axis.
|
||||
/// </summary>
|
||||
Collapse,
|
||||
/// <summary>
|
||||
/// The header size remains that of the last tab prior to the tab header becoming empty.
|
||||
/// </summary>
|
||||
PreviousTab,
|
||||
//TODO implement EmptyHeaderSizingHint.Stretch
|
||||
/// <summary>
|
||||
/// The header stretches along the according axis.
|
||||
/// </summary>
|
||||
//Stretch
|
||||
}
|
||||
}
|
||||
49
Others/Dragablz/Dragablz/HeaderedDragablzItem.cs
Normal file
49
Others/Dragablz/Dragablz/HeaderedDragablzItem.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class HeaderedDragablzItem : DragablzItem
|
||||
{
|
||||
static HeaderedDragablzItem()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(HeaderedDragablzItem), new FrameworkPropertyMetadata(typeof(HeaderedDragablzItem)));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HeaderContentProperty = DependencyProperty.Register(
|
||||
"HeaderContent", typeof (object), typeof (HeaderedDragablzItem), new PropertyMetadata(default(object)));
|
||||
|
||||
public object HeaderContent
|
||||
{
|
||||
get { return (object) GetValue(HeaderContentProperty); }
|
||||
set { SetValue(HeaderContentProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HeaderContentStringFormatProperty = DependencyProperty.Register(
|
||||
"HeaderContentStringFormat", typeof (string), typeof (HeaderedDragablzItem), new PropertyMetadata(default(string)));
|
||||
|
||||
public string HeaderContentStringFormat
|
||||
{
|
||||
get { return (string) GetValue(HeaderContentStringFormatProperty); }
|
||||
set { SetValue(HeaderContentStringFormatProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HeaderContentTemplateProperty = DependencyProperty.Register(
|
||||
"HeaderContentTemplate", typeof (DataTemplate), typeof (HeaderedDragablzItem), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public DataTemplate HeaderContentTemplate
|
||||
{
|
||||
get { return (DataTemplate) GetValue(HeaderContentTemplateProperty); }
|
||||
set { SetValue(HeaderContentTemplateProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HeaderContentTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"HeaderContentTemplateSelector", typeof (DataTemplateSelector), typeof (HeaderedDragablzItem), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
|
||||
public DataTemplateSelector HeaderContentTemplateSelector
|
||||
{
|
||||
get { return (DataTemplateSelector) GetValue(HeaderContentTemplateSelectorProperty); }
|
||||
set { SetValue(HeaderContentTemplateSelectorProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
83
Others/Dragablz/Dragablz/HeaderedItemViewModel.cs
Normal file
83
Others/Dragablz/Dragablz/HeaderedItemViewModel.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to create view models, particularly for tool/MDI windows.
|
||||
/// </summary>
|
||||
public class HeaderedItemViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private bool _isSelected;
|
||||
private object _header;
|
||||
private object _content;
|
||||
|
||||
public HeaderedItemViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public HeaderedItemViewModel(object header, object content, bool isSelected = false)
|
||||
{
|
||||
_header = header;
|
||||
_content = content;
|
||||
_isSelected = isSelected;
|
||||
}
|
||||
|
||||
public object Header
|
||||
{
|
||||
get { return _header; }
|
||||
set
|
||||
{
|
||||
if (_header == value) return;
|
||||
_header = value;
|
||||
#if NET40
|
||||
OnPropertyChanged("Header");
|
||||
#else
|
||||
OnPropertyChanged();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public object Content
|
||||
{
|
||||
get { return _content; }
|
||||
set
|
||||
{
|
||||
if (_content == value) return;
|
||||
_content = value;
|
||||
#if NET40
|
||||
OnPropertyChanged("Content");
|
||||
#else
|
||||
OnPropertyChanged();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get { return _isSelected; }
|
||||
set
|
||||
{
|
||||
if (_isSelected == value) return;
|
||||
_isSelected = value;
|
||||
#if NET40
|
||||
OnPropertyChanged("IsSelected");
|
||||
#else
|
||||
OnPropertyChanged();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
#if NET40
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
#else
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
#endif
|
||||
{
|
||||
var handler = PropertyChanged;
|
||||
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Others/Dragablz/Dragablz/HorizontalOrganiser.cs
Normal file
16
Others/Dragablz/Dragablz/HorizontalOrganiser.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class HorizontalOrganiser : StackOrganiser
|
||||
{
|
||||
public HorizontalOrganiser() : base(Orientation.Horizontal)
|
||||
{ }
|
||||
|
||||
public HorizontalOrganiser(double itemOffset) : base(Orientation.Horizontal, itemOffset)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
11
Others/Dragablz/Dragablz/HorizontalPositionMonitor.cs
Normal file
11
Others/Dragablz/Dragablz/HorizontalPositionMonitor.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class HorizontalPositionMonitor : StackPositionMonitor
|
||||
{
|
||||
public HorizontalPositionMonitor() : base(Orientation.Horizontal)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Others/Dragablz/Dragablz/IInterLayoutClient.cs
Normal file
19
Others/Dragablz/Dragablz/IInterLayoutClient.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementors should provide a mechanism to provide a new host control which contains a new <see cref="TabablzControl"/>.
|
||||
/// </summary>
|
||||
public interface IInterLayoutClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide a new host control and tab into which will be placed into a newly created layout branch.
|
||||
/// </summary>
|
||||
/// <param name="partition">Provides the partition where the drag operation was initiated.</param>
|
||||
/// <param name="source">The source control where a dragging operation was initiated.</param>
|
||||
/// <returns></returns>
|
||||
INewTabHost<UIElement> GetNewHost(object partition, TabablzControl source);
|
||||
|
||||
}
|
||||
}
|
||||
27
Others/Dragablz/Dragablz/IInterTabClient.cs
Normal file
27
Others/Dragablz/Dragablz/IInterTabClient.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementors should provide mechanisms for providing new windows and closing old windows.
|
||||
/// </summary>
|
||||
public interface IInterTabClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide a new host window so a tab can be teared from an existing window into a new window.
|
||||
/// </summary>
|
||||
/// <param name="interTabClient"></param>
|
||||
/// <param name="partition">Provides the partition where the drag operation was initiated.</param>
|
||||
/// <param name="source">The source control where a dragging operation was initiated.</param>
|
||||
/// <returns></returns>
|
||||
INewTabHost<Window> GetNewHost(IInterTabClient interTabClient, object partition, TabablzControl source);
|
||||
/// <summary>
|
||||
/// Called when a tab has been emptied, and thus typically a window needs closing.
|
||||
/// </summary>
|
||||
/// <param name="tabControl"></param>
|
||||
/// <param name="window"></param>
|
||||
/// <returns></returns>
|
||||
TabEmptiedResponse TabEmptiedHandler(TabablzControl tabControl, Window window);
|
||||
}
|
||||
}
|
||||
21
Others/Dragablz/Dragablz/IItemsOrganiser.cs
Normal file
21
Others/Dragablz/Dragablz/IItemsOrganiser.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public interface IItemsOrganiser
|
||||
{
|
||||
void Organise(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> items);
|
||||
void Organise(DragablzItemsControl requestor, Size measureBounds, IOrderedEnumerable<DragablzItem> items);
|
||||
void OrganiseOnMouseDownWithin(DragablzItemsControl requestor, Size measureBounds, List<DragablzItem> siblingItems, DragablzItem dragablzItem);
|
||||
void OrganiseOnDragStarted(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem);
|
||||
void OrganiseOnDrag(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem);
|
||||
void OrganiseOnDragCompleted(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem);
|
||||
Point ConstrainLocation(DragablzItemsControl requestor, Size measureBounds, Point itemCurrentLocation, Size itemCurrentSize, Point itemDesiredLocation, Size itemDesiredSize);
|
||||
Size Measure(DragablzItemsControl requestor, Size availableSize, IEnumerable<DragablzItem> items);
|
||||
IEnumerable<DragablzItem> Sort(IEnumerable<DragablzItem> items);
|
||||
}
|
||||
}
|
||||
8
Others/Dragablz/Dragablz/IManualInterTabClient.cs
Normal file
8
Others/Dragablz/Dragablz/IManualInterTabClient.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Dragablz
|
||||
{
|
||||
public interface IManualInterTabClient : IInterTabClient
|
||||
{
|
||||
void Add(object item);
|
||||
void Remove(object item);
|
||||
}
|
||||
}
|
||||
10
Others/Dragablz/Dragablz/INewTabHost.cs
Normal file
10
Others/Dragablz/Dragablz/INewTabHost.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public interface INewTabHost<out TElement> where TElement : UIElement
|
||||
{
|
||||
TElement Container { get; }
|
||||
TabablzControl TabablzControl { get; }
|
||||
}
|
||||
}
|
||||
73
Others/Dragablz/Dragablz/InterTabController.cs
Normal file
73
Others/Dragablz/Dragablz/InterTabController.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Dynamic;
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class InterTabController : FrameworkElement
|
||||
{
|
||||
public InterTabController()
|
||||
{
|
||||
HorizontalPopoutGrace = 8;
|
||||
VerticalPopoutGrace = 8;
|
||||
MoveWindowWithSolitaryTabs = true;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HorizontalPopoutGraceProperty = DependencyProperty.Register(
|
||||
"HorizontalPopoutGrace", typeof (double), typeof (InterTabController), new PropertyMetadata(8.0));
|
||||
|
||||
public double HorizontalPopoutGrace
|
||||
{
|
||||
get { return (double) GetValue(HorizontalPopoutGraceProperty); }
|
||||
set { SetValue(HorizontalPopoutGraceProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty VerticalPopoutGraceProperty = DependencyProperty.Register(
|
||||
"VerticalPopoutGrace", typeof (double), typeof (InterTabController), new PropertyMetadata(8.0));
|
||||
|
||||
public double VerticalPopoutGrace
|
||||
{
|
||||
get { return (double) GetValue(VerticalPopoutGraceProperty); }
|
||||
set { SetValue(VerticalPopoutGraceProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MoveWindowWithSolitaryTabsProperty = DependencyProperty.Register(
|
||||
"MoveWindowWithSolitaryTabs", typeof (bool), typeof (InterTabController), new PropertyMetadata(true));
|
||||
|
||||
public bool MoveWindowWithSolitaryTabs
|
||||
{
|
||||
get { return (bool) GetValue(MoveWindowWithSolitaryTabsProperty); }
|
||||
set { SetValue(MoveWindowWithSolitaryTabsProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty InterTabClientProperty = DependencyProperty.Register(
|
||||
"InterTabClient", typeof (IInterTabClient), typeof (InterTabController),
|
||||
new PropertyMetadata(new DefaultInterTabClient()));
|
||||
|
||||
public IInterTabClient InterTabClient
|
||||
{
|
||||
get { return (IInterTabClient) GetValue(InterTabClientProperty); }
|
||||
set { SetValue(InterTabClientProperty, value); }
|
||||
}
|
||||
|
||||
/*
|
||||
public static readonly DependencyProperty PartitionProperty = DependencyProperty.Register(
|
||||
"Partition", typeof (object), typeof (InterTabController), new PropertyMetadata(default(object)));
|
||||
|
||||
/// <summary>
|
||||
/// The partition allows on or more tab environments in a single application. Only tabs which have a tab controller
|
||||
/// with a common partition will be allowed to have tabs dragged between them. <c>null</c> is a valid partition (i.e global).
|
||||
/// </summary>
|
||||
public object Partition
|
||||
{
|
||||
get { return (object) GetValue(PartitionProperty); }
|
||||
set { SetValue(PartitionProperty, value); }
|
||||
}
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// The partition allows on or more tab environments in a single application. Only tabs which have a tab controller
|
||||
/// with a common partition will be allowed to have tabs dragged between them. <c>null</c> is a valid partition (i.e global).
|
||||
/// </summary>
|
||||
public string Partition { get; set; }
|
||||
}
|
||||
}
|
||||
47
Others/Dragablz/Dragablz/ItemActionCallbackArgs.cs
Normal file
47
Others/Dragablz/Dragablz/ItemActionCallbackArgs.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public delegate void ItemActionCallback(ItemActionCallbackArgs<TabablzControl> args);
|
||||
|
||||
public class ItemActionCallbackArgs<TOwner> where TOwner : FrameworkElement
|
||||
{
|
||||
private readonly Window _window;
|
||||
private readonly TOwner _owner;
|
||||
private readonly DragablzItem _dragablzItem;
|
||||
|
||||
public ItemActionCallbackArgs(Window window, TOwner owner, DragablzItem dragablzItem)
|
||||
{
|
||||
if (window == null) throw new ArgumentNullException("window");
|
||||
if (owner == null) throw new ArgumentNullException("owner");
|
||||
if (dragablzItem == null) throw new ArgumentNullException("dragablzItem");
|
||||
|
||||
_window = window;
|
||||
_owner = owner;
|
||||
_dragablzItem = dragablzItem;
|
||||
}
|
||||
|
||||
public Window Window
|
||||
{
|
||||
get { return _window; }
|
||||
}
|
||||
|
||||
public TOwner Owner
|
||||
{
|
||||
get { return _owner; }
|
||||
}
|
||||
|
||||
public DragablzItem DragablzItem
|
||||
{
|
||||
get { return _dragablzItem; }
|
||||
}
|
||||
|
||||
public bool IsCancelled { get; private set; }
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
IsCancelled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Others/Dragablz/Dragablz/LocationChangedEventArgs.cs
Normal file
29
Others/Dragablz/Dragablz/LocationChangedEventArgs.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class LocationChangedEventArgs : EventArgs
|
||||
{
|
||||
private readonly object _item;
|
||||
private readonly Point _location;
|
||||
|
||||
public LocationChangedEventArgs(object item, Point location)
|
||||
{
|
||||
if (item == null) throw new ArgumentNullException("item");
|
||||
|
||||
_item = item;
|
||||
_location = location;
|
||||
}
|
||||
|
||||
public object Item
|
||||
{
|
||||
get { return _item; }
|
||||
}
|
||||
|
||||
public Point Location
|
||||
{
|
||||
get { return _location; }
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Others/Dragablz/Dragablz/LocationHint.cs
Normal file
26
Others/Dragablz/Dragablz/LocationHint.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies where an item should appear when added to tab control, as the headers order do not
|
||||
/// specifically correlate to the order of the the source items.
|
||||
/// </summary>
|
||||
public enum AddLocationHint
|
||||
{
|
||||
/// <summary>
|
||||
/// Display item in the first position.
|
||||
/// </summary>
|
||||
First,
|
||||
/// <summary>
|
||||
/// Display item in the first position.
|
||||
/// </summary>
|
||||
Last,
|
||||
/// <summary>
|
||||
/// Display an item prior to the selected, or specified item.
|
||||
/// </summary>
|
||||
Prior,
|
||||
/// <summary>
|
||||
/// Display an item after the selected, or specified item.
|
||||
/// </summary>
|
||||
After
|
||||
}
|
||||
}
|
||||
31
Others/Dragablz/Dragablz/MoveItemRequest.cs
Normal file
31
Others/Dragablz/Dragablz/MoveItemRequest.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
namespace Dragablz
|
||||
{
|
||||
public class MoveItemRequest
|
||||
{
|
||||
private readonly object _item;
|
||||
private readonly object _context;
|
||||
private readonly AddLocationHint _addLocationHint;
|
||||
|
||||
public MoveItemRequest(object item, object context, AddLocationHint addLocationHint)
|
||||
{
|
||||
_item = item;
|
||||
_context = context;
|
||||
_addLocationHint = addLocationHint;
|
||||
}
|
||||
|
||||
public object Item
|
||||
{
|
||||
get { return _item; }
|
||||
}
|
||||
|
||||
public object Context
|
||||
{
|
||||
get { return _context; }
|
||||
}
|
||||
|
||||
public AddLocationHint AddLocationHint
|
||||
{
|
||||
get { return _addLocationHint; }
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Others/Dragablz/Dragablz/NewTabHost.cs
Normal file
30
Others/Dragablz/Dragablz/NewTabHost.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class NewTabHost<TElement> : INewTabHost<TElement> where TElement : UIElement
|
||||
{
|
||||
private readonly TElement _container;
|
||||
private readonly TabablzControl _tabablzControl;
|
||||
|
||||
public NewTabHost(TElement container, TabablzControl tabablzControl)
|
||||
{
|
||||
if (container == null) throw new ArgumentNullException("container");
|
||||
if (tabablzControl == null) throw new ArgumentNullException("tabablzControl");
|
||||
|
||||
_container = container;
|
||||
_tabablzControl = tabablzControl;
|
||||
}
|
||||
|
||||
public TElement Container
|
||||
{
|
||||
get { return _container; }
|
||||
}
|
||||
|
||||
public TabablzControl TabablzControl
|
||||
{
|
||||
get { return _tabablzControl; }
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Others/Dragablz/Dragablz/OrderChangedEventArgs.cs
Normal file
28
Others/Dragablz/Dragablz/OrderChangedEventArgs.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public class OrderChangedEventArgs : EventArgs
|
||||
{
|
||||
private readonly object[] _previousOrder;
|
||||
private readonly object[] _newOrder;
|
||||
|
||||
public OrderChangedEventArgs(object[] previousOrder, object[] newOrder)
|
||||
{
|
||||
if (newOrder == null) throw new ArgumentNullException("newOrder");
|
||||
|
||||
_previousOrder = previousOrder;
|
||||
_newOrder = newOrder;
|
||||
}
|
||||
|
||||
public object[] PreviousOrder
|
||||
{
|
||||
get { return _previousOrder; }
|
||||
}
|
||||
|
||||
public object[] NewOrder
|
||||
{
|
||||
get { return _newOrder; }
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Others/Dragablz/Dragablz/PositionMonitor.cs
Normal file
31
Others/Dragablz/Dragablz/PositionMonitor.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Consumers can provide a position monitor to receive updates regarding the location of an item.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A <see cref="PositionMonitor"/> can be used to listen to changes
|
||||
/// instead of routed events, which can be easier in a MVVM scenario.
|
||||
/// </remarks>
|
||||
public class PositionMonitor
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when the X,Y coordinate of a <see cref="DragablzItem"/> changes.
|
||||
/// </summary>
|
||||
public event EventHandler<LocationChangedEventArgs> LocationChanged;
|
||||
|
||||
internal virtual void OnLocationChanged(LocationChangedEventArgs e)
|
||||
{
|
||||
if (e == null) throw new ArgumentNullException("e");
|
||||
|
||||
var handler = LocationChanged;
|
||||
handler?.Invoke(this, e);
|
||||
}
|
||||
|
||||
internal virtual void ItemsChanged() { }
|
||||
}
|
||||
}
|
||||
64
Others/Dragablz/Dragablz/Properties/AssemblyInfo.cs
Normal file
64
Others/Dragablz/Dragablz/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
|
||||
// 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("Dragablz")]
|
||||
[assembly: AssemblyDescription("Dragable tabable")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Mulholland Software Ltd/James Willock")]
|
||||
[assembly: AssemblyProduct("Dragablz")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: XmlnsPrefix("http://dragablz.net/winfx/xaml/dragablz", "dragablz")]
|
||||
[assembly: XmlnsDefinition("http://dragablz.net/winfx/xaml/dragablz",
|
||||
"Dragablz")]
|
||||
[assembly: XmlnsPrefix("http://dragablz.net/winfx/xaml/dockablz", "dockablz")]
|
||||
[assembly: XmlnsDefinition("http://dragablz.net/winfx/xaml/dockablz",
|
||||
"Dragablz.Dockablz")]
|
||||
|
||||
// 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)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> 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)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.0.4.0")]
|
||||
[assembly: AssemblyFileVersion("0.0.4.0")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Dragablz.Test")]
|
||||
63
Others/Dragablz/Dragablz/Properties/Resources.Designer.cs
generated
Normal file
63
Others/Dragablz/Dragablz/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Dragablz.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// 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()]
|
||||
internal 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() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Dragablz.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
Others/Dragablz/Dragablz/Properties/Resources.resx
Normal file
117
Others/Dragablz/Dragablz/Properties/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
26
Others/Dragablz/Dragablz/Properties/Settings.Designer.cs
generated
Normal file
26
Others/Dragablz/Dragablz/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Dragablz.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Others/Dragablz/Dragablz/Properties/Settings.settings
Normal file
7
Others/Dragablz/Dragablz/Properties/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Dragablz.Referenceless
|
||||
{
|
||||
internal sealed class AnonymousDisposable : ICancelable, IDisposable
|
||||
{
|
||||
private volatile Action _dispose;
|
||||
|
||||
public bool IsDisposed
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._dispose == null;
|
||||
}
|
||||
}
|
||||
|
||||
public AnonymousDisposable(Action dispose)
|
||||
{
|
||||
this._dispose = dispose;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var action = Interlocked.Exchange<Action>(ref _dispose, (Action)null);
|
||||
if (action == null)
|
||||
return;
|
||||
action();
|
||||
}
|
||||
}
|
||||
}
|
||||
21
Others/Dragablz/Dragablz/Referenceless/DefaultDisposable.cs
Normal file
21
Others/Dragablz/Dragablz/Referenceless/DefaultDisposable.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Referenceless
|
||||
{
|
||||
internal sealed class DefaultDisposable : IDisposable
|
||||
{
|
||||
public static readonly DefaultDisposable Instance = new DefaultDisposable();
|
||||
|
||||
static DefaultDisposable()
|
||||
{
|
||||
}
|
||||
|
||||
private DefaultDisposable()
|
||||
{
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Others/Dragablz/Dragablz/Referenceless/Disposable.cs
Normal file
23
Others/Dragablz/Dragablz/Referenceless/Disposable.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Referenceless
|
||||
{
|
||||
internal static class Disposable
|
||||
{
|
||||
public static IDisposable Empty
|
||||
{
|
||||
get
|
||||
{
|
||||
return (IDisposable)DefaultDisposable.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static IDisposable Create(Action dispose)
|
||||
{
|
||||
if (dispose == null)
|
||||
throw new ArgumentNullException("dispose");
|
||||
else
|
||||
return (IDisposable)new AnonymousDisposable(dispose);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Others/Dragablz/Dragablz/Referenceless/ICancelable.cs
Normal file
9
Others/Dragablz/Dragablz/Referenceless/ICancelable.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Dragablz.Referenceless
|
||||
{
|
||||
internal interface ICancelable : IDisposable
|
||||
{
|
||||
bool IsDisposed { get; }
|
||||
}
|
||||
}
|
||||
84
Others/Dragablz/Dragablz/Referenceless/SerialDisposable.cs
Normal file
84
Others/Dragablz/Dragablz/Referenceless/SerialDisposable.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dragablz.Referenceless
|
||||
{
|
||||
internal sealed class SerialDisposable : ICancelable, IDisposable
|
||||
{
|
||||
private readonly object _gate = new object();
|
||||
private IDisposable _current;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the object is disposed.
|
||||
///
|
||||
/// </summary>
|
||||
public bool IsDisposed
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (this._gate)
|
||||
return this._disposed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the underlying disposable.
|
||||
///
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// If the SerialDisposable has already been disposed, assignment to this property causes immediate disposal of the given disposable object. Assigning this property disposes the previous disposable object.
|
||||
/// </remarks>
|
||||
public IDisposable Disposable
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._current;
|
||||
}
|
||||
set
|
||||
{
|
||||
bool flag = false;
|
||||
IDisposable disposable = (IDisposable)null;
|
||||
lock (this._gate)
|
||||
{
|
||||
flag = this._disposed;
|
||||
if (!flag)
|
||||
{
|
||||
disposable = this._current;
|
||||
this._current = value;
|
||||
}
|
||||
}
|
||||
if (disposable != null)
|
||||
disposable.Dispose();
|
||||
if (!flag || value == null)
|
||||
return;
|
||||
value.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the underlying disposable as well as all future replacements.
|
||||
///
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
IDisposable disposable = (IDisposable)null;
|
||||
lock (this._gate)
|
||||
{
|
||||
if (!this._disposed)
|
||||
{
|
||||
this._disposed = true;
|
||||
disposable = this._current;
|
||||
this._current = (IDisposable)null;
|
||||
}
|
||||
}
|
||||
if (disposable == null)
|
||||
return;
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
309
Others/Dragablz/Dragablz/StackOrganiser.cs
Normal file
309
Others/Dragablz/Dragablz/StackOrganiser.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Animation;
|
||||
using Dragablz.Core;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
public abstract class StackOrganiser : IItemsOrganiser
|
||||
{
|
||||
private readonly Orientation _orientation;
|
||||
private readonly double _itemOffset;
|
||||
private readonly Func<DragablzItem, double> _getDesiredSize;
|
||||
private readonly Func<DragablzItem, double> _getLocation;
|
||||
private readonly DependencyProperty _canvasDependencyProperty;
|
||||
private readonly Action<DragablzItem, double> _setLocation;
|
||||
|
||||
private readonly Dictionary<DragablzItem, double> _activeStoryboardTargetLocations =
|
||||
new Dictionary<DragablzItem, double>();
|
||||
|
||||
protected StackOrganiser(Orientation orientation, double itemOffset = 0)
|
||||
{
|
||||
_orientation = orientation;
|
||||
_itemOffset = itemOffset;
|
||||
|
||||
switch (orientation)
|
||||
{
|
||||
case Orientation.Horizontal:
|
||||
_getDesiredSize = item => item.DesiredSize.Width;
|
||||
_getLocation = item => item.X;
|
||||
_setLocation = (item, coord) => item.SetCurrentValue(DragablzItem.XProperty, coord);
|
||||
_canvasDependencyProperty = Canvas.LeftProperty;
|
||||
break;
|
||||
case Orientation.Vertical:
|
||||
_getDesiredSize = item => item.DesiredSize.Height;
|
||||
_getLocation = item => item.Y;
|
||||
_setLocation = (item, coord) => item.SetCurrentValue(DragablzItem.YProperty, coord);
|
||||
_canvasDependencyProperty = Canvas.TopProperty;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("orientation");
|
||||
}
|
||||
}
|
||||
|
||||
#region LocationInfo
|
||||
|
||||
private class LocationInfo
|
||||
{
|
||||
private readonly DragablzItem _item;
|
||||
private readonly double _start;
|
||||
private readonly double _mid;
|
||||
private readonly double _end;
|
||||
|
||||
public LocationInfo(DragablzItem item, double start, double mid, double end)
|
||||
{
|
||||
_item = item;
|
||||
_start = start;
|
||||
_mid = mid;
|
||||
_end = end;
|
||||
}
|
||||
|
||||
public double Start
|
||||
{
|
||||
get { return _start; }
|
||||
}
|
||||
|
||||
public double Mid
|
||||
{
|
||||
get { return _mid; }
|
||||
}
|
||||
|
||||
public double End
|
||||
{
|
||||
get { return _end; }
|
||||
}
|
||||
|
||||
public DragablzItem Item
|
||||
{
|
||||
get { return _item; }
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public virtual Orientation Orientation
|
||||
{
|
||||
get { return _orientation; }
|
||||
}
|
||||
|
||||
public virtual void Organise(DragablzItemsControl requestor, Size measureBounds, IEnumerable<DragablzItem> items)
|
||||
{
|
||||
if (items == null) throw new ArgumentNullException("items");
|
||||
|
||||
OrganiseInternal(
|
||||
requestor,
|
||||
measureBounds,
|
||||
items.Select((di, idx) => new Tuple<int, DragablzItem>(idx, di))
|
||||
.OrderBy(tuple => tuple,
|
||||
MultiComparer<Tuple<int, DragablzItem>>.Ascending(tuple => _getLocation(tuple.Item2))
|
||||
.ThenAscending(tuple => tuple.Item1))
|
||||
.Select(tuple => tuple.Item2));
|
||||
}
|
||||
|
||||
public virtual void Organise(DragablzItemsControl requestor, Size measureBounds, IOrderedEnumerable<DragablzItem> items)
|
||||
{
|
||||
if (items == null) throw new ArgumentNullException("items");
|
||||
|
||||
OrganiseInternal(
|
||||
requestor,
|
||||
measureBounds,
|
||||
items);
|
||||
}
|
||||
|
||||
private void OrganiseInternal(DragablzItemsControl requestor, Size measureBounds,
|
||||
IEnumerable<DragablzItem> items)
|
||||
{
|
||||
var currentCoord = 0.0;
|
||||
var z = int.MaxValue;
|
||||
var logicalIndex = 0;
|
||||
foreach (var newItem in items)
|
||||
{
|
||||
Panel.SetZIndex(newItem, newItem.IsSelected ? int.MaxValue : --z);
|
||||
SetLocation(newItem, currentCoord);
|
||||
newItem.LogicalIndex = logicalIndex++;
|
||||
newItem.Measure(measureBounds);
|
||||
var desiredSize = _getDesiredSize(newItem);
|
||||
if (desiredSize == 0.0) desiredSize = 1.0; //no measure? create something to help sorting
|
||||
currentCoord += desiredSize + _itemOffset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual void OrganiseOnMouseDownWithin(DragablzItemsControl requestor, Size measureBounds,
|
||||
List<DragablzItem> siblingItems, DragablzItem dragablzItem)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private IDictionary<DragablzItem, LocationInfo> _siblingItemLocationOnDragStart;
|
||||
|
||||
public virtual void OrganiseOnDragStarted(DragablzItemsControl requestor, Size measureBounds,
|
||||
IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)
|
||||
{
|
||||
if (siblingItems == null) throw new ArgumentNullException("siblingItems");
|
||||
if (dragItem == null) throw new ArgumentNullException("dragItem");
|
||||
|
||||
_siblingItemLocationOnDragStart = siblingItems.Select(GetLocationInfo).ToDictionary(loc => loc.Item);
|
||||
}
|
||||
|
||||
public virtual void OrganiseOnDrag(DragablzItemsControl requestor, Size measureBounds,
|
||||
IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)
|
||||
{
|
||||
if (siblingItems == null) throw new ArgumentNullException("siblingItems");
|
||||
if (dragItem == null) throw new ArgumentNullException("dragItem");
|
||||
|
||||
var currentLocations = siblingItems
|
||||
.Select(GetLocationInfo)
|
||||
.Union(new[] {GetLocationInfo(dragItem)})
|
||||
.OrderBy(loc => loc.Item == dragItem ? loc.Start : _siblingItemLocationOnDragStart[loc.Item].Start);
|
||||
|
||||
var currentCoord = 0.0;
|
||||
var zIndex = int.MaxValue;
|
||||
foreach (var location in currentLocations)
|
||||
{
|
||||
if (!Equals(location.Item, dragItem))
|
||||
{
|
||||
SendToLocation(location.Item, currentCoord);
|
||||
Panel.SetZIndex(location.Item, --zIndex);
|
||||
}
|
||||
currentCoord += _getDesiredSize(location.Item) + _itemOffset;
|
||||
}
|
||||
Panel.SetZIndex(dragItem, int.MaxValue);
|
||||
}
|
||||
|
||||
public virtual void OrganiseOnDragCompleted(DragablzItemsControl requestor, Size measureBounds,
|
||||
IEnumerable<DragablzItem> siblingItems, DragablzItem dragItem)
|
||||
{
|
||||
if (siblingItems == null) throw new ArgumentNullException("siblingItems");
|
||||
var currentLocations = siblingItems
|
||||
.Select(GetLocationInfo)
|
||||
.Union(new[] {GetLocationInfo(dragItem)})
|
||||
.OrderBy(loc => loc.Item == dragItem ? loc.Start : _siblingItemLocationOnDragStart[loc.Item].Start);
|
||||
|
||||
var currentCoord = 0.0;
|
||||
var z = int.MaxValue;
|
||||
var logicalIndex = 0;
|
||||
foreach (var location in currentLocations)
|
||||
{
|
||||
SetLocation(location.Item, currentCoord);
|
||||
currentCoord += _getDesiredSize(location.Item) + _itemOffset;
|
||||
Panel.SetZIndex(location.Item, --z);
|
||||
location.Item.LogicalIndex = logicalIndex++;
|
||||
}
|
||||
Panel.SetZIndex(dragItem, int.MaxValue);
|
||||
}
|
||||
|
||||
public virtual Point ConstrainLocation(DragablzItemsControl requestor, Size measureBounds, Point itemCurrentLocation,
|
||||
Size itemCurrentSize, Point itemDesiredLocation, Size itemDesiredSize)
|
||||
{
|
||||
var fixedItems = requestor.FixedItemCount;
|
||||
var lowerBound = fixedItems == 0
|
||||
? -1d
|
||||
: GetLocationInfo(requestor.DragablzItems()
|
||||
.Take(fixedItems)
|
||||
.Last()).End + _itemOffset - 1;
|
||||
|
||||
return new Point(
|
||||
_orientation == Orientation.Vertical
|
||||
? 0
|
||||
: Math.Min(Math.Max(lowerBound, itemDesiredLocation.X), (measureBounds.Width) + 1),
|
||||
_orientation == Orientation.Horizontal
|
||||
? 0
|
||||
: Math.Min(Math.Max(lowerBound, itemDesiredLocation.Y), (measureBounds.Height) + 1)
|
||||
);
|
||||
}
|
||||
|
||||
public virtual Size Measure(DragablzItemsControl requestor, Size availableSize, IEnumerable<DragablzItem> items)
|
||||
{
|
||||
if (items == null) throw new ArgumentNullException("items");
|
||||
|
||||
var size = new Size(double.PositiveInfinity, double.PositiveInfinity);
|
||||
|
||||
double width = 0, height = 0;
|
||||
var isFirst = true;
|
||||
foreach (var dragablzItem in items)
|
||||
{
|
||||
dragablzItem.Measure(size);
|
||||
if (_orientation == Orientation.Horizontal)
|
||||
{
|
||||
width += !dragablzItem.IsLoaded ? dragablzItem.DesiredSize.Width : dragablzItem.ActualWidth;
|
||||
if (!isFirst)
|
||||
width += _itemOffset;
|
||||
height = Math.Max(height,
|
||||
!dragablzItem.IsLoaded ? dragablzItem.DesiredSize.Height : dragablzItem.ActualHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
width = Math.Max(width,
|
||||
!dragablzItem.IsLoaded ? dragablzItem.DesiredSize.Width : dragablzItem.ActualWidth);
|
||||
height += !dragablzItem.IsLoaded ? dragablzItem.DesiredSize.Height : dragablzItem.ActualHeight;
|
||||
if (!isFirst)
|
||||
height += _itemOffset;
|
||||
}
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
return new Size(Math.Max(width, 0), Math.Max(height, 0));
|
||||
}
|
||||
|
||||
public virtual IEnumerable<DragablzItem> Sort(IEnumerable<DragablzItem> items)
|
||||
{
|
||||
if (items == null) throw new ArgumentNullException("items");
|
||||
|
||||
return items.OrderBy(i => GetLocationInfo(i).Start);
|
||||
}
|
||||
|
||||
private void SetLocation(DragablzItem dragablzItem, double location)
|
||||
{
|
||||
_setLocation(dragablzItem, location);
|
||||
}
|
||||
|
||||
private void SendToLocation(DragablzItem dragablzItem, double location)
|
||||
{
|
||||
double activeTarget;
|
||||
if (Math.Abs(_getLocation(dragablzItem) - location) < 1.0
|
||||
||
|
||||
_activeStoryboardTargetLocations.TryGetValue(dragablzItem, out activeTarget)
|
||||
&& Math.Abs(activeTarget - location) < 1.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_activeStoryboardTargetLocations[dragablzItem] = location;
|
||||
|
||||
var storyboard = new Storyboard {FillBehavior = FillBehavior.Stop};
|
||||
storyboard.WhenComplete(sb =>
|
||||
{
|
||||
_setLocation(dragablzItem, location);
|
||||
sb.Remove(dragablzItem);
|
||||
_activeStoryboardTargetLocations.Remove(dragablzItem);
|
||||
});
|
||||
|
||||
var timeline = new DoubleAnimationUsingKeyFrames();
|
||||
timeline.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(_canvasDependencyProperty));
|
||||
timeline.KeyFrames.Add(
|
||||
new EasingDoubleKeyFrame(location, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200)))
|
||||
{
|
||||
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut }
|
||||
});
|
||||
storyboard.Children.Add(timeline);
|
||||
storyboard.Begin(dragablzItem, true);
|
||||
}
|
||||
|
||||
private LocationInfo GetLocationInfo(DragablzItem item)
|
||||
{
|
||||
var size = _getDesiredSize(item);
|
||||
double startLocation;
|
||||
if (!_activeStoryboardTargetLocations.TryGetValue(item, out startLocation))
|
||||
startLocation = _getLocation(item);
|
||||
var midLocation = startLocation + size / 2;
|
||||
var endLocation = startLocation + size;
|
||||
|
||||
return new LocationInfo(item, startLocation, midLocation, endLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Others/Dragablz/Dragablz/StackPositionMonitor.cs
Normal file
46
Others/Dragablz/Dragablz/StackPositionMonitor.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// A linear position monitor simplifies the montoring of the order of items, where they are laid out
|
||||
/// horizontally or vertically (typically via a <see cref="StackOrganiser"/>.
|
||||
/// </summary>
|
||||
public abstract class StackPositionMonitor : PositionMonitor
|
||||
{
|
||||
private readonly Func<DragablzItem, double> _getLocation;
|
||||
|
||||
protected StackPositionMonitor(Orientation orientation)
|
||||
{
|
||||
switch (orientation)
|
||||
{
|
||||
case Orientation.Horizontal:
|
||||
_getLocation = item => item.X;
|
||||
break;
|
||||
case Orientation.Vertical:
|
||||
_getLocation = item => item.Y;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("orientation");
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<OrderChangedEventArgs> OrderChanged;
|
||||
|
||||
internal virtual void OnOrderChanged(OrderChangedEventArgs e)
|
||||
{
|
||||
var handler = OrderChanged;
|
||||
if (handler != null) handler(this, e);
|
||||
}
|
||||
|
||||
internal IEnumerable<DragablzItem> Sort(IEnumerable<DragablzItem> items)
|
||||
{
|
||||
if (items == null) throw new ArgumentNullException("items");
|
||||
|
||||
return items.OrderBy(i => _getLocation(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
41
Others/Dragablz/Dragablz/StoryboardCompletionListener.cs
Normal file
41
Others/Dragablz/Dragablz/StoryboardCompletionListener.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
internal class StoryboardCompletionListener
|
||||
{
|
||||
private readonly Storyboard _storyboard;
|
||||
private readonly Action<Storyboard> _continuation;
|
||||
|
||||
public StoryboardCompletionListener(Storyboard storyboard, Action<Storyboard> continuation)
|
||||
{
|
||||
if (storyboard == null) throw new ArgumentNullException("storyboard");
|
||||
if (continuation == null) throw new ArgumentNullException("continuation");
|
||||
|
||||
_storyboard = storyboard;
|
||||
_continuation = continuation;
|
||||
|
||||
_storyboard.Completed += StoryboardOnCompleted;
|
||||
}
|
||||
|
||||
private void StoryboardOnCompleted(object sender, EventArgs eventArgs)
|
||||
{
|
||||
_storyboard.Completed -= StoryboardOnCompleted;
|
||||
_continuation(_storyboard);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class StoryboardCompletionListenerExtension
|
||||
{
|
||||
private static readonly IDictionary<Storyboard, Action<Storyboard>> ContinuationIndex = new Dictionary<Storyboard, Action<Storyboard>>();
|
||||
|
||||
public static void WhenComplete(this Storyboard storyboard, Action<Storyboard> continuation)
|
||||
{
|
||||
// ReSharper disable once ObjectCreationAsStatement
|
||||
new StoryboardCompletionListener(storyboard, continuation);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Others/Dragablz/Dragablz/TabEmptiedResponse.cs
Normal file
14
Others/Dragablz/Dragablz/TabEmptiedResponse.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Dragablz
|
||||
{
|
||||
public enum TabEmptiedResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Allow the Window to be closed automatically.
|
||||
/// </summary>
|
||||
CloseWindowOrLayoutBranch,
|
||||
/// <summary>
|
||||
/// The window will not be closed by the <see cref="TabablzControl"/>, probably meaning the implementor will close the window manually
|
||||
/// </summary>
|
||||
DoNothing
|
||||
}
|
||||
}
|
||||
1538
Others/Dragablz/Dragablz/TabablzControl.cs
Normal file
1538
Others/Dragablz/Dragablz/TabablzControl.cs
Normal file
File diff suppressed because it is too large
Load Diff
50
Others/Dragablz/Dragablz/TabablzHeaderSizeConverter.cs
Normal file
50
Others/Dragablz/Dragablz/TabablzHeaderSizeConverter.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a little help for sizing the header panel in the tab control
|
||||
/// </summary>
|
||||
public class TabablzHeaderSizeConverter : IMultiValueConverter
|
||||
{
|
||||
public Orientation Orientation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The first value should be the total size available size, typically the parent control size.
|
||||
/// The second value should be from <see cref="DragablzItemsControl.ItemsPresenterWidthProperty"/> or (height equivalent)
|
||||
/// All additional values should be siblings sizes (width or height) which will affect (reduce) the available size.
|
||||
/// </summary>
|
||||
/// <param name="values"></param>
|
||||
/// <param name="targetType"></param>
|
||||
/// <param name="parameter"></param>
|
||||
/// <param name="culture"></param>
|
||||
/// <returns></returns>
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (values == null) throw new ArgumentNullException("values");
|
||||
|
||||
if (values.Length < 2) return Binding.DoNothing;
|
||||
|
||||
var val = values
|
||||
.Skip(2)
|
||||
.OfType<double>()
|
||||
.Where(d => !double.IsInfinity(d) && !double.IsNaN(d))
|
||||
.Aggregate(values.OfType<double>().First(), (current, diminish) => current - diminish);
|
||||
|
||||
var maxWidth = values.Take(2).OfType<double>().Min();
|
||||
|
||||
return Math.Min(Math.Max(val, 0), maxWidth);
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Others/Dragablz/Dragablz/TabablzItemStyleSelector.cs
Normal file
27
Others/Dragablz/Dragablz/TabablzItemStyleSelector.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects style to apply to a <see cref="DragablzItem"/> according to the tab item content itself.
|
||||
/// </summary>
|
||||
public class TabablzItemStyleSelector : StyleSelector
|
||||
{
|
||||
private readonly Style _defaultHeaderItemStyle;
|
||||
private readonly Style _customHeaderItemStyle;
|
||||
|
||||
public TabablzItemStyleSelector(Style defaultHeaderItemStyle, Style customHeaderItemStyle)
|
||||
{
|
||||
_defaultHeaderItemStyle = defaultHeaderItemStyle;
|
||||
_customHeaderItemStyle = customHeaderItemStyle;
|
||||
}
|
||||
|
||||
public override Style SelectStyle(object item, DependencyObject container)
|
||||
{
|
||||
if (item is TabItem) return _defaultHeaderItemStyle;
|
||||
|
||||
return _customHeaderItemStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Dragablz.Themes
|
||||
{
|
||||
public class BrushToRadialGradientBrushConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var solidColorBrush = value as SolidColorBrush;
|
||||
if (solidColorBrush == null) return Binding.DoNothing;
|
||||
|
||||
return new RadialGradientBrush(solidColorBrush.Color, Colors.Transparent)
|
||||
{
|
||||
Center = new Point(.5, .5),
|
||||
GradientOrigin = new Point(.5, .5),
|
||||
RadiusX = .5,
|
||||
RadiusY = .5,
|
||||
Opacity = .39
|
||||
};
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Binding.DoNothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Others/Dragablz/Dragablz/Themes/Dockablz.xaml
Normal file
8
Others/Dragablz/Dragablz/Themes/Dockablz.xaml
Normal file
@@ -0,0 +1,8 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:dockablz="clr-namespace:Dragablz.Dockablz"
|
||||
xmlns:converters="clr-namespace:Dragablz.Converters">
|
||||
|
||||
|
||||
|
||||
</ResourceDictionary>
|
||||
1896
Others/Dragablz/Dragablz/Themes/Generic.xaml
Normal file
1896
Others/Dragablz/Dragablz/Themes/Generic.xaml
Normal file
File diff suppressed because it is too large
Load Diff
443
Others/Dragablz/Dragablz/Themes/MahApps.xaml
Normal file
443
Others/Dragablz/Dragablz/Themes/MahApps.xaml
Normal file
@@ -0,0 +1,443 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:dragablz="clr-namespace:Dragablz"
|
||||
xmlns:dockablz="clr-namespace:Dragablz.Dockablz"
|
||||
xmlns:converters="clr-namespace:Dragablz.Converters">
|
||||
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<converters:EqualityToVisibilityConverter x:Key="EqualityToVisibilityConverter" />
|
||||
<converters:BooleanAndToVisibilityConverter x:Key="BooleanAndToVisibilityConverter" />
|
||||
<converters:EqualityToBooleanConverter x:Key="EqualityToBooleanConverter" />
|
||||
<converters:ShowDefaultCloseButtonConverter x:Key="ShowDefaultCloseButtonConverter" />
|
||||
|
||||
<Style x:Key="MahAppsFocusVisual">
|
||||
<Setter Property="Control.Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type Thumb}" x:Key="MahAppsInvisibleThumbStyle">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid Background="{TemplateBinding Background}" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type Button}" x:Key="MahAppsMenuCommandButtonStyle">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource MahAppsFocusVisual}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Padding" Value="1"/>
|
||||
<Setter Property="Opacity" Value=".8"/>
|
||||
<Setter Property="Width" Value="24"/>
|
||||
<Setter Property="Height" Value="20"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
|
||||
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsDefaulted" Value="true">
|
||||
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Opacity" TargetName="border" Value=".5"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background" Value="{x:Static dragablz:DragablzColors.WindowGlassBrush}"/>
|
||||
<Setter Property="Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="true">
|
||||
<Setter Property="Opacity" Value="1"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type Button}" x:Key="MahAppsCloseItemCommandButtonStyle" BasedOn="{StaticResource MahAppsMenuCommandButtonStyle}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid>
|
||||
<Ellipse Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}"
|
||||
Fill="{TemplateBinding Background}"/>
|
||||
<Path x:Name="Path"
|
||||
Data="M0.5,71 L70,0.5 M0.5,1 L70,70.5"
|
||||
Width="6" Height="6"
|
||||
Stretch="Uniform"
|
||||
Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="1.5"
|
||||
StrokeStartLineCap="Square"
|
||||
StrokeEndLineCap="Square"
|
||||
SnapsToDevicePixels="True" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<SolidColorBrush Color="{x:Static SystemColors.ActiveBorderColor}" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Width" Value="12" />
|
||||
<Setter Property="Height" Value="12" />
|
||||
<Setter Property="Margin" Value="4 0 2 0" />
|
||||
<Setter Property="Opacity" Value=".75" />
|
||||
<Setter Property="Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Opacity" Value="1"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type Button}" x:Key="AddItemCommandButtonStyle" BasedOn="{StaticResource MahAppsMenuCommandButtonStyle}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid>
|
||||
<Ellipse Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}"
|
||||
Fill="{TemplateBinding Background}"/>
|
||||
<Path x:Name="Path"
|
||||
Data="M38,6L38.0003451911513,70.6666666666666 M70.3336667356886,38L5.50002465137562,38"
|
||||
Width="6" Height="6"
|
||||
Stretch="Uniform"
|
||||
Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="1.5"
|
||||
StrokeStartLineCap="Square"
|
||||
StrokeEndLineCap="Square"
|
||||
SnapsToDevicePixels="True" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Background">
|
||||
<Setter.Value>
|
||||
<SolidColorBrush Color="{x:Static SystemColors.ActiveBorderColor}" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Width" Value="12" />
|
||||
<Setter Property="Height" Value="12" />
|
||||
<Setter Property="Margin" Value="4 0 2 0" />
|
||||
<Setter Property="Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background" Value="{x:Static dragablz:DragablzColors.WindowGlassBrush}"/>
|
||||
<Setter Property="Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="true">
|
||||
<Setter Property="Opacity" Value="1"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MahAppsTrapezoidDragableTabItemStyle" TargetType="{x:Type dragablz:DragablzItem}">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource MahAppsFocusVisual}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource BlackBrush}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Margin" Value="0 0 0 0"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type dragablz:DragablzItem}">
|
||||
<Grid x:Name="templateRoot" SnapsToDevicePixels="true" Margin="0 1 0 -1">
|
||||
<dragablz:Trapezoid x:Name="Trapezoid"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
Background="{TemplateBinding Background}"
|
||||
LongBasePenBrush="{TemplateBinding Background}"
|
||||
PenThickness="0"
|
||||
Margin="0 0 0 0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
|
||||
Margin="{TemplateBinding Control.Padding }"
|
||||
x:Name="contentPresenter" />
|
||||
<Thumb Grid.Column="0" HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
|
||||
x:Name="PART_Thumb"
|
||||
Style="{StaticResource MahAppsInvisibleThumbStyle}" />
|
||||
<Button Grid.Column="1"
|
||||
Style="{StaticResource MahAppsCloseItemCommandButtonStyle}"
|
||||
Command="{x:Static dragablz:TabablzControl.CloseItemCommand}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}">
|
||||
<Button.Visibility>
|
||||
<MultiBinding Converter="{StaticResource ShowDefaultCloseButtonConverter}">
|
||||
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}" Path="ShowDefaultCloseButton" />
|
||||
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}" Path="FixedHeaderCount" />
|
||||
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="LogicalIndex" />
|
||||
</MultiBinding>
|
||||
</Button.Visibility>
|
||||
</Button>
|
||||
</Grid>
|
||||
</dragablz:Trapezoid>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="dragablz:TabablzControl.IsWrappingTabItem" Value="True">
|
||||
<Setter TargetName="contentPresenter" Property="Content" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Header}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource AccentColorBrush3}" TargetName="Trapezoid"/>
|
||||
<Setter Property="LongBasePenBrush" Value="{DynamicResource AccentColorBrush3}" TargetName="Trapezoid"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource AccentColorBrush}" TargetName="Trapezoid"/>
|
||||
<Setter Property="LongBasePenBrush" Value="{DynamicResource AccentColorBrush}" TargetName="Trapezoid"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource WhiteBrush}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MahAppsMetroBaseWindowButtonStyle" TargetType="{x:Type Button}">
|
||||
<Setter Property="Background" Value="{DynamicResource TransparentWhiteBrush}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource WhiteColorBrush}" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="Padding" Value="1" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Grid Background="{TemplateBinding Background}">
|
||||
<ContentPresenter x:Name="contentPresenter"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
RecognizesAccessKey="True"
|
||||
Opacity="0.75" />
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="contentPresenter" Property="Opacity" Value="1" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="False">
|
||||
<Setter TargetName="contentPresenter" Property="Opacity" Value=".5" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource SemiTransparentWhiteBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource HighlightBrush}" />
|
||||
<Setter Property="Foreground" Value="White" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Foreground" Value="#ADADAD" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MahAppsToolWindowButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource MahAppsMetroBaseWindowButtonStyle}">
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter Property="Width" Value="30" />
|
||||
<Setter Property="MaxHeight" Value="30" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type dragablz:HeaderedDragablzItem}" x:Key="MahAppsToolDragablzItemStyle">
|
||||
<Style.Setters>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AccentColorBrush2}" />
|
||||
<Setter Property="BorderThickness" Value="4" />
|
||||
<Setter Property="Canvas.Left" Value="{Binding X, RelativeSource={RelativeSource Self}}" />
|
||||
<Setter Property="Canvas.Top" Value="{Binding Y, RelativeSource={RelativeSource Self}}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type dragablz:HeaderedDragablzItem}">
|
||||
<Grid Margin="{TemplateBinding Margin}">
|
||||
<Border Background="{DynamicResource WhiteColorBrush}">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="10" ShadowDepth="5" Direction="315" Color="{DynamicResource AccentColor2}" Opacity=".5" />
|
||||
</Border.Effect>
|
||||
</Border>
|
||||
<Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="{TemplateBinding Control.Padding}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" SnapsToDevicePixels="True">
|
||||
<DockPanel>
|
||||
<Grid DockPanel.Dock="Top" Background="{TemplateBinding BorderBrush}">
|
||||
<Thumb HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch" x:Name="PART_Thumb"
|
||||
Style="{StaticResource MahAppsInvisibleThumbStyle}"
|
||||
/>
|
||||
<DockPanel Margin="{TemplateBinding Control.Padding }">
|
||||
<Button DockPanel.Dock="Right"
|
||||
Command="{x:Static dockablz:Layout.CloseFloatingItem}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Margin="1 0 0 0"
|
||||
Style="{DynamicResource MahAppsToolWindowButtonStyle}"
|
||||
Focusable="False"
|
||||
RenderOptions.EdgeMode="Aliased"
|
||||
>
|
||||
<Path Data="M 10.009,1.704 L 8.331,0.026 5.03,3.327 1.703,0 0,1.704 3.326,5.031 0.025,8.332 1.703,10.009 5.004,6.708 8.305,10.009 10.009,8.305 6.708,5.005"
|
||||
SnapsToDevicePixels="True"
|
||||
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" />
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right"
|
||||
Command="{x:Static dockablz:Layout.UnfloatItemCommand}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Margin="1 0 0 0"
|
||||
Style="{DynamicResource MahAppsToolWindowButtonStyle}"
|
||||
>
|
||||
<Path Width="12" Height="12" Stretch="UniformToFill" Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" Data="M 19 19 H 5 V 5 h 7 V 3 H 5 C 3.89 3 3 3.9 3 5 v 14 c 0 1.1 0.89 2 2 2 h 14 c 1.1 0 2 -0.9 2 -2 v -7 h -2 v 7 z M 14 3 v 2 h 3.59 L 7.76 14.83 9.17 16.24 19 6.41 V 10 h 2 V 3 h -7 z" />
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right"
|
||||
Command="{x:Static dockablz:Layout.MaximiseFloatingItem}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Margin="1 0 0 0"
|
||||
Style="{DynamicResource MahAppsToolWindowButtonStyle}"
|
||||
>
|
||||
<Path Width="10"
|
||||
Height="10"
|
||||
Data="F1M0,0L0,9 9,9 9,0 0,0 0,3 8,3 8,8 1,8 1,3z"
|
||||
SnapsToDevicePixels="True"
|
||||
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" />
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right"
|
||||
Command="{x:Static dockablz:Layout.RestoreFloatingItem}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Margin="1 0 0 0"
|
||||
Style="{DynamicResource MahAppsToolWindowButtonStyle}"
|
||||
>
|
||||
<Path Width="10"
|
||||
Height="10"
|
||||
Data="F1M0,10L0,3 3,3 3,0 10,0 10,2 4,2 4,3 7,3 7,6 6,6 6,5 1,5 1,10z M1,10L7,10 7,7 10,7 10,2 9,2 9,6 6,6 6,9 1,9z"
|
||||
SnapsToDevicePixels="True"
|
||||
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" />
|
||||
</Button>
|
||||
<ContentPresenter Content="{TemplateBinding HeaderContent}"
|
||||
ContentTemplate="{TemplateBinding HeaderContentTemplate}"
|
||||
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
|
||||
ContentTemplateSelector="{TemplateBinding HeaderContentTemplateSelector}"
|
||||
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
|
||||
IsHitTestVisible="False"
|
||||
/>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
|
||||
Margin="{TemplateBinding Control.Padding }"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
<Thumb Style="{StaticResource MahAppsInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Left}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="Left"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Stretch"
|
||||
Cursor="SizeWE"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MahAppsInvisibleThumbStyle}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Top}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="Top"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Cursor="SizeNS"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MahAppsInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="Right"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch"
|
||||
Cursor="SizeWE"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MahAppsInvisibleThumbStyle}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="Bottom"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Bottom"
|
||||
Cursor="SizeNS"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MahAppsInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="TopLeft"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Cursor="SizeNWSE"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MahAppsInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="TopRight"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Cursor="SizeNESW"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MahAppsInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="BottomRight"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Cursor="SizeNWSE"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MahAppsInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="BottomLeft"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
Cursor="SizeNESW"
|
||||
/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style.Setters>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="dockablz:Layout.FloatingItemState" Value="Maximized">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="Canvas.Left" Value="0" />
|
||||
<Setter Property="Canvas.Top" Value="0" />
|
||||
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualWidth}" />
|
||||
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualHeight}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type dragablz:TabablzControl}" x:Key="MahAppsTabablzControlStyle">
|
||||
<Setter Property="Background" Value="{DynamicResource WhiteColorBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AccentColorBrush}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource BlackColorBrush}"/>
|
||||
<Setter Property="AdjacentHeaderItemOffset" Value="-12" />
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource MahAppsTrapezoidDragableTabItemStyle}" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
803
Others/Dragablz/Dragablz/Themes/MaterialDesign.xaml
Normal file
803
Others/Dragablz/Dragablz/Themes/MaterialDesign.xaml
Normal file
@@ -0,0 +1,803 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:dragablz="clr-namespace:Dragablz"
|
||||
xmlns:dockablz="clr-namespace:Dragablz.Dockablz"
|
||||
xmlns:converters="clr-namespace:Dragablz.Converters"
|
||||
xmlns:local="clr-namespace:Dragablz.Themes">
|
||||
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<converters:EqualityToVisibilityConverter x:Key="EqualityToVisibilityConverter" />
|
||||
<converters:BooleanAndToVisibilityConverter x:Key="BooleanAndToVisibilityConverter" />
|
||||
<converters:EqualityToBooleanConverter x:Key="EqualityToBooleanConverter" />
|
||||
<converters:ShowDefaultCloseButtonConverter x:Key="ShowDefaultCloseButtonConverter" />
|
||||
<local:BrushToRadialGradientBrushConverter x:Key="BrushToRadialGradientBrushConverter" />
|
||||
|
||||
<Style x:Key="MaterialDesignFocusVisual">
|
||||
<Setter Property="Control.Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type Thumb}" x:Key="MaterialDesignInvisibleThumbStyle">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid Background="{TemplateBinding Background}" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type Button}" x:Key="MaterialDesignMenuCommandButtonStyle">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource MaterialDesignFocusVisual}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Padding" Value="1"/>
|
||||
<Setter Property="Opacity" Value=".8"/>
|
||||
<Setter Property="Width" Value="24"/>
|
||||
<Setter Property="Height" Value="20"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
|
||||
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsDefaulted" Value="true">
|
||||
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Opacity" TargetName="border" Value=".5"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background" Value="{x:Static dragablz:DragablzColors.WindowGlassBrush}"/>
|
||||
<Setter Property="Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="true">
|
||||
<Setter Property="Opacity" Value="1"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type Button}" x:Key="MaterialDesignCloseItemCommandButtonStyle" BasedOn="{StaticResource MaterialDesignMenuCommandButtonStyle}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid>
|
||||
<Ellipse Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}"
|
||||
Fill="{TemplateBinding Background}"/>
|
||||
<Path x:Name="Path"
|
||||
Data="M0.5,71 L70,0.5 M0.5,1 L70,70.5"
|
||||
Width="6" Height="6"
|
||||
Stretch="Uniform"
|
||||
Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="1.5"
|
||||
StrokeStartLineCap="Square"
|
||||
StrokeEndLineCap="Square"
|
||||
SnapsToDevicePixels="True" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueMidBrush}" />
|
||||
<Setter Property="Width" Value="12" />
|
||||
<Setter Property="Height" Value="12" />
|
||||
<Setter Property="Margin" Value="4 0 2 0" />
|
||||
<Setter Property="Opacity" Value=".75" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidForegroundBrush}" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueLightForegroundBrush}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type Button}" x:Key="MaterialDesignAddItemCommandButtonStyle" BasedOn="{StaticResource MaterialDesignMenuCommandButtonStyle}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid>
|
||||
<Ellipse Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}"
|
||||
Fill="{TemplateBinding Background}"/>
|
||||
<Path x:Name="Path"
|
||||
Data="M38,6L38.0003451911513,70.6666666666666 M70.3336667356886,38L5.50002465137562,38"
|
||||
Width="6" Height="6"
|
||||
Stretch="Uniform"
|
||||
Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="1.5"
|
||||
StrokeStartLineCap="Square"
|
||||
StrokeEndLineCap="Square"
|
||||
SnapsToDevicePixels="True" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueMidBrush}" />
|
||||
<Setter Property="Width" Value="12" />
|
||||
<Setter Property="Height" Value="12" />
|
||||
<Setter Property="Margin" Value="4 0 2 0" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidForegroundBrush}" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueLightForegroundBrush}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
|
||||
|
||||
<Style x:Key="MaterialDesignDragableTabItemStyle" TargetType="{x:Type dragablz:DragablzItem}">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource MaterialDesignFocusVisual}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidForegroundBrush}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="local:MaterialDesignAssist.IndicatorBrush" Value="{DynamicResource SecondaryAccentBrush}" />
|
||||
<Setter Property="Margin" Value="0 0 0 0"/>
|
||||
<Setter Property="Padding" Value="8"/>
|
||||
<Setter Property="MinWidth" Value="80" />
|
||||
<Setter Property="Height" Value="40" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="TextBlock.FontWeight" Value="Medium" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type dragablz:DragablzItem}">
|
||||
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}"
|
||||
Background="{TemplateBinding Background}"
|
||||
Margin="0 0 0 0">
|
||||
<local:Ripple HorizontalContentAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
|
||||
x:Name="contentPresenter"
|
||||
Margin="{TemplateBinding Control.Padding}"
|
||||
Opacity=".87"/>
|
||||
<Thumb Grid.Column="0" HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
|
||||
x:Name="PART_Thumb"
|
||||
Style="{StaticResource MaterialDesignInvisibleThumbStyle}" />
|
||||
<Button Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignCloseItemCommandButtonStyle}"
|
||||
Command="{x:Static dragablz:TabablzControl.CloseItemCommand}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}">
|
||||
<Button.Visibility>
|
||||
<MultiBinding Converter="{StaticResource ShowDefaultCloseButtonConverter}">
|
||||
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}" Path="ShowDefaultCloseButton" />
|
||||
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}" Path="FixedHeaderCount" />
|
||||
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="LogicalIndex" />
|
||||
</MultiBinding>
|
||||
</Button.Visibility>
|
||||
</Button>
|
||||
</Grid>
|
||||
</local:Ripple>
|
||||
</Border>
|
||||
<Border x:Name="SelectionHighlightBorder" Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:MaterialDesignAssist.IndicatorBrush)}" Height="2"
|
||||
Grid.Row="1"
|
||||
Visibility="Hidden"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="dragablz:TabablzControl.IsWrappingTabItem" Value="True">
|
||||
<Setter TargetName="contentPresenter" Property="Content" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Header}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="contentPresenter" Property="Opacity" Value="1"/>
|
||||
<Setter TargetName="SelectionHighlightBorder" Property="Visibility" Value="Visible" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MaterialDesignDragableTabItemVerticalStyle" TargetType="{x:Type dragablz:DragablzItem}">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource MaterialDesignFocusVisual}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidForegroundBrush}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Margin" Value="0 0 0 0"/>
|
||||
<Setter Property="Width" Value="80" />
|
||||
<Setter Property="MinHeight" Value="40" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="TextBlock.FontWeight" Value="Medium" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type dragablz:DragablzItem}">
|
||||
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}"
|
||||
Background="{TemplateBinding Background}"
|
||||
Margin="0 0 0 0">
|
||||
<local:Ripple HorizontalContentAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
|
||||
x:Name="contentPresenter"
|
||||
RenderTransformOrigin=".5, .5">
|
||||
<ContentPresenter.RenderTransform>
|
||||
<RotateTransform Angle="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(dragablz:DragablzItem.ContentRotateTransformAngle)}" />
|
||||
</ContentPresenter.RenderTransform>
|
||||
</ContentPresenter>
|
||||
<Thumb Grid.Row="0" HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch"
|
||||
x:Name="PART_Thumb"
|
||||
Style="{StaticResource MaterialDesignInvisibleThumbStyle}" />
|
||||
<Button Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignCloseItemCommandButtonStyle}"
|
||||
Command="{x:Static dragablz:TabablzControl.CloseItemCommand}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}">
|
||||
<Button.Visibility>
|
||||
<MultiBinding Converter="{StaticResource ShowDefaultCloseButtonConverter}">
|
||||
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}" Path="ShowDefaultCloseButton" />
|
||||
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type dragablz:TabablzControl}}" Path="FixedHeaderCount" />
|
||||
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="LogicalIndex" />
|
||||
</MultiBinding>
|
||||
</Button.Visibility>
|
||||
</Button>
|
||||
</Grid>
|
||||
</local:Ripple>
|
||||
</Border>
|
||||
<Border x:Name="SelectionHighlightBorder" Background="{DynamicResource SecondaryAccentBrush}" Width="2"
|
||||
Grid.Column="1"
|
||||
Visibility="Hidden"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="dragablz:TabablzControl.IsWrappingTabItem" Value="True">
|
||||
<Setter TargetName="contentPresenter" Property="Content" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Header}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="contentPresenter" Property="Opacity" Value="1"/>
|
||||
<Setter TargetName="SelectionHighlightBorder" Property="Visibility" Value="Visible" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MaterialDesignMetroBaseWindowButtonStyle" TargetType="{x:Type Button}">
|
||||
<Setter Property="Background" Value="{DynamicResource TransparentWhiteBrush}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource WhiteColorBrush}" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="Padding" Value="1" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Grid Background="{TemplateBinding Background}">
|
||||
<ContentPresenter x:Name="contentPresenter"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
RecognizesAccessKey="True"
|
||||
Opacity="0.75" />
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="contentPresenter" Property="Opacity" Value="1" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="False">
|
||||
<Setter TargetName="contentPresenter" Property="Opacity" Value=".5" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource SemiTransparentWhiteBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource HighlightBrush}" />
|
||||
<Setter Property="Foreground" Value="White" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Foreground" Value="#ADADAD" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MaterialDesignToolWindowButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignMetroBaseWindowButtonStyle}">
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter Property="Width" Value="30" />
|
||||
<Setter Property="MaxHeight" Value="30" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type dragablz:HeaderedDragablzItem}" x:Key="MaterialDesignToolDragablzItemStyle">
|
||||
<Style.Setters>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AccentColorBrush2}" />
|
||||
<Setter Property="BorderThickness" Value="4" />
|
||||
<Setter Property="Canvas.Left" Value="{Binding X, RelativeSource={RelativeSource Self}}" />
|
||||
<Setter Property="Canvas.Top" Value="{Binding Y, RelativeSource={RelativeSource Self}}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type dragablz:HeaderedDragablzItem}">
|
||||
<Grid Margin="{TemplateBinding Margin}">
|
||||
<Border Background="{DynamicResource WhiteColorBrush}">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="10" ShadowDepth="5" Direction="315" Color="{DynamicResource AccentColor2}" Opacity=".5" />
|
||||
</Border.Effect>
|
||||
</Border>
|
||||
<Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="{TemplateBinding Control.Padding}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" SnapsToDevicePixels="True">
|
||||
<DockPanel>
|
||||
<Grid DockPanel.Dock="Top" Background="{TemplateBinding BorderBrush}">
|
||||
<Thumb HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch" x:Name="PART_Thumb"
|
||||
Style="{StaticResource MaterialDesignInvisibleThumbStyle}"
|
||||
/>
|
||||
<DockPanel Margin="{TemplateBinding Control.Padding }">
|
||||
<Button DockPanel.Dock="Right"
|
||||
Command="{x:Static dockablz:Layout.CloseFloatingItem}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Margin="1 0 0 0"
|
||||
Style="{DynamicResource MaterialDesignToolWindowButtonStyle}"
|
||||
Focusable="False"
|
||||
RenderOptions.EdgeMode="Aliased"
|
||||
>
|
||||
<Path Data="M 10.009,1.704 L 8.331,0.026 5.03,3.327 1.703,0 0,1.704 3.326,5.031 0.025,8.332 1.703,10.009 5.004,6.708 8.305,10.009 10.009,8.305 6.708,5.005"
|
||||
SnapsToDevicePixels="True"
|
||||
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" />
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right"
|
||||
Command="{x:Static dockablz:Layout.UnfloatItemCommand}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Margin="1 0 0 0"
|
||||
Style="{DynamicResource MaterialDesignToolWindowButtonStyle}"
|
||||
>
|
||||
<Path Width="12" Height="12" Stretch="UniformToFill" Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" Data="M 19 19 H 5 V 5 h 7 V 3 H 5 C 3.89 3 3 3.9 3 5 v 14 c 0 1.1 0.89 2 2 2 h 14 c 1.1 0 2 -0.9 2 -2 v -7 h -2 v 7 z M 14 3 v 2 h 3.59 L 7.76 14.83 9.17 16.24 19 6.41 V 10 h 2 V 3 h -7 z" />
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right"
|
||||
Command="{x:Static dockablz:Layout.MaximiseFloatingItem}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Margin="1 0 0 0"
|
||||
Style="{DynamicResource MaterialDesignToolWindowButtonStyle}"
|
||||
>
|
||||
<Path Width="10"
|
||||
Height="10"
|
||||
Data="F1M0,0L0,9 9,9 9,0 0,0 0,3 8,3 8,8 1,8 1,3z"
|
||||
SnapsToDevicePixels="True"
|
||||
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" />
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right"
|
||||
Command="{x:Static dockablz:Layout.RestoreFloatingItem}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Margin="1 0 0 0"
|
||||
Style="{DynamicResource MaterialDesignToolWindowButtonStyle}"
|
||||
>
|
||||
<Path Width="10"
|
||||
Height="10"
|
||||
Data="F1M0,10L0,3 3,3 3,0 10,0 10,2 4,2 4,3 7,3 7,6 6,6 6,5 1,5 1,10z M1,10L7,10 7,7 10,7 10,2 9,2 9,6 6,6 6,9 1,9z"
|
||||
SnapsToDevicePixels="True"
|
||||
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" />
|
||||
</Button>
|
||||
<ContentPresenter Content="{TemplateBinding HeaderContent}"
|
||||
ContentTemplate="{TemplateBinding HeaderContentTemplate}"
|
||||
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
|
||||
ContentTemplateSelector="{TemplateBinding HeaderContentTemplateSelector}"
|
||||
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
|
||||
IsHitTestVisible="False"
|
||||
/>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
|
||||
Margin="{TemplateBinding Control.Padding }"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
<Thumb Style="{StaticResource MaterialDesignInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Left}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="Left"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Stretch"
|
||||
Cursor="SizeWE"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MaterialDesignInvisibleThumbStyle}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Top}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="Top"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Cursor="SizeNS"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MaterialDesignInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="Right"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch"
|
||||
Cursor="SizeWE"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MaterialDesignInvisibleThumbStyle}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="Bottom"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Bottom"
|
||||
Cursor="SizeNS"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MaterialDesignInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="TopLeft"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Cursor="SizeNWSE"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MaterialDesignInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="TopRight"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Cursor="SizeNESW"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MaterialDesignInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="BottomRight"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Cursor="SizeNWSE"
|
||||
/>
|
||||
<Thumb Style="{StaticResource MaterialDesignInvisibleThumbStyle}"
|
||||
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Right}"
|
||||
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness.Bottom}"
|
||||
IsEnabled="{Binding Path=(dockablz:Layout.FloatingItemState), RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource EqualityToBooleanConverter}, ConverterParameter={x:Static WindowState.Normal}}"
|
||||
dragablz:DragablzItem.SizeGrip="BottomLeft"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
Cursor="SizeNESW"
|
||||
/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style.Setters>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="dockablz:Layout.FloatingItemState" Value="Maximized">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="Canvas.Left" Value="0" />
|
||||
<Setter Property="Canvas.Top" Value="0" />
|
||||
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualWidth}" />
|
||||
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dockablz:Layout}}, Path=ActualHeight}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="TabablzScrollViewerControlTemplate" TargetType="{x:Type ScrollViewer}">
|
||||
<Grid x:Name="Grid" Background="{TemplateBinding Background}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
|
||||
<ScrollBar x:Name="PART_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"
|
||||
Margin="0 1 0 0" />
|
||||
<ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="0" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"
|
||||
Margin="1 0 0 0" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style TargetType="{x:Type dragablz:DragablzItemsControl}" x:Key="TabablzDragablzItemsControlStyle">
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<Canvas IsItemsHost="True" />
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type dragablz:DragablzItemsControl}">
|
||||
<Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="{TemplateBinding Control.Padding}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" SnapsToDevicePixels="True">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
|
||||
Width="{TemplateBinding ActualWidth}"
|
||||
Height="{TemplateBinding ActualHeight}"
|
||||
Template="{StaticResource TabablzScrollViewerControlTemplate}">
|
||||
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Width="{TemplateBinding ItemsPresenterWidth}"
|
||||
Height="{TemplateBinding ItemsPresenterHeight}"/>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StandardEmbeddedButtonStyle" TargetType="{x:Type Button}">
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
|
||||
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsDefaulted" Value="true">
|
||||
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type dragablz:TabablzControl}" x:Key="MaterialDesignTabablzControlStyle">
|
||||
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=Background}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryHueMidBrush}" />
|
||||
<Setter Property="TextElement.Foreground" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=(TextElement.Foreground)}" />
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource MaterialDesignDragableTabItemStyle}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type dragablz:TabablzControl}">
|
||||
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
|
||||
<RowDefinition x:Name="RowDefinition1" Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border x:Name="contentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local"
|
||||
Margin="0 -1 0 0">
|
||||
<Grid x:Name="PART_ItemsHolder" />
|
||||
</Border>
|
||||
<Grid Grid.Column="0" Grid.Row="0" x:Name="HeaderContainerGrid" Visibility="{TemplateBinding IsHeaderPanelVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<Grid.Resources>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource StandardEmbeddedButtonStyle}"></Style>
|
||||
</Grid.Resources>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Background="{TemplateBinding BorderBrush}" Grid.ColumnSpan="4">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="5" ShadowDepth="2" Direction="270" Opacity=".5" />
|
||||
</Border.Effect>
|
||||
</Border>
|
||||
<ContentControl Grid.Column="0" x:Name="PrefixContentControl"
|
||||
Content="{TemplateBinding HeaderPrefixContent}"
|
||||
ContentStringFormat="{TemplateBinding HeaderPrefixContentStringFormat}"
|
||||
ContentTemplate="{TemplateBinding HeaderPrefixContentStringFormat}"
|
||||
ContentTemplateSelector="{TemplateBinding HeaderPrefixContentTemplateSelector}"/>
|
||||
<dragablz:DragablzItemsControl x:Name="PART_HeaderItemsControl"
|
||||
Grid.Column="1"
|
||||
FixedItemCount="{TemplateBinding FixedHeaderCount}"
|
||||
ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items}"
|
||||
ItemContainerStyle="{TemplateBinding ItemContainerStyle}"
|
||||
ItemsOrganiser="{TemplateBinding HeaderItemsOrganiser}"
|
||||
KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"
|
||||
ItemTemplate="{TemplateBinding HeaderItemTemplate}"
|
||||
Style="{StaticResource TabablzDragablzItemsControlStyle}">
|
||||
<dragablz:DragablzItemsControl.MaxWidth>
|
||||
<MultiBinding>
|
||||
<MultiBinding.Converter>
|
||||
<dragablz:TabablzHeaderSizeConverter Orientation="Horizontal"/>
|
||||
</MultiBinding.Converter>
|
||||
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="ActualWidth" />
|
||||
<Binding RelativeSource="{RelativeSource Self}" Path="ItemsPresenterWidth" />
|
||||
<Binding ElementName="PrefixContentControl" Path="ActualWidth" />
|
||||
<Binding ElementName="DefaultAddButton" Path="DesiredSize.Width" />
|
||||
<Binding ElementName="SuffixContentControl" Path="DesiredSize.Width" />
|
||||
</MultiBinding>
|
||||
</dragablz:DragablzItemsControl.MaxWidth>
|
||||
</dragablz:DragablzItemsControl>
|
||||
<Button Style="{StaticResource MaterialDesignAddItemCommandButtonStyle}"
|
||||
x:Name="DefaultAddButton"
|
||||
Grid.Column="2"
|
||||
Command="{x:Static dragablz:TabablzControl.AddItemCommand}"
|
||||
Visibility="{TemplateBinding ShowDefaultAddButton, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
/>
|
||||
<ContentControl Grid.Column="3" x:Name="SuffixContentControl"
|
||||
Content="{TemplateBinding HeaderSuffixContent}"
|
||||
ContentStringFormat="{TemplateBinding HeaderSuffixContentStringFormat}"
|
||||
ContentTemplate="{TemplateBinding HeaderSuffixContentStringFormat}"
|
||||
ContentTemplateSelector="{TemplateBinding HeaderSuffixContentTemplateSelector}"
|
||||
HorizontalAlignment="Stretch"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="TabStripPlacement" Value="Bottom">
|
||||
<Setter Property="Grid.Row" TargetName="PART_HeaderItemsControl" Value="1"/>
|
||||
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
|
||||
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
|
||||
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsDraggingWindow" Value="True">
|
||||
<Setter TargetName="DefaultAddButton" Property="Visibility" Value="Hidden" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="TabStripPlacement" Value="Left">
|
||||
<Setter Property="HeaderItemsOrganiser">
|
||||
<Setter.Value>
|
||||
<dragablz:VerticalOrganiser />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource MaterialDesignDragableTabItemVerticalStyle}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type dragablz:TabablzControl}">
|
||||
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="ColumnDefinition0" Width="Auto"/>
|
||||
<ColumnDefinition x:Name="ColumnDefinition1" Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border x:Name="contentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local" Margin="-1 0 0 0">
|
||||
<Grid x:Name="PART_ItemsHolder" />
|
||||
</Border>
|
||||
<Grid Grid.Column="0" x:Name="HeaderContainerGrid" Visibility="{TemplateBinding IsHeaderPanelVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<Grid.Resources>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource StandardEmbeddedButtonStyle}" />
|
||||
</Grid.Resources>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Border Background="{TemplateBinding BorderBrush}" Grid.RowSpan="4">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="5" ShadowDepth="2" Direction="0" Opacity=".5" />
|
||||
</Border.Effect>
|
||||
</Border>
|
||||
<ContentControl Grid.Row="0" x:Name="PrefixContentControl"
|
||||
Content="{TemplateBinding HeaderPrefixContent}"
|
||||
ContentStringFormat="{TemplateBinding HeaderPrefixContentStringFormat}"
|
||||
ContentTemplate="{TemplateBinding HeaderPrefixContentStringFormat}"
|
||||
ContentTemplateSelector="{TemplateBinding HeaderPrefixContentTemplateSelector}"/>
|
||||
<dragablz:DragablzItemsControl x:Name="PART_HeaderItemsControl"
|
||||
Grid.Row="1"
|
||||
ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items}"
|
||||
ItemContainerStyle="{TemplateBinding ItemContainerStyle}"
|
||||
FixedItemCount="{TemplateBinding FixedHeaderCount}"
|
||||
ItemsOrganiser="{TemplateBinding HeaderItemsOrganiser}"
|
||||
KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"
|
||||
ItemTemplate="{TemplateBinding HeaderItemTemplate}"
|
||||
Style="{StaticResource TabablzDragablzItemsControlStyle}">
|
||||
<dragablz:DragablzItemsControl.MaxHeight>
|
||||
<MultiBinding>
|
||||
<MultiBinding.Converter>
|
||||
<dragablz:TabablzHeaderSizeConverter Orientation="Vertical"/>
|
||||
</MultiBinding.Converter>
|
||||
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="ActualHeight" />
|
||||
<Binding RelativeSource="{RelativeSource Self}" Path="ItemsPresenterHeight" />
|
||||
<Binding ElementName="PrefixContentControl" Path="ActualHeight" />
|
||||
<Binding ElementName="DefaultAddButton" Path="DesiredSize.Height" />
|
||||
<Binding ElementName="SuffixContentControl" Path="DesiredSize.Height" />
|
||||
</MultiBinding>
|
||||
</dragablz:DragablzItemsControl.MaxHeight>
|
||||
</dragablz:DragablzItemsControl>
|
||||
<Button Style="{StaticResource MaterialDesignAddItemCommandButtonStyle}"
|
||||
x:Name="DefaultAddButton"
|
||||
Grid.Row="2"
|
||||
Command="{x:Static dragablz:TabablzControl.AddItemCommand}"
|
||||
Visibility="{TemplateBinding ShowDefaultAddButton, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
<ContentControl Grid.Row="3" x:Name="SuffixContentControl"
|
||||
Content="{TemplateBinding HeaderSuffixContent}"
|
||||
ContentStringFormat="{TemplateBinding HeaderSuffixContentStringFormat}"
|
||||
ContentTemplate="{TemplateBinding HeaderSuffixContentStringFormat}"
|
||||
ContentTemplateSelector="{TemplateBinding HeaderSuffixContentTemplateSelector}"
|
||||
VerticalAlignment="Top" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsDraggingWindow" Value="True">
|
||||
<Setter TargetName="DefaultAddButton" Property="Visibility" Value="Hidden" />
|
||||
</Trigger>
|
||||
<Trigger Property="TabStripPlacement" Value="Right">
|
||||
<!-- TODO -->
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MaterialDesignAlternateDragableTabItemStyle" TargetType="{x:Type dragablz:DragablzItem}" BasedOn="{StaticResource MaterialDesignDragableTabItemStyle}">
|
||||
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignColumnHeader}"/>
|
||||
<Setter Property="local:MaterialDesignAssist.IndicatorBrush" Value="{DynamicResource PrimaryHueMidBrush}" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidBrush}" />
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsSelected" Value="False" />
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
|
||||
</MultiTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="MaterialDesignAlternateDragableTabItemVerticalStyle" TargetType="{x:Type dragablz:DragablzItem}" BasedOn="{StaticResource MaterialDesignDragableTabItemVerticalStyle}">
|
||||
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignColumnHeader}"/>
|
||||
<Setter Property="local:MaterialDesignAssist.IndicatorBrush" Value="{DynamicResource PrimaryHueMidBrush}" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueMidBrush}" />
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsSelected" Value="False" />
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
|
||||
</MultiTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type dragablz:TabablzControl}" x:Key="MaterialDesignAlternateTabablzControlStyle" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}">
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesignPaper}" />
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource MaterialDesignAlternateDragableTabItemStyle}" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="TabStripPlacement" Value="Left">
|
||||
<Setter Property="ItemContainerStyle" Value="{StaticResource MaterialDesignAlternateDragableTabItemVerticalStyle}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
42
Others/Dragablz/Dragablz/Themes/MaterialDesignAssist.cs
Normal file
42
Others/Dragablz/Dragablz/Themes/MaterialDesignAssist.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Dragablz.Themes
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper propries for configuring the material design style.
|
||||
/// </summary>
|
||||
public static class MaterialDesignAssist
|
||||
{
|
||||
/// <summary>
|
||||
/// Framework use only.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IndicatorBrushProperty = DependencyProperty.RegisterAttached(
|
||||
"IndicatorBrush", typeof (Brush), typeof (MaterialDesignAssist), new PropertyMetadata(default(Brush)));
|
||||
|
||||
/// <summary>
|
||||
/// The indicator (underline) brush.
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void SetIndicatorBrush(DependencyObject element, Brush value)
|
||||
{
|
||||
element.SetValue(IndicatorBrushProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The indicator (underline) brush.
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
/// <returns></returns>
|
||||
public static Brush GetIndicatorBrush(DependencyObject element)
|
||||
{
|
||||
return (Brush) element.GetValue(IndicatorBrushProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
218
Others/Dragablz/Dragablz/Themes/Ripple.cs
Normal file
218
Others/Dragablz/Dragablz/Themes/Ripple.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace Dragablz.Themes
|
||||
{
|
||||
[TemplateVisualState(GroupName = "CommonStates", Name = TemplateStateNormal)]
|
||||
[TemplateVisualState(GroupName = "CommonStates", Name = TemplateStateMousePressed)]
|
||||
[TemplateVisualState(GroupName = "CommonStates", Name = TemplateStateMouseOut)]
|
||||
public class Ripple : ContentControl
|
||||
{
|
||||
public const string TemplateStateNormal = "Normal";
|
||||
public const string TemplateStateMousePressed = "MousePressed";
|
||||
public const string TemplateStateMouseOut = "MouseOut";
|
||||
|
||||
private static readonly HashSet<Ripple> PressedInstances = new HashSet<Ripple>();
|
||||
|
||||
static Ripple()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Ripple), new FrameworkPropertyMetadata(typeof(Ripple)));
|
||||
|
||||
EventManager.RegisterClassHandler(typeof(Window), Mouse.PreviewMouseUpEvent, new MouseButtonEventHandler(MouseButtonEventHandler), true);
|
||||
EventManager.RegisterClassHandler(typeof(Window), Mouse.MouseMoveEvent, new MouseEventHandler(MouseMouveEventHandler), true);
|
||||
EventManager.RegisterClassHandler(typeof(UserControl), Mouse.PreviewMouseUpEvent, new MouseButtonEventHandler(MouseButtonEventHandler), true);
|
||||
EventManager.RegisterClassHandler(typeof(UserControl), Mouse.MouseMoveEvent, new MouseEventHandler(MouseMouveEventHandler), true);
|
||||
}
|
||||
|
||||
public Ripple()
|
||||
{
|
||||
SizeChanged += OnSizeChanged;
|
||||
}
|
||||
|
||||
private static void MouseButtonEventHandler(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
foreach (var ripple in PressedInstances)
|
||||
{
|
||||
// adjust the transition scale time according to the current animated scale
|
||||
var scaleTrans = ripple.Template.FindName("ScaleTransform", ripple) as ScaleTransform;
|
||||
if (scaleTrans != null)
|
||||
{
|
||||
double currentScale = scaleTrans.ScaleX;
|
||||
var newTime = TimeSpan.FromMilliseconds(300 * (1.0 - currentScale));
|
||||
|
||||
// change the scale animation according to the current scale
|
||||
var scaleXKeyFrame = ripple.Template.FindName("MousePressedToNormalScaleXKeyFrame", ripple) as EasingDoubleKeyFrame;
|
||||
if (scaleXKeyFrame != null)
|
||||
{
|
||||
scaleXKeyFrame.KeyTime = KeyTime.FromTimeSpan(newTime);
|
||||
}
|
||||
var scaleYKeyFrame = ripple.Template.FindName("MousePressedToNormalScaleYKeyFrame", ripple) as EasingDoubleKeyFrame;
|
||||
if (scaleYKeyFrame != null)
|
||||
{
|
||||
scaleYKeyFrame.KeyTime = KeyTime.FromTimeSpan(newTime);
|
||||
}
|
||||
}
|
||||
|
||||
VisualStateManager.GoToState(ripple, TemplateStateNormal, true);
|
||||
}
|
||||
PressedInstances.Clear();
|
||||
}
|
||||
|
||||
private static void MouseMouveEventHandler(object sender, MouseEventArgs e)
|
||||
{
|
||||
foreach (var ripple in PressedInstances.ToList())
|
||||
{
|
||||
var relativePosition = Mouse.GetPosition(ripple);
|
||||
if (relativePosition.X < 0
|
||||
|| relativePosition.Y < 0
|
||||
|| relativePosition.X >= ripple.ActualWidth
|
||||
|| relativePosition.Y >= ripple.ActualHeight)
|
||||
|
||||
{
|
||||
VisualStateManager.GoToState(ripple, TemplateStateMouseOut, true);
|
||||
PressedInstances.Remove(ripple);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FeedbackProperty = DependencyProperty.Register(
|
||||
"Feedback", typeof(Brush), typeof(Ripple), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public Brush Feedback
|
||||
{
|
||||
get { return (Brush)GetValue(FeedbackProperty); }
|
||||
set { SetValue(FeedbackProperty, value); }
|
||||
}
|
||||
|
||||
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
var point = e.GetPosition(this);
|
||||
|
||||
if (RippleAssist.GetIsCentered(this))
|
||||
{
|
||||
var innerContent = (Content as FrameworkElement);
|
||||
|
||||
if (innerContent != null)
|
||||
{
|
||||
var position = innerContent.TransformToAncestor(this)
|
||||
.Transform(new Point(0, 0));
|
||||
|
||||
RippleX = position.X + innerContent.ActualWidth / 2 - RippleSize / 2;
|
||||
RippleY = position.Y + innerContent.ActualHeight / 2 - RippleSize / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
RippleX = ActualWidth / 2 - RippleSize / 2;
|
||||
RippleY = ActualHeight / 2 - RippleSize / 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RippleX = point.X - RippleSize / 2;
|
||||
RippleY = point.Y - RippleSize / 2;
|
||||
}
|
||||
|
||||
VisualStateManager.GoToState(this, TemplateStateNormal, false);
|
||||
VisualStateManager.GoToState(this, TemplateStateMousePressed, true);
|
||||
PressedInstances.Add(this);
|
||||
|
||||
base.OnPreviewMouseLeftButtonDown(e);
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey RippleSizePropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"RippleSize", typeof(double), typeof(Ripple),
|
||||
new PropertyMetadata(default(double)));
|
||||
|
||||
public static readonly DependencyProperty RippleSizeProperty =
|
||||
RippleSizePropertyKey.DependencyProperty;
|
||||
|
||||
public double RippleSize
|
||||
{
|
||||
get { return (double)GetValue(RippleSizeProperty); }
|
||||
private set { SetValue(RippleSizePropertyKey, value); }
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey RippleXPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"RippleX", typeof(double), typeof(Ripple),
|
||||
new PropertyMetadata(default(double)));
|
||||
|
||||
public static readonly DependencyProperty RippleXProperty =
|
||||
RippleXPropertyKey.DependencyProperty;
|
||||
|
||||
public double RippleX
|
||||
{
|
||||
get { return (double)GetValue(RippleXProperty); }
|
||||
private set { SetValue(RippleXPropertyKey, value); }
|
||||
}
|
||||
|
||||
private static readonly DependencyPropertyKey RippleYPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(
|
||||
"RippleY", typeof(double), typeof(Ripple),
|
||||
new PropertyMetadata(default(double)));
|
||||
|
||||
public static readonly DependencyProperty RippleYProperty =
|
||||
RippleYPropertyKey.DependencyProperty;
|
||||
|
||||
public double RippleY
|
||||
{
|
||||
get { return (double)GetValue(RippleYProperty); }
|
||||
private set { SetValue(RippleYPropertyKey, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The DependencyProperty for the RecognizesAccessKey property.
|
||||
/// Default Value: false
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty RecognizesAccessKeyProperty =
|
||||
DependencyProperty.Register(
|
||||
"RecognizesAccessKey", typeof(bool), typeof(Ripple),
|
||||
new PropertyMetadata(default(bool)));
|
||||
|
||||
/// <summary>
|
||||
/// Determine if Ripple should use AccessText in its style
|
||||
/// </summary>
|
||||
public bool RecognizesAccessKey
|
||||
{
|
||||
get { return (bool)GetValue(RecognizesAccessKeyProperty); }
|
||||
set { SetValue(RecognizesAccessKeyProperty, value); }
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
VisualStateManager.GoToState(this, TemplateStateNormal, false);
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
|
||||
{
|
||||
var innerContent = (Content as FrameworkElement);
|
||||
|
||||
double width, height;
|
||||
|
||||
if (RippleAssist.GetIsCentered(this) && innerContent != null)
|
||||
{
|
||||
width = innerContent.ActualWidth;
|
||||
height = innerContent.ActualHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = sizeChangedEventArgs.NewSize.Width;
|
||||
height = sizeChangedEventArgs.NewSize.Height;
|
||||
}
|
||||
|
||||
var radius = Math.Sqrt(Math.Pow(width, 2) + Math.Pow(height, 2));
|
||||
|
||||
RippleSize = 2 * radius * RippleAssist.GetRippleSizeMultiplier(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
Others/Dragablz/Dragablz/Themes/RippleAssist.cs
Normal file
74
Others/Dragablz/Dragablz/Themes/RippleAssist.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Dragablz.Themes
|
||||
{
|
||||
public static class RippleAssist
|
||||
{
|
||||
#region ClipToBound
|
||||
|
||||
public static readonly DependencyProperty ClipToBoundsProperty = DependencyProperty.RegisterAttached(
|
||||
"ClipToBounds", typeof(bool), typeof(RippleAssist), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetClipToBounds(DependencyObject element, bool value)
|
||||
{
|
||||
element.SetValue(ClipToBoundsProperty, value);
|
||||
}
|
||||
|
||||
public static bool GetClipToBounds(DependencyObject element)
|
||||
{
|
||||
return (bool)element.GetValue(ClipToBoundsProperty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region StayOnCenter
|
||||
|
||||
/// <summary>
|
||||
/// Set to <c>true</c> to cause the ripple to originate from the centre of the
|
||||
/// content. Otherwise the effect will originate from the mouse down position.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsCenteredProperty = DependencyProperty.RegisterAttached(
|
||||
"IsCentered", typeof(bool), typeof(RippleAssist), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
/// <summary>
|
||||
/// Set to <c>true</c> to cause the ripple to originate from the centre of the
|
||||
/// content. Otherwise the effect will originate from the mouse down position.
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void SetIsCentered(DependencyObject element, bool value)
|
||||
{
|
||||
element.SetValue(IsCenteredProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set to <c>true</c> to cause the ripple to originate from the centre of the
|
||||
/// content. Otherwise the effect will originate from the mouse down position.
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
public static bool GetIsCentered(DependencyObject element)
|
||||
{
|
||||
return (bool)element.GetValue(IsCenteredProperty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RippleSizeMultiplier
|
||||
|
||||
public static readonly DependencyProperty RippleSizeMultiplierProperty = DependencyProperty.RegisterAttached(
|
||||
"RippleSizeMultiplier", typeof(double), typeof(RippleAssist), new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetRippleSizeMultiplier(DependencyObject element, double value)
|
||||
{
|
||||
element.SetValue(RippleSizeMultiplierProperty, value);
|
||||
}
|
||||
|
||||
public static double GetRippleSizeMultiplier(DependencyObject element)
|
||||
{
|
||||
return (double)element.GetValue(RippleSizeMultiplierProperty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
34
Others/Dragablz/Dragablz/Themes/SystemCommandIcon.cs
Normal file
34
Others/Dragablz/Dragablz/Themes/SystemCommandIcon.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Dragablz.Themes
|
||||
{
|
||||
public enum SystemCommandType
|
||||
{
|
||||
CloseWindow,
|
||||
MaximizeWindow,
|
||||
MinimzeWindow,
|
||||
RestoreWindow
|
||||
}
|
||||
|
||||
public class SystemCommandIcon : Control
|
||||
{
|
||||
static SystemCommandIcon()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(SystemCommandIcon), new FrameworkPropertyMetadata(typeof(SystemCommandIcon)));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SystemCommandTypeProperty = DependencyProperty.Register(
|
||||
"SystemCommandType", typeof (SystemCommandType), typeof (SystemCommandIcon), new PropertyMetadata(default(SystemCommandType)));
|
||||
|
||||
public SystemCommandType SystemCommandType
|
||||
{
|
||||
get { return (SystemCommandType) GetValue(SystemCommandTypeProperty); }
|
||||
set { SetValue(SystemCommandTypeProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user