diff --git a/PluginCommon/VisBitmap8.cs b/PluginCommon/VisBitmap8.cs index 6de27d0..ca738ef 100644 --- a/PluginCommon/VisBitmap8.cs +++ b/PluginCommon/VisBitmap8.cs @@ -55,6 +55,8 @@ namespace PluginCommon { mNextColorIdx = 0; } + // TODO: add GetPixelIndex, which returns the index we passed into SetPixelIndex + public int GetPixel(int x, int y) { byte pix = mData[x + y * Width]; return mPalette[pix]; diff --git a/SourceGen/DisplayList.cs b/SourceGen/DisplayList.cs index 13c6762..699e3f3 100644 --- a/SourceGen/DisplayList.cs +++ b/SourceGen/DisplayList.cs @@ -369,6 +369,10 @@ namespace SourceGen { // examined by a data trigger in CodeListItemStyle.xaml. public bool HasAddrLabelHighlight { get; private set; } + // Set to true if we want to highlight the operand field. This is + // examined by a data trigger in CodeListItemStyle.xaml. + public bool HasOperandHighlight { get; private set; } + // Set to true if the Flags field has been modified. public bool HasModifiedFlags { get { return (mPartFlags & PartFlags.HasModifiedFlags) != 0; } @@ -502,18 +506,30 @@ namespace SourceGen { return parts; } - public static FormattedParts AddSelectionHighlight(FormattedParts orig) { + public static FormattedParts AddSelectionAddrHighlight(FormattedParts orig) { FormattedParts newParts = Clone(orig); newParts.HasAddrLabelHighlight = true; return newParts; } - public static FormattedParts RemoveSelectionHighlight(FormattedParts orig) { + public static FormattedParts RemoveSelectionAddrHighlight(FormattedParts orig) { FormattedParts newParts = Clone(orig); newParts.HasAddrLabelHighlight = false; return newParts; } + public static FormattedParts AddSelectionOperHighlight(FormattedParts orig) { + FormattedParts newParts = Clone(orig); + newParts.HasOperandHighlight = true; + return newParts; + } + + public static FormattedParts RemoveSelectionOperHighlight(FormattedParts orig) { + FormattedParts newParts = Clone(orig); + newParts.HasOperandHighlight = false; + return newParts; + } + public override string ToString() { return "[Parts: index=" + ListIndex + " off=" + Offset + "]"; } diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs index 0cd1787..5a24a13 100644 --- a/SourceGen/MainController.cs +++ b/SourceGen/MainController.cs @@ -181,6 +181,11 @@ namespace SourceGen { /// private int mTargetHighlightIndex = -1; + /// + /// Tracks the operands we have highlighted. + /// + private List mOperandHighlights = new List(); + /// /// Code list color scheme. /// @@ -879,8 +884,20 @@ namespace SourceGen { CodeLineList, mMainWin.CodeDisplayList.SelectedIndices, topItemIndex); //savedSel.DebugDump(); - // Clear this so we don't try to fiddle with it later. + // Clear the addr/label highlight index. + // (Certain changes will blow away the CodeDisplayList and affect the selection, + // which will cause the selection-changed handler to try to un-highlight something + // that doesn't exist. We want to clear the index here, but we probably also want + // to clear the highlighting before we do it. As it happens, changes will either + // be big enough to wipe out our highlight, or small enough that we immediately + // re-highlight the thing that's already highlighted, so it doesn't really matter. + // If we start to see vestigial highlighting after a change, we'll need to be + // more rigorous here.) mTargetHighlightIndex = -1; + + // Clear operand highlighting indices as well. + mOperandHighlights.Clear(); + mReanalysisTimer.EndTask("Save selection"); mReanalysisTimer.StartTask("Apply changes"); @@ -1404,7 +1421,11 @@ namespace SourceGen { } mDataPathName = null; mProjectPathName = null; + + // We may get a "selection changed" message as things are being torn down. Clear + // these so we don't try to remove the highlight from something that doesn't exist. mTargetHighlightIndex = -1; + mOperandHighlights.Clear(); mMainWin.ShowCodeListView = false; mMainWin.ProjectClosing(); @@ -3405,16 +3426,19 @@ namespace SourceGen { private bool mUpdatingSelectionHighlight; // recursion guard for next method /// - /// Updates the selection highlight. When a code item with an operand offset is + /// Updates the selection highlights. When a code or data item with an operand offset is /// selected, such as a branch, we want to highlight the address and label of the - /// target. + /// target. When a code or data item is referenced by another instruction, such as a + /// branch, we want to highlight the operands of all such instructions. /// private void UpdateSelectionHighlight() { if (mUpdatingSelectionHighlight) { return; } + mUpdatingSelectionHighlight = true; - int targetIndex = FindSelectionHighlight(); + int targetIndex = FindSelectionAddrHighlight(out bool isSingleCodeData, + out int selIndex); if (mTargetHighlightIndex != targetIndex) { Debug.WriteLine("Target highlight moving from " + mTargetHighlightIndex + " to " + targetIndex); @@ -3429,25 +3453,47 @@ namespace SourceGen { // it will be the selected line while we're doing this little dance. When the // calls below update the selection, this method will be called again. This // turns into infinite recursion. - mUpdatingSelectionHighlight = true; - mMainWin.CodeListView_RemoveSelectionHighlight(mTargetHighlightIndex); - mMainWin.CodeListView_AddSelectionHighlight(targetIndex); - mUpdatingSelectionHighlight = false; + mMainWin.CodeListView_RemoveSelectionAddrHighlight(mTargetHighlightIndex); + mMainWin.CodeListView_AddSelectionAddrHighlight(targetIndex); mTargetHighlightIndex = targetIndex; } + + if (mOperandHighlights.Count > 0) { + foreach (int index in mOperandHighlights) { + mMainWin.CodeListView_RemoveSelectionOperHighlight(index); + } + mOperandHighlights.Clear(); + } + if (isSingleCodeData) { + LineListGen.Line line = CodeLineList[selIndex]; + XrefSet xrefs = mProject.GetXrefSet(line.FileOffset); + if (xrefs != null) { + foreach (XrefSet.Xref xr in xrefs) { + int refIndex = CodeLineList.FindCodeDataIndexByOffset(xr.Offset); + mMainWin.CodeListView_AddSelectionOperHighlight(refIndex); + mOperandHighlights.Add(refIndex); + } + } + } + + mUpdatingSelectionHighlight = false; } - private int FindSelectionHighlight() { + private int FindSelectionAddrHighlight(out bool isSingleCodeData, out int selIndex) { if (mMainWin.CodeListView_GetSelectionCount() != 1) { + isSingleCodeData = false; + selIndex = -1; return -1; } - int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex(); + selIndex = mMainWin.CodeListView_GetFirstSelectedIndex(); LineListGen.Line line = CodeLineList[selIndex]; if (!line.IsCodeOrData) { + isSingleCodeData = false; return -1; } Debug.Assert(line.FileOffset >= 0); + isSingleCodeData = true; // Does this have an operand with an in-file target offset? // TODO: may not work correctly with reloc data? diff --git a/SourceGen/WpfGui/CodeListItemStyle.xaml b/SourceGen/WpfGui/CodeListItemStyle.xaml index aa6e30d..9b32fd2 100644 --- a/SourceGen/WpfGui/CodeListItemStyle.xaml +++ b/SourceGen/WpfGui/CodeListItemStyle.xaml @@ -407,4 +407,22 @@ See also https://github.com/fadden/DisasmUiTest + + + + + + + + + + \ No newline at end of file diff --git a/SourceGen/WpfGui/MainWindow.xaml b/SourceGen/WpfGui/MainWindow.xaml index 94bd636..55ec836 100644 --- a/SourceGen/WpfGui/MainWindow.xaml +++ b/SourceGen/WpfGui/MainWindow.xaml @@ -771,7 +771,7 @@ limitations under the License. + CellTemplate="{StaticResource operandHighlightTemplate}"/> diff --git a/SourceGen/WpfGui/MainWindow.xaml.cs b/SourceGen/WpfGui/MainWindow.xaml.cs index fba729c..bd60035 100644 --- a/SourceGen/WpfGui/MainWindow.xaml.cs +++ b/SourceGen/WpfGui/MainWindow.xaml.cs @@ -981,24 +981,48 @@ namespace SourceGen.WpfGui { /// Adds an address/label selection highlight to the specified line. /// /// Line index. If < 0, method has no effect. - public void CodeListView_AddSelectionHighlight(int index) { + public void CodeListView_AddSelectionAddrHighlight(int index) { if (index < 0) { return; } CodeListView_ReplaceEntry(index, - DisplayList.FormattedParts.AddSelectionHighlight(CodeDisplayList[index])); + DisplayList.FormattedParts.AddSelectionAddrHighlight(CodeDisplayList[index])); } /// /// Removes an address/label selection highlight from the specified line. /// /// Line index. If < 0, method has no effect. - public void CodeListView_RemoveSelectionHighlight(int index) { + public void CodeListView_RemoveSelectionAddrHighlight(int index) { if (index < 0) { return; } CodeListView_ReplaceEntry(index, - DisplayList.FormattedParts.RemoveSelectionHighlight(CodeDisplayList[index])); + DisplayList.FormattedParts.RemoveSelectionAddrHighlight(CodeDisplayList[index])); + } + + /// + /// Adds an operand selection highlight to the specified line. + /// + public void CodeListView_AddSelectionOperHighlight(int index) { + Debug.Assert(index >= 0); + CodeListView_ReplaceEntry(index, + DisplayList.FormattedParts.AddSelectionOperHighlight(CodeDisplayList[index])); + } + + /// + /// Removes an operand selection highlight from the specified line. + /// + public void CodeListView_RemoveSelectionOperHighlight(int index) { + Debug.Assert(index >= 0); + if (index >= CodeDisplayList.Count) { + // Shouldn't happen unless we resize the list without clearing the highlights. + Debug.WriteLine("NOTE: selection oper high index exceeds count (" + + index + " vs. " + CodeDisplayList.Count + ")"); + return; + } + CodeListView_ReplaceEntry(index, + DisplayList.FormattedParts.RemoveSelectionOperHighlight(CodeDisplayList[index])); } ///