Skip to content

Commit

Permalink
Merge pull request #40 from WiseTechGlobal/RAL/WI00655146/Implement_s…
Browse files Browse the repository at this point in the history
…electionBox_while_scrolling

SelectionBox now updates when scrolling
  • Loading branch information
Alvarenga1 authored Jun 20, 2024
2 parents 7182eaa + 63b8622 commit eddd879
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 19 deletions.
74 changes: 55 additions & 19 deletions src/Blazor.Diagrams.Core/Behaviors/SelectionBoxBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,25 @@ public class SelectionBoxBehavior : DragBehavior
private Point? _initialClientPoint;

public event EventHandler<Rectangle?>? SelectionBoundsChanged;
private double? _lastClientX;
private double? _lastClientY;
private Point? _initialPan;

public SelectionBoxBehavior(Diagram diagram)
: base(diagram)
{
Diagram.PointerDown += OnPointerDown;
Diagram.PointerMove += OnPointerMove;
Diagram.PointerUp += OnPointerUp;
Diagram.PanChanged += OnPanChanged;
}

public override void Dispose()
{
Diagram.PointerDown -= OnPointerDown;
Diagram.PointerMove -= OnPointerMove;
Diagram.PointerUp -= OnPointerUp;
Diagram.PanChanged -= OnPanChanged;
}

protected override void OnPointerDown(Model? model, PointerEventArgs e)
Expand All @@ -34,37 +39,32 @@ protected override void OnPointerDown(Model? model, PointerEventArgs e)
return;

_initialClientPoint = new Point(e.ClientX, e.ClientY);
_lastClientX = e.ClientX;
_lastClientY = e.ClientY;
_initialPan = Diagram.Pan;
}

