diff --git a/src/DiffEngineViewer.Tests/ImageScreenTests.cs b/src/DiffEngineViewer.Tests/ImageScreenTests.cs index a5b7a82f..8e944c3d 100644 --- a/src/DiffEngineViewer.Tests/ImageScreenTests.cs +++ b/src/DiffEngineViewer.Tests/ImageScreenTests.cs @@ -99,8 +99,10 @@ public Task DeleteInQueue() => public async Task PanesCarryThePicture() { var screen = ScreenBuilder.Build(State(Received(), Expected())); - await Assert.That(screen.Left.Image).IsEqualTo(new("temp/sample.received.png", 800, 600)); - await Assert.That(screen.Right.Image).IsEqualTo(new("code/sample.verified.png", 800, 600)); + // The hash the side carried, which is how a head tells one picture from another at the + // same path and size - and how the Windows head knows to repaint for it + await Assert.That(screen.Left.Image).IsEqualTo(new("temp/sample.received.png", 800, 600, "0A")); + await Assert.That(screen.Right.Image).IsEqualTo(new("code/sample.verified.png", 800, 600, "0A")); } [Test] diff --git a/src/DiffEngineViewer.Windows.Tests/PaneChangeTests.cs b/src/DiffEngineViewer.Windows.Tests/PaneChangeTests.cs new file mode 100644 index 00000000..1c92b3f5 --- /dev/null +++ b/src/DiffEngineViewer.Windows.Tests/PaneChangeTests.cs @@ -0,0 +1,56 @@ +/// +/// Whether two panes are the same pane, which is what decides whether the window repaints. +/// ScreenBuilder allocates a fresh Screen every frame, so record equality would report a change +/// sixty times a second and the comparison is by hand. +/// +public class PaneChangeTests +{ + /// + /// The rows an image side shows are format, dimensions and byte count, and a re-run that + /// rewrites a received image at the same size changes none of them - for BMP, which is + /// uncompressed, that is every re-run. So nothing about the screen differed, Apply returned + /// before repainting, and the pane kept the previous picture while the rows beside it + /// described the new one. + /// + [Test] + public async Task A_picture_that_changed_is_not_the_same_pane() + { + var before = ImagePane("A1B2"); + var after = ImagePane("C3D4"); + + await Assert.That(ViewerForm.Same(before, after)).IsFalse(); + } + + [Test] + public async Task A_picture_that_did_not_change_is_the_same_pane() => + await Assert.That(ViewerForm.Same(ImagePane("A1B2"), ImagePane("A1B2"))).IsTrue(); + + [Test] + public async Task A_picture_replaced_by_one_of_another_size_is_not_the_same_pane() + { + var before = ImagePane("A1B2"); + var after = before with + { + Image = new("sample.received.png", 20, 10, "A1B2") + }; + + await Assert.That(ViewerForm.Same(before, after)).IsFalse(); + } + + [Test] + public async Task Text_panes_are_unaffected() + { + var pane = new Pane("received", [new(1, RowKind.Unchanged, "one")], 0, 1); + + await Assert.That(ViewerForm.Same(pane, pane with { })).IsTrue(); + await Assert.That(ViewerForm.Same(pane, pane with { ScrollTop = 1 })).IsFalse(); + } + + static Pane ImagePane(string hash) => + new( + "received", + [], + 0, + 0, + new("sample.received.png", 10, 10, hash)); +} diff --git a/src/DiffEngineViewer.Windows/ViewerForm.cs b/src/DiffEngineViewer.Windows/ViewerForm.cs index fe3a3456..458e90ef 100644 --- a/src/DiffEngineViewer.Windows/ViewerForm.cs +++ b/src/DiffEngineViewer.Windows/ViewerForm.cs @@ -422,9 +422,14 @@ left is null left.Row == right.Row && left.Labels.SequenceEqual(right.Labels); - static bool Same(Pane left, Pane right) => + internal static bool Same(Pane left, Pane right) => left.Header == right.Header && left.ScrollTop == right.ScrollTop && left.TotalRows == right.TotalRows && + // Records all the way down, so this compares the path, the size and the content stamp. A + // re-run that rewrites a received image at the same size changes nothing else about the + // screen - the rows say format, dimensions and byte count, and for BMP those hold - so + // without it Apply returned before repainting and the pane kept the previous picture. + left.Image == right.Image && left.Rows.SequenceEqual(right.Rows); } diff --git a/src/DiffEngineViewer/Model/ImagePane.cs b/src/DiffEngineViewer/Model/ImagePane.cs index 65a2e68f..442ab821 100644 --- a/src/DiffEngineViewer/Model/ImagePane.cs +++ b/src/DiffEngineViewer/Model/ImagePane.cs @@ -13,4 +13,10 @@ /// worth trying. /// /// -record ImagePane(string Path, int Width, int Height); +/// +/// What the file held when the model was built, so a head can tell one picture from another at the +/// same path and size. Not for drawing - the head reads the file - but for deciding whether what +/// is on screen is still this. A re-run that rewrites a received image at the same dimensions +/// changes nothing else in the model, and for BMP that is every re-run. +/// +record ImagePane(string Path, int Width, int Height, string? Hash); diff --git a/src/DiffEngineViewer/ScreenBuilder.cs b/src/DiffEngineViewer/ScreenBuilder.cs index a77cb81f..8ac43630 100644 --- a/src/DiffEngineViewer/ScreenBuilder.cs +++ b/src/DiffEngineViewer/ScreenBuilder.cs @@ -95,7 +95,7 @@ static Pane BuildPane( return null; } - return new(file.Path, header.Width, header.Height); + return new(file.Path, header.Width, header.Height, file.Hash); } static IReadOnlyList BuildQueue(SessionState state, int body, out int top)