Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
Type: Window,
WindowState: Normal,
Content: {
Type: StackPanel,
Spacing: 8.0,
Orientation: Vertical,
Children: [
{
Type: ZoomControl,
Content: {
Type: WayfinderRenderTests.TrackableCanvas,
Background: Transparent,
Width: 800.0,
Height: 600.0,
Children: [
{
Type: Rectangle,
Fill: SteelBlue,
Width: 40.0,
Height: 40.0
},
{
Type: Rectangle,
Fill: SteelBlue,
Width: 40.0,
Height: 40.0
},
{
Type: Rectangle,
Fill: SteelBlue,
Width: 40.0,
Height: 40.0
},
{
Type: Rectangle,
Fill: SteelBlue,
Width: 40.0,
Height: 40.0
},
{
Type: Rectangle,
Fill: SteelBlue,
Width: 40.0,
Height: 40.0
}
]
},
Width: 400.0,
Height: 240.0
},
{
Type: Wayfinder,
Focusable: true,
Width: 200.0,
Height: 120.0,
ClipToBounds: true
}
]
},
Background: White,
Width: 420.0,
Height: 400.0,
IsVisible: true
}
93 changes: 93 additions & 0 deletions Westermo.GraphX.Controls.Avalonia.Tests/WayfinderRenderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Threading;
using Westermo.GraphX.Controls.Controls.Misc;
using Westermo.GraphX.Controls.Controls.ZoomControl;
using Westermo.GraphX.Controls.Models;

namespace Westermo.GraphX.Controls.Avalonia.Tests;

Expand Down Expand Up @@ -108,6 +110,64 @@ private static (Window window, ZoomControl zc, Wayfinder wf) BuildScene(
return (window, zc, wf);
}

private static (Window window, ZoomControl zc, Wayfinder wf) BuildOffsetTrackableScene(
Rect contentRect,
Action<Panel> populateContent)
{
// GraphArea reports the actual child extent via ITrackableContent.
// Reproduce that here without depending on graph layout algorithms.
var content = new TrackableCanvas(contentRect)
{
Width = contentRect.Width,
Height = contentRect.Height,
Background = Brushes.Transparent
};
populateContent(content);

var zc = new ZoomControl
{
Width = 400,
Height = 240,
Content = content
};

var wf = new Wayfinder
{
Width = WayfinderWidth,
Height = WayfinderHeight,
ZoomControl = zc,
Background = new SolidColorBrush(Color.FromRgb(0xF0, 0xF0, 0xF0)),
ShadowBrush = null,
ViewportBrush = Brushes.Transparent,
ViewportPen = null
};

var root = new StackPanel
{
Orientation = Orientation.Vertical,
Spacing = 8,
Children = { zc, wf }
};

var window = new Window
{
Width = 420,
Height = 400,
Background = Brushes.White,
Content = root
};
window.Show();

for (var i = 0; i < 3; i++)
{
window.Measure(new Size(420, 400));
window.Arrange(new Rect(0, 0, 420, 400));
Dispatcher.UIThread.RunJobs();
}

return (window, zc, wf);
}

private static VerifySettings GetSettings([CallerMemberName] string? testName = null)
{
var settings = new VerifySettings();
Expand Down Expand Up @@ -193,6 +253,28 @@ public async Task Viewport_ReachesLeftmostEdge_WhenPannedFully()
await Verify(window, GetSettings());
}

/// <summary>
/// Trackable graph content may have a positive top-left extent when all
/// vertices live away from the origin. The minimap must still render the
/// bottom/right of that extent instead of clipping it by the offset amount.
/// </summary>
[Test]
public async Task Renders_OffsetTrackableContent_WithoutClippingLowerOrRightEdges()
{
var contentRect = new Rect(100, 80, 800, 600);
var (window, _, wf) = BuildOffsetTrackableScene(contentRect, canvas =>
{
AddBox(canvas, 0, 0, 40, 40);
AddBox(canvas, 760, 0, 40, 40);
AddBox(canvas, 0, 560, 40, 40);
AddBox(canvas, 760, 560, 40, 40);
AddBox(canvas, 380, 280, 40, 40);
});

// Verify.Avalonia takes ownership of closing the window.
await Verify(window, GetSettings());
}

private static void AddBox(Panel canvas, double x, double y, double w, double h)
{
var rect = new Rectangle
Expand All @@ -205,4 +287,15 @@ private static void AddBox(Panel canvas, double x, double y, double w, double h)
Canvas.SetTop(rect, y);
canvas.Children.Add(rect);
}

private sealed class TrackableCanvas(Rect contentSize) : Canvas, ITrackableContent
{
public event ContentSizeChangedEventHandler? ContentSizeChanged
{
add { }
remove { }
}

public Rect ContentSize { get; } = contentSize;
}
}
64 changes: 64 additions & 0 deletions Westermo.GraphX.Controls.Avalonia.Tests/ZoomControlTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Threading;
using Westermo.GraphX.Controls.Controls.ZoomControl;
using Westermo.GraphX.Controls.Controls.ZoomControl.SupportClasses;
Expand Down Expand Up @@ -228,6 +229,69 @@ public async Task Mode_SetToFill_TriggersZoomToFill()

#endregion

#region Modifier Drag Gesture Tests

[Test]
public async Task Alt_LeftDrag_Zooms_To_Rectangle()
{
var (zc, window) = CreateZoomControlWithContent(800, 600, 1000, 1000);
try
{
zc.Mode = ZoomControlModes.Custom;
zc.Zoom = 1.0;

var areaSelectedCount = 0;
zc.AreaSelected += (_, _) => areaSelectedCount++;

var initialZoom = zc.Zoom;
var beganInteraction = zc.BeginInteractionForTest(KeyModifiers.Alt, new Point(100, 100));
await Assert.That(beganInteraction).IsTrue();
zc.MoveInteractionForTest(new Point(300, 300));
zc.CompleteInteractionForTest();

await Assert.That(zc.Zoom).IsGreaterThan(initialZoom);
await Assert.That(areaSelectedCount).IsEqualTo(0);
await Assert.That(zc.ZoomBox).IsEqualTo(default(Rect));
}
finally
{
window.Close();
}
}

[Test]
public async Task ControlAlt_LeftDrag_AreaSelects_Without_Zooming()
{
var (zc, window) = CreateZoomControlWithContent(800, 600, 1000, 1000);
try
{
zc.Mode = ZoomControlModes.Custom;
zc.Zoom = 1.0;

Rect? selectedRectangle = null;
zc.AreaSelected += (_, args) => selectedRectangle = args.Rectangle;

var initialZoom = zc.Zoom;
var beganInteraction =
zc.BeginInteractionForTest(KeyModifiers.Control | KeyModifiers.Alt, new Point(100, 100));
await Assert.That(beganInteraction).IsTrue();
zc.MoveInteractionForTest(new Point(300, 300));
zc.CompleteInteractionForTest();

await Assert.That(zc.Zoom).IsEqualTo(initialZoom);
await Assert.That(selectedRectangle.HasValue).IsTrue();
await Assert.That(Math.Abs(selectedRectangle!.Value.Width - 200)).IsLessThan(Tolerance);
await Assert.That(Math.Abs(selectedRectangle.Value.Height - 200)).IsLessThan(Tolerance);
await Assert.That(zc.ZoomBox).IsEqualTo(default(Rect));
}
finally
{
window.Close();
}
}

#endregion

#region ZoomToContent Tests

[Test]
Expand Down
Loading
Loading