appending to a table should refresh the table view

so that new elements can be seen when in single-table-focus

don't write runs into other runs when changing pointers in text-pointer tables.
This commit is contained in:
haven1433
2022-10-23 20:09:47 -05:00
parent 93ccd80230
commit a78ca56744
7 changed files with 56 additions and 11 deletions

View File

@@ -1018,15 +1018,15 @@ namespace HavenSoft.HexManiac.Core.Models {
IFormattedRun existingRun = null;
if (index < 0) {
index = ~index;
if (runs.Count == index || (runs[index].Start >= run.Start + run.Length && (index == 0 || runs[index - 1].Start + runs[index - 1].Length <= run.Start))) {
// check for conflict with previous run / next run
if (index > 0 && run.Start < runs[index - 1].Start + runs[index - 1].Length) {
Debug.Fail($"Trying to add a run at {run.Start:X6} which overlaps a run at {runs[index - 1].Start:X6}");
} else if (index < runs.Count && runs[index].Start < run.Start + run.Length) {
Debug.Fail($"Trying to add a run at {run.Start:X6} which overlaps a run at {runs[index].Start:X6}");
} else {
runs.Insert(index, run);
changeToken.AddRun(run);
} else {
// there's a conflict: the new run was written in a space already being used, but not where another run starts
// I'll need to do something here eventually... but for now, just error
// the right thing to do is probably to erase the existing format in favor of the new thing the user just tried to add.
// if the existing format was an anchor, clear all the pointers that pointed to it, since the writer is declaring that that address is not a valid anchor.
Debug.Fail($"Trying to add a run at {run.Start:X6} which overlaps a run at {runs[index].Start:X6}");
}
} else {
// replace / merge with existing

View File

@@ -136,7 +136,12 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
if (oldRun.PointerSources.Count == 0 && model.GetAnchorFromAddress(-1, oldRun.Start) == string.Empty) model.ClearFormat(token, oldDestination, 1);
}
var changed = model.WritePointer(token, start, address);
model.ObserveRunWritten(token, new NoInfoRun(address, new SortedSpan<int>(start)));
var existingRun = model.GetNextRun(address);
if (existingRun.Start < address) {
// can't actually add a NoInfoRun here
} else {
model.ObserveRunWritten(token, new NoInfoRun(address, new SortedSpan<int>(start)));
}
return changed;
}
default:

View File

@@ -15,7 +15,14 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Factory {
// our token will be a no-change token if we're in the middle of exploring the data.
// If so, don't actually add the run. It's enough to know that we _can_ add the run.
if (!(token is NoDataChangeDeltaModel)) owner.ObserveRunWritten(token, new PCSRun(owner, destination, length));
if (token is not NoDataChangeDeltaModel) {
var existingRun = owner.GetNextRun(destination);
// don't add a format if it would conflict with an existing format
if (existingRun.Start < destination) return false;
if (existingRun.Start > destination && existingRun.Start < destination + length) return false;
owner.ObserveRunWritten(token, new PCSRun(owner, destination, length));
}
// even if we didn't add the format, we're _capable_ of adding it... so return true
return true;

View File

@@ -222,8 +222,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
}
} else {
append.RaiseCanExecuteChanged();
viewPort.Refresh();
}
viewPort.Refresh();
RequestMenuClose?.Invoke(this, EventArgs.Empty);
if (model is PokemonModel pModel) pModel.ResolveConflicts();
}

View File

@@ -90,6 +90,10 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public event EventHandler PreviewScrollChanged;
public int DataStart => scroll.DataStart;
public int DataLength => scroll.DataLength - scroll.DataStart;
public int Width {
get => scroll.Width;
set {
@@ -1252,8 +1256,9 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
scroll.DataLength = Model.Count;
var selectionStart = ConvertViewPointToAddress(SelectionStart);
if (selectionStart > Model.Count + 1) SelectionStart = ConvertAddressToViewPoint(Model.Count + 1);
RefreshBackingData();
scroll.UpdateHeaders();
if (Model.GetNextRun(selectionStart) is ITableRun table) scroll.SetTableMode(table.Start, table.Length);
RefreshBackingData();
Tools?.TableTool.DataForCurrentRunChanged();
Tools?.SpriteTool.DataForCurrentRunChanged();
UpdateAnchorText(ConvertViewPointToAddress(SelectionStart));

View File

@@ -342,5 +342,20 @@ namespace HavenSoft.HexManiac.Tests {
Model.ResolveConflicts();
Assert.Equal(int.MaxValue, Model.GetNextRun(0x0).Start);
}
[Fact]
public void SingleTableFocus_ExpandTableStreamWithoutRepoint_SeeFullStream() {
SetFullModel(0xFF);
ViewPort.Edit("@100 00 00 11 11 22 22 @100 ^table[a. b.]!FFFF @000 ");
ViewPort.AllowSingleTableMode = true;
ViewPort.Goto.Execute("table");
Assert.Equal(8, ViewPort.DataLength);
ViewPort.SelectionStart = ViewPort.ConvertAddressToViewPoint(0x104);
ViewPort.Tools.TableTool.Append.Execute();
Assert.Equal(10, ViewPort.DataLength);
}
}
}

View File

@@ -1290,6 +1290,19 @@ namespace HavenSoft.HexManiac.Tests {
Assert.Single(table.Search(Model, "names", 0));
}
[Fact]
public void PointersToTextTable_ChangeToPointToMiddleOfText_NoErrorsRedPointer() {
SetFullModel(0xFF);
ViewPort.Edit("<null> <null> <null> @000 ^table[ptr<\"\">]3 <100> @100 Content ");
ViewPort.Edit("@004 <102>"); // points to middle of existing content
ViewPort.Goto.Execute(0);
var pFormat = (Pointer)ViewPort[4, 0].Format;
Assert.True(pFormat.HasError); // points to the middle of existing content = error pointer
Assert.Equal(0x100, Model.GetNextRun(0x102).Start); // text run still starts at 0x100
}
private void ArrangeTrainerPokemonTeamData(byte structType, byte pokemonCount, int trainerCount) {
CreateTextTable(HardcodeTablesModel.PokemonNameTable, 0x180, "ABCDEFGHIJKLMNOP".Select(c => c.ToString()).ToArray());
CreateTextTable(HardcodeTablesModel.MoveNamesTable, 0x1B0, "qrstuvwxyz".Select(c => c.ToString()).ToArray());