make string tool interact with main viewport in the expected ways.

This commit is contained in:
Benjamin Popp
2019-01-03 21:23:44 -06:00
parent 07e14fc264
commit 6f1845f5fe
6 changed files with 92 additions and 8 deletions

View File

@@ -94,7 +94,7 @@ namespace HavenSoft.Gen3Hex.Core.Models {
bool isEscaped = index > Start && data[index - 1] == PCSString.Escape;
var fullString = PCSString.Convert(data, Start, Length);
if (isEscaped) {
return new EscapedPCS(Start, index-Start, fullString, data[Start + index]);
return new EscapedPCS(Start, index-Start, fullString, data[index]);
} else {
var character = PCSString.Convert(data, index, 1).Substring(1); // trim leading "
if (index == Start) character = '"' + character; // include the opening quotation mark, only for the first character

View File

@@ -61,7 +61,7 @@ namespace HavenSoft.Gen3Hex.Core.Models {
result.Add((byte)i);
index += PCS[i].Length - 1;
if (i == Escape) {
result.Add(byte.Parse(input.Substring(index, 2), NumberStyles.HexNumber));
result.Add(byte.Parse(input.Substring(index + 1, 2), NumberStyles.HexNumber));
index += 2;
}
break;

View File

@@ -1,5 +1,6 @@
using HavenSoft.Gen3Hex.Core.Models;
using HavenSoft.Gen3Hex.Core.ViewModels.DataFormats;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
@@ -64,8 +65,18 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
if (run == null) return;
var bytes = PCSString.Convert(content);
var newRun = model.RelocateForExpansion(run, bytes.Count);
if (run.Start != newRun.Start) ModelDataMoved?.Invoke(this, (run.Start, newRun.Start));
// clear out excess bytes that are no longer in use
if (run.Start == newRun.Start) {
for (int i = bytes.Count; i < run.Length; i++) model[run.Start + i] = 0xFF;
}
for (int i = 0; i < bytes.Count; i++) model[newRun.Start + i] = bytes[i];
model.ObserveRunWritten(new PCSRun(newRun.Start, bytes.Count, newRun.PointerSources));
run = new PCSRun(newRun.Start, bytes.Count, newRun.PointerSources);
model.ObserveRunWritten(run);
ModelDataChanged?.Invoke(this, run);
TryUpdate(ref address, newRun.Start, nameof(Address));
}
}
}
@@ -82,6 +93,9 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
}
}
public event EventHandler<IFormattedRun> ModelDataChanged;
public event EventHandler<(int originalLocation, int newLocation)> ModelDataMoved;
public PCSTool(IModel model) => this.model = model;
}
}

View File

