This repository has been archived by the owner on Jul 10, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
40a6ffb
commit b149aa7
Showing
1 changed file
with
200 additions
and
0 deletions.
There are no files selected for viewing
200 changes: 200 additions & 0 deletions
200
src/OneWare.Essentials/Behaviours/ContextDragBubbleBehavior.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
using Avalonia; | ||
using Avalonia.Controls; | ||
using Avalonia.Input; | ||
using Avalonia.Interactivity; | ||
using Avalonia.LogicalTree; | ||
using Avalonia.Xaml.Interactions.DragAndDrop; | ||
using Avalonia.Xaml.Interactivity; | ||
|
||
namespace OneWare.Essentials.Behaviours; | ||
|
||
public class ContextDragBubbleBehavior : Behavior<Control> | ||
{ | ||
private Point _dragStartPoint; | ||
private PointerEventArgs? _triggerEvent; | ||
private bool _lock; | ||
private bool _captured; | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public static readonly StyledProperty<object?> ContextProperty = | ||
AvaloniaProperty.Register<ContextDragBehavior, object?>(nameof(Context)); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public static readonly StyledProperty<IDragHandler?> HandlerProperty = | ||
AvaloniaProperty.Register<ContextDragBehavior, IDragHandler?>(nameof(Handler)); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public static readonly StyledProperty<double> HorizontalDragThresholdProperty = | ||
AvaloniaProperty.Register<ContextDragBehavior, double>(nameof(HorizontalDragThreshold), 3); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public static readonly StyledProperty<double> VerticalDragThresholdProperty = | ||
AvaloniaProperty.Register<ContextDragBehavior, double>(nameof(VerticalDragThreshold), 3); | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public object? Context | ||
{ | ||
get => GetValue(ContextProperty); | ||
set => SetValue(ContextProperty, value); | ||
} | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public IDragHandler? Handler | ||
{ | ||
get => GetValue(HandlerProperty); | ||
set => SetValue(HandlerProperty, value); | ||
} | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public double HorizontalDragThreshold | ||
{ | ||
get => GetValue(HorizontalDragThresholdProperty); | ||
set => SetValue(HorizontalDragThresholdProperty, value); | ||
} | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public double VerticalDragThreshold | ||
{ | ||
get => GetValue(VerticalDragThresholdProperty); | ||
set => SetValue(VerticalDragThresholdProperty, value); | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override void OnAttachedToVisualTree() | ||
{ | ||
AssociatedObject?.AddHandler(InputElement.PointerPressedEvent, AssociatedObject_PointerPressed, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble); | ||
AssociatedObject?.AddHandler(InputElement.PointerReleasedEvent, AssociatedObject_PointerReleased, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble); | ||
AssociatedObject?.AddHandler(InputElement.PointerMovedEvent, AssociatedObject_PointerMoved, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble); | ||
AssociatedObject?.AddHandler(InputElement.PointerCaptureLostEvent, AssociatedObject_CaptureLost, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble); | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override void OnDetachedFromVisualTree() | ||
{ | ||
AssociatedObject?.RemoveHandler(InputElement.PointerPressedEvent, AssociatedObject_PointerPressed); | ||
AssociatedObject?.RemoveHandler(InputElement.PointerReleasedEvent, AssociatedObject_PointerReleased); | ||
AssociatedObject?.RemoveHandler(InputElement.PointerMovedEvent, AssociatedObject_PointerMoved); | ||
AssociatedObject?.RemoveHandler(InputElement.PointerCaptureLostEvent, AssociatedObject_CaptureLost); | ||
} | ||
|
||
private async Task DoDragDrop(PointerEventArgs triggerEvent, object? value) | ||
Check warning on line 96 in src/OneWare.Essentials/Behaviours/ContextDragBubbleBehavior.cs GitHub Actions / build
Check warning on line 96 in src/OneWare.Essentials/Behaviours/ContextDragBubbleBehavior.cs GitHub Actions / build
|
||
{ | ||
var data = new DataObject(); | ||
data.Set(ContextDropBehavior.DataFormat, value!); | ||
|
||
var effect = DragDropEffects.None; | ||
|
||
if (triggerEvent.KeyModifiers.HasFlag(KeyModifiers.Alt)) | ||
{ | ||
effect |= DragDropEffects.Link; | ||
} | ||
else if (triggerEvent.KeyModifiers.HasFlag(KeyModifiers.Shift)) | ||
{ | ||
effect |= DragDropEffects.Move; | ||
} | ||
else if (triggerEvent.KeyModifiers.HasFlag(KeyModifiers.Control)) | ||
{ | ||
effect |= DragDropEffects.Copy; | ||
} | ||
else | ||
{ | ||
effect |= DragDropEffects.Move; | ||
} | ||
|
||
await DragDrop.DoDragDrop(triggerEvent, data, effect); | ||
} | ||
|
||
private void Released() | ||
{ | ||
_triggerEvent = null; | ||
_lock = false; | ||
} | ||
|
||
private void AssociatedObject_PointerPressed(object? sender, PointerPressedEventArgs e) | ||
{ | ||
var properties = e.GetCurrentPoint(AssociatedObject).Properties; | ||
if (properties.IsLeftButtonPressed) | ||
{ | ||
if (e.Source is Control control | ||
&& AssociatedObject?.DataContext == control.DataContext) | ||
{ | ||
if ((control as ISelectable ?? control.Parent as ISelectable)?.IsSelected ?? false) e.Handled = true; //avoid deselection on drag | ||
_dragStartPoint = e.GetPosition(null); | ||
_triggerEvent = e; | ||
_lock = true; | ||
_captured = true; | ||
} | ||
} | ||
} | ||
|
||
private void AssociatedObject_PointerReleased(object? sender, PointerReleasedEventArgs e) | ||
{ | ||
if (_captured) | ||
{ | ||
if (e.InitialPressMouseButton == MouseButton.Left && _triggerEvent is not null) | ||
{ | ||
Released(); | ||
} | ||
|
||
_captured = false; | ||
} | ||
} | ||
|
||
private async void AssociatedObject_PointerMoved(object? sender, PointerEventArgs e) | ||
Check warning on line 159 in src/OneWare.Essentials/Behaviours/ContextDragBubbleBehavior.cs GitHub Actions / build
Check warning on line 159 in src/OneWare.Essentials/Behaviours/ContextDragBubbleBehavior.cs GitHub Actions / build
|
||
{ | ||
var properties = e.GetCurrentPoint(AssociatedObject).Properties; | ||
if (_captured | ||
&& properties.IsLeftButtonPressed && | ||
_triggerEvent is not null) | ||
{ | ||
var point = e.GetPosition(null); | ||
var diff = _dragStartPoint - point; | ||
var horizontalDragThreshold = HorizontalDragThreshold; | ||
var verticalDragThreshold = VerticalDragThreshold; | ||
|
||
if (Math.Abs(diff.X) > horizontalDragThreshold || Math.Abs(diff.Y) > verticalDragThreshold) | ||
{ | ||
if (_lock) | ||
{ | ||
_lock = false; | ||
} | ||
else | ||
{ | ||
return; | ||
} | ||
|
||
var context = Context ?? AssociatedObject?.DataContext; | ||
|
||
Handler?.BeforeDragDrop(sender, _triggerEvent, context); | ||
|
||
await DoDragDrop(_triggerEvent, context); | ||
|
||
Handler?.AfterDragDrop(sender, _triggerEvent, context); | ||
|
||
_triggerEvent = null; | ||
} | ||
} | ||
} | ||
|
||
private void AssociatedObject_CaptureLost(object? sender, PointerCaptureLostEventArgs e) | ||
{ | ||
Released(); | ||
_captured = false; | ||
} | ||
} |