1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-25 05:29:31 +00:00

Layout and basic integration of Format Split Address Table

This commit is contained in:
Andy McFadden 2019-07-13 13:31:51 -07:00
parent 0d75282756
commit c6b63afb3e
6 changed files with 687 additions and 1 deletions

View File

@ -1851,6 +1851,72 @@ namespace SourceGenWPF {
mMainWin.CodeListView_Focus();
}
public bool CanFormatSplitAddress() {
EntityCounts counts = SelectionAnalysis.mEntityCounts;
// Must be at least one byte of data, and no code.
return (counts.mDataLines > 0 && counts.mCodeLines == 0);
}
public void FormatSplitAddress() {
TypedRangeSet trs = GroupedOffsetSetFromSelected();
if (trs.Count == 0) {
// shouldn't happen
Debug.Assert(false, "FormatSplitAddressTable found nothing to edit");
return;
}
FormatSplitAddress dlg = new FormatSplitAddress(mMainWin, mProject, trs,
mOutputFormatter);
dlg.ShowDialog();
if (dlg.DialogResult != true) {
return;
}
// Start with the format descriptors.
ChangeSet cs = mProject.GenerateFormatMergeSet(dlg.NewFormatDescriptors);
// Add in the user labels.
foreach (KeyValuePair<int, Symbol> kvp in dlg.NewUserLabels) {
Symbol oldUserValue = null;
if (mProject.UserLabels.ContainsKey(kvp.Key)) {
Debug.Assert(false, "should not be replacing label");
oldUserValue = mProject.UserLabels[kvp.Key];
}
UndoableChange uc = UndoableChange.CreateLabelChange(kvp.Key,
oldUserValue, kvp.Value);
cs.Add(uc);
}
// Apply code hints.
if (dlg.WantCodeHints) {
TypedRangeSet newSet = new TypedRangeSet();
TypedRangeSet undoSet = new TypedRangeSet();
foreach (int offset in dlg.AllTargetOffsets) {
if (!mProject.GetAnattrib(offset).IsInstruction) {
CodeAnalysis.TypeHint oldType = mProject.TypeHints[offset];
if (oldType == CodeAnalysis.TypeHint.Code) {
continue; // already set
}
undoSet.Add(offset, (int)oldType);
newSet.Add(offset, (int)CodeAnalysis.TypeHint.Code);
}
}
if (newSet.Count != 0) {
cs.Add(UndoableChange.CreateTypeHintChange(undoSet, newSet));
}
}
// Finally, apply the change.
if (cs.Count != 0) {
ApplyUndoableChanges(cs);
} else {
Debug.WriteLine("No changes found");
}
}
public void Goto() {
GotoBox dlg = new GotoBox(mMainWin, mProject, mOutputFormatter);
if (dlg.ShowDialog() == true) {

View File

@ -112,6 +112,9 @@
<Compile Include="WpfGui\FontPicker.xaml.cs">
<DependentUpon>FontPicker.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\FormatSplitAddress.xaml.cs">
<DependentUpon>FormatSplitAddress.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\GotoBox.xaml.cs">
<DependentUpon>GotoBox.xaml</DependentUpon>
</Compile>
@ -257,6 +260,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\FormatSplitAddress.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\GotoBox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@ -0,0 +1,139 @@
<!--
Copyright 2019 faddenSoft
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<Window x:Class="SourceGenWPF.WpfGui.FormatSplitAddress"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SourceGenWPF.WpfGui"
mc:Ignorable="d"
Title="Format Split-Address Table"
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
Loaded="Window_Loaded">
<Window.Resources>
<system:String x:Key="str_SingleByte">One byte is selected</system:String>
<system:String x:Key="str_SingleGroup">There are {0} bytes selected</system:String>
<system:String x:Key="str_MultiGroup">There are {0} bytes selected, across {1} groups</system:String>
</Window.Resources>
<Grid Margin="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2"
Text="{StaticResource str_MultiGroup}"/>
<StackPanel Grid.Column="0" Grid.Row="1" Margin="0,8,8,0">
<GroupBox Header="Address Characteristics">
<StackPanel>
<RadioButton Name="width16Radio" GroupName="Addr" Margin="0,4,0,0"
Content="16-bit"/>
<RadioButton Name="width24Radio" GroupName="Addr" Margin="0,4,0,0"
Content="24-bit"/>
<CheckBox Margin="0,4,0,0" Content="Adjusted for RTS/RTL (target - 1)"/>
</StackPanel>
</GroupBox>
<GroupBox Header="Low Bytes">
<StackPanel>
<RadioButton Name="lowFirstPartRadio" GroupName="Low" Margin="0,4,0,0"
Content="First part of selection"/>
<RadioButton Name="lowSecondPartRadio" GroupName="Low" Margin="0,4,0,0"
Content="Second part of selection"/>
<RadioButton Name="lowThirdPartRadio" GroupName="Low" Margin="0,4,0,0"
Content="Third part of selection"/>
</StackPanel>
</GroupBox>
<GroupBox Header="High Bytes">
<StackPanel>
<RadioButton Name="highFirstPartRadio" GroupName="High" Margin="0,4,0,0"
Content="First part of selection"/>
<RadioButton Name="highSecondPartRadio" GroupName="High" Margin="0,4,0,0"
Content="Second part of selection"/>
<RadioButton Name="highThirdPartRadio" GroupName="High" Margin="0,4,0,0"
Content="Third part of selection"/>
<StackPanel Orientation="Horizontal">
<RadioButton Name="highConstantRadio" GroupName="High" Margin="0,4,0,0"
Content="Constant:"/>
<TextBox Name="highConstantTextBox" Width="100" Margin="8,1,0,0"/>
</StackPanel>
</StackPanel>
</GroupBox>
<GroupBox Header="Bank Bytes">
<StackPanel>
<RadioButton Name="bankNthPartRadio" GroupName="Bank" Margin="0,4,0,0"
Content="Nth part of selection"/>
<StackPanel Orientation="Horizontal">
<RadioButton Name="bankConstantRadio" GroupName="Bank" Margin="0,4,0,0"
Content="Constant:"/>
<TextBox Name="bankConstantTextBox" Width="100" Margin="8,1,0,0"/>
</StackPanel>
</StackPanel>
</GroupBox>
<GroupBox Header="Options">
<StackPanel>
<CheckBox Content="Add code entry hint if needed" Margin="0,4,0,0"/>
</StackPanel>
</GroupBox>
</StackPanel>
<DockPanel Grid.Column="1" Grid.Row="1" Margin="0,8,0,0">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,8,0,0">
<Button Name="okButton" Content="OK" IsDefault="True" Width="70"
IsEnabled="{Binding IsValid}" Click="OkButton_Click"/>
<Button Name="cancelButton" Content="Cancel" IsCancel="True"
Width="70" Margin="4,0,0,0"/>
</StackPanel>
<GroupBox DockPanel.Dock="Top" Header="Generated Addresses">
<!-- We're currently auto-sizing everything outside this, so the width of
the columns determines the width of the window. Resizing the columns resizes
the window, even though the window isn't resizeable. "It's a feature." -->
<DataGrid Name="outputPreviewList"
Margin="0,2,0,0"
IsReadOnly="True"
ItemsSource="{Binding OutputPreviewList}"
FontFamily="{StaticResource GeneralMonoFont}"
SnapsToDevicePixels="True"
GridLinesVisibility="Vertical"
VerticalGridLinesBrush="#FF7F7F7F"
AutoGenerateColumns="False"
HeadersVisibility="Column"
CanUserReorderColumns="False"
SelectionMode="Single">
<DataGrid.Columns>
<DataGridTextColumn Header="Addr" Width="60" Binding="{Binding Addr}"/>
<DataGridTextColumn Header="Offset" Width="60" Binding="{Binding Offset}"/>
<DataGridTextColumn Header="Symbol" Width="180" Binding="{Binding Type}"/>
</DataGrid.Columns>
</DataGrid>
</GroupBox>
</DockPanel>
</Grid>
</Window>

View File

@ -0,0 +1,463 @@
/*
* Copyright 2019 faddenSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using Asm65;
using CommonUtil;
namespace SourceGenWPF.WpfGui {
/// <summary>
/// Split-address table generator.
/// </summary>
public partial class FormatSplitAddress : Window, INotifyPropertyChanged {
/// Format descriptors to apply.
/// </summary>
public SortedList<int, FormatDescriptor> NewFormatDescriptors { get; private set; }
/// <summary>
/// User labels to apply.
/// </summary>
public Dictionary<int, Symbol> NewUserLabels { get; private set; }
/// <summary>
/// All target offsets found. The list may contain redundant entries.
/// </summary>
public List<int> AllTargetOffsets { get; private set; }
public bool WantCodeHints = true; // TODO
#if false
{
get {
return addCodeHintCheckBox.Checked;
}
}
/// <summary>
/// Set to true when valid output is available.
/// </summary>
private bool mOutputReady;
#endif
/// <summary>
/// Set to true when input is valid. Controls whether the OK button is enabled.
/// </summary>
public bool IsValid {
get { return mIsValid; }
set {
mIsValid = value;
OnPropertyChanged();
}
}
private bool mIsValid;
/// <summary>
/// Selected offsets. An otherwise contiguous range of offsets can be broken up
/// by user-specified labels and address discontinuities, so this needs to be
/// processed by range.
/// </summary>
private TypedRangeSet mSelection;
/// <summary>
/// Project reference.
/// </summary>
private DisasmProject mProject;
/// <summary>
/// Formatter to use when displaying addresses and hex values.
/// </summary>
private Formatter mFormatter;
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public FormatSplitAddress(Window owner, DisasmProject project, TypedRangeSet selection,
Formatter formatter) {
InitializeComponent();
Owner = owner;
DataContext = this;
mProject = project;
mFormatter = formatter;
mSelection = selection;
IsValid = false;
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
// TDOO
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
DialogResult = true;
}
#if false
private void FormatSplitAddress_Load(object sender, EventArgs e) {
mInitializing = true;
string fmt = selectionInfoLabel.Text;
selectionInfoLabel.Text = string.Format(fmt, mSelection.Count, mSelection.RangeCount);
width16Radio.Checked = true;
lowFirstPartRadio.Checked = true;
highSecondPartRadio.Checked = true;
bankNthPartRadio.Checked = true;
incompatibleSelectionLabel.Visible = invalidConstantLabel.Visible = false;
if (mProject.CpuDef.HasAddr16) {
// Disable the 24-bit option. Having 16-bit selected will disable the rest.
width24Radio.Enabled = false;
}
outputPreviewListView.SetDoubleBuffered(true);
mInitializing = false;
UpdateControls();
}
private void UpdateControls() {
if (mInitializing) {
return;
}
mInitializing = true; // no re-entry
lowThirdPartRadio.Enabled = width24Radio.Checked;
highThirdPartRadio.Enabled = width24Radio.Checked;
bankByteGroupBox.Enabled = width24Radio.Checked;
lowSecondPartRadio.Enabled = true;
// If the user selects "constant" for high byte or bank byte, then there is no
// 3rd part available for low/high, so we need to turn those back off.
if (width24Radio.Checked) {
bool haveThree = !(highConstantRadio.Checked || bankConstantRadio.Checked);
lowThirdPartRadio.Enabled = haveThree;
highThirdPartRadio.Enabled = haveThree;
// If "constant" is selected for high byte *and* bank byte, then there's no
// 2nd part available for low.
if (highConstantRadio.Checked && bankConstantRadio.Checked) {
lowSecondPartRadio.Enabled = false;
}
} else {
// For 16-bit address, if high byte is constant, then there's no second
// part for the low byte.
if (highConstantRadio.Checked) {
lowSecondPartRadio.Enabled = false;
}
}
// Was a now-invalidated radio button selected before?
if (!lowThirdPartRadio.Enabled && lowThirdPartRadio.Checked) {
// low now invalid, switch to whatever high isn't using
if (highFirstPartRadio.Checked) {
lowSecondPartRadio.Checked = true;
} else {
lowFirstPartRadio.Checked = true;
}
}
if (!highThirdPartRadio.Enabled && highThirdPartRadio.Checked) {
// high now invalid, switch to whatever low isn't using
if (lowFirstPartRadio.Checked) {
highSecondPartRadio.Checked = true;
} else {
highFirstPartRadio.Checked = true;
}
}
if (!lowSecondPartRadio.Enabled && lowSecondPartRadio.Checked) {
// Should only happen when high part is constant.
Debug.Assert(highFirstPartRadio.Checked == false);
lowFirstPartRadio.Checked = true;
}
mInitializing = false;
UpdatePreview();
okButton.Enabled = mOutputReady;
}
private void widthRadio_CheckedChanged(object sender, EventArgs e) {
UpdateControls();
}
private void pushRtsCheckBox_CheckedChanged(object sender, EventArgs e) {
UpdateControls();
}
private void lowByte_CheckedChanged(object sender, EventArgs e) {
// If we conflict with the high byte, change the high byte.
if (lowFirstPartRadio.Checked && highFirstPartRadio.Checked) {
highSecondPartRadio.Checked = true;
} else if (lowSecondPartRadio.Checked && highSecondPartRadio.Checked) {
highFirstPartRadio.Checked = true;
} else if (lowThirdPartRadio.Checked && highThirdPartRadio.Checked) {
highFirstPartRadio.Checked = true;
}
UpdateControls();
}
private void highByte_CheckedChanged(object sender, EventArgs e) {
// If we conflict with the low byte, change the low byte.
if (lowFirstPartRadio.Checked && highFirstPartRadio.Checked) {
lowSecondPartRadio.Checked = true;
} else if (lowSecondPartRadio.Checked && highSecondPartRadio.Checked) {
lowFirstPartRadio.Checked = true;
} else if (lowThirdPartRadio.Checked && highThirdPartRadio.Checked) {
lowFirstPartRadio.Checked = true;
}
UpdateControls();
}
private void bankByte_CheckedChanged(object sender, EventArgs e) {
UpdateControls();
}
private void highConstantTextBox_TextChanged(object sender, EventArgs e) {
highConstantRadio.Checked = true;
UpdateControls();
}
private void bankConstantTextBox_TextChanged(object sender, EventArgs e) {
bankConstantRadio.Checked = true;
UpdateControls();
}
private void UpdatePreview() {
mOutputReady = false;
int minDiv;
if (width16Radio.Checked) {
if (highConstantRadio.Checked) {
minDiv = 1;
} else {
minDiv = 2;
}
} else {
if (highConstantRadio.Checked) {
if (bankConstantRadio.Checked) {
minDiv = 1;
} else {
minDiv = 2;
}
} else {
if (bankConstantRadio.Checked) {
minDiv = 2;
} else {
minDiv = 3;
}
}
}
incompatibleSelectionLabel.Visible = invalidConstantLabel.Visible = false;
try {
// Start by clearing the previous contents of the list. If something goes
// wrong, we want to show the error messages on an empty list.
outputPreviewListView.BeginUpdate();
outputPreviewListView.Items.Clear();
if ((mSelection.Count % minDiv) != 0) {
incompatibleSelectionLabel.Visible = true;
return;
}
int highConstant = -1;
if (highConstantRadio.Checked) {
if (!Number.TryParseInt(highConstantTextBox.Text, out highConstant,
out int unused) || (highConstant != (byte) highConstant)) {
invalidConstantLabel.Visible = true;
return;
}
}
int bankConstant = -1;
if (bankConstantRadio.Enabled && bankConstantRadio.Checked) {
if (!Number.TryParseInt(bankConstantTextBox.Text, out bankConstant,
out int unused) || (bankConstant != (byte) bankConstant)) {
invalidConstantLabel.Visible = true;
return;
}
}
// Looks valid, generate format list.
GenerateFormats(minDiv, highConstant, bankConstant);
} finally {
outputPreviewListView.EndUpdate();
}
}
private void GenerateFormats(int div, int highConst, int bankConst) {
SortedList<int, FormatDescriptor> newDfds = new SortedList<int, FormatDescriptor>();
Dictionary<int, Symbol> newLabels = new Dictionary<int, Symbol>();
List<int> targetOffsets = new List<int>();
// Identify the offset where each set of data starts.
int span = mSelection.Count / div;
int lowOff, highOff, bankOff;
if (lowFirstPartRadio.Checked) {
lowOff = 0;
} else if (lowSecondPartRadio.Checked) {
lowOff = span;
} else if (lowThirdPartRadio.Checked) {
lowOff = span * 2;
} else {
Debug.Assert(false);
lowOff = -1;
}
if (highFirstPartRadio.Checked) {
highOff = 0;
} else if (highSecondPartRadio.Checked) {
highOff = span;
} else if (highThirdPartRadio.Checked) {
highOff = span * 2;
} else {
highOff = -1; // use constant
}
if (width24Radio.Checked) {
if (bankNthPartRadio.Checked) {
// Use whichever part isn't being used by the other two.
if (lowOff != 0 && highOff != 0) {
bankOff = 0;
} else if (lowOff != span && highOff != span) {
bankOff = span;
} else {
Debug.Assert(lowOff != span * 2 && highOff != span * 2);
bankOff = span * 2;
}
} else {
bankOff = -1; // use constant
}
} else {
bankOff = -1; // use constant
bankConst = 0; // always bank 0
}
Debug.WriteLine("Extract from low=" + lowOff + " high=" + highOff +
" bank=" + bankOff);
// The TypedRangeSet doesn't have an index operation, so copy the values into
// an array.
int[] offsets = new int[mSelection.Count];
int index = 0;
foreach (TypedRangeSet.Tuple tup in mSelection) {
offsets[index++] = tup.Value;
}
int adj = 0;
if (pushRtsCheckBox.Checked) {
adj = 1;
}
// Walk through the file data, generating addresses as we go.
byte[] fileData = mProject.FileData;
for (int i = 0; i < span; i++) {
byte low, high, bank;
low = fileData[offsets[lowOff + i]];
if (highOff >= 0) {
high = fileData[offsets[highOff + i]];
} else {
high = (byte) highConst;
}
if (bankOff >= 0) {
bank = fileData[offsets[bankOff + i]];
} else {
bank = (byte) bankConst;
}
int addr = ((bank << 16) | (high << 8) | low) + adj;
int targetOffset = mProject.AddrMap.AddressToOffset(offsets[0], addr);
if (targetOffset < 0) {
// Address not within file bounds.
// TODO(maybe): look for matching platform/project symbols
AddPreviewItem(addr, -1, Properties.Resources.INVALID_ADDRESS);
} else {
// Note the same target offset may appear more than once.
targetOffsets.Add(targetOffset);
// If there's a user-defined label there already, use it. Otherwise, we'll
// need to generate one.
string targetLabel;
if (mProject.UserLabels.TryGetValue(targetOffset, out Symbol sym)) {
targetLabel = sym.Label;
AddPreviewItem(addr, targetOffset, targetLabel);
} else {
// Generate a symbol that's unique vs. the symbol table. We don't need
// it to be unique vs. the labels we're generating here, because we
// won't generate identical labels for different addresses, and we do
// want to generate a single label if more than one table entry refers
// to the same target.
Symbol tmpSym = AutoLabel.GenerateUniqueForAddress(addr,
mProject.SymbolTable, "T");
// tmpSym was returned as an auto-label, make it a user label instead
tmpSym = new Symbol(tmpSym.Label, tmpSym.Value, Symbol.Source.User,
Symbol.Type.LocalOrGlobalAddr);
newLabels[targetOffset] = tmpSym; // overwrites previous
targetLabel = tmpSym.Label;
AddPreviewItem(addr, targetOffset, "(+) " + targetLabel);
}
// Now we need to create format descriptors for the addresses where we
// extracted the low, high, and bank values.
newDfds.Add(offsets[lowOff + i], FormatDescriptor.Create(1,
new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.Low), false));
if (highOff >= 0) {
newDfds.Add(offsets[highOff + i], FormatDescriptor.Create(1,
new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.High), false));
}
if (bankOff >= 0) {
newDfds.Add(offsets[bankOff + i], FormatDescriptor.Create(1,
new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.Bank), false));
}
}
}
NewFormatDescriptors = newDfds;
NewUserLabels = newLabels;
AllTargetOffsets = targetOffsets;
// Don't show ready if all addresses are invalid.
mOutputReady = (AllTargetOffsets.Count > 0);
}
private void AddPreviewItem(int addr, int offset, string label) {
ListViewItem lvi = new ListViewItem(mFormatter.FormatAddress(addr,
!mProject.CpuDef.HasAddr16));
if (offset >= 0) {
lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi,
mFormatter.FormatOffset24(offset)));
} else {
lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, "---"));
}
lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, label));
outputPreviewListView.Items.Add(lvi);
}
#endif
}
}

View File

@ -86,6 +86,7 @@ limitations under the License.
<KeyGesture>F3</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="FormatSplitAddressCmd" Text="Format Split-Address Table..."/>
<RoutedUICommand x:Key="GotoCmd" Text="Go To...">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+G</KeyGesture>
@ -172,6 +173,8 @@ limitations under the License.
CanExecute="IsProjectOpen" Executed="FindCmd_Executed"/>
<CommandBinding Command="{StaticResource FindNextCmd}"
CanExecute="IsProjectOpen" Executed="FindNextCmd_Executed"/>
<CommandBinding Command="{StaticResource FormatSplitAddressCmd}"
CanExecute="CanFormatSplitAddress" Executed="FormatSplitAddressCmd_Executed"/>
<CommandBinding Command="{StaticResource GotoCmd}"
CanExecute="IsProjectOpen" Executed="GotoCmd_Executed"/>
<CommandBinding Command="Help"
@ -267,7 +270,7 @@ limitations under the License.
<MenuItem Command="{StaticResource HintAsInlineDataCmd}" InputGestureText="Ctrl+H, Ctrl+I"/>
<MenuItem Command="{StaticResource RemoveHintsCmd}" InputGestureText="Ctrl+H, Ctrl+R"/>
<Separator/>
<MenuItem Header="Format Split-Address Table..."/>
<MenuItem Command="{StaticResource FormatSplitAddressCmd}"/>
<MenuItem Header="Toggle Single-Byte Format"/> <!-- Ctrl+B -->
<MenuItem Header="Format As Word"/> <!-- Ctrl+W -->
<MenuItem Header="Delete Note/Long Comment"/> <!-- Del -->

View File

@ -769,6 +769,10 @@ namespace SourceGenWPF.WpfGui {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanEditStatusFlags();
}
private void CanFormatSplitAddress(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanFormatSplitAddress();
}
private void CanHintAsCodeEntryPoint(object sender, CanExecuteRoutedEventArgs e) {
if (!IsProjectOpen()) {
e.CanExecute = false;
@ -892,6 +896,10 @@ namespace SourceGenWPF.WpfGui {
mMainCtrl.FindNext();
}
private void FormatSplitAddressCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.FormatSplitAddress();
}
private void GotoCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.Goto();
}