Skip to content

Commit

Permalink
Merge pull request #207 from wieslawsoltes/FixHostWindowDrag
Browse files Browse the repository at this point in the history
  • Loading branch information
wieslawsoltes authored Jul 25, 2021
2 parents 2249601 + 462f229 commit 3b40c50
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 109 deletions.
19 changes: 19 additions & 0 deletions samples/AvaloniaDemo/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,25 @@ private void DebugFactoryEvents(IFactory factory)
{
Debug.WriteLine($"[WindowRemoved] Title='{args.Window?.Title}'");
};

factory.WindowMoveDragBegin += (_, args) =>
{
// NOTE: Set to True to cancel window dragging.
#if false
args.Cancel = true;
#endif
Debug.WriteLine($"[WindowMoveDragBegin] Title='{args.Window?.Title}', Cancel={args.Cancel}, X='{args.Window?.X}', Y='{args.Window?.Y}'");
};

factory.WindowMoveDrag += (_, args) =>
{
Debug.WriteLine($"[WindowMoveDrag] Title='{args.Window?.Title}', X='{args.Window?.X}', Y='{args.Window?.Y}");
};

factory.WindowMoveDragEnd += (_, args) =>
{
Debug.WriteLine($"[WindowMoveDragEnd] Title='{args.Window?.Title}', X='{args.Window?.X}', Y='{args.Window?.Y}");
};
}

public void CloseLayout()
Expand Down
10 changes: 10 additions & 0 deletions src/Dock.Avalonia/Controls/HostWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,14 @@
</Template>
</Setter>
</Style>
<Style Selector="idc|HostWindow:toolwindow">
<Setter Property="Background" Value="{DynamicResource DockThemeBackgroundBrush}" />
<Setter Property="TransparencyLevelHint" Value="None"/>
<Setter Property="Opacity" Value="1.0" />
</Style>
<Style Selector="idc|HostWindow:toolwindow:dragging">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="TransparencyLevelHint" Value="Transparent"/>
<Setter Property="Opacity" Value="0.5" />
</Style>
</Styles>
162 changes: 56 additions & 106 deletions src/Dock.Avalonia/Controls/HostWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
using System.Reactive.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Chrome;
using Avalonia.Controls.Metadata;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Styling;
using Dock.Avalonia.Internal;
using Dock.Model;
Expand All @@ -20,16 +18,10 @@ namespace Dock.Avalonia.Controls
[PseudoClasses(":toolwindow")]
public class HostWindow : Window, IStyleable, IHostWindow
{
/// <summary>
/// Use custom drag instead of BeginMoveDrag.
/// </summary>
public static bool s_useCustomDrag = true;

private readonly DockManager _dockManager;
private readonly HostWindowState _hostWindowState;
private Control? _chromeGrip;
private bool _mouseDown;
private Point _startPoint;

/// <summary>
/// Define <see cref="IsToolWindow"/> property.
Expand Down Expand Up @@ -65,11 +57,6 @@ public bool IsToolWindow
/// </summary>
public HostWindow()
{
AddHandler(PointerPressedEvent, Pressed, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
AddHandler(PointerReleasedEvent, Released, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
AddHandler(PointerMovedEvent, Moved, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
AddHandler(PointerCaptureLostEvent, CaptureLost, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble);

PositionChanged += HostWindow_PositionChanged;
LayoutUpdated += HostWindow_LayoutUpdated;

Expand All @@ -82,54 +69,26 @@ public HostWindow()
}

/// <inheritdoc/>
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);

Window?.Factory?.HostWindows.Add(this);
}

/// <inheritdoc/>
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);

Window?.Factory?.HostWindows.Remove(this);

if (Window is { })
{
Window.Factory?.OnWindowClosed(Window);

if (IsTracked)
{
Window?.Factory?.RemoveWindow(Window);
}
}
}

/// <inheritdoc/>
protected override void OnClosing(CancelEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnClosing(e);
base.OnPointerPressed(e);

if (Window is { })
if (_chromeGrip is { } && _chromeGrip.IsPointerOver)
{
if (Window.Factory?.OnWindowClosing(Window) == false)
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
e.Cancel = true;
return;
}
}
if (Window?.Factory?.OnWindowMoveDragBegin(Window) == true)
{
_mouseDown = true;
_hostWindowState.Process(e.GetPosition(this), EventType.Pressed);

if (Window is { } && IsTracked)
{
Window.Save();
PseudoClasses.Set(":dragging", true);
BeginMoveDrag(e);
PseudoClasses.Set(":dragging", false);

if (Window.Layout is IDock root)
{
if (root.Close.CanExecute(null))
{
root.Close.Execute(null);
Window?.Factory?.OnWindowMoveDragEnd(Window);
_hostWindowState.Process(e.GetPosition(this), EventType.Released);
_mouseDown = false;
}
}
}
Expand All @@ -140,9 +99,13 @@ private void HostWindow_PositionChanged(object? sender, PixelPointEventArgs e)
if (Window is { } && IsTracked)
{
Window.Save();
}

_hostWindowState.Process(Position.ToPoint(1.0), EventType.Moved);
if (_chromeGrip is { } && _chromeGrip.IsPointerOver && _mouseDown)
{
Window.Factory?.OnWindowMoveDrag(Window);
_hostWindowState.Process(Position.ToPoint(1.0), EventType.Moved);
}
}
}

private void HostWindow_LayoutUpdated(object? sender, EventArgs e)
Expand All @@ -153,26 +116,6 @@ private void HostWindow_LayoutUpdated(object? sender, EventArgs e)
}
}

