mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-29 10:50:28 +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;
|
||||
}
|
||||
|
||||
|
||||
public override string ToString() {
|
||||
return Label + "{" + SymbolSource + "," + SymbolType +
|
||||
",val=$" + Value.ToString("x4") + "}";
|
||||
|
@ -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() {
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user