protected override void OnPointerMove(Model? model, PointerEventArgs e)
{
if (_initialClientPoint == null)
return;

UpdateSelectionBox(e);
_lastClientX = e.ClientX;
_lastClientY = e.ClientY;

var start = Diagram.GetRelativeMousePoint(_initialClientPoint.X, _initialClientPoint.Y);
var end = Diagram.GetRelativeMousePoint(e.ClientX, e.ClientY);
var (sX, sY) = (Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
var (eX, eY) = (Math.Max(start.X, end.X), Math.Max(start.Y, end.Y));
var bounds = new Rectangle(sX, sY, eX, eY);
UpdateSelectionBox(e.ClientX, e.ClientY);
SelectNodesInBounds(e.ClientX, e.ClientY);
}

foreach (var node in Diagram.Nodes)
void UpdateSelectionBox(double clientX, double clientY)
{
if(_initialClientPoint == null || _initialPan == null)
{
var nodeBounds = node.GetBounds();
if (nodeBounds == null)
continue;

if (bounds.Overlap(nodeBounds))
Diagram.SelectModel(node, false);
else if (node.Selected) Diagram.UnselectModel(node);
return;
}
}

void UpdateSelectionBox(MouseEventArgs e)
{
var start = Diagram.GetRelativePoint(_initialClientPoint!.X, _initialClientPoint.Y);
var end = Diagram.GetRelativePoint(e.ClientX, e.ClientY);
var start = Diagram.GetRelativePoint(_initialClientPoint.X + Diagram.Pan.X - _initialPan.X, _initialClientPoint.Y + Diagram.Pan.Y - _initialPan.Y);
var end = Diagram.GetRelativePoint(clientX, clientY);
var (sX, sY) = (Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
var (eX, eY) = (Math.Max(start.X, end.X), Math.Max(start.Y, end.Y));
SelectionBoundsChanged?.Invoke(this, new Rectangle(sX, sY, eX, eY));
Expand All @@ -74,6 +74,42 @@ protected override void OnPointerUp(Model? model, PointerEventArgs e)
{
_initialClientPoint = null;
SelectionBoundsChanged?.Invoke(this, null);
_lastClientX = null;
_lastClientY = null;
_initialPan = null;
}

public void OnPanChanged(double deltaX, double deltaY)
{
if (_initialClientPoint == null || _lastClientX == null || _lastClientY == null)
return;

UpdateSelectionBox((double) _lastClientX, (double) _lastClientY);
SelectNodesInBounds((double) _lastClientX, (double) _lastClientY);
}

void SelectNodesInBounds(double clientX, double clientY)
{
if(_initialClientPoint == null || _initialPan == null)
{
return;
}

var start = Diagram.GetRelativeMousePoint(_initialClientPoint.X + Diagram.Pan.X - _initialPan.X, _initialClientPoint.Y + Diagram.Pan.Y - _initialPan.Y);
var end = Diagram.GetRelativeMousePoint(clientX, clientY);
var (sX, sY) = (Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
var (eX, eY) = (Math.Max(start.X, end.X), Math.Max(start.Y, end.Y));
var bounds = new Rectangle(sX, sY, eX, eY);

foreach (var node in Diagram.Nodes)
{
var nodeBounds = node.GetBounds();
if (nodeBounds == null)
continue;
if (bounds.Overlap(nodeBounds))
Diagram.SelectModel(node, false);
else if (node.Selected) Diagram.UnselectModel(node);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,38 @@ public void Behavior_WhenBehaviorEnabled_ShouldUpdateSelectionBounds()
Assert.Equal(100, lastBounds.Left);
}

[Fact]
public void Behavior_WhenBehaviorEnabled_ShouldUpdateSelectionBoundsOnScroll()
{
// Arrange
var diagram = new TestDiagram();
diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior<PanBehavior>();
diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior<SelectionBoxBehavior>();
diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior<ScrollBehavior>();
diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));

var selectionBoxBehavior = diagram.GetBehavior<SelectionBoxBehavior>()!;
bool boundsChangedEventInvoked = false;
Rectangle? lastBounds = null;
selectionBoxBehavior.SelectionBoundsChanged += (_, newBounds) =>
{
boundsChangedEventInvoked = true;
lastBounds = newBounds;
};

// Act
diagram.TriggerPointerDown(null,
new PointerEventArgs(100, 100, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, 200, 150, 0, 0));

// Assert
Assert.True(boundsChangedEventInvoked);
Assert.Equal(200, lastBounds!.Width);
Assert.Equal(150, lastBounds.Height);
Assert.Equal(-50, lastBounds.Top);
Assert.Equal(-100, lastBounds.Left);
}

[Fact]
public void Behavior_WhenBehaviorDisabled_ShouldNotUpdateSelectionBounds()
{
Expand Down Expand Up @@ -99,6 +131,39 @@ public void Behavior_WithBoundsChangedDelegate_ShouldSelectNodesInsideArea()
Assert.False(node.Selected);
}

[Fact]
public void Behavior_WithBoundsChangedDelegate_ShouldSelectNodesInsideAreaWhenScrolling()
{
// Arrange
var diagram = new TestDiagram();
diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior<PanBehavior>();
diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior<SelectionBoxBehavior>();
diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior<ScrollBehavior>();
diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));

var selectionBoxBehavior = diagram.GetBehavior<SelectionBoxBehavior>()!;
selectionBoxBehavior.SelectionBoundsChanged += (_, _) => { };

var node = new NodeModel()
{
Size = new Size(100, 100),
Position = new Point(150, 150)
};
diagram.Nodes.Add(node);

// Act
diagram.TriggerPointerDown(null,
new PointerEventArgs(100, 100, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, 200, 200, 0, 0));

// Assert
Assert.True(node.Selected);

diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, -200, -200, 0, 0));

Assert.False(node.Selected);
}

[Fact]
public void Behavior_WithoutBoundsChangedDelegate_ShouldNotSelectNodesInsideArea()
{
Expand Down Expand Up @@ -127,5 +192,36 @@ public void Behavior_WithoutBoundsChangedDelegate_ShouldNotSelectNodesInsideArea
new PointerEventArgs(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
Assert.False(node.Selected);
}

[Fact]
public void Behavior_WithoutBoundsChangedDelegate_ShouldNotSelectNodesInsideAreaWhenScrolling()
{
// Arrange
var diagram = new TestDiagram();
diagram.BehaviorOptions.DiagramDragBehavior = diagram.GetBehavior<PanBehavior>();
diagram.BehaviorOptions.DiagramShiftDragBehavior = diagram.GetBehavior<SelectionBoxBehavior>();
diagram.BehaviorOptions.DiagramWheelBehavior = diagram.GetBehavior<ScrollBehavior>();
diagram.SetContainer(new Rectangle(Point.Zero, new Size(100, 100)));

var node = new NodeModel()
{
Size = new Size(100, 100),
Position = new Point(150, 150)
};
diagram.Nodes.Add(node);

// Act
diagram.TriggerPointerDown(null,
new PointerEventArgs(100, 100, 0, 0, false, true, false, 0, 0, 0, 0, 0, 0, string.Empty, true));
diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, 200, 200, 0, 0));


// Assert
Assert.False(node.Selected);

diagram.TriggerWheel(new WheelEventArgs(100, 100, 0, 0, false, true, false, -200, -200, 0, 0));

Assert.False(node.Selected);
}
}
}

0 comments on commit eddd879

Please sign in to comment.