@@ -226,6 +226,8 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
Model = model ?? new BasicModel(file.Contents);
FileName = file.Name;
Tools = new ToolTray(Model);
Tools.StringTool.ModelDataChanged += ModelChangedByTool;
Tools.StringTool.ModelDataMoved += ModelDataMovedByTool;
scroll = new ScrollRegion { DataLength = Model.Count };
scroll.PropertyChanged += ScrollPropertyChanged;
@@ -748,7 +750,7 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
// last character edit: might require relocation
var newRun = Model.RelocateForExpansion(run, run.Length + extraBytesNeeded);
if (newRun != run) {
var offset = memoryLocation - scroll.ViewPointToDataIndex(new Point(0, 0));
var offset = memoryLocation - scroll.DataIndex;
selection.GotoAddress(newRun.Start + pcs.Position - offset);
memoryLocation += newRun.Start - run.Start;
run = newRun;
@@ -805,6 +807,21 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
selection.PropertyChanged += SelectionPropertyChanged;
}
private void ModelChangedByTool(object sender, IFormattedRun run) {
if (run.Start < scroll.ViewPointToDataIndex(new Point(Width - 1, Height - 1)) || run.Start + run.Length > scroll.DataIndex) {
// there's some visible data that changed
RefreshBackingData();
}
}
private void ModelDataMovedByTool(object sender, (int originalLocation, int newLocation) locations) {
if (scroll.DataIndex <= locations.originalLocation && locations.originalLocation < scroll.ViewPointToDataIndex(new Point(Width - 1, Height - 1))) {
// data was moved from onscreen: follow it
int offset = locations.originalLocation - scroll.DataIndex;
selection.GotoAddress(locations.newLocation - offset);
}
}
private void RefreshBackingData() {
currentView = new HexElement[Width, Height];
IFormattedRun run = null;

View File

@@ -1,6 +1,8 @@
using HavenSoft.Gen3Hex.Core.Models;
using HavenSoft.Gen3Hex.Core.ViewModels;
using HavenSoft.Gen3Hex.Core.ViewModels.DataFormats;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Xunit;
@@ -8,12 +10,12 @@ namespace HavenSoft.Gen3Hex.Tests {
public class ToolTests {
[Fact]
public void ViewPortHasTools() {
var viewPort = new ViewPort(new Core.Models.LoadedFile("file.txt", new byte[100]));
var viewPort = new ViewPort(new LoadedFile("file.txt", new byte[100]));
Assert.True(viewPort.HasTools);
}
[Fact]
public void StringToolCanMoveData() {
public void StringToolCanOpenOnChosenData() {
var buffer = Enumerable.Repeat((byte)0xFF, 0x200).ToArray();
var model = new PointerAndStringModel(buffer);
var viewPort = new ViewPort(new LoadedFile("test.txt", buffer), model) { Width = 0x10, Height = 0x10 };
@@ -26,6 +28,57 @@ namespace HavenSoft.Gen3Hex.Tests {
Assert.IsType<PCSTool>(viewPort.Tools[viewPort.Tools.SelectedIndex]);
}
// TODO tool changes should be immediately reflected in the ViewPort
[Fact]
public void StringToolEditsAreReflectedInViewPort() {
var buffer = Enumerable.Repeat((byte)0xFF, 0x200).ToArray();
var model = new PointerAndStringModel(buffer);
var viewPort = new ViewPort(new LoadedFile("test.txt", buffer), model) { Width = 0x10, Height = 0x10 };
viewPort.Edit("^bob\"\" \"Some Text\" 00 <000100>");
viewPort.Tools.StringTool.Address = 0;
viewPort.Tools.StringTool.Content = "Some Test"; // Text -> Test
var pcs = (PCS)viewPort[7, 0].Format;
Assert.Equal("s", pcs.ThisCharacter);
}
[Fact]
public void StringToolCanMoveData() {
var buffer = Enumerable.Repeat((byte)0xFF, 0x200).ToArray();
var model = new PointerAndStringModel(buffer);
var viewPort = new ViewPort(new LoadedFile("test.txt", buffer), model) { Width = 0x10, Height = 0x10 };
viewPort.Edit("^bob\"\" \"Some Text\" 00 <000100>");
var toolProperties = new List<string>();
viewPort.Tools.StringTool.PropertyChanged += (sender, e) => toolProperties.Add(e.PropertyName);
viewPort.Tools.StringTool.Address = 0;
toolProperties.Clear();
viewPort.Tools.StringTool.Content = "Some More Text";
Assert.Contains("Address", toolProperties);
}
[Fact]
public void ViewPortMovesWhenStringToolMovesData() {
var buffer = Enumerable.Repeat((byte)0xFF, 0x200).ToArray();
var model = new PointerAndStringModel(buffer);
var viewPort = new ViewPort(new LoadedFile("test.txt", buffer), model) { Width = 0x10, Height = 0x10 };
viewPort.Edit("^bob\"\" \"Some Text\" 00 <000100>");
viewPort.Tools.StringTool.Address = 0;
viewPort.Tools.StringTool.Content = "Some More Text";
Assert.NotEqual(0, int.Parse(viewPort.Headers[0], NumberStyles.HexNumber));
}
[Fact]
public void StringToolMultiCharacterDeleteCleansUpUnusedBytes() {
var buffer = Enumerable.Repeat((byte)0xFF, 0x200).ToArray();
var model = new PointerAndStringModel(buffer);
var viewPort = new ViewPort(new LoadedFile("test.txt", buffer), model) { Width = 0x10, Height = 0x10 };
viewPort.Edit("^bob\"\" \"Some Text\" 00 <000100>");
viewPort.Tools.StringTool.Address = 0;
viewPort.Tools.StringTool.Content = "Some "; // removed 'Text' from the end
Assert.Equal(0xFF, model[7]);
}
}
}

View File

@@ -209,7 +209,7 @@
</Style>
</StackPanel.Style>
<TextBox Text="{Binding StringTool.Address, Converter={StaticResource Hex}}" Margin="5,15"/>
<TextBox Text="{Binding StringTool.Content}" Margin="5,15" AcceptsReturn="True" MinHeight="50" TextWrapping="Wrap"/>
<TextBox Text="{Binding StringTool.Content, UpdateSourceTrigger=PropertyChanged}" Margin="5,15" AcceptsReturn="True" MinHeight="50" MinWidth="50" MaxWidth="150" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
<ScrollBar DockPanel.Dock="Right"