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

Implement three shortcut commands

Added:
  Toggle Single-BYte Format (Ctrl+B)
  Format As Word (Ctrl+W)
  Delete Note/Long Comment (Del)
This commit is contained in:
Andy McFadden 2019-07-14 13:50:15 -07:00
parent 2dd21d433d
commit 12874d32ba
5 changed files with 290 additions and 51 deletions

View File

@ -1438,6 +1438,42 @@ namespace SourceGenWPF {
}
}
public bool CanDeleteMlc() {
if (SelectionAnalysis.mNumItemsSelected != 1) {
return false;
}
Debug.WriteLine("LINE TYPE " + SelectionAnalysis.mLineType);
return (SelectionAnalysis.mLineType == LineListGen.Line.Type.LongComment ||
SelectionAnalysis.mLineType == LineListGen.Line.Type.Note);
}
// Delete multi-line comment (Note or LongComment)
public void DeleteMlc() {
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
LineListGen.Line line = CodeLineList[selIndex];
int offset = line.FileOffset;
UndoableChange uc;
if (line.LineType == LineListGen.Line.Type.Note) {
if (!mProject.Notes.TryGetValue(offset, out MultiLineComment oldNote)) {
Debug.Assert(false);
return;
}
uc = UndoableChange.CreateNoteChange(offset, oldNote, null);
} else if (line.LineType == LineListGen.Line.Type.LongComment) {
if (!mProject.LongComments.TryGetValue(offset, out MultiLineComment oldComment)) {
Debug.Assert(false);
return;
}
uc = UndoableChange.CreateLongCommentChange(offset, oldComment, null);
} else {
Debug.Assert(false);
return;
}
ChangeSet cs = new ChangeSet(uc);
ApplyUndoableChanges(cs);
}
public bool CanEditAddress() {
if (SelectionAnalysis.mNumItemsSelected != 1) {
return false;
@ -1917,6 +1953,100 @@ namespace SourceGenWPF {
mMainWin.CodeListView_Focus();
}
public bool CanFormatAsWord() {
EntityCounts counts = SelectionAnalysis.mEntityCounts;
// This is insufficient -- we need to know how many bytes are selected, and
// whether they're already formatted as multi-byte items. Too expensive to
// deal with here, so we'll need to show failure dialogs instead (ugh).
return (counts.mDataLines > 0 && counts.mCodeLines == 0);
}
public void FormatAsWord() {
TypedRangeSet trs = GroupedOffsetSetFromSelected();
if (trs.Count == 0) {
Debug.Assert(false, "nothing to edit"); // shouldn't happen
return;
}
// If the user has only selected a single byte, we want to add the following byte
// to the selection, then proceed as usual. We can't simply modify the ListView
// selection because the following item might be an auto-detected string or fill,
// and we'd be adding multiple bytes. We have to be careful when grabbing the byte
// in case there's a region-split at that point (e.g. user label or .ORG).
//
// We could expand this to allow multiple regions, each of which is a single byte,
// but we'd need to deal with the case where the user selects two adjacent bytes that
// cross a region boundary.
if (trs.RangeCount == 1) {
// Exactly one range entry. Check its size.
IEnumerator<TypedRangeSet.TypedRange> checkIter = trs.RangeListIterator;
checkIter.MoveNext();
TypedRangeSet.TypedRange rng = checkIter.Current;
if (rng.Low == rng.High && rng.Low < mProject.FileDataLength - 1) {
// Single byte selected. Check to see if it's okay to grab the next byte.
Anattrib thisAttr = mProject.GetAnattrib(rng.Low);
Debug.Assert(thisAttr.DataDescriptor.Length == 1);
int nextOffset = rng.Low + 1;
Anattrib nextAttr = mProject.GetAnattrib(nextOffset);
// This must match what GroupedOffsetSetFromSelected() does.
if (!mProject.UserLabels.ContainsKey(nextOffset) &&
!mProject.HasCommentOrNote(nextOffset) &&
thisAttr.Address == nextAttr.Address - 1) {
// Good to go.
Debug.WriteLine("Grabbing second byte from +" + nextOffset.ToString("x6"));
trs.Add(nextOffset, rng.Type);
}
}
}
// Confirm that every selected byte is a single-byte data item (either set by
// the user or as part of the uncategorized data scan).
foreach (TypedRangeSet.Tuple tup in trs) {
FormatDescriptor dfd = mProject.GetAnattrib(tup.Value).DataDescriptor;
if (dfd != null && dfd.Length != 1) {
Debug.WriteLine("Can't format as word: offset +" + tup.Value.ToString("x6") +
" has len=" + dfd.Length + " (must be 1)");
MessageBox.Show(Res.Strings.INVALID_FORMAT_WORD_SEL_NON1,
Res.Strings.INVALID_FORMAT_WORD_SEL_CAPTION,
MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
// Confirm that, in each region, an even number of bytes are selected.
IEnumerator<TypedRangeSet.TypedRange> rngIter = trs.RangeListIterator;
while (rngIter.MoveNext()) {
TypedRangeSet.TypedRange rng = rngIter.Current;
int rangeLen = rng.High - rng.Low + 1;
if ((rangeLen & 0x01) != 0) {
string msg = string.Format(Res.Strings.INVALID_FORMAT_WORD_SEL_UNEVEN_FMT,
trs.RangeCount);
MessageBox.Show(msg,
Res.Strings.INVALID_FORMAT_WORD_SEL_CAPTION,
MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
// Selection is good, generate changes.
SortedList<int, FormatDescriptor> newFmts = new SortedList<int, FormatDescriptor>();
rngIter.Reset();
FormatDescriptor newDfd = FormatDescriptor.Create(2, FormatDescriptor.Type.NumericLE,
FormatDescriptor.SubType.None);
while (rngIter.MoveNext()) {
TypedRangeSet.TypedRange rng = rngIter.Current;
for (int i = rng.Low; i <= rng.High; i += 2) {
newFmts.Add(i, newDfd);
}
}
ChangeSet cs = mProject.GenerateFormatMergeSet(newFmts);
if (cs.Count != 0) {
ApplyUndoableChanges(cs);
}
}
public bool CanFormatSplitAddress() {
EntityCounts counts = SelectionAnalysis.mEntityCounts;
// Must be at least one line of data, and no code. Note this is lines, not bytes,
@ -2408,54 +2538,6 @@ namespace SourceGenWPF {
}
}
public bool CanUndo() {
return (mProject != null && mProject.CanUndo);
}
/// <summary>
/// Handles Edit - Undo.
/// </summary>
public void UndoChanges() {
if (!mProject.CanUndo) {
Debug.Assert(false, "Nothing to undo");
return;
}
ChangeSet cs = mProject.PopUndoSet();
ApplyChanges(cs, true);
#if false
UpdateMenuItemsAndTitle();
// If the debug dialog is visible, update it.
if (mShowUndoRedoHistoryDialog != null) {
mShowUndoRedoHistoryDialog.BodyText = mProject.DebugGetUndoRedoHistory();
}
#endif
}
public bool CanRedo() {
return (mProject != null && mProject.CanRedo);
}
/// <summary>
/// Handles Edit - Redo.
/// </summary>
public void RedoChanges() {
if (!mProject.CanRedo) {
Debug.Assert(false, "Nothing to redo");
return;
}
ChangeSet cs = mProject.PopRedoSet();
ApplyChanges(cs, false);
#if false
UpdateMenuItemsAndTitle();
// If the debug dialog is visible, update it.
if (mShowUndoRedoHistoryDialog != null) {
mShowUndoRedoHistoryDialog.BodyText = mProject.DebugGetUndoRedoHistory();
}
#endif
}
/// <summary>
/// Handles the four Actions - edit hint commands.
/// </summary>
@ -2559,6 +2641,61 @@ namespace SourceGenWPF {
ApplyUndoableChanges(new ChangeSet(uc));
}
public bool CanToggleSingleByteFormat() {
EntityCounts counts = SelectionAnalysis.mEntityCounts;
return (counts.mDataLines > 0 && counts.mCodeLines == 0);
}
public void ToggleSingleByteFormat() {
TypedRangeSet trs = GroupedOffsetSetFromSelected();
if (trs.Count == 0) {
Debug.Assert(false, "nothing to edit"); // shouldn't happen
return;
}
// Check the format descriptor of the first selected offset.
int firstOffset = -1;
foreach (TypedRangeSet.Tuple tup in trs) {
firstOffset = tup.Value;
break;
}
Debug.Assert(mProject.GetAnattrib(firstOffset).IsDataStart);
bool toDefault = false;
if (mProject.OperandFormats.TryGetValue(firstOffset, out FormatDescriptor curDfd)) {
if (curDfd.FormatType == FormatDescriptor.Type.NumericLE &&
curDfd.FormatSubType == FormatDescriptor.SubType.None &&
curDfd.Length == 1) {
// Currently single-byte, toggle to default.
toDefault = true;
}
}
// Iterate through the selected regions.
SortedList<int, FormatDescriptor> newFmts = new SortedList<int, FormatDescriptor>();
IEnumerator<TypedRangeSet.TypedRange> rngIter = trs.RangeListIterator;
while (rngIter.MoveNext()) {
TypedRangeSet.TypedRange rng = rngIter.Current;
if (toDefault) {
// Create a single REMOVE descriptor that covers the full span.
FormatDescriptor newDfd = FormatDescriptor.Create(rng.High - rng.Low + 1,
FormatDescriptor.Type.REMOVE, FormatDescriptor.SubType.None);
newFmts.Add(rng.Low, newDfd);
} else {
// Add individual single-byte format descriptors for everything.
FormatDescriptor newDfd = FormatDescriptor.Create(1,
FormatDescriptor.Type.NumericLE, FormatDescriptor.SubType.None);
for (int i = rng.Low; i <= rng.High; i++) {
newFmts.Add(i, newDfd);
}
}
}
ChangeSet cs = mProject.GenerateFormatMergeSet(newFmts);
if (cs.Count != 0) {
ApplyUndoableChanges(cs);
}
}
/// <summary>
/// Converts the ListView's selected items into a set of offsets. If a line
/// spans multiple offsets (e.g. a 3-byte instruction), offsets for every
@ -2741,6 +2878,54 @@ namespace SourceGenWPF {
}
}
public bool CanUndo() {
return (mProject != null && mProject.CanUndo);
}
/// <summary>
/// Handles Edit - Undo.
/// </summary>
public void UndoChanges() {
if (!mProject.CanUndo) {
Debug.Assert(false, "Nothing to undo");
return;
}
ChangeSet cs = mProject.PopUndoSet();
ApplyChanges(cs, true);
#if false
UpdateMenuItemsAndTitle();
// If the debug dialog is visible, update it.
if (mShowUndoRedoHistoryDialog != null) {
mShowUndoRedoHistoryDialog.BodyText = mProject.DebugGetUndoRedoHistory();
}
#endif
}
public bool CanRedo() {
return (mProject != null && mProject.CanRedo);
}
/// <summary>
/// Handles Edit - Redo.
/// </summary>
public void RedoChanges() {
if (!mProject.CanRedo) {
Debug.Assert(false, "Nothing to redo");
return;
}
ChangeSet cs = mProject.PopRedoSet();
ApplyChanges(cs, false);
#if false
UpdateMenuItemsAndTitle();
// If the debug dialog is visible, update it.
if (mShowUndoRedoHistoryDialog != null) {
mShowUndoRedoHistoryDialog.BodyText = mProject.DebugGetUndoRedoHistory();
}
#endif
}
#endregion References panel
#region Notes panel

View File

@ -75,6 +75,9 @@ limitations under the License.
<system:String x:Key="str_InitialParameters">Default settings:</system:String>
<system:String x:Key="str_InitialSymbolFiles">Symbol files:</system:String>
<system:String x:Key="str_InvalidAddress">(unknown address)</system:String>
<system:String x:Key="str_InvalidFormatWordSelCaption">Invalid Selection</system:String>
<system:String x:Key="str_InvalidFormatWordSelNon1" xml:space="preserve">Unable to format as word: selection must be an even number of bytes that have not previously been formatted as multi-byte values.&#x0d;&#x0d;Use Toggle Data Scan (Ctrl+D) to turn off auto-detection of strings and memory fill.</system:String>
<system:String x:Key="str_InvalidFormatWordSelUnevenFmt">Unable to format as word: each selected region must have an even number of bytes ({0} region(s) are selected).</system:String>
<system:String x:Key="str_NoFilesAvailable">no files available</system:String>
<system:String x:Key="str_OpenDataDoesntExist">The file doesn't exist.</system:String>
<system:String x:Key="str_OpenDataEmpty">File is empty</system:String>

View File

@ -131,6 +131,12 @@ namespace SourceGenWPF.Res {
(string)Application.Current.FindResource("str_InitialSymbolFiles");
public static string INVALID_ADDRESS =
(string)Application.Current.FindResource("str_InvalidAddress");
public static string INVALID_FORMAT_WORD_SEL_CAPTION =
(string)Application.Current.FindResource("str_InvalidFormatWordSelCaption");
public static string INVALID_FORMAT_WORD_SEL_NON1 =
(string)Application.Current.FindResource("str_InvalidFormatWordSelNon1");
public static string INVALID_FORMAT_WORD_SEL_UNEVEN_FMT =
(string)Application.Current.FindResource("str_InvalidFormatWordSelUnevenFmt");
public static string NO_FILES_AVAILABLE =
(string)Application.Current.FindResource("str_NoFilesAvailable");
public static string OPEN_DATA_DOESNT_EXIST =

View File

@ -55,6 +55,11 @@ limitations under the License.
</RoutedUICommand>
<RoutedUICommand x:Key="CloseCmd" Text="Close"/>
<RoutedUICommand x:Key="DebugSourceGenerationTestsCmd" Text="Source Generation Tests..."/>
<RoutedUICommand x:Key="DeleteMlcCmd" Text="Delete Note/Long Comment">
<RoutedUICommand.InputGestures>
<KeyGesture>Del</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="EditAddressCmd" Text="Set Address..."/>
<RoutedUICommand x:Key="EditAppSettingsCmd" Text="Settings..."/>
<RoutedUICommand x:Key="EditCommentCmd" Text="Edit Comment...">
@ -92,6 +97,11 @@ limitations under the License.
<KeyGesture>F3</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="FormatAsWordCmd" Text="Format As Word">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+W</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="FormatSplitAddressCmd" Text="Format Split-Address Table..."/>
<RoutedUICommand x:Key="GotoCmd" Text="Go To...">
<RoutedUICommand.InputGestures>
@ -135,6 +145,11 @@ limitations under the License.
<KeyGesture>Ctrl+D</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="ToggleSingleByteFormatCmd" Text="Toggle Single-Byte Format">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+B</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="UndoCmd" Text="Undo">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+Z</KeyGesture>
@ -157,6 +172,8 @@ limitations under the License.
CanExecute="IsProjectOpen" Executed="CloseCmd_Executed"/>
<CommandBinding Command="Copy"
CanExecute="IsProjectOpen" Executed="CopyCmd_Executed"/>
<CommandBinding Command="{StaticResource DeleteMlcCmd}"
CanExecute="CanDeleteMlc" Executed="DeleteMlcCmd_Executed"/>
<CommandBinding Command="{StaticResource DebugSourceGenerationTestsCmd}"
Executed="DebugSourceGenerationTestsCmd_Executed"/>
<CommandBinding Command="{StaticResource EditAddressCmd}"
@ -183,6 +200,8 @@ limitations under the License.
CanExecute="IsProjectOpen" Executed="FindCmd_Executed"/>
<CommandBinding Command="{StaticResource FindNextCmd}"
CanExecute="IsProjectOpen" Executed="FindNextCmd_Executed"/>
<CommandBinding Command="{StaticResource FormatAsWordCmd}"
CanExecute="CanFormatAsWord" Executed="FormatAsWordCmd_Executed"/>
<CommandBinding Command="{StaticResource FormatSplitAddressCmd}"
CanExecute="CanFormatSplitAddress" Executed="FormatSplitAddressCmd_Executed"/>
<CommandBinding Command="{StaticResource GotoCmd}"
@ -224,6 +243,8 @@ limitations under the License.
CanExecute="IsProjectOpen" Executed="ShowHexDumpCmd_Executed"/>
<CommandBinding Command="{StaticResource ToggleDataScanCmd}"
CanExecute="IsProjectOpen" Executed="ToggleDataScanCmd_Executed"/>
<CommandBinding Command="{StaticResource ToggleSingleByteFormatCmd}"
CanExecute="CanToggleSingleByteFormat" Executed="ToggleSingleByteFormatCmd_Executed"/>
<CommandBinding Command="{StaticResource UndoCmd}"
CanExecute="CanUndo" Executed="UndoCmd_Executed"/>
</Window.CommandBindings>
@ -281,9 +302,9 @@ limitations under the License.
<MenuItem Command="{StaticResource RemoveHintsCmd}" InputGestureText="Ctrl+H, Ctrl+R"/>
<Separator/>
<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 -->
<MenuItem Command="{StaticResource ToggleSingleByteFormatCmd}"/>
<MenuItem Command="{StaticResource FormatAsWordCmd}"/>
<MenuItem Command="{StaticResource DeleteMlcCmd}"/>
<Separator/>
<MenuItem Command="{StaticResource ShowHexDumpCmd}"/>
</MenuItem>

View File

@ -745,6 +745,10 @@ namespace SourceGenWPF.WpfGui {
e.CanExecute = IsProjectOpen();
}
private void CanDeleteMlc(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanDeleteMlc();
}
private void CanEditAddress(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanEditAddress();
}
@ -777,6 +781,10 @@ namespace SourceGenWPF.WpfGui {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanEditStatusFlags();
}
private void CanFormatAsWord(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanFormatAsWord();
}
private void CanFormatSplitAddress(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanFormatSplitAddress();
}
@ -818,6 +826,10 @@ namespace SourceGenWPF.WpfGui {
(counts.mCodeHints != 0 || counts.mDataHints != 0 || counts.mInlineDataHints != 0);
}
private void CanToggleSingleByteFormat(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanToggleSingleByteFormat();
}
private void CanNavigateBackward(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanNavigateBackward();
}
@ -860,6 +872,10 @@ namespace SourceGenWPF.WpfGui {
mMainCtrl.RunSourceGenerationTests();
}
private void DeleteMlcCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.DeleteMlc();
}
private void EditAddressCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.EditAddress();
}
@ -912,6 +928,10 @@ namespace SourceGenWPF.WpfGui {
mMainCtrl.FindNext();
}
private void FormatAsWordCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.FormatAsWord();
}
private void FormatSplitAddressCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.FormatSplitAddress();
}
@ -1023,6 +1043,10 @@ namespace SourceGenWPF.WpfGui {
mMainCtrl.ToggleDataScan();
}
private void ToggleSingleByteFormatCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.ToggleSingleByteFormat();
}
private void UndoCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.UndoChanges();
}