From 76df0b7bb025ec8702d8c51cd9617afa13faabe3 Mon Sep 17 00:00:00 2001 From: Benjamin Popp Date: Mon, 27 May 2019 14:01:09 -0500 Subject: [PATCH] Add text pointer content to tool. --- .../Tools/IArrayElementViewModel.cs | 45 +++++++++++++++++++ .../ViewModels/Tools/TableTool.cs | 13 ++++++ src/HexManiac.Tests/NestedTablesTests.cs | 15 +++++++ src/HexManiac.WPF/Controls/TabView.xaml | 3 ++ 4 files changed, 76 insertions(+) diff --git a/src/HexManiac.Core/ViewModels/Tools/IArrayElementViewModel.cs b/src/HexManiac.Core/ViewModels/Tools/IArrayElementViewModel.cs index 6b843078..8a74390b 100644 --- a/src/HexManiac.Core/ViewModels/Tools/IArrayElementViewModel.cs +++ b/src/HexManiac.Core/ViewModels/Tools/IArrayElementViewModel.cs @@ -215,4 +215,49 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools { } } } + + public class TextStreamArrayElementViewModel : ViewModelCore, IArrayElementViewModel { + private readonly ChangeHistory history; + private readonly IDataModel model; + private readonly string name; + private readonly int start; + + public bool IsInError => !string.IsNullOrEmpty(ErrorText); + public string ErrorText { get; private set; } + public event EventHandler DataChanged; + public event EventHandler<(int originalStart, int newStart)> DataMoved; + + string content; + public string Content { + get => content; + set { + if (TryUpdate(ref content, value)) { + var destination = model.ReadPointer(start); + var run = model.GetNextRun(destination); + var data = PCSString.Convert(content); + var newRun = model.RelocateForExpansion(history.CurrentChange, run, data.Count); + if (run.Start != newRun.Start) DataMoved?.Invoke(this, (run.Start, newRun.Start)); + run = newRun; + for (int i = 0; i < data.Count; i++) history.CurrentChange.ChangeData(model, run.Start + i, data[i]); + for (int i = data.Count; i < run.Length; i++) history.CurrentChange.ChangeData(model, run.Start + i, 0xFF); + DataChanged?.Invoke(this, EventArgs.Empty); + model.ObserveRunWritten(history.CurrentChange, new PCSRun(run.Start, data.Count)); + } + } + } + + public TextStreamArrayElementViewModel(ChangeHistory history, IDataModel model, string name, int start) { + this.history = history; + this.model = model; + this.name = name; + this.start = start; + + var destination = model.ReadPointer(start); + + // by the time we get this far, we're guaranteed that this will be a PCSRun. + // if it's not a PCSRun, we shouldn't have asked to construct this object. + var run = (PCSRun)model.GetNextRun(destination); + content = PCSString.Convert(model, run.Start, run.Length); + } + } } diff --git a/src/HexManiac.Core/ViewModels/Tools/TableTool.cs b/src/HexManiac.Core/ViewModels/Tools/TableTool.cs index bee22d76..eac504c2 100644 --- a/src/HexManiac.Core/ViewModels/Tools/TableTool.cs +++ b/src/HexManiac.Core/ViewModels/Tools/TableTool.cs @@ -161,10 +161,23 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools { } Children.Add(viewModel); viewModel.DataChanged += ForwardModelChanged; + if (item is ArrayRunPointerSegment pointerSegment) { + if (pointerSegment.DestinationDataMatchesPointerFormat(model, history.CurrentChange, model.ReadPointer(itemAddress))) { + if (pointerSegment.InnerFormat == $"{PCSRun.StringDelimeter}{PCSRun.StringDelimeter}") { + var streamElement = new TextStreamArrayElementViewModel(history, model, item.Name, itemAddress); + streamElement.DataChanged += ForwardModelChanged; + streamElement.DataMoved += ForwardModelDataMoved; + Children.Add(streamElement); + } else { + throw new NotImplementedException(); + } + } + } itemAddress += item.Length; } } private void ForwardModelChanged(object sender, EventArgs e) => ModelDataChanged?.Invoke(this, model.GetNextRun(Address)); + private void ForwardModelDataMoved(object sender, (int originalStart, int newStart) e) => ModelDataMoved?.Invoke(this, e); } } diff --git a/src/HexManiac.Tests/NestedTablesTests.cs b/src/HexManiac.Tests/NestedTablesTests.cs index 0026c805..f4baa2a5 100644 --- a/src/HexManiac.Tests/NestedTablesTests.cs +++ b/src/HexManiac.Tests/NestedTablesTests.cs @@ -2,6 +2,7 @@ using HavenSoft.HexManiac.Core.Models.Runs; using HavenSoft.HexManiac.Core.ViewModels; using HavenSoft.HexManiac.Core.ViewModels.DataFormats; +using HavenSoft.HexManiac.Core.ViewModels.Tools; using System.Collections.Generic; using Xunit; @@ -122,5 +123,19 @@ namespace HavenSoft.HexManiac.Tests { Assert.IsType(viewPort[1, 1].Format); // no PCS format was added } + + [Fact] + public void TableToolAllowsEditingTextContent() { + viewPort.Edit("FF"); // have to put the FF first, or trying to create a text run will fail + viewPort.MoveSelectionStart.Execute(Direction.Left); + viewPort.Edit("^text\"\" Some Text\""); + + viewPort.SelectionStart = new Point(0, 4); + viewPort.Edit("^table[description<\"\">]4 <000000>"); // note that this auto-scrolls, since a table was created + viewPort.FollowLink(0, 0); + + Assert.Equal(2, viewPort.Tools.TableTool.Children.Count); + Assert.IsType(viewPort.Tools.TableTool.Children[1]); + } } } diff --git a/src/HexManiac.WPF/Controls/TabView.xaml b/src/HexManiac.WPF/Controls/TabView.xaml index 52de87f0..3bc0bf73 100644 --- a/src/HexManiac.WPF/Controls/TabView.xaml +++ b/src/HexManiac.WPF/Controls/TabView.xaml @@ -129,6 +129,9 @@ + + +