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:
parent
0abc7a7587
commit
1a0a229b9b
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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}"/>
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user