From bc62a3bb7e50fe0ce1b2ee6ddcf3e525bf20646e Mon Sep 17 00:00:00 2001 From: Benjamin Popp Date: Thu, 31 Jan 2019 20:15:09 -0600 Subject: [PATCH] add a "clear format" right-click option when adding an anchor, search for pointers to that spot --- src/Gen3Hex.Core/Models/PokemonModel.cs | 31 ++++++++++++++++++++++++- src/Gen3Hex.Core/ViewModels/ViewPort.cs | 6 +++++ src/Gen3Hex.Tests/PointerModelTests.cs | 29 +++++++++++++++++++++++ src/Gen3Hex.WPF/Controls/HexContent.cs | 10 ++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/Gen3Hex.Core/Models/PokemonModel.cs b/src/Gen3Hex.Core/Models/PokemonModel.cs index ac1092e5..dde10ccd 100644 --- a/src/Gen3Hex.Core/Models/PokemonModel.cs +++ b/src/Gen3Hex.Core/Models/PokemonModel.cs @@ -700,7 +700,12 @@ namespace HavenSoft.Gen3Hex.Core.Models { /// private IReadOnlyList GetSourcesPointingToNewAnchor(ModelDelta changeToken, string anchorName) { if (!addressForAnchor.TryGetValue(anchorName, out int location)) return new List(); // new anchor is unnamed, so nothing points to it yet - if (!unmappedNameToSources.TryGetValue(anchorName, out var sources)) return new List(); // no pointer was waiting for this anchor to be created + + if (!unmappedNameToSources.TryGetValue(anchorName, out var sources)) { + // no pointer was waiting for this anchor to be created + // but the user things there's something pointing here + return SearchForPointersToAnchor(changeToken, location); + } foreach (var source in sources) { var index = BinarySearch(source); @@ -715,6 +720,27 @@ namespace HavenSoft.Gen3Hex.Core.Models { return sources; } + private IReadOnlyList SearchForPointersToAnchor(ModelDelta changeToken, int address) { + var results = new List(); + + for (int i = 3; i < RawData.Length; i++) { + if (RawData[i] != 0x08 && RawData[i] != 0x09) continue; + int destination = ReadPointer(i - 3); + if (destination != address) continue; + var index = BinarySearch(i-3); + if (index > 0) continue; + index = ~index; + if (runs[index].Start <= i) continue; + if (index > 0 && runs[index - 1].Start + runs[index - 1].Length > i - 3) continue; + var newRun = new PointerRun(i - 3); + runs.Insert(index, newRun); + changeToken.AddRun(newRun); + results.Add(i - 3); + } + + return results; + } + private IFormattedRun MoveRun(ModelDelta changeToken, IFormattedRun run, int newStart) { // repoint foreach (var source in run.PointerSources) { @@ -774,6 +800,9 @@ namespace HavenSoft.Gen3Hex.Core.Models { return true; } + // if an existing run starts exactly at start, return that index + // otherwise, return a number such that ~index would be inserted into the list at the correct index + // so ~index - 1 is the previous run, and ~index is the next run private int BinarySearch(int start) { var index = runs.BinarySearch(new CompareFormattedRun(start), FormattedRunComparer.Instance); return index; diff --git a/src/Gen3Hex.Core/ViewModels/ViewPort.cs b/src/Gen3Hex.Core/ViewModels/ViewPort.cs index 61f3e7bf..f640c9ae 100644 --- a/src/Gen3Hex.Core/ViewModels/ViewPort.cs +++ b/src/Gen3Hex.Core/ViewModels/ViewPort.cs @@ -328,6 +328,12 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels { public bool IsSelected(Point point) => selection.IsSelected(point); + public void ClearFormat(Point point) { + var dataIndex = scroll.ViewPointToDataIndex(point); + Model.ClearFormat(history.CurrentChange, dataIndex, 1); + RefreshBackingData(); + } + public void Edit(string input) { exitEditEarly = false; using (Tools.DeferUpdates) { diff --git a/src/Gen3Hex.Tests/PointerModelTests.cs b/src/Gen3Hex.Tests/PointerModelTests.cs index c4520076..084d5928 100644 --- a/src/Gen3Hex.Tests/PointerModelTests.cs +++ b/src/Gen3Hex.Tests/PointerModelTests.cs @@ -695,5 +695,34 @@ namespace HavenSoft.Gen3Hex.Tests { } } } + + [Fact] + public void AddingAnchorShouldSearchForPointersToThatLocation() { + var data = new byte[0x200]; + var model = new PokemonModel(data); + var change = new ModelDelta(); + model.WritePointer(change, 0x23, 0x050); // a pointer that isn't 4-byte aligned, pointing to data that is + model.WritePointer(change, 0x10, 0x087); // a pointer that is 4-byte aligned, but pointing to something that isn't + model.WritePointer(change, 2, 0xA2); // a pointer that isn't 4-byte aligned, pointing to something not 4-byte aligned + var viewPort = new ViewPort(new LoadedFile("test.txt", data), model) { Width = 0x10, Height = 0x10 }; + + // got to 50 and write an anchor + viewPort.SelectionStart = new Point(0x0, 0x5); + viewPort.Edit("^test1 "); + Assert.IsType(viewPort[0x3, 0x2].Format); + Assert.Single(((Anchor)viewPort[0x0, 0x5].Format).Sources); + + // go to 87 and write an anchor + viewPort.SelectionStart = new Point(0x7, 0x8); + viewPort.Edit("^test2 "); + Assert.IsType(viewPort[0x0, 0x1].Format); + Assert.Single(((Anchor)viewPort[0x7, 0x8].Format).Sources); + + // go to A2 and write an anchor + viewPort.SelectionStart = new Point(0x2, 0xA); + viewPort.Edit("^test3 "); + Assert.IsType(viewPort[0x2, 0x0].Format); + Assert.Single(((Anchor)viewPort[0x2, 0xA].Format).Sources); + } } } diff --git a/src/Gen3Hex.WPF/Controls/HexContent.cs b/src/Gen3Hex.WPF/Controls/HexContent.cs index 3a3ece4e..dbf74fe9 100644 --- a/src/Gen3Hex.WPF/Controls/HexContent.cs +++ b/src/Gen3Hex.WPF/Controls/HexContent.cs @@ -202,6 +202,7 @@ namespace HavenSoft.Gen3Hex.WPF.Controls { } if (format is PCS pcs) children.AddRange(GetStringChildren(p)); if (format is Pointer pointer) children.AddRange(GetPointerChildren(p)); + if (!(format is None || format is Undefined)) children.AddRange(GetClearFormattingChildren(p)); } else { children.AddRange(GetSearchChildren(p)); } @@ -354,6 +355,15 @@ namespace HavenSoft.Gen3Hex.WPF.Controls { yield return CreateFollowLinkButton("Open in main tab", p); } + private IEnumerable GetClearFormattingChildren(ModelPoint p) { + yield return new Button { + Content = new TextBlock { Text = "Clear Format" }, + }.SetEvent(ButtonBase.ClickEvent, (sender, e) => { + ((ViewPort)ViewPort).ClearFormat(p); + recentMenu.IsOpen = false; + }); + } + private Button CreateFollowLinkButton(string message, ModelPoint p) { return new Button { Content = new StackPanel {