mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-01 22:50:35 +00:00
Populate symbol table, with filtering and sorting
The filtering uses the DataGrid View filtering mechanism. The built-in sorting only operates on a single column, and we really want a secondary sort on label when the type is used as the key, so we provide a custom sort method.
This commit is contained in:
parent
b45382d294
commit
9e525d1428
@ -122,7 +122,6 @@ namespace SourceGen {
|
|||||||
SourceTypeString = sts;
|
SourceTypeString = sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return Label + "{" + SymbolSource + "," + SymbolType +
|
return Label + "{" + SymbolSource + "," + SymbolType +
|
||||||
",val=$" + Value.ToString("x4") + "}";
|
",val=$" + Value.ToString("x4") + "}";
|
||||||
|
@ -401,16 +401,14 @@ namespace SourceGenWPF {
|
|||||||
CodeListGen = new LineListGen(mProject, mMainWin.CodeDisplayList,
|
CodeListGen = new LineListGen(mProject, mMainWin.CodeDisplayList,
|
||||||
mOutputFormatter, mPseudoOpNames);
|
mOutputFormatter, mPseudoOpNames);
|
||||||
|
|
||||||
// Prep the symbol table subset object. Replace the old one with a new one.
|
|
||||||
//mSymbolSubset = new SymbolTableSubset(mProject.SymbolTable);
|
|
||||||
|
|
||||||
RefreshProject(UndoableChange.ReanalysisScope.CodeAndData);
|
RefreshProject(UndoableChange.ReanalysisScope.CodeAndData);
|
||||||
//ShowProject();
|
|
||||||
//InvalidateControls(null);
|
// Populate the Symbols list.
|
||||||
|
PopulateSymbolsList();
|
||||||
|
|
||||||
mMainWin.ShowCodeListView = true;
|
mMainWin.ShowCodeListView = true;
|
||||||
mNavStack.Clear();
|
mNavStack.Clear();
|
||||||
|
|
||||||
// Want to do this after ShowProject() or we see a weird glitch.
|
|
||||||
UpdateRecentProjectList(mProjectPathName);
|
UpdateRecentProjectList(mProjectPathName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1388,6 +1386,21 @@ namespace SourceGenWPF {
|
|||||||
|
|
||||||
#endregion References panel
|
#endregion References panel
|
||||||
|
|
||||||
|
#region Symbols panel
|
||||||
|
|
||||||
|
private void PopulateSymbolsList() {
|
||||||
|
mMainWin.SymbolsList.Clear();
|
||||||
|
foreach (Symbol sym in mProject.SymbolTable) {
|
||||||
|
MainWindow.SymbolsListItem sli = new MainWindow.SymbolsListItem(sym,
|
||||||
|
sym.SourceTypeString,
|
||||||
|
mOutputFormatter.FormatHexValue(sym.Value, 0),
|
||||||
|
sym.Label);
|
||||||
|
mMainWin.SymbolsList.Add(sli);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Symbols panel
|
||||||
|
|
||||||
#region Info panel
|
#region Info panel
|
||||||
|
|
||||||
private void UpdateInfoPanel() {
|
private void UpdateInfoPanel() {
|
||||||
|
@ -69,6 +69,9 @@ limitations under the License.
|
|||||||
<KeyGesture>Ctrl+Z</KeyGesture>
|
<KeyGesture>Ctrl+Z</KeyGesture>
|
||||||
</RoutedUICommand.InputGestures>
|
</RoutedUICommand.InputGestures>
|
||||||
</RoutedUICommand>
|
</RoutedUICommand>
|
||||||
|
|
||||||
|
<CollectionViewSource x:Key="SymbolTableSource" Source="{Binding SymbolsList}"
|
||||||
|
Filter="SymbolsList_Filter"/>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
|
||||||
@ -344,26 +347,38 @@ limitations under the License.
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<WrapPanel Grid.Row="0">
|
<WrapPanel Grid.Row="0">
|
||||||
<ToggleButton Content="User" Width="40" Margin="2,2"/>
|
<ToggleButton Name="symUserLabels" Content="User" Width="40" Margin="2,2"
|
||||||
<ToggleButton Content="Proj" Width="40" Margin="2,2"/>
|
Checked="SymbolsListFilter_Changed" Unchecked="SymbolsListFilter_Changed"/>
|
||||||
<ToggleButton Content="Plat" Width="40" Margin="2,2"/>
|
<ToggleButton Name="symProjectSymbols" Content="Proj" Width="40" Margin="2,2"
|
||||||
<ToggleButton Content="Auto" Width="40" Margin="2,2"/>
|
Checked="SymbolsListFilter_Changed" Unchecked="SymbolsListFilter_Changed"/>
|
||||||
<ToggleButton Content="Addr" Width="40" Margin="2,2"/>
|
<ToggleButton Name="symPlatformSymbols" Content="Plat" Width="40" Margin="2,2"
|
||||||
<ToggleButton Content="Cnst" Width="40" Margin="2,2"/>
|
Checked="SymbolsListFilter_Changed" Unchecked="SymbolsListFilter_Changed"/>
|
||||||
|
<ToggleButton Name="symAutoLabels" Content="Auto" Width="40" Margin="2,2"
|
||||||
|
Checked="SymbolsListFilter_Changed" Unchecked="SymbolsListFilter_Changed"/>
|
||||||
|
<ToggleButton Name="symAddresses" Content="Addr" Width="40" Margin="2,2"
|
||||||
|
Checked="SymbolsListFilter_Changed" Unchecked="SymbolsListFilter_Changed"/>
|
||||||
|
<ToggleButton Name="symConstants" Content="Cnst" Width="40" Margin="2,2"
|
||||||
|
Checked="SymbolsListFilter_Changed" Unchecked="SymbolsListFilter_Changed"/>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="1"
|
<DataGrid Grid.Row="1" Name="symbolsList"
|
||||||
VerticalScrollBarVisibility="Disabled"
|
IsReadOnly="True"
|
||||||
HorizontalScrollBarVisibility="Auto" Margin="0,4,0,0">
|
ItemsSource="{Binding Source={StaticResource SymbolTableSource}}"
|
||||||
<DataGrid Name="SymbolsList" IsReadOnly="True"
|
FontFamily="{StaticResource GeneralMonoFont}"
|
||||||
FontFamily="{StaticResource GeneralMonoFont}">
|
SnapsToDevicePixels="True"
|
||||||
|
GridLinesVisibility="Vertical"
|
||||||
|
VerticalGridLinesBrush="#FF7F7F7F"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
CanUserReorderColumns="False"
|
||||||
|
SelectionMode="Single"
|
||||||
|
Sorting="SymbolsList_Sorting">
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
|
<DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
|
||||||
<DataGridTextColumn Header="Value" Binding="{Binding Value}"/>
|
<DataGridTextColumn Header="Value" Binding="{Binding Value}"/>
|
||||||
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
|
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
</ScrollViewer>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
@ -516,24 +517,6 @@ namespace SourceGenWPF.ProjWin {
|
|||||||
#endregion Command handlers
|
#endregion Command handlers
|
||||||
|
|
||||||
|
|
||||||
#region Info panel
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Text to display in the Info panel. This is a simple TextBox.
|
|
||||||
/// </summary>
|
|
||||||
public string InfoPanelContents {
|
|
||||||
get {
|
|
||||||
return mInfoBoxContents;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
mInfoBoxContents = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private string mInfoBoxContents;
|
|
||||||
|
|
||||||
#endregion Info panel
|
|
||||||
|
|
||||||
#region References panel
|
#region References panel
|
||||||
|
|
||||||
public class ReferencesListItem {
|
public class ReferencesListItem {
|
||||||
@ -557,5 +540,192 @@ namespace SourceGenWPF.ProjWin {
|
|||||||
new ObservableCollection<ReferencesListItem>();
|
new ObservableCollection<ReferencesListItem>();
|
||||||
|
|
||||||
#endregion References panel
|
#endregion References panel
|
||||||
|
|
||||||
|
|
||||||
|
#region Notes panel
|
||||||
|
// TODO
|
||||||
|
#endregion Notes panel
|
||||||
|
|
||||||
|
|
||||||
|
#region Symbols panel
|
||||||
|
|
||||||
|
public class SymbolsListItem {
|
||||||
|
public Symbol Sym { get; private set; }
|
||||||
|
public string Type { get; private set; }
|
||||||
|
public string Value { get; private set; }
|
||||||
|
public string Name { get; private set; }
|
||||||
|
|
||||||
|
public SymbolsListItem(Symbol sym, string type, string value, string name) {
|
||||||
|
Sym = sym;
|
||||||
|
|
||||||
|
Type = type;
|
||||||
|
Value = value;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return "[SymbolsListItem: type=" + Type + " value=" + Value + " name=" +
|
||||||
|
Name + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<SymbolsListItem> SymbolsList { get; private set; } =
|
||||||
|
new ObservableCollection<SymbolsListItem>();
|
||||||
|
|
||||||
|
private void SymbolsList_Filter(object sender, FilterEventArgs e) {
|
||||||
|
SymbolsListItem sli = (SymbolsListItem)e.Item;
|
||||||
|
if (sli == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((symUserLabels.IsChecked != true && sli.Sym.SymbolSource == Symbol.Source.User) ||
|
||||||
|
(symProjectSymbols.IsChecked != true && sli.Sym.SymbolSource == Symbol.Source.Project) ||
|
||||||
|
(symPlatformSymbols.IsChecked != true && sli.Sym.SymbolSource == Symbol.Source.Platform) ||
|
||||||
|
(symAutoLabels.IsChecked != true && sli.Sym.SymbolSource == Symbol.Source.Auto) ||
|
||||||
|
(symConstants.IsChecked != true && sli.Sym.SymbolType == Symbol.Type.Constant) ||
|
||||||
|
(symAddresses.IsChecked != true && sli.Sym.SymbolType != Symbol.Type.Constant))
|
||||||
|
{
|
||||||
|
e.Accepted = false;
|
||||||
|
} else {
|
||||||
|
e.Accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Refreshes the symbols list when a filter option changes. Set this to be called
|
||||||
|
/// for Checked/Unchecked events on the filter option buttons.
|
||||||
|
/// </summary>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles a Sorting event. We want to do a secondary sort on Name when one of the
|
||||||
|
/// other columns is the primary sort key.
|
||||||
|
/// </summary>
|
||||||
|
private void SymbolsList_Sorting(object sender, DataGridSortingEventArgs e) {
|
||||||
|
DataGridColumn col = e.Column;
|
||||||
|
|
||||||
|
// Set the SortDirection to a specific value. If we don't do this, SortDirection
|
||||||
|
// remains un-set, and the column header doesn't show up/down arrows or change
|
||||||
|
// direction when clicked twice.
|
||||||
|
ListSortDirection direction = (col.SortDirection != ListSortDirection.Ascending) ?
|
||||||
|
ListSortDirection.Ascending : ListSortDirection.Descending;
|
||||||
|
col.SortDirection = direction;
|
||||||
|
|
||||||
|
bool isAscending = direction != ListSortDirection.Descending;
|
||||||
|
|
||||||
|
IComparer comparer;
|
||||||
|
|
||||||
|
switch (col.Header) {
|
||||||
|
case "Type":
|
||||||
|
comparer = new SymTabSortComparer(SymTabSortField.CombinedType, isAscending);
|
||||||
|
break;
|
||||||
|
case "Value":
|
||||||
|
comparer = new SymTabSortComparer(SymTabSortField.Value, isAscending);
|
||||||
|
break;
|
||||||
|
case "Name":
|
||||||
|
comparer = new SymTabSortComparer(SymTabSortField.Name, isAscending);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
comparer = null;
|
||||||
|
Debug.Assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListCollectionView lcv =
|
||||||
|
(ListCollectionView)CollectionViewSource.GetDefaultView(symbolsList.ItemsSource);
|
||||||
|
lcv.CustomSort = comparer;
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Symbol table sort comparison helper.
|
||||||
|
private enum SymTabSortField { CombinedType, Value, Name };
|
||||||
|
private class SymTabSortComparer : IComparer {
|
||||||
|
private SymTabSortField mSortField;
|
||||||
|
private bool mIsAscending;
|
||||||
|
|
||||||
|
public SymTabSortComparer(SymTabSortField prim, bool isAscending) {
|
||||||
|
mSortField = prim;
|
||||||
|
mIsAscending = isAscending;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IComparer interface
|
||||||
|
public int Compare(object oa, object ob) {
|
||||||
|
Symbol a = ((SymbolsListItem)oa).Sym;
|
||||||
|
Symbol b = ((SymbolsListItem)ob).Sym;
|
||||||
|
|
||||||
|
// Label is always unique, so we use it as a secondary sort.
|
||||||
|
if (mSortField == SymTabSortField.CombinedType) {
|
||||||
|
if (mIsAscending) {
|
||||||
|
int cmp = string.Compare(a.SourceTypeString, b.SourceTypeString);
|
||||||
|
if (cmp == 0) {
|
||||||
|
cmp = string.Compare(a.Label, b.Label);
|
||||||
|
}
|
||||||
|
return cmp;
|
||||||
|
} else {
|
||||||
|
int cmp = string.Compare(a.SourceTypeString, b.SourceTypeString);
|
||||||
|
if (cmp == 0) {
|
||||||
|
// secondary sort is always ascending, so negate
|
||||||
|
cmp = -string.Compare(a.Label, b.Label);
|
||||||
|
}
|
||||||
|
return -cmp;
|
||||||
|
}
|
||||||
|
} else if (mSortField == SymTabSortField.Value) {
|
||||||
|
if (mIsAscending) {
|
||||||
|
int cmp;
|
||||||
|
if (a.Value < b.Value) {
|
||||||
|
cmp = -1;
|
||||||
|
} else if (a.Value > b.Value) {
|
||||||
|
cmp = 1;
|
||||||
|
} else {
|
||||||
|
cmp = string.Compare(a.Label, b.Label);
|
||||||
|
}
|
||||||
|
return cmp;
|
||||||
|
} else {
|
||||||
|
int cmp;
|
||||||
|
if (a.Value < b.Value) {
|
||||||
|
cmp = -1;
|
||||||
|
} else if (a.Value > b.Value) {
|
||||||
|
cmp = 1;
|
||||||
|
} else {
|
||||||
|
cmp = -string.Compare(a.Label, b.Label);
|
||||||
|
}
|
||||||
|
return -cmp;
|
||||||
|
}
|
||||||
|
} else if (mSortField == SymTabSortField.Name) {
|
||||||
|
if (mIsAscending) {
|
||||||
|
return string.Compare(a.Label, b.Label);
|
||||||
|
} else {
|
||||||
|
return -string.Compare(a.Label, b.Label);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Debug.Assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Symbols panel
|
||||||
|
|
||||||
|
|
||||||
|
#region Info panel
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text to display in the Info panel. This is a simple TextBox.
|
||||||
|
/// </summary>
|
||||||
|
public string InfoPanelContents {
|
||||||
|
get {
|
||||||
|
return mInfoBoxContents;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
mInfoBoxContents = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private string mInfoBoxContents;
|
||||||
|
|
||||||
|
#endregion Info panel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user