mirror of
https://github.com/fadden/6502bench.git
synced 2025-01-20 14:31:17 +00:00
Update editors to work with local variables
The table editor is now editing the table, and the DefSymbol editor now asks for the Width data when editing a local var. This also moves EditDefSymbol closer to proper WPF style, with bound properties for the input fields. No changes yet to serialization or analysis.
This commit is contained in:
parent
5fe032c93a
commit
1cc9d2bd70
@ -24,6 +24,8 @@ namespace SourceGen {
|
||||
/// </summary>
|
||||
public class DefSymbol : Symbol {
|
||||
public const int NO_WIDTH = -1;
|
||||
public const int MIN_WIDTH = 1;
|
||||
public const int MAX_WIDTH = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Data format descriptor.
|
||||
@ -93,6 +95,25 @@ namespace SourceGen {
|
||||
Tag = tag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="label">Symbol's label.</param>
|
||||
/// <param name="value">Symbol's value.</param>
|
||||
/// <param name="source">Symbol source (general point of origin).</param>
|
||||
/// <param name="type">Symbol type.</param>
|
||||
/// <param name="formatSubType">Format descriptor sub-type, so we know how the
|
||||
/// user wants the value to be displayed.</param>
|
||||
/// <param name="comment">End-of-line comment.</param>
|
||||
/// <param name="tag">Symbol tag, used for grouping platform symbols.</param>
|
||||
/// <param name="width">Variable width.</param>
|
||||
public DefSymbol(string label, int value, Source source, Type type,
|
||||
FormatDescriptor.SubType formatSubType, string comment, string tag, int width)
|
||||
: this(label, value, source, type, formatSubType, comment, tag) {
|
||||
Debug.Assert(width == NO_WIDTH || (width >= MIN_WIDTH && width <= MAX_WIDTH));
|
||||
Width = width;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a DefSymbol from a Symbol and a format descriptor. This is used
|
||||
/// for project symbols.
|
||||
|
@ -15,18 +15,23 @@
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SourceGen {
|
||||
/// <summary>
|
||||
/// Table of redefinable variables. A project may have several of these, at different
|
||||
/// offsets. The contents of later tables overwrite the contents of earlier tables.
|
||||
///
|
||||
/// The class is mutable, but may only be modified by the LvTable editor (which makes
|
||||
/// changes to a work object that moves through the undo/redo buffer) or the
|
||||
/// deserializer.
|
||||
/// </summary>
|
||||
public class LocalVariableTable {
|
||||
/// <summary>
|
||||
/// List of variables. The symbol's label must be unique within a table, so we sort
|
||||
/// on that.
|
||||
/// </summary>
|
||||
private SortedList<string, DefSymbol> mVariables;
|
||||
public SortedList<string, DefSymbol> Variables;
|
||||
|
||||
/// <summary>
|
||||
/// If set, all values from previous VariableTables should be discarded when this
|
||||
@ -40,25 +45,65 @@ namespace SourceGen {
|
||||
/// </remarks>
|
||||
public bool ClearPrevious { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indexer.
|
||||
/// </summary>
|
||||
/// <param name="key">Symbol's label.</param>
|
||||
/// <returns>Matching symbol. Throws an exception if not found.</returns>
|
||||
public DefSymbol this[string key] {
|
||||
get {
|
||||
return mVariables[key];
|
||||
}
|
||||
set {
|
||||
mVariables[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an empty table.
|
||||
/// </summary>
|
||||
public LocalVariableTable() {
|
||||
mVariables = new SortedList<string, DefSymbol>();
|
||||
Variables = new SortedList<string, DefSymbol>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy constructor.
|
||||
/// </summary>
|
||||
/// <param name="src">Object to clone.</param>
|
||||
public LocalVariableTable(LocalVariableTable src) : this() {
|
||||
ClearPrevious = src.ClearPrevious;
|
||||
|
||||
foreach (KeyValuePair<string, DefSymbol> kvp in src.Variables) {
|
||||
Variables[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
Debug.Assert(this == src);
|
||||
}
|
||||
|
||||
public static bool operator ==(LocalVariableTable a, LocalVariableTable b) {
|
||||
if (ReferenceEquals(a, b)) {
|
||||
return true; // same object, or both null
|
||||
}
|
||||
if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) {
|
||||
return false; // one is null
|
||||
}
|
||||
// All fields must be equal.
|
||||
if (a.ClearPrevious != b.ClearPrevious) {
|
||||
return false;
|
||||
}
|
||||
if (a.Variables.Count != b.Variables.Count) {
|
||||
return false;
|
||||
}
|
||||
// Compare all list entries.
|
||||
for (int i = 0; i < a.Variables.Count; i++) {
|
||||
if (a.Variables.Values[i] != b.Variables.Values[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static bool operator !=(LocalVariableTable a, LocalVariableTable b) {
|
||||
return !(a == b);
|
||||
}
|
||||
public override bool Equals(object obj) {
|
||||
return obj is LocalVariableTable && this == (LocalVariableTable)obj;
|
||||
}
|
||||
public override int GetHashCode() {
|
||||
int hashCode = 0;
|
||||
foreach (KeyValuePair<string, DefSymbol> kvp in Variables) {
|
||||
hashCode ^= kvp.Value.GetHashCode();
|
||||
}
|
||||
if (ClearPrevious) {
|
||||
hashCode++;
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1689,12 +1689,15 @@ namespace SourceGen {
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
private LocalVariableTable lvt = new LocalVariableTable();
|
||||
public void EditLocalVariableTable() {
|
||||
// TODO
|
||||
EditLocalVariableTable dlg = new EditLocalVariableTable(mMainWin);
|
||||
EditLocalVariableTable dlg = new EditLocalVariableTable(mMainWin, mProject.SymbolTable,
|
||||
mOutputFormatter, lvt);
|
||||
if (dlg.ShowDialog() != true) {
|
||||
return;
|
||||
}
|
||||
lvt = dlg.NewTable;
|
||||
}
|
||||
|
||||
public bool CanEditLongComment() {
|
||||
@ -1937,12 +1940,11 @@ namespace SourceGen {
|
||||
Debug.Assert(origDefSym.SymbolSource == Symbol.Source.Project);
|
||||
|
||||
EditDefSymbol dlg = new EditDefSymbol(mMainWin, mOutputFormatter,
|
||||
mProject.ProjectProps.ProjectSyms);
|
||||
dlg.DefSym = origDefSym;
|
||||
mProject.ProjectProps.ProjectSyms, origDefSym);
|
||||
if (dlg.ShowDialog() == true) {
|
||||
ProjectProperties newProps = new ProjectProperties(mProject.ProjectProps);
|
||||
newProps.ProjectSyms.Remove(origDefSym.Label);
|
||||
newProps.ProjectSyms[dlg.DefSym.Label] = dlg.DefSym;
|
||||
newProps.ProjectSyms[dlg.NewSym.Label] = dlg.NewSym;
|
||||
|
||||
UndoableChange uc = UndoableChange.CreateProjectPropertiesChange(
|
||||
mProject.ProjectProps, newProps);
|
||||
|
@ -20,7 +20,8 @@ namespace SourceGen {
|
||||
/// <summary>
|
||||
/// A collection of project properties.
|
||||
///
|
||||
/// The class is mutable, but may only be modified by DisasmProject.ApplyChanges or
|
||||
/// The class is mutable, but may only be modified by the property editor (which updates
|
||||
/// a work object that gets put into the project by DisasmProject.ApplyChanges) or
|
||||
/// the deserializer.
|
||||
///
|
||||
/// All fields are explicitly handled by the ProjectFile serializer.
|
||||
|
@ -36,40 +36,47 @@ limitations under the License.
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Text="Label:"/>
|
||||
<StackPanel Grid.Column="1" Grid.Row="0">
|
||||
<TextBox Name="labelTextBox" Margin="0,1,0,0"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"
|
||||
TextChanged="LabelTextBox_TextChanged"/>
|
||||
<TextBox Name="labelTextBox" Margin="0,1,0,0" Text="{Binding Label, UpdateSourceTrigger=PropertyChanged}"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"/>
|
||||
<TextBlock Name="labelNotesLabel" Text="• 2+ alphanumerics, starting with letter" Margin="0,4,0,0"/>
|
||||
<TextBlock Name="labelUniqueLabel" Text="• Unique among project symbols" Margin="0,4,0,16"/>
|
||||
<TextBlock Name="projectLabelUniqueLabel" Text="• Unique among project symbols" Margin="0,4,0,16"/>
|
||||
<TextBlock Name="labelUniqueLabel" Text="• Unique" Margin="0,4,0,16"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" Text="Value:"/>
|
||||
<StackPanel Grid.Column="1" Grid.Row="1">
|
||||
<TextBox Name="valueTextBox" Margin="0,1,0,0"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"
|
||||
TextChanged="ValueTextBox_TextChanged"/>
|
||||
<TextBox Margin="0,1,0,0" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"/>
|
||||
<TextBlock Name="valueNotesLabel" Text="• Decimal, hex ($), or binary (%)" Margin="0,4,0,16"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="2" Text="Comment:" Margin="0,0,8,0"/>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2">
|
||||
<TextBox Name="commentTextBox" Margin="0,1,0,0"
|
||||
<TextBlock Name="widthEntry1" Grid.Column="0" Grid.Row="2" Text="Width:"/>
|
||||
<StackPanel Name="widthEntry2" Grid.Column="1" Grid.Row="2">
|
||||
<TextBox Margin="0,1,0,0" Text="{Binding VarWidth, UpdateSourceTrigger=PropertyChanged}"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"/>
|
||||
<TextBlock Name="widthNotesLabel" Text="• Decimal, 1-4" Margin="0,4,0,16"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="3" Text="Comment:" Margin="0,0,8,0"/>
|
||||
<StackPanel Grid.Column="1" Grid.Row="3">
|
||||
<TextBox Margin="0,1,0,0" Text="{Binding Comment, UpdateSourceTrigger=PropertyChanged}"
|
||||
FontFamily="{StaticResource GeneralMonoFont}"/>
|
||||
<TextBlock Text="• Optional" Margin="0,4,0,16"/>
|
||||
</StackPanel>
|
||||
|
||||
<GroupBox Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" Header="Symbol Type" Padding="4">
|
||||
<GroupBox Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="2" Header="Symbol Type" Padding="4">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<RadioButton Name="addressRadioButton" Content="Address"/>
|
||||
<RadioButton Name="constantRadioButton" Content="Constant" Margin="24,0,0,0"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<StackPanel Grid.Column="1" Grid.Row="4" Margin="0,16,0,0"
|
||||
<StackPanel Grid.Column="1" Grid.Row="5" Margin="0,16,0,0"
|
||||
Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="OK" Width="70" IsDefault="True" IsEnabled="{Binding IsValid}"
|
||||
Click="OkButton_Click"/>
|
||||
|
@ -30,33 +30,63 @@ namespace SourceGen.WpfGui {
|
||||
/// </summary>
|
||||
public partial class EditDefSymbol : Window, INotifyPropertyChanged {
|
||||
/// <summary>
|
||||
/// Set to previous value before calling; may be null if creating a new symbol.
|
||||
/// Will be set to new value on OK result.
|
||||
/// Result; will be set non-null on OK.
|
||||
/// </summary>
|
||||
public DefSymbol DefSym { get; set; }
|
||||
public DefSymbol NewSym { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true when all fields are valid. Controls whether the OK button is enabled.
|
||||
/// </summary>
|
||||
public bool IsValid {
|
||||
get { return mIsValid; }
|
||||
set {
|
||||
mIsValid = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
set { mIsValid = value; OnPropertyChanged(); }
|
||||
}
|
||||
private bool mIsValid;
|
||||
|
||||
public string Label {
|
||||
get { return mLabel; }
|
||||
set { mLabel = value; OnPropertyChanged(); UpdateControls(); }
|
||||
}
|
||||
private string mLabel;
|
||||
|
||||
public string Value {
|
||||
get { return mValue; }
|
||||
set { mValue = value; OnPropertyChanged(); UpdateControls(); }
|
||||
}
|
||||
private string mValue;
|
||||
|
||||
public string VarWidth {
|
||||
get { return mWidth; }
|
||||
set { mWidth = value; OnPropertyChanged(); UpdateControls(); }
|
||||
}
|
||||
private string mWidth;
|
||||
|
||||
public string Comment {
|
||||
get { return mComment; }
|
||||
set { mComment = value; OnPropertyChanged(); }
|
||||
}
|
||||
private string mComment;
|
||||
|
||||
/// <summary>
|
||||
/// Format object to use when formatting addresses and constants.
|
||||
/// </summary>
|
||||
private Formatter mNumFormatter;
|
||||
|
||||
/// <summary>
|
||||
/// Old symbol value. May be null.
|
||||
/// </summary>
|
||||
private DefSymbol mOldSym;
|
||||
|
||||
/// <summary>
|
||||
/// List of existing symbols, for uniqueness check. The list will not be modified.
|
||||
/// </summary>
|
||||
private SortedList<string, DefSymbol> mDefSymbolList;
|
||||
|
||||
/// <summary>
|
||||
/// Full symbol table, for extended uniqueness check.
|
||||
/// </summary>
|
||||
private SymbolTable mSymbolTable;
|
||||
|
||||
// Saved off at dialog load time.
|
||||
private Brush mDefaultLabelColor;
|
||||
|
||||
@ -67,26 +97,50 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor, for editing a project symbol.
|
||||
/// </summary>
|
||||
public EditDefSymbol(Window owner, Formatter formatter,
|
||||
SortedList<string, DefSymbol> defList) {
|
||||
SortedList<string, DefSymbol> defList, DefSymbol defSym) {
|
||||
InitializeComponent();
|
||||
Owner = owner;
|
||||
DataContext = this;
|
||||
|
||||
mNumFormatter = formatter;
|
||||
mDefSymbolList = defList;
|
||||
|
||||
mOldSym = defSym;
|
||||
|
||||
Label = Value = VarWidth = Comment = string.Empty;
|
||||
widthEntry1.Visibility = widthEntry2.Visibility = labelUniqueLabel.Visibility =
|
||||
Visibility.Collapsed;
|
||||
projectLabelUniqueLabel.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor, for editing a local variable.
|
||||
/// </summary>
|
||||
public EditDefSymbol(Window owner, Formatter formatter,
|
||||
SortedList<string, DefSymbol> defList, DefSymbol defSym,
|
||||
SymbolTable symbolTable) : this(owner, formatter, defList, defSym) {
|
||||
mSymbolTable = symbolTable;
|
||||
|
||||
widthEntry1.Visibility = widthEntry2.Visibility = labelUniqueLabel.Visibility =
|
||||
Visibility.Visible;
|
||||
projectLabelUniqueLabel.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e) {
|
||||
mDefaultLabelColor = labelNotesLabel.Foreground;
|
||||
|
||||
if (DefSym != null) {
|
||||
labelTextBox.Text = DefSym.Label;
|
||||
valueTextBox.Text = mNumFormatter.FormatValueInBase(DefSym.Value,
|
||||
DefSym.DataDescriptor.NumBase);
|
||||
commentTextBox.Text = DefSym.Comment;
|
||||
if (mOldSym != null) {
|
||||
Label = mOldSym.Label;
|
||||
Value = mNumFormatter.FormatValueInBase(mOldSym.Value,
|
||||
mOldSym.DataDescriptor.NumBase);
|
||||
VarWidth = mOldSym.Width.ToString();
|
||||
Comment = mOldSym.Comment;
|
||||
|
||||
if (DefSym.SymbolType == Symbol.Type.Constant) {
|
||||
if (mOldSym.SymbolType == Symbol.Type.Constant) {
|
||||
constantRadioButton.IsChecked = true;
|
||||
} else {
|
||||
addressRadioButton.IsChecked = true;
|
||||
@ -100,37 +154,55 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
|
||||
private void UpdateControls() {
|
||||
bool labelValid, labelUnique, valueValid;
|
||||
if (!IsLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Label must be valid and not already exist in project symbol list. (It's okay
|
||||
// if it exists elsewhere.)
|
||||
labelValid = Asm65.Label.ValidateLabel(labelTextBox.Text);
|
||||
// Label must be valid and not already exist in project symbol list. (For project
|
||||
// symbols, it's okay if an identical label exists elsewhere.)
|
||||
bool labelValid = Asm65.Label.ValidateLabel(Label);
|
||||
bool labelUnique;
|
||||
|
||||
if (mDefSymbolList.TryGetValue(labelTextBox.Text, out DefSymbol existing)) {
|
||||
if (mDefSymbolList.TryGetValue(Label, out DefSymbol existing)) {
|
||||
// It's okay if it's the same object.
|
||||
labelUnique = (existing == DefSym);
|
||||
labelUnique = (existing == mOldSym);
|
||||
} else {
|
||||
labelUnique = true;
|
||||
}
|
||||
|
||||
// For local variables, do a secondary uniqueness check.
|
||||
if (labelUnique && mSymbolTable != null) {
|
||||
labelUnique = !mSymbolTable.TryGetValue(Label, out Symbol sym);
|
||||
}
|
||||
|
||||
// Value must be blank, meaning "erase any earlier definition", or valid value.
|
||||
// (Hmm... don't currently have a way to specify "no symbol" in DefSymbol.)
|
||||
//if (!string.IsNullOrEmpty(valueTextBox.Text)) {
|
||||
valueValid = ParseValue(out int unused1, out int unused2);
|
||||
bool valueValid = ParseValue(out int unused1, out int unused2);
|
||||
//} else {
|
||||
// valueValid = true;
|
||||
//}
|
||||
|
||||
bool widthValid = true;
|
||||
if (widthEntry1.Visibility == Visibility.Visible) {
|
||||
if (!int.TryParse(VarWidth, out int width) ||
|
||||
width < DefSymbol.MIN_WIDTH || width > DefSymbol.MAX_WIDTH) {
|
||||
widthValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(maybe): do this the XAML way, with properties and Styles
|
||||
labelNotesLabel.Foreground = labelValid ? mDefaultLabelColor : Brushes.Red;
|
||||
labelUniqueLabel.Foreground = labelUnique ? mDefaultLabelColor : Brushes.Red;
|
||||
labelUniqueLabel.Foreground = projectLabelUniqueLabel.Foreground =
|
||||
labelUnique ? mDefaultLabelColor : Brushes.Red;
|
||||
valueNotesLabel.Foreground = valueValid ? mDefaultLabelColor : Brushes.Red;
|
||||
widthNotesLabel.Foreground = widthValid ? mDefaultLabelColor : Brushes.Red;
|
||||
|
||||
IsValid = labelValid && labelUnique && valueValid;
|
||||
IsValid = labelValid && labelUnique && valueValid && widthValid;
|
||||
}
|
||||
|
||||
private bool ParseValue(out int value, out int numBase) {
|
||||
string str = valueTextBox.Text;
|
||||
string str = Value;
|
||||
if (str.IndexOf('/') >= 0) {
|
||||
// treat as address
|
||||
numBase = 16;
|
||||
@ -145,19 +217,16 @@ namespace SourceGen.WpfGui {
|
||||
|
||||
ParseValue(out int value, out int numBase);
|
||||
FormatDescriptor.SubType subType = FormatDescriptor.GetSubTypeForBase(numBase);
|
||||
DefSym = new DefSymbol(labelTextBox.Text, value, Symbol.Source.Project,
|
||||
int width = DefSymbol.NO_WIDTH;
|
||||
if (!string.IsNullOrEmpty(VarWidth)) {
|
||||
width = int.Parse(VarWidth);
|
||||
}
|
||||
|
||||
NewSym = new DefSymbol(Label, value, Symbol.Source.Project,
|
||||
isConstant ? Symbol.Type.Constant : Symbol.Type.ExternalAddr,
|
||||
subType, commentTextBox.Text, string.Empty);
|
||||
subType, Comment, string.Empty, width);
|
||||
|
||||
DialogResult = true;
|
||||
}
|
||||
|
||||
private void LabelTextBox_TextChanged(object sender, TextChangedEventArgs e) {
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
private void ValueTextBox_TextChanged(object sender, TextChangedEventArgs e) {
|
||||
UpdateControls();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ limitations under the License.
|
||||
Click="RemoveSymbolButton_Click"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Grid.Column="0" Grid.Row="2" Margin="0,4" Click="DeleteTableButton_Click"
|
||||
<CheckBox Grid.Column="0" Grid.Row="2" Margin="0,4" IsChecked="{Binding ClearPrevious}"
|
||||
Content="Clear values from previous tables"/>
|
||||
|
||||
<DockPanel Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" Margin="0,8,0,0" LastChildFill="False">
|
||||
<Button DockPanel.Dock="Left" Content="Delete Table" Width="120"/>
|
||||
<Button DockPanel.Dock="Left" Content="Delete Table" Width="120" Click="DeleteTableButton_Click"/>
|
||||
<Button DockPanel.Dock="Right" Content="Cancel" Width="70" Margin="8,0,0,0" IsCancel="True"/>
|
||||
<Button DockPanel.Dock="Right" Grid.Column="1" Content="OK" Width="70"
|
||||
IsDefault="True" Click="OkButton_Click"/>
|
||||
|
@ -24,12 +24,21 @@ using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
using Asm65;
|
||||
using CommonWPF;
|
||||
|
||||
namespace SourceGen.WpfGui {
|
||||
/// <summary>
|
||||
/// Edit a LocalVariableTable.
|
||||
/// </summary>
|
||||
public partial class EditLocalVariableTable : Window {
|
||||
// Item for the symbol list view.
|
||||
/// <summary>
|
||||
/// Result. Will be null if the table was deleted, or if cancel was hit while
|
||||
/// creating a new table.
|
||||
/// </summary>
|
||||
public LocalVariableTable NewTable { get; private set; }
|
||||
|
||||
// Item for the symbol list view ItemsSource.
|
||||
public class FormattedSymbol {
|
||||
public string Label { get; private set; }
|
||||
public string Value { get; private set; }
|
||||
@ -49,35 +58,171 @@ namespace SourceGen.WpfGui {
|
||||
public ObservableCollection<FormattedSymbol> Variables { get; private set; } =
|
||||
new ObservableCollection<FormattedSymbol>();
|
||||
|
||||
public EditLocalVariableTable(Window owner) {
|
||||
public bool ClearPrevious {
|
||||
get { return mWorkTable.ClearPrevious; }
|
||||
set { mWorkTable.ClearPrevious = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Working set. Used internally to hold state.
|
||||
/// </summary>
|
||||
private LocalVariableTable mWorkTable;
|
||||
|
||||
/// <summary>
|
||||
/// Symbol table for uniqueness check.
|
||||
/// </summary>
|
||||
private SymbolTable mSymbolTable;
|
||||
|
||||
/// <summary>
|
||||
/// Format object to use when formatting addresses and constants.
|
||||
/// </summary>
|
||||
private Formatter mFormatter;
|
||||
|
||||
// INotifyPropertyChanged implementation
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
|
||||
public EditLocalVariableTable(Window owner, SymbolTable symbolTable, Formatter formatter,
|
||||
LocalVariableTable lvt) {
|
||||
InitializeComponent();
|
||||
Owner = owner;
|
||||
DataContext = this;
|
||||
|
||||
mSymbolTable = symbolTable;
|
||||
mFormatter = formatter;
|
||||
|
||||
if (lvt != null) {
|
||||
mWorkTable = new LocalVariableTable(lvt);
|
||||
} else {
|
||||
mWorkTable = new LocalVariableTable();
|
||||
}
|
||||
|
||||
LoadVariables();
|
||||
}
|
||||
|
||||
public void Window_Loaded(object sender, RoutedEventArgs e) {
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads entries from the work table into the items source.
|
||||
/// </summary>
|
||||
private void LoadVariables() {
|
||||
Variables.Clear();
|
||||
|
||||
foreach (KeyValuePair<string, DefSymbol> kvp in mWorkTable.Variables) {
|
||||
DefSymbol defSym = kvp.Value;
|
||||
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,
|
||||
mFormatter.FormatValueInBase(defSym.Value, defSym.DataDescriptor.NumBase),
|
||||
typeStr,
|
||||
defSym.Width == DefSymbol.NO_WIDTH ?
|
||||
string.Empty : defSym.Width.ToString(),
|
||||
defSym.Comment);
|
||||
|
||||
Variables.Add(fsym);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
removeSymbolButton.IsEnabled = (symSelCount == 1);
|
||||
editSymbolButton.IsEnabled = (symSelCount == 1);
|
||||
}
|
||||
|
||||
private void OkButton_Click(object sender, RoutedEventArgs e) {
|
||||
NewTable = mWorkTable;
|
||||
DialogResult = true;
|
||||
}
|
||||
|
||||
private void DeleteTableButton_Click(object sender, RoutedEventArgs e) {
|
||||
// TODO - get confirmation, then set result=true with LvTable=null
|
||||
}
|
||||
|
||||
private void SymbolsListView_SelectionChanged(object sender, SelectionChangedEventArgs e) {
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
private void SymbolsListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
|
||||
ListViewItem lvi = symbolsListView.GetClickedItem(e);
|
||||
if (lvi == null) {
|
||||
return;
|
||||
}
|
||||
FormattedSymbol item = (FormattedSymbol)lvi.Content;
|
||||
DefSymbol defSym = mWorkTable.Variables[item.Label];
|
||||
DoEditSymbol(defSym);
|
||||
}
|
||||
|
||||
private void NewSymbolButton_Click(object sender, RoutedEventArgs e) {
|
||||
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter, mWorkTable.Variables, null,
|
||||
mSymbolTable);
|
||||
dlg.ShowDialog();
|
||||
if (dlg.DialogResult == true) {
|
||||
Debug.WriteLine("ADD: " + dlg.NewSym);
|
||||
mWorkTable.Variables[dlg.NewSym.Label] = 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();
|
||||
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];
|
||||
DefSymbol defSym = mWorkTable.Variables[item.Label];
|
||||
DoEditSymbol(defSym);
|
||||
}
|
||||
|
||||
private void DoEditSymbol(DefSymbol defSym) {
|
||||
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter, mWorkTable.Variables, defSym,
|
||||
mSymbolTable);
|
||||
dlg.ShowDialog();
|
||||
if (dlg.DialogResult == true) {
|
||||
// Label might have changed, so remove old before adding new.
|
||||
mWorkTable.Variables.Remove(defSym.Label);
|
||||
mWorkTable.Variables[dlg.NewSym.Label] = dlg.NewSym;
|
||||
LoadVariables();
|
||||
UpdateControls();
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveSymbolButton_Click(object sender, RoutedEventArgs e) {
|
||||
// Single-select list view, button dimmed when no selection.
|
||||
Debug.Assert(symbolsListView.SelectedItems.Count == 1);
|
||||
|
||||
int selectionIndex = symbolsListView.SelectedIndex;
|
||||
FormattedSymbol item = (FormattedSymbol)symbolsListView.SelectedItems[0];
|
||||
DefSymbol defSym = mWorkTable.Variables[item.Label];
|
||||
mWorkTable.Variables.Remove(defSym.Label);
|
||||
LoadVariables();
|
||||
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;
|
||||
if (selectionIndex >= newCount) {
|
||||
selectionIndex = newCount - 1;
|
||||
}
|
||||
if (selectionIndex >= 0) {
|
||||
symbolsListView.SelectedIndex = selectionIndex;
|
||||
removeSymbolButton.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,10 +157,10 @@ namespace SourceGen.WpfGui {
|
||||
NewProps = new ProjectProperties(mWorkProps);
|
||||
DialogResult = true;
|
||||
|
||||
GridView view = (GridView)projectSymbolsListView.View;
|
||||
foreach (GridViewColumn header in view.Columns) {
|
||||
Debug.WriteLine("WIDTH " + header.ActualWidth);
|
||||
}
|
||||
//GridView view = (GridView)projectSymbolsListView.View;
|
||||
//foreach (GridViewColumn header in view.Columns) {
|
||||
// Debug.WriteLine("WIDTH " + header.ActualWidth);
|
||||
//}
|
||||
}
|
||||
|
||||
private void UpdateControls() {
|
||||
@ -431,11 +431,11 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
|
||||
private void NewSymbolButton_Click(object sender, RoutedEventArgs e) {
|
||||
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter, mWorkProps.ProjectSyms);
|
||||
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter, mWorkProps.ProjectSyms, null);
|
||||
dlg.ShowDialog();
|
||||
if (dlg.DialogResult == true) {
|
||||
Debug.WriteLine("ADD: " + dlg.DefSym);
|
||||
mWorkProps.ProjectSyms[dlg.DefSym.Label] = dlg.DefSym;
|
||||
Debug.WriteLine("ADD: " + dlg.NewSym);
|
||||
mWorkProps.ProjectSyms[dlg.NewSym.Label] = dlg.NewSym;
|
||||
IsDirty = true;
|
||||
|
||||
// Reload the contents. This loses the selection, but that shouldn't be an
|
||||
@ -466,13 +466,13 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
|
||||
private void DoEditSymbol(DefSymbol defSym) {
|
||||
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter, mWorkProps.ProjectSyms);
|
||||
dlg.DefSym = defSym;
|
||||
EditDefSymbol dlg = new EditDefSymbol(this, mFormatter, mWorkProps.ProjectSyms,
|
||||
defSym);
|
||||
dlg.ShowDialog();
|
||||
if (dlg.DialogResult == true) {
|
||||
// Label might have changed, so remove old before adding new.
|
||||
mWorkProps.ProjectSyms.Remove(defSym.Label);
|
||||
mWorkProps.ProjectSyms[dlg.DefSym.Label] = dlg.DefSym;
|
||||
mWorkProps.ProjectSyms[dlg.NewSym.Label] = dlg.NewSym;
|
||||
IsDirty = true;
|
||||
LoadProjectSymbols();
|
||||
UpdateControls();
|
||||
|
Loading…
x
Reference in New Issue
Block a user