mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-04 08:06:36 +08:00
371 lines
16 KiB
C#
371 lines
16 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|