mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-29 08:29:52 +00:00
Allow explicit widths in project/platform symbols, part 2
Added a Width column to the list in the project symbol editor. Changed the local variable table editor and the project symbol editor to use DataGrid instead of ListView. This gets us easy sorting on arbitrary columns. The previous code was reloading the display list after every change; now we just add/edit/remove individual items, which helps keep the list position and selection stable.
This commit is contained in:
parent
2a41d70e04
commit
14150af004
@ -48,28 +48,37 @@ limitations under the License.
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="0,4,0,0"
|
||||
Text="{Binding TableHeaderText, FallbackValue=Symbols defined in table at +######:}"/>
|
||||
|
||||
<ListView Name="symbolsListView" Grid.Column="0" Grid.Row="1" Margin="0,4,4,0"
|
||||
Height="300"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"
|
||||
<DataGrid Name="symbolsList" Grid.Column="0" Grid.Row="1" Margin="0,4,4,0"
|
||||
Width="582" Height="300"
|
||||
ItemsSource="{Binding Variables}"
|
||||
SnapsToDevicePixels="True" SelectionMode="Single"
|
||||
SelectionChanged="SymbolsListView_SelectionChanged"
|
||||
MouseDoubleClick="SymbolsListView_MouseDoubleClick">
|
||||
<ListView.Resources>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
|
||||
</Style>
|
||||
</ListView.Resources>
|
||||
<ListView.View>
|
||||
<GridView AllowsColumnReorder="False">
|
||||
<GridViewColumn Header="Name" Width="118" DisplayMemberBinding="{Binding Label}"/>
|
||||
<GridViewColumn Header="Value" Width="72" DisplayMemberBinding="{Binding Value}"/>
|
||||
<GridViewColumn Header="Type" Width="45" DisplayMemberBinding="{Binding Type}"/>
|
||||
<GridViewColumn Header="Width" Width="45" DisplayMemberBinding="{Binding Width}"/>
|
||||
<GridViewColumn Header="Comment" Width="300" DisplayMemberBinding="{Binding Comment}"/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
IsReadOnly="True"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"
|
||||
SnapsToDevicePixels="True"
|
||||
GridLinesVisibility="Vertical"
|
||||
VerticalGridLinesBrush="#FF7F7F7F"
|
||||
AutoGenerateColumns="False"
|
||||
HeadersVisibility="Column"
|
||||
CanUserReorderColumns="False"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="SymbolsList_SelectionChanged"
|
||||
Sorting="SymbolsList_Sorting"
|
||||
MouseDoubleClick="SymbolsList_MouseDoubleClick">
|
||||
<DataGrid.Resources>
|
||||
<!-- make the no-focus color the same as the in-focus color -->
|
||||
<!-- thanks: https://stackoverflow.com/a/13053511/294248 -->
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
|
||||
Color="{x:Static SystemColors.HighlightColor}"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}"
|
||||
Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||
</DataGrid.Resources>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Name" Width="118" Binding="{Binding Label}"/>
|
||||
<DataGridTextColumn Header="Value" Width="72" Binding="{Binding Value}"/>
|
||||
<DataGridTextColumn Header="Type" Width="45" Binding="{Binding Type}"/>
|
||||
<DataGridTextColumn Header="Width" Width="45" Binding="{Binding Width}"/>
|
||||
<DataGridTextColumn Header="Comment" Width="300" Binding="{Binding Comment}"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<StackPanel Grid.Column="1" Grid.Row="1">
|
||||
<Button Name="newSymbolButton" Width="120" Margin="4" Content="_New Symbol..."
|
||||
|
@ -14,12 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
|
||||
using Asm65;
|
||||
@ -46,18 +48,25 @@ namespace SourceGen.WpfGui {
|
||||
public string Label { get; private set; }
|
||||
public string Value { get; private set; }
|
||||
public string Type { get; private set; }
|
||||
public string Width { get; private set; }
|
||||
public int Width { get; private set; }
|
||||
public string Comment { get; private set; }
|
||||
|
||||
public FormattedSymbol(string label, string value, string type, string width,
|
||||
string comment) {
|
||||
// Numeric form of Value, used so we can sort hex/dec/binary correctly.
|
||||
public int NumericValue { get; private set; }
|
||||
|
||||
public FormattedSymbol(string label, int numericValue, string value, string type,
|
||||
int width, string comment) {
|
||||
Label = label;
|
||||
Value = value;
|
||||
Type = type;
|
||||
Width = width;
|
||||
Comment = comment;
|
||||
|
||||
NumericValue = numericValue;
|
||||
}
|
||||
}
|
||||
|
||||
// List of items. The Label is guaranteed to be unique.
|
||||
public ObservableCollection<FormattedSymbol> Variables { get; private set; } =
|
||||
new ObservableCollection<FormattedSymbol>();
|
||||
|
||||
@ -141,7 +150,10 @@ namespace SourceGen.WpfGui {
|
||||
mWorkTable = new LocalVariableTable();
|
||||
}
|
||||
|
||||
LoadVariables();
|
||||
for (int i = 0; i < mWorkTable.Count; i++) {
|
||||
DefSymbol defSym = mWorkTable[i];
|
||||
Variables.Add(CreateFormattedSymbol(defSym));
|
||||
}
|
||||
}
|
||||
|
||||
public void Window_Loaded(object sender, RoutedEventArgs e) {
|
||||
@ -154,33 +166,106 @@ namespace SourceGen.WpfGui {
|
||||
/// <summary>
|
||||
/// Loads entries from the work table into the items source.
|
||||
/// </summary>
|
||||
private void LoadVariables() {
|
||||
Variables.Clear();
|
||||
private FormattedSymbol CreateFormattedSymbol(DefSymbol defSym) {
|
||||
string typeStr;
|
||||
if (defSym.SymbolType == Symbol.Type.Constant) {
|
||||
typeStr = Res.Strings.ABBREV_STACK_RELATIVE;
|
||||
} else {
|
||||
typeStr = Res.Strings.ABBREV_ADDRESS;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mWorkTable.Count; i++) {
|
||||
DefSymbol defSym = mWorkTable[i];
|
||||
string typeStr;
|
||||
if (defSym.SymbolType == Symbol.Type.Constant) {
|
||||
typeStr = Res.Strings.ABBREV_STACK_RELATIVE;
|
||||
} else {
|
||||
typeStr = Res.Strings.ABBREV_ADDRESS;
|
||||
FormattedSymbol fsym = new FormattedSymbol(
|
||||
defSym.Label,
|
||||
defSym.Value,
|
||||
mFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase),
|
||||
typeStr,
|
||||
defSym.DataDescriptor.Length,
|
||||
defSym.Comment);
|
||||
return fsym;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles a Sorting event. We need to sort by numeric value on the Value field, but
|
||||
/// we want to use custom-formatted numeric values in multiple bases.
|
||||
/// </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 = new SymbolsListComparer(col.DisplayIndex, isAscending);
|
||||
ListCollectionView lcv =
|
||||
(ListCollectionView)CollectionViewSource.GetDefaultView(symbolsList.ItemsSource);
|
||||
lcv.CustomSort = comparer;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private class SymbolsListComparer : IComparer {
|
||||
// Must match order of items in DataGrid. DataGrid must not allow columns to be
|
||||
// reordered. We could check col.Header instead, but then we have to assume that
|
||||
// the Header is a string that doesn't get renamed.
|
||||
private enum SortField {
|
||||
Label = 0, Value = 1, Type = 2, Width = 3, Comment = 4
|
||||
}
|
||||
private SortField mSortField;
|
||||
private bool mIsAscending;
|
||||
|
||||
public SymbolsListComparer(int displayIndex, bool isAscending) {
|
||||
Debug.Assert(displayIndex >= 0 && displayIndex <= 4);
|
||||
mIsAscending = isAscending;
|
||||
mSortField = (SortField)displayIndex;
|
||||
}
|
||||
|
||||
// IComparer interface
|
||||
public int Compare(object o1, object o2) {
|
||||
FormattedSymbol fsym1 = (FormattedSymbol)o1;
|
||||
FormattedSymbol fsym2 = (FormattedSymbol)o2;
|
||||
|
||||
// Sort primarily by specified field, secondarily by label (which should
|
||||
// be unique).
|
||||
int cmp;
|
||||
switch (mSortField) {
|
||||
case SortField.Label:
|
||||
cmp = string.Compare(fsym1.Label, fsym2.Label);
|
||||
break;
|
||||
case SortField.Value:
|
||||
cmp = fsym1.NumericValue - fsym2.NumericValue;
|
||||
break;
|
||||
case SortField.Type:
|
||||
cmp = string.Compare(fsym1.Type, fsym2.Type);
|
||||
break;
|
||||
case SortField.Width:
|
||||
cmp = fsym1.Width - fsym2.Width;
|
||||
break;
|
||||
case SortField.Comment:
|
||||
cmp = string.Compare(fsym1.Comment, fsym2.Comment);
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FormattedSymbol fsym = new FormattedSymbol(
|
||||
defSym.Label,
|
||||
mFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase),
|
||||
typeStr,
|
||||
defSym.DataDescriptor.Length.ToString(),
|
||||
defSym.Comment);
|
||||
|
||||
Variables.Add(fsym);
|
||||
if (cmp == 0) {
|
||||
cmp = string.Compare(fsym1.Label, fsym2.Label);
|
||||
}
|
||||
if (!mIsAscending) {
|
||||
cmp = -cmp;
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateControls() {
|
||||
// Enable or disable the edit/remove buttons based on how many items are selected.
|
||||
// (We're currently configured for single-select, so this is really just a != 0 test.)
|
||||
int symSelCount = symbolsListView.SelectedItems.Count;
|
||||
int symSelCount = symbolsList.SelectedItems.Count;
|
||||
removeSymbolButton.IsEnabled = (symSelCount == 1);
|
||||
editSymbolButton.IsEnabled = (symSelCount == 1);
|
||||
}
|
||||
@ -207,16 +292,17 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
}
|
||||
|
||||
private void SymbolsListView_SelectionChanged(object sender, SelectionChangedEventArgs e) {
|
||||
private void SymbolsList_SelectionChanged(object sender, SelectionChangedEventArgs e) {
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
private void SymbolsListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
|
||||
ListViewItem lvi = symbolsListView.GetClickedItem(e);
|
||||
if (lvi == null) {
|
||||
private void SymbolsList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
|
||||
if (!symbolsList.GetClickRowColItem(e, out int unusedRow, out int unusedCol,
|
||||
out object objItem)) {
|
||||
// Header or empty area; ignore.
|
||||
return;
|
||||
}
|
||||
FormattedSymbol item = (FormattedSymbol)lvi.Content;
|
||||
FormattedSymbol item = (FormattedSymbol)objItem;
|
||||
DefSymbol defSym = mWorkTable.GetByLabel(item.Label);
|
||||
DoEditSymbol(defSym);
|
||||
}
|
||||
@ -229,19 +315,22 @@ namespace SourceGen.WpfGui {
|
||||
Debug.WriteLine("ADD: " + dlg.NewSym);
|
||||
mWorkTable.AddOrReplace(dlg.NewSym);
|
||||
|
||||
// Reload the contents. This loses the selection, but that shouldn't be an
|
||||
// issue when adding new symbols. To do this incrementally we'd need to add
|
||||
// the symbol at the correct sorted position.
|
||||
LoadVariables();
|
||||
// Add it to the display list, select it, and scroll it into view.
|
||||
FormattedSymbol newItem = CreateFormattedSymbol(dlg.NewSym);
|
||||
Variables.Add(newItem);
|
||||
symbolsList.SelectedItem = newItem;
|
||||
symbolsList.ScrollIntoView(newItem);
|
||||
|
||||
UpdateControls();
|
||||
}
|
||||
}
|
||||
|
||||
private void EditSymbolButton_Click(object sender, EventArgs e) {
|
||||
// Single-select list view, button dimmed when no selection.
|
||||
Debug.Assert(symbolsListView.SelectedItems.Count == 1);
|
||||
FormattedSymbol item = (FormattedSymbol)symbolsListView.SelectedItems[0];
|
||||
Debug.Assert(symbolsList.SelectedItems.Count == 1);
|
||||
FormattedSymbol item = (FormattedSymbol)symbolsList.SelectedItems[0];
|
||||
DefSymbol defSym = mWorkTable.GetByLabel(item.Label);
|
||||
Debug.Assert(defSym != null);
|
||||
DoEditSymbol(defSym);
|
||||
}
|
||||
|
||||
@ -253,30 +342,43 @@ namespace SourceGen.WpfGui {
|
||||
// Label might have changed, so remove old before adding new.
|
||||
mWorkTable.RemoveByLabel(defSym.Label);
|
||||
mWorkTable.AddOrReplace(dlg.NewSym);
|
||||
LoadVariables();
|
||||
|
||||
// Replace entry in items source.
|
||||
for (int i = 0; i < Variables.Count; i++) {
|
||||
if (Variables[i].Label.Equals(defSym.Label)) {
|
||||
Variables[i] = CreateFormattedSymbol(dlg.NewSym);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateControls();
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveSymbolButton_Click(object sender, RoutedEventArgs e) {
|
||||
// Single-select list view, button dimmed when no selection.
|
||||
Debug.Assert(symbolsListView.SelectedItems.Count == 1);
|
||||
Debug.Assert(symbolsList.SelectedItems.Count == 1);
|
||||
|
||||
int selectionIndex = symbolsListView.SelectedIndex;
|
||||
FormattedSymbol item = (FormattedSymbol)symbolsListView.SelectedItems[0];
|
||||
int selectionIndex = symbolsList.SelectedIndex;
|
||||
FormattedSymbol item = (FormattedSymbol)symbolsList.SelectedItems[0];
|
||||
mWorkTable.RemoveByLabel(item.Label);
|
||||
LoadVariables();
|
||||
for (int i = 0; i < Variables.Count; i++) {
|
||||
if (Variables[i].Label.Equals(item.Label)) {
|
||||
Variables.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
UpdateControls();
|
||||
|
||||
// Restore selection to the item that used to come after the one we just deleted,
|
||||
// so you can hit "Remove" repeatedly to delete multiple items.
|
||||
int newCount = symbolsListView.Items.Count;
|
||||
int newCount = symbolsList.Items.Count;
|
||||
if (selectionIndex >= newCount) {
|
||||
selectionIndex = newCount - 1;
|
||||
}
|
||||
if (selectionIndex >= 0) {
|
||||
symbolsListView.SelectedIndex = selectionIndex;
|
||||
removeSymbolButton.Focus();
|
||||
symbolsList.SelectedIndex = selectionIndex;
|
||||
removeSymbolButton.Focus(); // so you can keep banging on Enter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ limitations under the License.
|
||||
xmlns:local="clr-namespace:SourceGen.WpfGui"
|
||||
mc:Ignorable="d"
|
||||
Title="Edit Project Properties"
|
||||
Width="600" Height="400" ResizeMode="NoResize"
|
||||
Width="640" Height="400" ResizeMode="NoResize"
|
||||
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
||||
Loaded="Window_Loaded">
|
||||
|
||||
@ -146,26 +146,36 @@ limitations under the License.
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2"
|
||||
Margin="4,0,0,0" Text="Symbols defined in project:"/>
|
||||
|
||||
<ListView Name="projectSymbolsListView" Grid.Column="0" Grid.Row="1" Margin="4,4,4,0"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"
|
||||
<DataGrid Name="projectSymbolsList" Grid.Column="0" Grid.Row="1" Margin="4,4,4,0"
|
||||
ItemsSource="{Binding ProjectSymbols}"
|
||||
SnapsToDevicePixels="True" SelectionMode="Single"
|
||||
IsReadOnly="True"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"
|
||||
SnapsToDevicePixels="True"
|
||||
GridLinesVisibility="Vertical"
|
||||
VerticalGridLinesBrush="#FF7F7F7F"
|
||||
AutoGenerateColumns="False"
|
||||
HeadersVisibility="Column"
|
||||
CanUserReorderColumns="False"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="List_SelectionChanged"
|
||||
MouseDoubleClick="ProjectSymbolsListView_MouseDoubleClick">
|
||||
<ListView.Resources>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
|
||||
</Style>
|
||||
</ListView.Resources>
|
||||
<ListView.View>
|
||||
<GridView AllowsColumnReorder="False">
|
||||
<GridViewColumn Header="Name" Width="118" DisplayMemberBinding="{Binding Label}"/>
|
||||
<GridViewColumn Header="Value" Width="72" DisplayMemberBinding="{Binding Value}"/>
|
||||
<GridViewColumn Header="Type" Width="45" DisplayMemberBinding="{Binding Type}"/>
|
||||
<GridViewColumn Header="Comment" Width="300" DisplayMemberBinding="{Binding Comment}"/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
Sorting="ProjectSymbolsList_Sorting"
|
||||
MouseDoubleClick="ProjectSymbolsList_MouseDoubleClick">
|
||||
<DataGrid.Resources>
|
||||
<!-- make the no-focus color the same as the in-focus color -->
|
||||
<!-- thanks: https://stackoverflow.com/a/13053511/294248 -->
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
|
||||
Color="{x:Static SystemColors.HighlightColor}"/>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}"
|
||||
Color="{x:Static SystemColors.HighlightTextColor}"/>
|
||||
</DataGrid.Resources>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Name" Width="118" Binding="{Binding Label}"/>
|
||||
<DataGridTextColumn Header="Value" Width="72" Binding="{Binding Value}"/>
|
||||
<DataGridTextColumn Header="Type" Width="45" Binding="{Binding Type}"/>
|
||||
<DataGridTextColumn Header="Width" Width="45" Binding="{Binding Width}"/>
|
||||
<DataGridTextColumn Header="Comment" Width="300" Binding="{Binding Comment}"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<StackPanel Grid.Column="1" Grid.Row="1">
|
||||
<Button Name="newSymbolButton" Width="120" Margin="4" Content="_New Symbol..."
|
||||
@ -230,7 +240,7 @@ limitations under the License.
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Margin="4,0,0,0"
|
||||
Text="Currently configured symbol files:"/>
|
||||
Text="Currently configured extension scripts:"/>
|
||||
|
||||
<ListBox Name="extensionScriptsListBox" Grid.Column="0" Grid.Row="1" Margin="4"
|
||||
SelectionMode="Extended"
|
||||
|
@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
@ -23,6 +24,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.Win32;
|
||||
|
||||
@ -36,6 +38,8 @@ namespace SourceGen.WpfGui {
|
||||
/// Project properties dialog.
|
||||
/// </summary>
|
||||
public partial class EditProjectProperties : Window, INotifyPropertyChanged {
|
||||
private const string NO_WIDTH_STR = "-";
|
||||
|
||||
/// <summary>
|
||||
/// New set. Updated when Apply or OK is hit. This will be null if no changes have
|
||||
/// been applied.
|
||||
@ -169,7 +173,7 @@ namespace SourceGen.WpfGui {
|
||||
//
|
||||
// Enable or disable the edit/remove buttons based on how many items are selected.
|
||||
// (We're currently configured for single-select, so this is really just a != 0 test.)
|
||||
int symSelCount = projectSymbolsListView.SelectedItems.Count;
|
||||
int symSelCount = projectSymbolsList.SelectedItems.Count;
|
||||
removeSymbolButton.IsEnabled = (symSelCount == 1);
|
||||
editSymbolButton.IsEnabled = (symSelCount == 1);
|
||||
|
||||
@ -401,13 +405,23 @@ namespace SourceGen.WpfGui {
|
||||
public string Label { get; private set; }
|
||||
public string Value { get; private set; }
|
||||
public string Type { get; private set; }
|
||||
public string Width { get; private set; }
|
||||
public string Comment { get; private set; }
|
||||
|
||||
public FormattedSymbol(string label, string value, string type, string comment) {
|
||||
// Numeric form of Value, used so we can sort hex/dec/binary correctly.
|
||||
public int NumericValue { get; private set; }
|
||||
public int NumericWidth { get; private set; }
|
||||
|
||||
public FormattedSymbol(string label, int numericValue, string value, string type,
|
||||
int numericWidth, string width, string comment) {
|
||||
Label = label;
|
||||
Value = value;
|
||||
Type = type;
|
||||
Width = width;
|
||||
Comment = comment;
|
||||
|
||||
NumericValue = numericValue;
|
||||
NumericWidth = numericWidth;
|
||||
}
|
||||
}
|
||||
public ObservableCollection<FormattedSymbol> ProjectSymbols { get; private set; } =
|
||||
@ -421,20 +435,121 @@ namespace SourceGen.WpfGui {
|
||||
|
||||
foreach (KeyValuePair<string, DefSymbol> kvp in mWorkProps.ProjectSyms) {
|
||||
DefSymbol defSym = kvp.Value;
|
||||
string typeStr;
|
||||
if (defSym.SymbolType == Symbol.Type.Constant) {
|
||||
typeStr = Res.Strings.ABBREV_CONSTANT;
|
||||
} else {
|
||||
typeStr = Res.Strings.ABBREV_ADDRESS;
|
||||
ProjectSymbols.Add(CreateFormattedSymbol(defSym));
|
||||
}
|
||||
|
||||
// This doesn't seem to enable "live sorting". It does an initial sort, but
|
||||
// without calling the Sorting function. I'm not sure what the point of this is,
|
||||
// or how to cause the DataGrid to behave like somebody clicked on a header.
|
||||
|
||||
//ICollectionView view =
|
||||
// CollectionViewSource.GetDefaultView(projectSymbolsList.ItemsSource);
|
||||
//SortDescriptionCollection sortDes = view.SortDescriptions;
|
||||
//sortDes.Add(new SortDescription("Value", ListSortDirection.Descending));
|
||||
//projectSymbolsList.Columns[0].SortDirection = ListSortDirection.Ascending;
|
||||
//view.Refresh();
|
||||
}
|
||||
|
||||
private FormattedSymbol CreateFormattedSymbol(DefSymbol defSym) {
|
||||
string typeStr;
|
||||
if (defSym.SymbolType == Symbol.Type.Constant) {
|
||||
typeStr = Res.Strings.ABBREV_CONSTANT;
|
||||
} else {
|
||||
typeStr = Res.Strings.ABBREV_ADDRESS;
|
||||
}
|
||||
|
||||
FormattedSymbol fsym = new FormattedSymbol(
|
||||
defSym.Label,
|
||||
defSym.Value,
|
||||
mFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase),
|
||||
typeStr,
|
||||
defSym.DataDescriptor.Length,
|
||||
defSym.HasWidth ? defSym.DataDescriptor.Length.ToString() : NO_WIDTH_STR,
|
||||
defSym.Comment);
|
||||
return fsym;
|
||||
}
|
||||
|
||||
private void ProjectSymbolsList_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 = new ProjectSymbolComparer(col.DisplayIndex, isAscending);
|
||||
ListCollectionView lcv = (ListCollectionView)
|
||||
CollectionViewSource.GetDefaultView(projectSymbolsList.ItemsSource);
|
||||
lcv.CustomSort = comparer;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private class ProjectSymbolComparer : IComparer {
|
||||
// Must match order of items in DataGrid. DataGrid must not allow columns to be
|
||||
// reordered. We could check col.Header instead, but then we have to assume that
|
||||
// the Header is a string that doesn't get renamed.
|
||||
private enum SortField {
|
||||
Label = 0, Value = 1, Type = 2, Width = 3, Comment = 4
|
||||
}
|
||||
private SortField mSortField;
|
||||
private bool mIsAscending;
|
||||
|
||||
public ProjectSymbolComparer(int displayIndex, bool isAscending) {
|
||||
Debug.Assert(displayIndex >= 0 && displayIndex <= 4);
|
||||
mIsAscending = isAscending;
|
||||
mSortField = (SortField)displayIndex;
|
||||
}
|
||||
|
||||
// IComparer interface
|
||||
public int Compare(object o1, object o2) {
|
||||
FormattedSymbol fsym1 = (FormattedSymbol)o1;
|
||||
FormattedSymbol fsym2 = (FormattedSymbol)o2;
|
||||
|
||||
// Sort primarily by specified field, secondarily by label (which should
|
||||
// be unique).
|
||||
int cmp;
|
||||
switch (mSortField) {
|
||||
case SortField.Label:
|
||||
cmp = string.Compare(fsym1.Label, fsym2.Label);
|
||||
break;
|
||||
case SortField.Value:
|
||||
cmp = fsym1.NumericValue - fsym2.NumericValue;
|
||||
break;
|
||||
case SortField.Type:
|
||||
cmp = string.Compare(fsym1.Type, fsym2.Type);
|
||||
break;
|
||||
case SortField.Width:
|
||||
// The no-width case is a little weird, because the actual width will
|
||||
// be 1, but we want it to sort separately.
|
||||
if (fsym1.Width == fsym2.Width) {
|
||||
cmp = 0;
|
||||
} else if (fsym1.Width == NO_WIDTH_STR) {
|
||||
cmp = -1;
|
||||
} else if (fsym2.Width == NO_WIDTH_STR) {
|
||||
cmp = 1;
|
||||
} else {
|
||||
cmp = fsym1.NumericWidth - fsym2.NumericWidth;
|
||||
}
|
||||
break;
|
||||
case SortField.Comment:
|
||||
cmp = string.Compare(fsym1.Comment, fsym2.Comment);
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FormattedSymbol fsym = new FormattedSymbol(
|
||||
defSym.Label,
|
||||
mFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase),
|
||||
typeStr,
|
||||
defSym.Comment);
|
||||
|
||||
ProjectSymbols.Add(fsym);
|
||||
if (cmp == 0) {
|
||||
cmp = string.Compare(fsym1.Label, fsym2.Label);
|
||||
}
|
||||
if (!mIsAscending) {
|
||||
cmp = -cmp;
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
}
|
||||
|
||||
@ -447,31 +562,31 @@ namespace SourceGen.WpfGui {
|
||||
mWorkProps.ProjectSyms[dlg.NewSym.Label] = dlg.NewSym;
|
||||
IsDirty = true;
|
||||
|
||||
// Reload the contents. This loses the selection, but that shouldn't be an
|
||||
// issue when adding new symbols. To do this incrementally we'd need to add
|
||||
// the symbol at the correct sorted position.
|
||||
LoadProjectSymbols();
|
||||
UpdateControls();
|
||||
FormattedSymbol newItem = CreateFormattedSymbol(dlg.NewSym);
|
||||
ProjectSymbols.Add(newItem);
|
||||
projectSymbolsList.SelectedItem = newItem;
|
||||
projectSymbolsList.ScrollIntoView(newItem);
|
||||
|
||||
UpdateControls();
|
||||
okButton.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void EditSymbolButton_Click(object sender, EventArgs e) {
|
||||
// Single-select list view, button dimmed when no selection.
|
||||
Debug.Assert(projectSymbolsListView.SelectedItems.Count == 1);
|
||||
FormattedSymbol item = (FormattedSymbol)projectSymbolsListView.SelectedItems[0];
|
||||
Debug.Assert(projectSymbolsList.SelectedItems.Count == 1);
|
||||
FormattedSymbol item = (FormattedSymbol)projectSymbolsList.SelectedItems[0];
|
||||
DefSymbol defSym = mWorkProps.ProjectSyms[item.Label];
|
||||
DoEditSymbol(defSym);
|
||||
}
|
||||
|
||||
private void ProjectSymbolsListView_MouseDoubleClick(object sender,
|
||||
MouseButtonEventArgs e) {
|
||||
ListViewItem lvi = projectSymbolsListView.GetClickedItem(e);
|
||||
if (lvi == null) {
|
||||
private void ProjectSymbolsList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
|
||||
if (!projectSymbolsList.GetClickRowColItem(e, out int unusedRow, out int unusedCol,
|
||||
out object objItem)) {
|
||||
// Header or empty area; ignore.
|
||||
return;
|
||||
}
|
||||
FormattedSymbol item = (FormattedSymbol)lvi.Content;
|
||||
FormattedSymbol item = (FormattedSymbol)objItem;
|
||||
DefSymbol defSym = mWorkProps.ProjectSyms[item.Label];
|
||||
DoEditSymbol(defSym);
|
||||
}
|
||||
@ -485,33 +600,46 @@ namespace SourceGen.WpfGui {
|
||||
mWorkProps.ProjectSyms.Remove(defSym.Label);
|
||||
mWorkProps.ProjectSyms[dlg.NewSym.Label] = dlg.NewSym;
|
||||
IsDirty = true;
|
||||
LoadProjectSymbols();
|
||||
UpdateControls();
|
||||
|
||||
// Replace entry in items source.
|
||||
for (int i = 0; i < ProjectSymbols.Count; i++) {
|
||||
if (ProjectSymbols[i].Label.Equals(defSym.Label)) {
|
||||
ProjectSymbols[i] = CreateFormattedSymbol(dlg.NewSym);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateControls();
|
||||
okButton.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveSymbolButton_Click(object sender, RoutedEventArgs e) {
|
||||
// Single-select list view, button dimmed when no selection.
|
||||
Debug.Assert(projectSymbolsListView.SelectedItems.Count == 1);
|
||||
Debug.Assert(projectSymbolsList.SelectedItems.Count == 1);
|
||||
|
||||
int selectionIndex = projectSymbolsListView.SelectedIndex;
|
||||
FormattedSymbol item = (FormattedSymbol)projectSymbolsListView.SelectedItems[0];
|
||||
int selectionIndex = projectSymbolsList.SelectedIndex;
|
||||
FormattedSymbol item = (FormattedSymbol)projectSymbolsList.SelectedItems[0];
|
||||
DefSymbol defSym = mWorkProps.ProjectSyms[item.Label];
|
||||
mWorkProps.ProjectSyms.Remove(defSym.Label);
|
||||
IsDirty = true;
|
||||
LoadProjectSymbols();
|
||||
|
||||
for (int i = 0; i < ProjectSymbols.Count; i++) {
|
||||
if (ProjectSymbols[i].Label.Equals(item.Label)) {
|
||||
ProjectSymbols.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
UpdateControls();
|
||||
|
||||
// Restore selection to the item that used to come after the one we just deleted,
|
||||
// so you can hit "Remove" repeatedly to delete multiple items.
|
||||
int newCount = projectSymbolsListView.Items.Count;
|
||||
int newCount = projectSymbolsList.Items.Count;
|
||||
if (selectionIndex >= newCount) {
|
||||
selectionIndex = newCount - 1;
|
||||
}
|
||||
if (selectionIndex >= 0) {
|
||||
projectSymbolsListView.SelectedIndex = selectionIndex;
|
||||
projectSymbolsList.SelectedIndex = selectionIndex;
|
||||
removeSymbolButton.Focus();
|
||||
}
|
||||
}
|
||||
@ -551,7 +679,7 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
if (foundCount != 0) {
|
||||
IsDirty = true;
|
||||
LoadProjectSymbols();
|
||||
LoadProjectSymbols(); // just reload the whole set
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
|
@ -462,8 +462,9 @@ limitations under the License.
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="2" Header="Notes">
|
||||
<DataGrid Name="notesGrid" IsReadOnly="True"
|
||||
<DataGrid Name="notesGrid"
|
||||
ItemsSource="{Binding NotesList}"
|
||||
IsReadOnly="True"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"
|
||||
SnapsToDevicePixels="True"
|
||||
GridLinesVisibility="Vertical"
|
||||
|
@ -1420,7 +1420,7 @@ namespace SourceGen.WpfGui {
|
||||
new ObservableCollection<ReferencesListItem>();
|
||||
|
||||
private void ReferencesList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
|
||||
if (!referencesGrid.GetClickRowColItem(e, out int rowIndex, out int colIndex,
|
||||
if (!referencesGrid.GetClickRowColItem(e, out int unusedRow, out int unusedCol,
|
||||
out object item)) {
|
||||
// Header or empty area; ignore.
|
||||
return;
|
||||
@ -1460,7 +1460,7 @@ namespace SourceGen.WpfGui {
|
||||
new ObservableCollection<NotesListItem>();
|
||||
|
||||
private void NotesList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
|
||||
if (!notesGrid.GetClickRowColItem(e, out int rowIndex, out int colIndex,
|
||||
if (!notesGrid.GetClickRowColItem(e, out int unusedRow, out int unusedCol,
|
||||
out object item)) {
|
||||
// Header or empty area; ignore.
|
||||
return;
|
||||
@ -1501,7 +1501,7 @@ namespace SourceGen.WpfGui {
|
||||
new ObservableCollection<SymbolsListItem>();
|
||||
|
||||
private void SymbolsList_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
|
||||
if (!symbolsGrid.GetClickRowColItem(e, out int rowIndex, out int colIndex,
|
||||
if (!symbolsGrid.GetClickRowColItem(e, out int unusedRow, out int unusedCol,
|
||||
out object item)) {
|
||||
// Header or empty area; ignore.
|
||||
return;
|
||||
@ -1544,6 +1544,9 @@ namespace SourceGen.WpfGui {
|
||||
/// 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>
|
||||
/// <remarks>
|
||||
/// https://stackoverflow.com/a/2130557/294248
|
||||
/// </remarks>
|
||||
private void SymbolsList_Sorting(object sender, DataGridSortingEventArgs e) {
|
||||
DataGridColumn col = e.Column;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user