329 lines
7.9 KiB
C#
329 lines
7.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using System.Windows;
|
|
using System.Windows.Input;
|
|
|
|
namespace JD.WPF.Utils
|
|
{
|
|
public class WindowResizer
|
|
{
|
|
private readonly Window _target;
|
|
|
|
private bool _resizeRight;
|
|
private bool _resizeLeft;
|
|
private bool _resizeUp;
|
|
private bool _resizeDown;
|
|
|
|
private readonly Dictionary<UIElement, short> _leftElements = new Dictionary<UIElement, short>();
|
|
private readonly Dictionary<UIElement, short> _rightElements = new Dictionary<UIElement, short>();
|
|
private readonly Dictionary<UIElement, short> _upElements = new Dictionary<UIElement, short>();
|
|
private readonly Dictionary<UIElement, short> _downElements = new Dictionary<UIElement, short>();
|
|
|
|
private PointAPI _resizePoint;
|
|
private Size _resizeSize;
|
|
private Point _resizeWindowPoint;
|
|
|
|
private delegate void RefreshDelegate();
|
|
|
|
public WindowResizer(Window target)
|
|
{
|
|
_target = target;
|
|
|
|
if (target == null)
|
|
{
|
|
throw new Exception("Invalid Window handle");
|
|
}
|
|
}
|
|
|
|
private void ConnectMouseHandlers(UIElement element)
|
|
{
|
|
if ( element == null )
|
|
return;
|
|
|
|
element.MouseLeftButtonDown += Element_MouseLeftButtonDown;
|
|
element.MouseLeftButtonUp += Element_MouseLeftButtonUp;
|
|
element.MouseEnter += Element_MouseEnter;
|
|
element.MouseLeave += SetArrowCursor;
|
|
}
|
|
|
|
public void AddResizerRight(UIElement element)
|
|
{
|
|
if ( element == null )
|
|
return;
|
|
|
|
ConnectMouseHandlers(element);
|
|
_rightElements.Add(element, 0);
|
|
}
|
|
|
|
public void AddResizerLeft(UIElement element)
|
|
{
|
|
if ( element == null )
|
|
return;
|
|
|
|
ConnectMouseHandlers(element);
|
|
_leftElements.Add(element, 0);
|
|
}
|
|
|
|
public void AddResizerUp(UIElement element)
|
|
{
|
|
if ( element == null )
|
|
return;
|
|
|
|
ConnectMouseHandlers(element);
|
|
_upElements.Add(element, 0);
|
|
}
|
|
|
|
public void AddResizerDown(UIElement element)
|
|
{
|
|
if ( element == null )
|
|
return;
|
|
|
|
ConnectMouseHandlers(element);
|
|
_downElements.Add(element, 0);
|
|
}
|
|
|
|
public void AddResizerRightDown(UIElement element)
|
|
{
|
|
if ( element == null )
|
|
return;
|
|
|
|
ConnectMouseHandlers(element);
|
|
_rightElements.Add(element, 0);
|
|
_downElements.Add(element, 0);
|
|
}
|
|
|
|
public void AddResizerLeftDown(UIElement element)
|
|
{
|
|
if ( element == null )
|
|
return;
|
|
|
|
ConnectMouseHandlers(element);
|
|
_leftElements.Add(element, 0);
|
|
_downElements.Add(element, 0);
|
|
}
|
|
|
|
public void AddResizerRightUp(UIElement element)
|
|
{
|
|
if ( element == null )
|
|
return;
|
|
|
|
ConnectMouseHandlers(element);
|
|
_rightElements.Add(element, 0);
|
|
_upElements.Add(element, 0);
|
|
}
|
|
|
|
public void AddResizerLeftUp(UIElement element)
|
|
{
|
|
if ( element == null )
|
|
return;
|
|
|
|
ConnectMouseHandlers(element);
|
|
_leftElements.Add(element, 0);
|
|
_upElements.Add(element, 0);
|
|
}
|
|
|
|
private void Element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
{
|
|
if ((sender as UIElement).Visibility != Visibility.Visible)
|
|
return;
|
|
|
|
(sender as UIElement)?.CaptureMouse();
|
|
|
|
GetCursorPos(out _resizePoint);
|
|
_resizeSize = new Size(_target.Width, _target.Height);
|
|
_resizeWindowPoint = new Point(_target.Left, _target.Top);
|
|
|
|
UIElement sourceSender = (UIElement)sender;
|
|
if (_leftElements.ContainsKey(sourceSender))
|
|
{
|
|
_resizeLeft = true;
|
|
}
|
|
if (_rightElements.ContainsKey(sourceSender))
|
|
{
|
|
_resizeRight = true;
|
|
}
|
|
if (_upElements.ContainsKey(sourceSender))
|
|
{
|
|
_resizeUp = true;
|
|
}
|
|
if (_downElements.ContainsKey(sourceSender))
|
|
{
|
|
_resizeDown = true;
|
|
}
|
|
|
|
Thread t = new Thread(UpdateSizeLoop) {Name = "Mouse Position Poll Thread"};
|
|
t.Start();
|
|
}
|
|
|
|
void Element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
|
{
|
|
(sender as UIElement).ReleaseMouseCapture();
|
|
}
|
|
|
|
private void UpdateSizeLoop()
|
|
{
|
|
try
|
|
{
|
|
while (_resizeDown || _resizeLeft || _resizeRight || _resizeUp)
|
|
{
|
|
_target.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new RefreshDelegate(UpdateSize));
|
|
_target.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new RefreshDelegate(UpdateMouseDown));
|
|
|
|
Thread.Sleep(10);
|
|
}
|
|
|
|
_target.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new RefreshDelegate(SetArrowCursor));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// continue
|
|
}
|
|
}
|
|
|
|
private void UpdateSize()
|
|
{
|
|
PointAPI p;
|
|
GetCursorPos(out p);
|
|
|
|
if (_resizeRight)
|
|
{
|
|
_target.Width = Math.Max(_target.MinWidth, _resizeSize.Width - (_resizePoint.X - p.X));
|
|
}
|
|
|
|
if (_resizeDown)
|
|
{
|
|
_target.Height = Math.Max(_target.MinHeight, _resizeSize.Height - (_resizePoint.Y - p.Y));
|
|
}
|
|
|
|
if (_resizeLeft)
|
|
{
|
|
// TODO : Fix refresh issues.
|
|
double currentRight = _target.Left + _target.Width;
|
|
double candidateLeft = _resizeWindowPoint.X - (_resizePoint.X - p.X);
|
|
if (candidateLeft + _target.MinWidth > currentRight)
|
|
_target.Left = currentRight - _target.MinWidth;
|
|
else
|
|
_target.Left = candidateLeft;
|
|
_target.Width = Math.Max(_target.MinWidth, _resizeSize.Width + (_resizePoint.X - p.X));
|
|
}
|
|
|
|
if (_resizeUp)
|
|
{
|
|
// TODO : Fix Refresh issues.
|
|
double currentBottom = _target.Top + _target.Height;
|
|
double candidateTop = _resizeWindowPoint.Y - (_resizePoint.Y - p.Y);
|
|
if (candidateTop + _target.MinHeight > currentBottom)
|
|
_target.Top = currentBottom - _target.MinHeight;
|
|
else
|
|
_target.Top = candidateTop;
|
|
_target.Height = Math.Max(_target.MinHeight, _resizeSize.Height + (_resizePoint.Y - p.Y));
|
|
}
|
|
}
|
|
|
|
private void UpdateMouseDown()
|
|
{
|
|
if (Mouse.LeftButton == MouseButtonState.Released)
|
|
{
|
|
_resizeRight = false;
|
|
_resizeLeft = false;
|
|
_resizeUp = false;
|
|
_resizeDown = false;
|
|
}
|
|
}
|
|
|
|
private void Element_MouseEnter(object sender, MouseEventArgs e)
|
|
{
|
|
bool resizeRight = false;
|
|
bool resizeLeft = false;
|
|
bool resizeUp = false;
|
|
bool resizeDown = false;
|
|
|
|
var window = (Window)((FrameworkElement)sender).TemplatedParent;
|
|
if ( window != null && window.WindowState == WindowState.Maximized)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UIElement sourceSender = (UIElement)sender;
|
|
|
|
if (_leftElements.ContainsKey(sourceSender))
|
|
{
|
|
resizeLeft = true;
|
|
}
|
|
if (_rightElements.ContainsKey(sourceSender))
|
|
{
|
|
resizeRight = true;
|
|
}
|
|
if (_upElements.ContainsKey(sourceSender))
|
|
{
|
|
resizeUp = true;
|
|
}
|
|
if (_downElements.ContainsKey(sourceSender))
|
|
{
|
|
resizeDown = true;
|
|
}
|
|
|
|
if ((resizeLeft && resizeDown) || (resizeRight && resizeUp))
|
|
{
|
|
SetNESWCursor(sender, e);
|
|
}
|
|
else if ((resizeRight && resizeDown) || (resizeLeft && resizeUp))
|
|
{
|
|
SetNWSECursor(sender, e);
|
|
}
|
|
else if (resizeLeft || resizeRight)
|
|
{
|
|
SetWECursor(sender, e);
|
|
}
|
|
else if (resizeUp || resizeDown)
|
|
{
|
|
SetNSCursor(sender, e);
|
|
}
|
|
}
|
|
|
|
private void SetWECursor(object sender, MouseEventArgs e)
|
|
{
|
|
_target.Cursor = Cursors.SizeWE;
|
|
}
|
|
|
|
private void SetNSCursor(object sender, MouseEventArgs e)
|
|
{
|
|
_target.Cursor = Cursors.SizeNS;
|
|
}
|
|
|
|
private void SetNESWCursor(object sender, MouseEventArgs e)
|
|
{
|
|
_target.Cursor = Cursors.SizeNESW;
|
|
}
|
|
|
|
private void SetNWSECursor(object sender, MouseEventArgs e)
|
|
{
|
|
_target.Cursor = Cursors.SizeNWSE;
|
|
}
|
|
|
|
private void SetArrowCursor(object sender, MouseEventArgs e)
|
|
{
|
|
if (!_resizeDown && !_resizeLeft && !_resizeRight && !_resizeUp)
|
|
{
|
|
_target.Cursor = Cursors.Arrow;
|
|
}
|
|
}
|
|
|
|
private void SetArrowCursor()
|
|
{
|
|
_target.Cursor = Cursors.Arrow;
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
static extern bool GetCursorPos(out PointAPI lpPoint);
|
|
|
|
private struct PointAPI
|
|
{
|
|
public int X;
|
|
public int Y;
|
|
}
|
|
}
|
|
}
|