1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-11-25 14:34:27 +00:00

Wire up sub-window double-click handlers and list nav

Wired up the double-click handlers for References, Notes, and
Symbols.  These jump to the item at the offset that was double-
clicked.  Also hooked up the navigate forward/backward buttons
in the toolbar.

Except for the usual WPF gymnastics required to figure out what you
actually double-clicked on, this went smoothly.
This commit is contained in:
Andy McFadden 2019-06-15 16:00:31 -07:00
parent 0abc7a7587
commit 1a0a229b9b
4 changed files with 327 additions and 48 deletions

View File

@ -82,7 +82,7 @@ namespace CommonWPF {
Debug.Assert(false, "ListView does not have a VirtualizingStackPanel");
return -1;
}
return (int) vsp.VerticalOffset;
return (int)vsp.VerticalOffset;
}
/// <summary>
@ -123,9 +123,7 @@ namespace CommonWPF {
/// </summary>
/// <remarks>
/// There's just no other way to do this with ListView. With DataGrid you can do this
/// somewhat reasonably
/// (https://blog.scottlogic.com/2008/12/02/wpf-datagrid-detecting-clicked-cell-and-row.html),
/// but ListView just doesn't want to help.
/// somewhat reasonably (see below), but ListView just doesn't want to help.
/// </remarks>
/// <returns>Column index, or -1 if the click was outside the columns (e.g. off the right
/// edge).</returns>
@ -149,4 +147,74 @@ namespace CommonWPF {
return -1;
}
}
/// <summary>
/// Helper functions for working with DataGrids.
/// </summary>
/// <remarks>
/// It's tempting to handle double-click actions by using the selected row. This gets a
/// little weird, though, because double-clicking on a header or blank area doesn't
/// clear the selection.
/// </remarks>
public static class DataGridExtensions {
/// <summary>
/// Determines which row and column was the target of a mouse button action.
/// </summary>
/// <remarks>
/// Based on https://blog.scottlogic.com/2008/12/02/wpf-datagrid-detecting-clicked-cell-and-row.html
/// </remarks>
/// <returns>True if the click was on a data item.</returns>
public static bool GetClickRowColItem(this DataGrid dg, MouseButtonEventArgs e,
out int rowIndex, out int colIndex, out object item) {
rowIndex = colIndex = -1;
item = null;
DependencyObject dep = (DependencyObject)e.OriginalSource;
// The initial dep will likely be a TextBlock. Walk up the tree until we find
// an object for the cell. If we don't find one, this might be a click in the
// header or off the bottom of the list.
while (!(dep is DataGridCell)) {
dep = VisualTreeHelper.GetParent(dep);
if (dep == null) {
return false;
}
}
DataGridCell cell = (DataGridCell)dep;
// Now search up for the DataGridRow object.
do {
dep = VisualTreeHelper.GetParent(dep);
if (dep == null) {
Debug.Assert(false, "Found cell but not row?");
return false;
}
} while (!(dep is DataGridRow));
DataGridRow row = (DataGridRow)dep;
// Get a row index for the entry.
DataGrid rowGrid = (DataGrid)ItemsControl.ItemsControlFromItemContainer(row);
rowIndex = rowGrid.ItemContainerGenerator.IndexFromContainer(row);
// Column index is, weirdly enough, just sitting in a property.
colIndex = cell.Column.DisplayIndex;
// Item is part of the row.
item = row.Item;
return true;
}
#if false
public static DataGridRow GetRow(this DataGrid grid, int index) {
DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null) {
// May be virtualized, bring into view and try again.
grid.UpdateLayout();
grid.ScrollIntoView(grid.Items[index]);
row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
#endif
}
}

View File

