add a "clear format" right-click option

when adding an anchor, search for pointers to that spot
This commit is contained in:
Benjamin Popp 2019-01-31 20:15:09 -06:00
parent 75a65ce502
commit bc62a3bb7e
4 changed files with 75 additions and 1 deletions

View File

@ -700,7 +700,12 @@ namespace HavenSoft.Gen3Hex.Core.Models {
/// </returns>
private IReadOnlyList<int> GetSourcesPointingToNewAnchor(ModelDelta changeToken, string anchorName) {
if (!addressForAnchor.TryGetValue(anchorName, out int location)) return new List<int>(); // new anchor is unnamed, so nothing points to it yet
if (!unmappedNameToSources.TryGetValue(anchorName, out var sources)) return new List<int>(); // 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<int> SearchForPointersToAnchor(ModelDelta changeToken, int address) {
var results = new List<int>();
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;

View File

@ -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) {

View File

@ -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<Pointer>(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<Pointer>(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<Pointer>(viewPort[0x2, 0x0].Format);
Assert.Single(((Anchor)viewPort[0x2, 0xA].Format).Sources);
}
}
}

View File

@ -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<FrameworkElement> 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 {