1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-24 08:29:29 +00:00

Finish wiring up code hint commands

This commit is contained in:
Andy McFadden 2019-06-08 17:13:11 -07:00
parent 80ec6b6c78
commit fa386a0d03
4 changed files with 129 additions and 32 deletions

View File

@ -23,12 +23,14 @@ using CommonUtil;
namespace SourceGenWPF {
/// <summary>
/// Tracks the items selected in the DisplayList.
///
/// Forward the SelectionChanged event. In WPF you can't get indices, only items, so we
/// have to store the item index in the item itself.
/// Tracks the items selected in the DisplayList, using forwarded SelectionChanged events.
/// When enumerated, provides an ordered list of selected indices.
/// </summary>
public class DisplayListSelection {
/// <remarks>
/// In WPF you can't get indices, only items, so we have to store the item index in the
/// item itself.
/// </remarks>
public class DisplayListSelection : IEnumerable<int> {
private BitArray mSelection;
/// <summary>
@ -49,26 +51,45 @@ namespace SourceGenWPF {
}
}
/// <summary>
/// Constructs an empty list.
/// </summary>
public DisplayListSelection() {
mSelection = new BitArray(0);
}
/// <summary>
/// Constructs a list of the specified length.
/// </summary>
/// <param name="length">Number of elements.</param>
public DisplayListSelection(int length) {
mSelection = new BitArray(length);
}
/// <summary>
/// Returns an enumeration of selected indices, in ascending order.
/// </summary>
public IEnumerator<int> GetEnumerator() {
for (int i = 0; i < mSelection.Length; i++) {
if (mSelection[i]) {
yield return i;
}
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
/// <summary>
/// Sets the length of the selection array.
///
/// If the new length is longer, the new elements are initialized to false. If the
/// new length is shorter, the excess elements are discarded. (This matches the behavior
/// of a virtual ListView selection set.)
/// new length is shorter, the excess elements are discarded.
/// </summary>
/// <param name="length">New length.</param>
public void SetLength(int length) {
//Debug.WriteLine("VirtualListViewSelection length now " + length);
mSelection.Length = length;
}
//public void SetLength(int length) {
// mSelection.Length = length;
//}
/// <summary>
/// Handles selection change.

View File

@ -388,13 +388,13 @@ namespace SourceGenWPF {
}
/// <summary>
/// Changes the Formatter object. Clears the display list, instigating a full re-render.
/// Changes the Formatter object. Clears the line list, instigating a full re-render.
/// </summary>
/// <param name="formatter">Formatter object.</param>
public void SetFormatter(Formatter formatter) {
mFormatter = formatter;
mLineList.Clear();
// TODO: update display list
mDisplayList.Clear();
// We probably just changed settings, so update this as well.
mShowCycleCounts = AppSettings.Global.GetBool(AppSettings.SRCGEN_SHOW_CYCLE_COUNTS,
@ -402,14 +402,14 @@ namespace SourceGenWPF {
}
/// <summary>
/// Changes the pseudo-op name object. Clears the display list, instigating a
/// Changes the pseudo-op name object. Clears the line list, instigating a
/// full re-render.
/// </summary>
/// <param name="opNames">Pseudo-op names.</param>
public void SetPseudoOpNames(PseudoOp.PseudoOpNames opNames) {
mPseudoOpNames = opNames;
mLineList.Clear();
// TODO: update display list
mDisplayList.Clear();
}
/// <summary>
@ -654,7 +654,7 @@ namespace SourceGenWPF {
// Out with the old, in with the new.
mLineList.RemoveRange(startIndex, endIndex - startIndex + 1);
mLineList.InsertRange(startIndex, newLines);
// TODO: update display list
Debug.Assert(false); // TODO: update display list
Debug.Assert(ValidateLineList(), "Display list failed validation");
}
@ -720,7 +720,7 @@ namespace SourceGenWPF {
}
Debug.WriteLine("Removing " + endIndex + " header lines");
mLineList.RemoveRange(0, endIndex);
// TODO: update display list
Debug.Assert(false); // TODO: update display list
}
/// <summary>

View File

@ -51,15 +51,6 @@ namespace SourceGenWPF {
/// an empty symbol table.
/// </summary>
private SymbolTableSubset mSymbolSubset;
/// <summary>
/// Current code list view selection. The length will match the DisplayList Count.
///
/// WinForms was bad -- a simple foreach through SelectedIndices on a 500K-line data set
/// took about 2.5 seconds on a fast Win10 x64 machine. In WPF you get a list of
/// selected objects, which is fine unless what you really want is the line number.
/// </summary>
private VirtualListViewSelection mCodeViewSelection = new VirtualListViewSelection();
#endif
/// <summary>
@ -493,7 +484,7 @@ namespace SourceGenWPF {
#endif
int topOffset = CodeListGen[topItem].FileOffset;
LineListGen.SavedSelection savedSel = LineListGen.SavedSelection.Generate(
CodeListGen, null /*mCodeViewSelection*/, topOffset);
CodeListGen, mMainWin.CodeDisplayList.SelectedIndices, topOffset);
//savedSel.DebugDump();
mReanalysisTimer.EndTask("Save selection");
@ -1051,18 +1042,19 @@ namespace SourceGenWPF {
/// </summary>
/// is selected.</param>
public SelectionState UpdateSelectionState() {
int firstIndex = mMainWin.GetFirstSelectedIndex();
Debug.WriteLine("SelectionChanged, firstIndex=" + firstIndex);
int selCount = mMainWin.GetSelectionCount();
Debug.WriteLine("SelectionChanged, selCount=" + selCount);
SelectionState state = new SelectionState();
// Use IsSingleItemSelected(), rather than just checking sel.Count, because we
// want the user to be able to e.g. EditData on a multi-line string even if all
// lines in the string are selected.
if (firstIndex == -1) {
if (selCount < 0) {
// nothing selected, leave everything set to false / 0
state.mEntityCounts = new EntityCounts();
} else if (IsSingleItemSelected()) {
int firstIndex = mMainWin.GetFirstSelectedIndex();
state.mNumSelected = 1;
state.mEntityCounts = GatherEntityCounts(firstIndex);
LineListGen.Line line = CodeListGen[firstIndex];
@ -1148,7 +1140,8 @@ namespace SourceGenWPF {
}
// A single line can span multiple offsets, each of which could have a
// different hint.
// different hint. Note the code/data hints are only applied to the first
// byte of each selected line, so we're not quite in sync with that.
for (int offset = line.FileOffset; offset < line.FileOffset + line.OffsetSpan;
offset++) {
switch (mProject.TypeHints[offset]) {
@ -1171,7 +1164,7 @@ namespace SourceGenWPF {
}
}
//Debug.WriteLine("GatherEntityCounts (len=" + mCodeViewSelection.Length + ") took " +
//Debug.WriteLine("GatherEntityCounts (len=" + CodeListGen.Count + ") took " +
// (DateTime.Now - startWhen).TotalMilliseconds + " ms");
return new EntityCounts() {
@ -1214,6 +1207,80 @@ namespace SourceGenWPF {
return false;
}
public void MarkAsType(CodeAnalysis.TypeHint hint, bool firstByteOnly) {
RangeSet sel;
if (firstByteOnly) {
sel = new RangeSet();
foreach (int index in mMainWin.CodeDisplayList.SelectedIndices) {
int offset = CodeListGen[index].FileOffset;
if (offset >= 0) {
// Not interested in the header stuff for hinting.
sel.Add(offset);
}
}
} else {
sel = OffsetSetFromSelected();
}
TypedRangeSet newSet = new TypedRangeSet();
TypedRangeSet undoSet = new TypedRangeSet();
foreach (int offset in sel) {
if (offset < 0) {
// header comment
continue;
}
CodeAnalysis.TypeHint oldType = mProject.TypeHints[offset];
if (oldType == hint) {
// no change, don't add to set
continue;
}
undoSet.Add(offset, (int)oldType);
newSet.Add(offset, (int)hint);
}
if (newSet.Count == 0) {
Debug.WriteLine("No changes found (" + hint + ", " + sel.Count + " offsets)");
return;
}
UndoableChange uc = UndoableChange.CreateTypeHintChange(undoSet, newSet);
ChangeSet cs = new ChangeSet(uc);
ApplyUndoableChanges(cs);
}
/// <summary>
/// Converts the set of selected items into a set of offsets. If a line
/// spans multiple offsets (e.g. a 3-byte instruction), offsets for every
/// byte are included.
///
/// Boundaries such as labels and address changes are ignored.
/// </summary>
/// <returns>RangeSet with all offsets.</returns>
private RangeSet OffsetSetFromSelected() {
RangeSet rs = new RangeSet();
foreach (int index in mMainWin.CodeDisplayList.SelectedIndices) {
int offset = CodeListGen[index].FileOffset;
// Mark every byte of an instruction or multi-byte data item --
// everything that is represented by the line the user selected.
int len;
if (offset >= 0) {
len = mProject.GetAnattrib(offset).Length;
} else {
// header area
len = 1;
}
Debug.Assert(len > 0);
for (int i = offset; i < offset + len; i++) {
rs.Add(i);
}
}
return rs;
}
#endregion Main window UI event handlers
}
}

View File

@ -210,6 +210,8 @@ namespace SourceGenWPF.ProjWin {
}
private void CodeListView_SelectionChanged(object sender, SelectionChangedEventArgs e) {
//DateTime startWhen = DateTime.Now;
// Update the selected-item bitmap.
CodeDisplayList.SelectedIndices.SelectionChanged(e);
@ -218,6 +220,9 @@ namespace SourceGenWPF.ProjWin {
Debug.Assert(CodeDisplayList.SelectedIndices.DebugValidateSelectionCount(
codeListView.SelectedItems.Count));
//Debug.WriteLine("SelectionChanged took " +
// (DateTime.Now - startWhen).TotalMilliseconds + " ms");
}
/// <summary>
@ -341,18 +346,22 @@ namespace SourceGenWPF.ProjWin {
private void HintAsCodeEntryPoint_Executed(object sender, ExecutedRoutedEventArgs e) {
Debug.WriteLine("hint as code entry point");
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.Code, true);
}
private void HintAsDataStart_Executed(object sender, ExecutedRoutedEventArgs e) {
Debug.WriteLine("hint as data start");
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.Data, true);
}
private void HintAsInlineData_Executed(object sender, ExecutedRoutedEventArgs e) {
Debug.WriteLine("hint as inline data");
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.InlineData, false);
}
private void RemoveHints_Executed(object sender, ExecutedRoutedEventArgs e) {
Debug.WriteLine("remove hints");
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.NoHint, false);
}
private void SelectAllCmd_Executed(object sender, ExecutedRoutedEventArgs e) {