diff --git a/SourceGen/Symbol.cs b/SourceGen/Symbol.cs index d5b785e..1723677 100644 --- a/SourceGen/Symbol.cs +++ b/SourceGen/Symbol.cs @@ -122,7 +122,6 @@ namespace SourceGen { SourceTypeString = sts; } - public override string ToString() { return Label + "{" + SymbolSource + "," + SymbolType + ",val=$" + Value.ToString("x4") + "}"; diff --git a/SourceGenWPF/MainController.cs b/SourceGenWPF/MainController.cs index 9a6067c..dca6e3b 100644 --- a/SourceGenWPF/MainController.cs +++ b/SourceGenWPF/MainController.cs @@ -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() { diff --git a/SourceGenWPF/ProjWin/MainWindow.xaml b/SourceGenWPF/ProjWin/MainWindow.xaml index 1f2aeb6..f648d81 100644 --- a/SourceGenWPF/ProjWin/MainWindow.xaml +++ b/SourceGenWPF/ProjWin/MainWindow.xaml @@ -69,6 +69,9 @@ limitations under the License. Ctrl+Z + + @@ -344,26 +347,38 @@ limitations under the License. - - - - - - + + + + + + - - - - - - - - - + + + + + + + diff --git a/SourceGenWPF/ProjWin/MainWindow.xaml.cs b/SourceGenWPF/ProjWin/MainWindow.xaml.cs index 2bdd068..79321c9 100644 --- a/SourceGenWPF/ProjWin/MainWindow.xaml.cs +++ b/SourceGenWPF/ProjWin/MainWindow.xaml.cs @@ -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 - - /// - /// Text to display in the Info panel. This is a simple TextBox. - /// - 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(); #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 SymbolsList { get; private set; } = + new ObservableCollection(); + + 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; + } + } + + /// + /// Refreshes the symbols list when a filter option changes. Set this to be called + /// for Checked/Unchecked events on the filter option buttons. + /// + 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(); + } + + /// + /// Handles a Sorting event. We want to do a secondary sort on Name when one of the + /// other columns is the primary sort key. + /// + 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 + + /// + /// Text to display in the Info panel. This is a simple TextBox. + /// + public string InfoPanelContents { + get { + return mInfoBoxContents; + } + set { + mInfoBoxContents = value; + OnPropertyChanged(); + } + } + private string mInfoBoxContents; + + #endregion Info panel } }