1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-25 05:29:31 +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:
Andy McFadden 2019-06-12 14:17:24 -07:00
parent b45382d294
commit 9e525d1428
4 changed files with 240 additions and 43 deletions

View File

@ -122,7 +122,6 @@ namespace SourceGen {
SourceTypeString = sts;
}
public override string ToString() {
return Label + "{" + SymbolSource + "," + SymbolType +
",val=$" + Value.ToString("x4") + "}";

View File

@ -401,16 +401,14 @@ namespace SourceGenWPF {
CodeListGen = new LineListGen(mProject, mMainWin.CodeDisplayList,
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);
//ShowProject();
//InvalidateControls(null);
// Populate the Symbols list.
PopulateSymbolsList();
mMainWin.ShowCodeListView = true;
mNavStack.Clear();
// Want to do this after ShowProject() or we see a weird glitch.
UpdateRecentProjectList(mProjectPathName);
}
@ -1388,6 +1386,21 @@ namespace SourceGenWPF {
#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
private void UpdateInfoPanel() {

View File

@ -69,6 +69,9 @@ limitations under the License.
<KeyGesture>Ctrl+Z</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<CollectionViewSource x:Key="SymbolTableSource" Source="{Binding SymbolsList}"
Filter="SymbolsList_Filter"/>
</ResourceDictionary>
</Window.Resources>
@ -344,26 +347,38 @@ limitations under the License.
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0">
<ToggleButton Content="User" Width="40" Margin="2,2"/>
<ToggleButton Content="Proj" Width="40" Margin="2,2"/>
<ToggleButton Content="Plat" Width="40" Margin="2,2"/>
<ToggleButton Content="Auto" Width="40" Margin="2,2"/>
<ToggleButton Content="Addr" Width="40" Margin="2,2"/>
<ToggleButton Content="Cnst" Width="40" Margin="2,2"/>
<ToggleButton Name="symUserLabels" Content="User" Width="40" Margin="2,2"
Checked="SymbolsListFilter_Changed" Unchecked="SymbolsListFilter_Changed"/>
<ToggleButton Name="symProjectSymbols" Content="Proj" Width="40" Margin="2,2"
Checked="SymbolsListFilter_Changed" Unchecked="SymbolsListFilter_Changed"/>
<ToggleButton Name="symPlatformSymbols" Content="Plat" 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>
<ScrollViewer Grid.Row="1"
VerticalScrollBarVisibility="Disabled"
HorizontalScrollBarVisibility="Auto" Margin="0,4,0,0">
<DataGrid Name="SymbolsList" IsReadOnly="True"
FontFamily="{StaticResource GeneralMonoFont}">
<DataGrid.Columns>
<DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
<DataGridTextColumn Header="Value" Binding="{Binding Value}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
<DataGrid Grid.Row="1" Name="symbolsList"
IsReadOnly="True"
ItemsSource="{Binding Source={StaticResource SymbolTableSource}}"
FontFamily="{StaticResource GeneralMonoFont}"
SnapsToDevicePixels="True"
GridLinesVisibility="Vertical"
VerticalGridLinesBrush="#FF7F7F7F"
AutoGenerateColumns="False"
HeadersVisibility="Column"
CanUserReorderColumns="False"
SelectionMode="Single"
Sorting="SymbolsList_Sorting">
<DataGrid.Columns>
<DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
<DataGridTextColumn Header="Value" Binding="{Binding Value}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</GroupBox>

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
@ -516,24 +517,6 @@ namespace SourceGenWPF.ProjWin {
#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
public class ReferencesListItem {
@ -557,5 +540,192 @@ namespace SourceGenWPF.ProjWin {
new ObservableCollection<ReferencesListItem>();
#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
}
}