Adding right click option to see if something is text

This commit is contained in:
Benjamin Popp
2019-04-07 13:07:59 -05:00
parent 76ae65d2b0
commit 46b9fe4ae3
4 changed files with 79 additions and 13 deletions

View File

@@ -124,13 +124,12 @@ namespace HavenSoft.HexManiac.Core.Models {
}
private void WriteStringRuns(Dictionary<int, List<int>> pointersForDestination) {
var destinations = pointersForDestination.Keys.OrderBy(i => i).GetEnumerator();
destinations.MoveNext();
var noDataChange = new NoDataChangeDeltaModel();
foreach (var destination in pointersForDestination.Keys.OrderBy(i => i)) {
var length = PCSString.ReadString(RawData, destination, false);
if (length < 2) continue;
if (GetNextRun(destination + 1).Start < destination + length) continue;
ObserveRunWritten(new ModelDelta(), new PCSRun(destination, length, pointersForDestination[destination]));
ObserveRunWritten(noDataChange, new PCSRun(destination, length, pointersForDestination[destination]));
}
}

View File

@@ -11,6 +11,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using static HavenSoft.HexManiac.Core.ICommandExtensions;
using static HavenSoft.HexManiac.Core.Models.Runs.ArrayRun;
@@ -29,7 +30,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
private static readonly NotifyCollectionChangedEventArgs ResetArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
private readonly StubCommand
clear = new StubCommand(),
copy = new StubCommand();
copy = new StubCommand(),
isText = new StubCommand();
private HexElement[,] currentView;
private bool exitEditEarly;
@@ -270,6 +272,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public ICommand Copy => copy;
public ICommand Clear => clear;
public ICommand IsText => isText;
public HexElement this[Point p] => this[p.X, p.Y];
@@ -354,6 +357,9 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
if (usedHistory) UpdateToolsFromSelection(left);
};
isText.CanExecute = CanAlwaysExecute;
isText.Execute = IsTextExecuted;
save.CanExecute = arg => !history.IsSaved;
save.Execute = arg => SaveExecuted((IFileSystem)arg);
@@ -518,20 +524,24 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
// for each of the results, we recognized it as text: see if we need to add a matching string run / pointers
private int ConsiderResultsAsTextRuns(IEnumerable<int> searchResults) {
int resultsRecognizedAsTextRuns = 0;
var parallelLock = new object();
foreach (var result in searchResults) {
Parallel.ForEach(searchResults, result => {
// foreach (var result in searchResults) {
var nextRun = Model.GetNextRun(result);
if (nextRun.Start < result) continue;
if (nextRun.Start == result && !(nextRun is NoInfoRun)) continue;
if (nextRun.Start < result) return;
if (nextRun.Start == result && !(nextRun is NoInfoRun)) return;
var pointers = Model.SearchForPointersToAnchor(history.CurrentChange, result);
if (pointers.Count == 0) continue;
if (pointers.Count == 0) return;
var length = PCSString.ReadString(Model, result, true);
if (length < 1) continue;
if (result + length > nextRun.Start && nextRun.Start != result) continue;
if (length < 1) return;
if (result + length > nextRun.Start && nextRun.Start != result) return;
var newRun = new PCSRun(result, length, pointers);
Model.ObserveAnchorWritten(history.CurrentChange, string.Empty, newRun);
resultsRecognizedAsTextRuns++;
}
lock (parallelLock) {
Model.ObserveAnchorWritten(history.CurrentChange, string.Empty, newRun);
resultsRecognizedAsTextRuns++;
}
});
return resultsRecognizedAsTextRuns;
}
@@ -734,6 +744,35 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
return point;
}
private void IsTextExecuted(object obj) {
var selectionStart = scroll.ViewPointToDataIndex(selection.SelectionStart);
var selectionEnd = scroll.ViewPointToDataIndex(selection.SelectionEnd);
var left = Math.Min(selectionStart, selectionEnd);
var length = Math.Abs(selectionEnd - selectionStart) + 1;
while (Model[left] != 0xFF && PCSString.PCS[Model[left]] != null) { left--; length++; }
left++; length--;
while (true) {
var run = Model.GetNextRun(left);
if (run.Start >= left) break;
length -= left - run.Start;
left = run.Start + run.Length;
}
var startPaces = new List<int>();
while (length > 0) {
startPaces.Add(left);
while (Model[left] != 0xFF) { left++; length--; }
left++; length--;
var run = Model.GetNextRun(left);
if (!(run is NoInfoRun)) break;
}
var foundCount = ConsiderResultsAsTextRuns(startPaces);
if (foundCount == 0) {
OnError?.Invoke(this, "Failed to automatically find text at that location.");
} else {
RefreshBackingData();
}
}
private bool ShouldAcceptInput(ref Point point, ref HexElement element, char input) {
var underEdit = element.Format as UnderEdit;
var innerFormat = underEdit?.OriginalFormat ?? element.Format;

View File

@@ -419,5 +419,23 @@ namespace HavenSoft.HexManiac.Tests {
Assert.NotEqual("anchor", ((Anchor)viewPort[0, 1].Format).Name);
Assert.Single(messages);
}
[Fact]
public void CanUseViewPortToAutoFindTextWithoutKnowingAboutPointersToIt() {
var text = PCSString.Convert("This is some text.");
var buffer = Enumerable.Range(0, 0x200).Select(i => (byte)0xFF).ToArray();
text.CopyTo(buffer, 0x10);
var model = new PokemonModel(buffer);
model.WritePointer(new ModelDelta(), 0x00, 0x10);
var viewPort = new ViewPort("file.txt", model) { Width = 0x10, Height = 0x10 };
viewPort.SelectionStart = new Point(3, 1); // just a random byte in the middle of the text
var errors = new List<string>();
viewPort.OnError += (sender, e) => errors.Add(e);
viewPort.IsText.Execute(); // this line should find the start of the text and add a run, even with no pointer to it
Assert.IsType<PCS>(viewPort[3, 1].Format);
}
}
}

View File

@@ -249,6 +249,7 @@ namespace HavenSoft.HexManiac.WPF.Controls {
if (format is PCS pcs) children.AddRange(GetStringChildren(p));
if (ViewPort.IsTable(p)) children.AddRange(GetTableChildren(p));
if (format is Pointer pointer) children.AddRange(GetPointerChildren(p));
if (format is None none) children.AddRange(GetNoneChildren(p));
if (editableViewPort.FormattedDataIsSelected) children.AddRange(GetClearFormattingChildren(p));
} else {
children.AddRange(GetSearchChildren(p));
@@ -410,6 +411,15 @@ namespace HavenSoft.HexManiac.WPF.Controls {
yield return CreateFollowLinkButton("Follow Pointer", p);
}
private IEnumerable<FrameworkElement> GetNoneChildren(ModelPoint p) {
yield return new Button {
Content = new TextBlock { Text = "This is Text" },
}.SetEvent(ButtonBase.ClickEvent, (sender, e) => {
((ViewPort)ViewPort).IsText.Execute();
recentMenu.IsOpen = false;
});
}
private IEnumerable<FrameworkElement> GetTableChildren(ModelPoint p) {
yield return new Button {
Content = new TextBlock { Text = "Open in Table Tool" },