@ -479,7 +479,7 @@ namespace SourceGenWPF {
mReanalysisTimer.StartTask("ProjectView.ApplyChanges()");
mReanalysisTimer.StartTask("Save selection");
int topItemIndex = mMainWin.GetCodeListTopIndex();
int topItemIndex = mMainWin.CodeListView_GetTopIndex();
LineListGen.SavedSelection savedSel = LineListGen.SavedSelection.Generate(
CodeListGen, mMainWin.CodeDisplayList.SelectedIndices,
CodeListGen[topItemIndex].FileOffset);
@ -509,8 +509,8 @@ namespace SourceGenWPF {
// Restore the selection. The selection-changed event will cause updates to the
// references, notes, and info panels.
mReanalysisTimer.StartTask("Restore selection and top position");
mMainWin.SetSelection(newSel);
mMainWin.SetCodeListTopIndex(topItemIndex);
mMainWin.CodeListView_SetSelection(newSel);
mMainWin.CodeListView_SetTopIndex(topItemIndex);
mReanalysisTimer.EndTask("Restore selection and top position");
// Update the Notes list as well.
@ -641,10 +641,6 @@ namespace SourceGenWPF {
#region Main window UI event handlers
public void HandleDoubleClick(int row, int col) {
Debug.WriteLine("DCLICK: row=" + row + " col=" + col);
}
public void OpenRecentProject(int projIndex) {
if (!CloseProject()) {
return;
@ -957,6 +953,105 @@ namespace SourceGenWPF {
return mProject != null;
}
public void HandleCodeListDoubleClick(int row, int col) {
Debug.WriteLine("DCLICK: row=" + row + " col=" + col);
}
/// <summary>
/// Moves the view and selection to the specified offset. We want to select stuff
/// differently if we're jumping to a note vs. jumping to an instruction.
/// </summary>
/// <param name="gotoOffset">Offset to jump to.</param>
/// <param name="doPush">If set, push new offset onto navigation stack.</param>
public void GoToOffset(int gotoOffset, bool jumpToNote, bool doPush) {
int curSelIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
int topLineIndex = CodeListGen.FindLineIndexByOffset(gotoOffset);
if (topLineIndex < 0) {
Debug.Assert(false, "failed goto offset +" + gotoOffset.ToString("x6"));
return;
}
int lastLineIndex;
if (jumpToNote) {
// Select all note lines, disregard the rest.
while (CodeListGen[topLineIndex].LineType != LineListGen.Line.Type.Note) {
topLineIndex++;
Debug.Assert(CodeListGen[topLineIndex].FileOffset == gotoOffset);
}
lastLineIndex = topLineIndex + 1;
while (lastLineIndex < CodeListGen.Count &&
CodeListGen[lastLineIndex].LineType == LineListGen.Line.Type.Note) {
lastLineIndex++;
}
} else if (gotoOffset < 0) {
// This is the offset of the header comment or a .EQ directive. Don't mess with it.
lastLineIndex = topLineIndex + 1;
} else {
// Advance to the code or data line.
while (CodeListGen[topLineIndex].LineType != LineListGen.Line.Type.Code &&
CodeListGen[topLineIndex].LineType != LineListGen.Line.Type.Data) {
topLineIndex++;
}
lastLineIndex = topLineIndex + 1;
}
// Make sure the item is visible. For notes, this can span multiple lines.
mMainWin.CodeListView_EnsureVisible(lastLineIndex - 1);
mMainWin.CodeListView_EnsureVisible(topLineIndex);
// Update the selection.
mMainWin.CodeListView_DeselectAll();
mMainWin.CodeListView_SelectRange(topLineIndex, lastLineIndex - topLineIndex);
if (doPush) {
if (curSelIndex >= 0) {
// Update the back stack and associated controls.
mNavStack.Push(CodeListGen[curSelIndex].FileOffset, gotoOffset);
#if false
UpdateMenuItemsAndTitle();
#endif
} else {
// This can happen when the project is first opened and nothing is selected.
Debug.WriteLine("no selection to go back to");
}
}
}
/// <summary>
/// Scrolls the code list so that the specified label is shown.
/// </summary>
/// <param name="sym">Label symbol.</param>
public void GoToLabel(Symbol sym) {
if (sym.IsInternalLabel) {
int offset = mProject.FindLabelOffsetByName(sym.Label);
if (offset >= 0) {
GoToOffset(offset, false, true);
} else {
Debug.WriteLine("DClick symbol: " + sym + ": label not found");
}
} else {
Debug.WriteLine("DClick symbol: " + sym + ": not label");
}
}
public bool CanNavigateBackward() {
return mNavStack.HasBackward;
}
public void NavigateBackward() {
Debug.Assert(mNavStack.HasBackward);
int backOff = mNavStack.Pop();
GoToOffset(backOff, false, false);
}
public bool CanNavigateForward() {
return mNavStack.HasForward;
}
public void NavigateForward() {
Debug.Assert(mNavStack.HasForward);
int fwdOff = mNavStack.PushPrevious();
GoToOffset(fwdOff, false, false);
}
public void SelectionChanged(out SelectionState newState) {
newState = UpdateSelectionState();
@ -997,7 +1092,7 @@ namespace SourceGenWPF {
/// </summary>
/// is selected.</param>
public SelectionState UpdateSelectionState() {
int selCount = mMainWin.GetSelectionCount();
int selCount = mMainWin.CodeListView_GetSelectionCount();
Debug.WriteLine("SelectionChanged, selCount=" + selCount);
SelectionState state = new SelectionState();
@ -1009,7 +1104,7 @@ namespace SourceGenWPF {
// nothing selected, leave everything set to false / 0
state.mEntityCounts = new EntityCounts();
} else if (IsSingleItemSelected()) {
int firstIndex = mMainWin.GetFirstSelectedIndex();
int firstIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
state.mNumSelected = 1;
state.mEntityCounts = GatherEntityCounts(firstIndex);
LineListGen.Line line = CodeListGen[firstIndex];
@ -1139,13 +1234,13 @@ namespace SourceGenWPF {
/// single-line item or a multi-line item.
/// </summary>
private bool IsSingleItemSelected() {
int firstIndex = mMainWin.GetFirstSelectedIndex();
int firstIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
if (firstIndex < 0) {
// empty selection
return false;
}
int lastIndex = mMainWin.GetLastSelectedIndex();
int lastIndex = mMainWin.CodeListView_GetLastSelectedIndex();
if (lastIndex == firstIndex) {
// only one line is selected
return true;
@ -1309,11 +1404,11 @@ namespace SourceGenWPF {
private void UpdateReferencesPanel() {
mMainWin.ReferencesList.Clear();
if (mMainWin.GetSelectionCount() != 1) {
if (mMainWin.CodeListView_GetSelectionCount() != 1) {
// Nothing selected, or multiple lines selected.
return;
}
int lineIndex = mMainWin.GetFirstSelectedIndex();
int lineIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
LineListGen.Line.Type type = CodeListGen[lineIndex].LineType;
if (type != LineListGen.Line.Type.Code &&
type != LineListGen.Line.Type.Data &&
@ -1380,7 +1475,7 @@ namespace SourceGenWPF {
break;
}
MainWindow.ReferencesListItem rli = new MainWindow.ReferencesListItem(
MainWindow.ReferencesListItem rli = new MainWindow.ReferencesListItem(xr.Offset,
formatter.FormatOffset24(xr.Offset),
formatter.FormatAddress(mProject.GetAnattrib(xr.Offset).Address, showBank),
(xr.IsSymbolic ? "Sym " : "Num ") + typeStr +
@ -1403,12 +1498,13 @@ namespace SourceGenWPF {
// Replace line break with bullet. If there's a single CRLF at the end, strip it.
string nocrlfStr;
if (mlc.Text.EndsWith("\r\n")) {
nocrlfStr = mlc.Text.Substring(0, mlc.Text.Length - 2).Replace("\r\n", " \u2022 ");
nocrlfStr =
mlc.Text.Substring(0, mlc.Text.Length - 2).Replace("\r\n", " \u2022 ");
} else {
nocrlfStr = mlc.Text.Replace("\r\n", " \u2022 ");
}
MainWindow.NotesListItem nli = new MainWindow.NotesListItem(
MainWindow.NotesListItem nli = new MainWindow.NotesListItem(offset,
mOutputFormatter.FormatOffset24(offset),
nocrlfStr,
mlc.BackgroundColor);
@ -1436,12 +1532,12 @@ namespace SourceGenWPF {
#region Info panel
private void UpdateInfoPanel() {
if (mMainWin.GetSelectionCount() != 1) {
if (mMainWin.CodeListView_GetSelectionCount() != 1) {
// Nothing selected, or multiple lines selected.
mMainWin.InfoPanelContents = string.Empty;
return;
}
int lineIndex = mMainWin.GetFirstSelectedIndex();
int lineIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
LineListGen.Line line = CodeListGen[lineIndex];
StringBuilder sb = new StringBuilder(250);

View File

@ -51,6 +51,18 @@ limitations under the License.
<RoutedUICommand x:Key="HintAsCodeEntryPointCmd" Text="Hint As Code Entry Point"/>
<RoutedUICommand x:Key="HintAsDataStartCmd" Text="Hint As Data Start"/>
<RoutedUICommand x:Key="HintAsInlineDataCmd" Text="Hint As Inline Data"/>
<RoutedUICommand x:Key="NavigateBackwardCmd" Text="Nav Backward">
<RoutedUICommand.InputGestures>
<KeyGesture>Alt+Left</KeyGesture>
<KeyGesture>Ctrl+Minus</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="NavigateForwardCmd" Text="Nav Forward">
<RoutedUICommand.InputGestures>
<KeyGesture>Alt+Right</KeyGesture>
<KeyGesture>Ctrl+Shift+Minus</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="RemoveHintsCmd" Text="Remove Hints"/>
<RoutedUICommand x:Key="RecentProjectCmd"/>
<RoutedUICommand x:Key="RedoCmd" Text="Redo">
@ -88,6 +100,10 @@ limitations under the License.
CanExecute="CanHintAsDataStart" Executed="HintAsDataStartCmd_Executed"/>
<CommandBinding Command="{StaticResource HintAsInlineDataCmd}"
CanExecute="CanHintAsInlineData" Executed="HintAsInlineDataCmd_Executed"/>
<CommandBinding Command="{StaticResource NavigateBackwardCmd}"
CanExecute="CanNavigateBackward" Executed="NavigateBackwardCmd_Executed"/>
<CommandBinding Command="{StaticResource NavigateForwardCmd}"
CanExecute="CanNavigateForward" Executed="NavigateForwardCmd_Executed"/>
<CommandBinding Command="{StaticResource RemoveHintsCmd}"
CanExecute="CanRemoveHints" Executed="RemoveHintsCmd_Executed"/>
<CommandBinding Command="{StaticResource RecentProjectCmd}" Executed="RecentProjectCmd_Executed"/>
@ -181,10 +197,10 @@ limitations under the License.
<ToolBarTray DockPanel.Dock="Top">
<ToolBar RenderOptions.BitmapScalingMode="NearestNeighbor">
<Button ToolTip="Navigate backward">
<Button ToolTip="Navigate backward" Command="{StaticResource NavigateBackwardCmd}">
<ContentControl Template="{StaticResource icon_StepBackwards}"/>
</Button>
<Button ToolTip="Navigate forward">
<Button ToolTip="Navigate forward" Command="{StaticResource NavigateForwardCmd}">
<ContentControl Template="{StaticResource icon_StepForward}"/>
</Button>
<Separator/>
@ -236,7 +252,7 @@ limitations under the License.
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="References">
<DataGrid Name="referencesList" IsReadOnly="True"
<DataGrid Name="referencesGrid" IsReadOnly="True"
ItemsSource="{Binding ReferencesList}"
FontFamily="{StaticResource GeneralMonoFont}"
SnapsToDevicePixels="True"
@ -245,7 +261,8 @@ limitations under the License.
AutoGenerateColumns="False"
HeadersVisibility="Column"
CanUserReorderColumns="False"
SelectionMode="Single">
SelectionMode="Single"
MouseDoubleClick="ReferencesList_MouseDoubleClick">
<DataGrid.Columns>
<DataGridTextColumn Header="Offset" Binding="{Binding Offset}"/>
<DataGridTextColumn Header="Addr" Binding="{Binding Addr}"/>
@ -255,7 +272,7 @@ limitations under the License.
</GroupBox>
<GroupBox Grid.Row="2" Header="Notes">
<DataGrid Name="notesList" IsReadOnly="True"
<DataGrid Name="notesGrid" IsReadOnly="True"
ItemsSource="{Binding NotesList}"
FontFamily="{StaticResource GeneralMonoFont}"
SnapsToDevicePixels="True"
@ -264,13 +281,18 @@ limitations under the License.
AutoGenerateColumns="False"
HeadersVisibility="Column"
CanUserReorderColumns="False"
SelectionMode="Single">
SelectionMode="Single"
MouseDoubleClick="NotesList_MouseDoubleClick">
<DataGrid.Columns>
<DataGridTextColumn Header="Offset" Binding="{Binding Offset}"/>
<DataGridTextColumn Header="Note" Binding="{Binding Note}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<!-- The default highlight uses dark blue background with
white text, but our highlight colors are meant to work
with black text. So override Foreground as well. -->
<Setter Property="Background" Value="{Binding BackBrush}"/>
<Setter Property="Foreground" Value="Black"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
@ -375,7 +397,7 @@ limitations under the License.
Checked="SymbolsListFilter_Changed" Unchecked="SymbolsListFilter_Changed"/>
</WrapPanel>
<DataGrid Grid.Row="1" Name="symbolsList"
<DataGrid Grid.Row="1" Name="symbolsGrid"
IsReadOnly="True"
ItemsSource="{Binding Source={StaticResource SymbolTableSource}}"
FontFamily="{StaticResource GeneralMonoFont}"
@ -386,7 +408,8 @@ limitations under the License.
HeadersVisibility="Column"
CanUserReorderColumns="False"
SelectionMode="Single"
Sorting="SymbolsList_Sorting">
Sorting="SymbolsList_Sorting"
MouseDoubleClick="SymbolsList_MouseDoubleClick">
<DataGrid.Columns>
<DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
<DataGridTextColumn Header="Value" Binding="{Binding Value}"/>

View File

@ -222,6 +222,13 @@ namespace SourceGenWPF.ProjWin {
}
}
/// <summary>
/// Sets the focus on the code list.
/// </summary>
//public void CodeListView_Focus() {
// codeListView.Focus();
//}
/// <summary>
/// Handles a double-click on the code list. We have to figure out which row and
/// column were clicked, which is not easy in WPF.
@ -239,7 +246,7 @@ namespace SourceGenWPF.ProjWin {
if (col < 0) {
return;
}
mMainCtrl.HandleDoubleClick(row, col);
mMainCtrl.HandleCodeListDoubleClick(row, col);
}
@ -268,7 +275,7 @@ namespace SourceGenWPF.ProjWin {
/// <returns>
/// The SelectedItems list appears to hold the full set, so we can just return the count.
/// </returns>
public int GetSelectionCount() {
public int CodeListView_GetSelectionCount() {
return codeListView.SelectedItems.Count;
}
@ -288,7 +295,7 @@ namespace SourceGenWPF.ProjWin {
/// common cases will be short selections and select-all, so this should handle both
/// efficiently.
/// </remarks>
public int GetFirstSelectedIndex() {
public int CodeListView_GetFirstSelectedIndex() {
int count = codeListView.SelectedItems.Count;
if (count == 0) {
return -1;
@ -312,7 +319,7 @@ namespace SourceGenWPF.ProjWin {
/// <remarks>
/// Again, the ListView does not provide what we need.
/// </remarks>
public int GetLastSelectedIndex() {
public int CodeListView_GetLastSelectedIndex() {
int count = codeListView.SelectedItems.Count;
if (count == 0) {
return -1;
@ -330,11 +337,34 @@ namespace SourceGenWPF.ProjWin {
}
}
/// <summary>
/// De-selects all items.
/// </summary>
public void CodeListView_DeselectAll() {
codeListView.SelectedItems.Clear();
}
/// <summary>
/// Selects a range of values. Does not clear the previous selection.
/// </summary>
/// <param name="start">First line to select.</param>
/// <param name="count">Number of lines to select.</param>
public void CodeListView_SelectRange(int start, int count) {
Debug.Assert(start >= 0 && start < CodeDisplayList.Count);
Debug.Assert(count > 0 && start + count <= CodeDisplayList.Count);
DisplayList.FormattedParts[] tmpArray = new DisplayList.FormattedParts[count];
for (int index = 0; index < count; index++) {
tmpArray[index] = CodeDisplayList[start + index];
}
listViewSetSelectedItems.Invoke(codeListView, new object[] { tmpArray });
}
/// <summary>
/// Sets the code list selection.
/// </summary>
/// <param name="sel">Selection bitmap.</param>
public void SetSelection(DisplayListSelection sel) {
public void CodeListView_SetSelection(DisplayListSelection sel) {
const int MAX_SEL_COUNT = 2000;
if (sel.IsAllSelected()) {
@ -369,11 +399,11 @@ namespace SourceGenWPF.ProjWin {
// (DateTime.Now - startWhen).TotalMilliseconds + " ms");
}
public int GetCodeListTopIndex() {
public int CodeListView_GetTopIndex() {
return codeListView.GetTopItemIndex();
}
public void SetCodeListTopIndex(int index) {
public void CodeListView_SetTopIndex(int index) {
// ScrollIntoView does the least amount of scrolling required. This extension
// method scrolls to the bottom, then scrolls back up to the top item.
//
@ -383,6 +413,11 @@ namespace SourceGenWPF.ProjWin {
codeListView.ScrollToTopItem(CodeDisplayList[index]);
}
public void CodeListView_EnsureVisible(int index) {
Debug.Assert(index >= 0 && index < CodeDisplayList.Count);
codeListView.ScrollIntoView(CodeDisplayList[index]);
}
#endregion Selection management
#region Can-execute handlers
@ -391,11 +426,11 @@ namespace SourceGenWPF.ProjWin {
/// Returns true if the project is open. Intended for use in XAML CommandBindings.
/// </summary>
private void IsProjectOpen(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = mMainCtrl.IsProjectOpen();
e.CanExecute = mMainCtrl != null && mMainCtrl.IsProjectOpen();
}
private void CanHintAsCodeEntryPoint(object sender, CanExecuteRoutedEventArgs e) {
if (!mMainCtrl.IsProjectOpen()) {
if (mMainCtrl == null || !mMainCtrl.IsProjectOpen()) {
e.CanExecute = false;
return;
}
@ -404,7 +439,7 @@ namespace SourceGenWPF.ProjWin {
(counts.mDataHints != 0 || counts.mInlineDataHints != 0 || counts.mNoHints != 0);
}
private void CanHintAsDataStart(object sender, CanExecuteRoutedEventArgs e) {
if (!mMainCtrl.IsProjectOpen()) {
if (mMainCtrl == null || !mMainCtrl.IsProjectOpen()) {
e.CanExecute = false;
return;
}
@ -413,7 +448,7 @@ namespace SourceGenWPF.ProjWin {
(counts.mCodeHints != 0 || counts.mInlineDataHints != 0 || counts.mNoHints != 0);
}
private void CanHintAsInlineData(object sender, CanExecuteRoutedEventArgs e) {
if (!mMainCtrl.IsProjectOpen()) {
if (mMainCtrl == null || !mMainCtrl.IsProjectOpen()) {
e.CanExecute = false;
return;
}
@ -422,7 +457,7 @@ namespace SourceGenWPF.ProjWin {
(counts.mCodeHints != 0 || counts.mDataHints != 0 || counts.mNoHints != 0);
}
private void CanRemoveHints(object sender, CanExecuteRoutedEventArgs e) {
if (!mMainCtrl.IsProjectOpen()) {
if (mMainCtrl == null || !mMainCtrl.IsProjectOpen()) {
e.CanExecute = false;
return;
}
@ -432,10 +467,17 @@ namespace SourceGenWPF.ProjWin {
}
private void CanRedo(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = mMainCtrl.CanRedo();
e.CanExecute = mMainCtrl != null && mMainCtrl.CanRedo();
}
private void CanUndo(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = mMainCtrl.CanUndo();
e.CanExecute = mMainCtrl != null && mMainCtrl.CanUndo();
}
private void CanNavigateBackward(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = mMainCtrl != null && mMainCtrl.CanNavigateBackward();
}
private void CanNavigateForward(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = mMainCtrl != null && mMainCtrl.CanNavigateForward();
}
#endregion Can-execute handlers
@ -473,6 +515,14 @@ namespace SourceGenWPF.ProjWin {
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.InlineData, false);
}
private void NavigateBackwardCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.NavigateBackward();
}
private void NavigateForwardCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.NavigateForward();
}
private void RemoveHintsCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
Debug.WriteLine("remove hints");
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.NoHint, false);
@ -520,11 +570,13 @@ namespace SourceGenWPF.ProjWin {
#region References panel
public class ReferencesListItem {
public int OffsetValue { get; private set; }
public string Offset { get; private set; }
public string Addr { get; private set; }
public string Type { get; private set; }
public ReferencesListItem(string offset, string addr, string type) {
public ReferencesListItem(int offsetValue, string offset, string addr, string type) {
OffsetValue = offsetValue;
Offset = offset;
Addr = addr;
Type = type;
@ -539,17 +591,32 @@ namespace SourceGenWPF.ProjWin {
public ObservableCollection<ReferencesListItem> ReferencesList { get; private set; } =
new ObservableCollection<ReferencesListItem>();
private void ReferencesList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
if (!referencesGrid.GetClickRowColItem(e, out int rowIndex, out int colIndex,
out object item)) {
// Header or empty area; ignore.
return;
}
ReferencesListItem rli = (ReferencesListItem)item;
// Jump to the offset, then shift the focus back to the code list.
mMainCtrl.GoToOffset(rli.OffsetValue, false, true);
codeListView.Focus();
}
#endregion References panel
#region Notes panel
public class NotesListItem {
public int OffsetValue { get; private set; }
public string Offset { get; private set; }
public string Note { get; private set; }
public SolidColorBrush BackBrush { get; private set; }
public NotesListItem(string offset, string note, Color backColor) {
public NotesListItem(int offsetValue, string offset, string note, Color backColor) {
OffsetValue = offsetValue;
Offset = offset;
Note = note;
BackBrush = new SolidColorBrush(backColor);
@ -564,6 +631,19 @@ namespace SourceGenWPF.ProjWin {
public ObservableCollection<NotesListItem> NotesList { get; private set; } =
new ObservableCollection<NotesListItem>();
private void NotesList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
if (!notesGrid.GetClickRowColItem(e, out int rowIndex, out int colIndex,
out object item)) {
// Header or empty area; ignore.
return;
}
NotesListItem nli = (NotesListItem)item;
// Jump to the offset, then shift the focus back to the code list.
mMainCtrl.GoToOffset(nli.OffsetValue, true, true);
codeListView.Focus();
}
#endregion Notes panel
@ -592,6 +672,18 @@ namespace SourceGenWPF.ProjWin {
public ObservableCollection<SymbolsListItem> SymbolsList { get; private set; } =
new ObservableCollection<SymbolsListItem>();
private void SymbolsList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
if (!symbolsGrid.GetClickRowColItem(e, out int rowIndex, out int colIndex,
out object item)) {
// Header or empty area; ignore.
return;
}
SymbolsListItem sli = (SymbolsListItem)item;
mMainCtrl.GoToLabel(sli.Sym);
codeListView.Focus();
}
private void SymbolsList_Filter(object sender, FilterEventArgs e) {
SymbolsListItem sli = (SymbolsListItem)e.Item;
if (sli == null) {
@ -617,7 +709,7 @@ namespace SourceGenWPF.ProjWin {
private void SymbolsListFilter_Changed(object sender, RoutedEventArgs e) {
// This delightfully obscure call causes the list to refresh. See
// https://docs.microsoft.com/en-us/dotnet/framework/wpf/controls/how-to-group-sort-and-filter-data-in-the-datagrid-control
CollectionViewSource.GetDefaultView(symbolsList.ItemsSource).Refresh();
CollectionViewSource.GetDefaultView(symbolsGrid.ItemsSource).Refresh();
}
/// <summary>
@ -655,7 +747,7 @@ namespace SourceGenWPF.ProjWin {
}
ListCollectionView lcv =
(ListCollectionView)CollectionViewSource.GetDefaultView(symbolsList.ItemsSource);
(ListCollectionView)CollectionViewSource.GetDefaultView(symbolsGrid.ItemsSource);
lcv.CustomSort = comparer;
e.Handled = true;
}