private void Pressed(object? sender, PointerPressedEventArgs e)
{
_hostWindowState.Process(e.GetPosition(this), EventType.Pressed);
}

private void Released(object? sender, PointerReleasedEventArgs e)
{
_hostWindowState.Process(e.GetPosition(this), EventType.Released);
}

private void Moved(object? sender, PointerEventArgs e)
{
// Using PositionChanged event instead of PointerMoved event.
}

private void CaptureLost(object? sender, PointerCaptureLostEventArgs e)
{
_hostWindowState.Process(new Point(), EventType.CaptureLost);
}

/// <summary>
/// Attaches grip to chrome.
/// </summary>
Expand Down Expand Up @@ -209,49 +152,56 @@ private void UpdatePseudoClasses(bool isToolWindow)
}

/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e)
protected override void OnOpened(EventArgs e)
{
base.OnPointerPressed(e);
base.OnOpened(e);

if (_chromeGrip is { } && _chromeGrip.IsPointerOver)
Window?.Factory?.HostWindows.Add(this);
}

/// <inheritdoc/>
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);

Window?.Factory?.HostWindows.Remove(this);

if (Window is { })
{
_mouseDown = true;
_startPoint = e.GetPosition(this);
Window.Factory?.OnWindowClosed(Window);

if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed && !s_useCustomDrag)
if (IsTracked)
{
BeginMoveDrag(e);
_mouseDown = false;
Window?.Factory?.RemoveWindow(Window);
}
}
else
{
_mouseDown = false;
}
}

/// <inheritdoc/>
protected override void OnPointerReleased(PointerReleasedEventArgs e)
protected override void OnClosing(CancelEventArgs e)
{
base.OnPointerReleased(e);

_mouseDown = false;
}
base.OnClosing(e);

/// <inheritdoc/>
protected override void OnPointerMoved(PointerEventArgs e)
{
base.OnPointerMoved(e);
if (Window is { })
{
if (Window.Factory?.OnWindowClosing(Window) == false)
{
e.Cancel = true;
return;
}
}

if (_chromeGrip is { } && _chromeGrip.IsPointerOver && _mouseDown && s_useCustomDrag)
if (Window is { } && IsTracked)
{
// Using custom method because BeginMoveDrag is releasing pointer capture on Windows.
var point = e.GetPosition(this);
var delta = point - _startPoint;
var x = Position.X + delta.X;
var y = Position.Y + delta.Y;
Position = Position.WithX((int)x).WithY((int)y);
_startPoint = new Point(point.X - delta.X, point.Y - delta.Y);
Window.Save();

if (Window.Layout is IDock root)
{
if (root.Close.CanExecute(null))
{
root.Close.Execute(null);
}
}
}
}

Expand Down
16 changes: 16 additions & 0 deletions src/Dock.Model.ReactiveUI/Core/DockWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@ public virtual bool OnClose()
return true;
}

/// <inheritdoc/>
public virtual bool OnMoveDragBegin()
{
return true;
}

/// <inheritdoc/>
public virtual void OnMoveDrag()
{
}

/// <inheritdoc/>
public virtual void OnMoveDragEnd()
{
}

/// <inheritdoc/>
public void Save()
{
Expand Down
29 changes: 29 additions & 0 deletions src/Dock.Model/Core/Events/WindowMoveDragBeginEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;

namespace Dock.Model.Core.Events
{
/// <summary>
/// Window begin dragging event args.
/// </summary>
public class WindowMoveDragBeginEventArgs : EventArgs
{
/// <summary>
/// Gets dragged window.
/// </summary>
public IDockWindow? Window { get; }

/// <summary>
/// Gets or sets flag indicating whether window dragging should be canceled.
/// </summary>
public bool Cancel { get; set; }

/// <summary>
/// Initializes new instance of the <see cref="WindowMoveDragBeginEventArgs"/> class.
/// </summary>
/// <param name="window">The dragged window.</param>
public WindowMoveDragBeginEventArgs(IDockWindow? window)
{
Window = window;
}
}
}
24 changes: 24 additions & 0 deletions src/Dock.Model/Core/Events/WindowMoveDragEndEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace Dock.Model.Core.Events
{
/// <summary>
/// Window dragging ended event args.
/// </summary>
public class WindowMoveDragEndEventArgs : EventArgs
{
/// <summary>
/// Gets dragged window.
/// </summary>
public IDockWindow? Window { get; }

/// <summary>
/// Initializes new instance of the <see cref="WindowMoveDragEndEventArgs"/> class.
/// </summary>
/// <param name="window">The dragged window.</param>
public WindowMoveDragEndEventArgs(IDockWindow? window)
{
Window = window;
}
}
}
24 changes: 24 additions & 0 deletions src/Dock.Model/Core/Events/WindowMoveDragEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace Dock.Model.Core.Events
{
/// <summary>
/// Window dragging event args.
/// </summary>
public class WindowMoveDragEventArgs : EventArgs
{
/// <summary>
/// Gets dragged window.
/// </summary>
public IDockWindow? Window { get; }

/// <summary>
/// Initializes new instance of the <see cref="WindowMoveDragEventArgs"/> class.
/// </summary>
/// <param name="window">The dragged window.</param>
public WindowMoveDragEventArgs(IDockWindow? window)
{
Window = window;
}
}
}
Loading

0 comments on commit 3b40c50

Please sign in to comment.