mirror of
https://github.com/fadden/6502bench.git
synced 2025-02-08 05:30:35 +00:00
Add Actions > Format As Word (Ctrl+W)
Formats a pair of bytes into a 16-bit word. As a special case, attempts to grab the next byte if only one byte is selected. (issue #29)
This commit is contained in:
parent
f5b36afd2e
commit
0e1530fe0f
13
SourceGen/AppForms/ProjectView.Designer.cs
generated
13
SourceGen/AppForms/ProjectView.Designer.cs
generated
@ -175,6 +175,7 @@ namespace SourceGen.AppForms
|
||||
this.symbolNameColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.infoGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.infoTextBox = new System.Windows.Forms.TextBox();
|
||||
this.formatAsWordToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mainMenuStrip.SuspendLayout();
|
||||
this.mainStatusStrip.SuspendLayout();
|
||||
this.mainToolStrip.SuspendLayout();
|
||||
@ -474,6 +475,7 @@ namespace SourceGen.AppForms
|
||||
this.toolStripMenuItem11,
|
||||
this.formatSplitAddressTableToolStripMenuItem,
|
||||
this.toggleSingleBytesToolStripMenuItem,
|
||||
this.formatAsWordToolStripMenuItem,
|
||||
this.deleteNoteCommentToolStripMenuItem,
|
||||
this.toolStripMenuItem9,
|
||||
this.showHexDumpToolStripMenuItem});
|
||||
@ -591,7 +593,7 @@ namespace SourceGen.AppForms
|
||||
//
|
||||
this.formatSplitAddressTableToolStripMenuItem.Name = "formatSplitAddressTableToolStripMenuItem";
|
||||
this.formatSplitAddressTableToolStripMenuItem.Size = new System.Drawing.Size(289, 22);
|
||||
this.formatSplitAddressTableToolStripMenuItem.Text = "Format Split-Address Table";
|
||||
this.formatSplitAddressTableToolStripMenuItem.Text = "Format Split-Address Table...";
|
||||
this.formatSplitAddressTableToolStripMenuItem.Click += new System.EventHandler(this.FormatSplitAddressTable_Click);
|
||||
//
|
||||
// toggleSingleBytesToolStripMenuItem
|
||||
@ -1451,6 +1453,14 @@ namespace SourceGen.AppForms
|
||||
this.infoTextBox.Size = new System.Drawing.Size(177, 120);
|
||||
this.infoTextBox.TabIndex = 0;
|
||||
//
|
||||
// formatAsWordToolStripMenuItem
|
||||
//
|
||||
this.formatAsWordToolStripMenuItem.Name = "formatAsWordToolStripMenuItem";
|
||||
this.formatAsWordToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.W)));
|
||||
this.formatAsWordToolStripMenuItem.Size = new System.Drawing.Size(289, 22);
|
||||
this.formatAsWordToolStripMenuItem.Text = "Format As Word";
|
||||
this.formatAsWordToolStripMenuItem.Click += new System.EventHandler(this.formatAsWordToolStripMenuItem_Click);
|
||||
//
|
||||
// ProjectView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@ -1636,6 +1646,7 @@ namespace SourceGen.AppForms
|
||||
private System.Windows.Forms.ToolStripMenuItem deleteNoteCommentToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem formatSplitAddressTableToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem toggleDataScanToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem formatAsWordToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2325,6 +2325,12 @@ namespace SourceGen.AppForms {
|
||||
toggleSingleBytesToolStripMenuItem.Enabled =
|
||||
(entityCounts.mDataLines > 0 && entityCounts.mCodeLines == 0);
|
||||
|
||||
// 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).
|
||||
formatAsWordToolStripMenuItem.Enabled =
|
||||
(entityCounts.mDataLines > 0 && entityCounts.mCodeLines == 0);
|
||||
|
||||
|
||||
// So long as some code or data is highlighted, allow these. Don't worry about
|
||||
// control lines. Disable options that would have no effect.
|
||||
@ -2835,6 +2841,94 @@ namespace SourceGen.AppForms {
|
||||
}
|
||||
}
|
||||
|
||||
private void formatAsWordToolStripMenuItem_Click(object sender, EventArgs e) {
|
||||
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)");
|
||||
string msg = string.Format(Properties.Resources.INVALID_FORMAT_WORD_SEL_NON1,
|
||||
"\r\n\r\n");
|
||||
MessageBox.Show(this, msg,
|
||||
Properties.Resources.INVALID_FORMAT_WORD_SEL_CAPTION,
|
||||
MessageBoxButtons.OK, MessageBoxIcon.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(Properties.Resources.INVALID_FORMAT_WORD_SEL_UNEVEN,
|
||||
trs.RangeCount);
|
||||
MessageBox.Show(this, msg,
|
||||
Properties.Resources.INVALID_FORMAT_WORD_SEL_CAPTION,
|
||||
MessageBoxButtons.OK, MessageBoxIcon.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);
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteNoteComment_Click(object sender, EventArgs e) {
|
||||
Debug.Assert(IsSingleItemSelected());
|
||||
ListView.SelectedIndexCollection sel = codeListView.SelectedIndices;
|
||||
@ -3216,16 +3310,15 @@ namespace SourceGen.AppForms {
|
||||
// The code does "LDA table,X / STA / LDA table+1,X / STA", which puts auto
|
||||
// labels at the first two addresses -- splitting the region. That's good
|
||||
// for the uncategorized data analyzer, but very annoying if you want to
|
||||
// slap a 16-bit numeric format on all entries.
|
||||
// slap a 16-bit numeric format on all entries in a table.
|
||||
groupNum++;
|
||||
} else if (mProject.HasCommentOrNote(offset)) {
|
||||
// Don't carry across a long comment or note.
|
||||
groupNum++;
|
||||
} else if (attr.Address != expectedAddr) {
|
||||
// For a contiguous selection, this should only happen if there's a .ORG
|
||||
// address change. For a selection that skips code/data lines this is
|
||||
// expected. In the later case, incrementing the group number is
|
||||
// unnecessary but harmless.
|
||||
// address change. For non-contiguous selection this is expected. In the
|
||||
// latter case, incrementing the group number is unnecessary but harmless.
|
||||
Debug.WriteLine("Address break: " + attr.Address + " vs. " + expectedAddr);
|
||||
//Debug.Assert(mProject.AddrMap.Get(offset) >= 0);
|
||||
|
||||
@ -3757,7 +3850,7 @@ namespace SourceGen.AppForms {
|
||||
int row = info.Item.Index;
|
||||
Symbol sym = mSymbolSubset.GetSubsetItem(row);
|
||||
|
||||
if (sym.SymbolSource == Symbol.Source.Auto || sym.SymbolSource == Symbol.Source.User) {
|
||||
if (sym.IsInternalLabel) {
|
||||
int offset = mProject.FindLabelOffsetByName(sym.Label);
|
||||
if (offset >= 0) {
|
||||
GoToOffset(offset, false, true);
|
||||
|
27
SourceGen/Properties/Resources.Designer.cs
generated
27
SourceGen/Properties/Resources.Designer.cs
generated
@ -591,6 +591,33 @@ namespace SourceGen.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid Selection.
|
||||
/// </summary>
|
||||
internal static string INVALID_FORMAT_WORD_SEL_CAPTION {
|
||||
get {
|
||||
return ResourceManager.GetString("INVALID_FORMAT_WORD_SEL_CAPTION", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unable to format as word: selection must be an even number of bytes that have not previously been formatted as multi-byte values.{0}Use Toggle Data Scan (Ctrl+D) to turn off auto-detection of strings and memory fill..
|
||||
/// </summary>
|
||||
internal static string INVALID_FORMAT_WORD_SEL_NON1 {
|
||||
get {
|
||||
return ResourceManager.GetString("INVALID_FORMAT_WORD_SEL_NON1", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unable to format as word: each selected region must have an even number of bytes ({0} region(s) are selected)..
|
||||
/// </summary>
|
||||
internal static string INVALID_FORMAT_WORD_SEL_UNEVEN {
|
||||
get {
|
||||
return ResourceManager.GetString("INVALID_FORMAT_WORD_SEL_UNEVEN", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Legal Stuff.
|
||||
/// </summary>
|
||||
|
@ -294,6 +294,15 @@
|
||||
<data name="INVALID_ADDRESS" xml:space="preserve">
|
||||
<value>(unknown address)</value>
|
||||
</data>
|
||||
<data name="INVALID_FORMAT_WORD_SEL_CAPTION" xml:space="preserve">
|
||||
<value>Invalid Selection</value>
|
||||
</data>
|
||||
<data name="INVALID_FORMAT_WORD_SEL_NON1" xml:space="preserve">
|
||||
<value>Unable to format as word: selection must be an even number of bytes that have not previously been formatted as multi-byte values.{0}Use Toggle Data Scan (Ctrl+D) to turn off auto-detection of strings and memory fill.</value>
|
||||
</data>
|
||||
<data name="INVALID_FORMAT_WORD_SEL_UNEVEN" xml:space="preserve">
|
||||
<value>Unable to format as word: each selected region must have an even number of bytes ({0} region(s) are selected).</value>
|
||||
</data>
|
||||
<data name="LEGAL_STUFF_TITLE" xml:space="preserve">
|
||||
<value>Legal Stuff</value>
|
||||
</data>
|
||||
|
@ -55,7 +55,8 @@ and 65816 code. The official web site is
|
||||
<li><a href="mainwin.html#navigation">Navigation</a></li>
|
||||
<li><a href="mainwin.html#hints">Adding and Removing Hints</a></li>
|
||||
<li><a href="mainwin.html#split-address">Format Split-Address Table</a></li>
|
||||
<li><a href="mainwin.html#toggle-format">Quick Format Toggle</a></li>
|
||||
<li><a href="mainwin.html#toggle-format">Toggle Single-Byte Format</a></li>
|
||||
<li><a href="mainwin.html#format-as-word">Format As Word</a></li>
|
||||
<li><a href="mainwin.html#toggle-data">Toggle Data Scan</a></li>
|
||||
<li><a href="mainwin.html#clipboard">Copying to Clipboard</a></li>
|
||||
</ul></li>
|
||||
|
@ -388,7 +388,7 @@ is just significantly more convenient. It also does everything as a single
|
||||
undoable action, so if it comes out looking wrong, just hit "undo".</p>
|
||||
|
||||
|
||||
<h3><a name="toggle-format">Quick Format Toggle</a></h3>
|
||||
<h3><a name="toggle-format">Toggle Single-Byte Format</a></h3>
|
||||
|
||||
<p>The "Toggle Single-Byte Format" feature provides a quick way to
|
||||
change a range of bytes to single bytes
|
||||
@ -399,6 +399,25 @@ selecting "Default".</p>
|
||||
string, but you want to see it as bytes or set a label in the middle.</p>
|
||||
|
||||
|
||||
<h3><a name="format-as-word">Format As Word</a></h3>
|
||||
|
||||
<p>This is a quick way to format pairs of bytes as 16-bit words. It's
|
||||
equivalent to opening the Edit Data Format dialog and selecting
|
||||
"16-bit words, little-endian", displayed as hex.</p>
|
||||
|
||||
<p>To avoid some confusing situations, it only works on sets of
|
||||
single-byte values. This means, for example, that you can't select a
|
||||
10-byte string and have it turn into five 16-bit words. You can select as
|
||||
many bytes as you want, but they must come in pairs. (Remember that you
|
||||
can turn off auto-generation of strings and .FILLs with
|
||||
<a href="#toggle-data">Toggle Data Scan</a>.)</p>
|
||||
<p>As a special case, if you select a single byte, the following byte will
|
||||
also be selected. This won't work if the following byte is part of a
|
||||
multi-byte data item, is the start of a new region (see
|
||||
<a href="editors.html#data">Edit Data Format</a> for a definition of
|
||||
what splits a region), or is the last byte in the file.</p>
|
||||
|
||||
|
||||
<h3><a name="toggle-data">Toggle Data Scan</a></h3>
|
||||
|
||||
<p>This menu item is in the Edit menu, and acts as a shortcut to opening
|
||||
@ -406,9 +425,9 @@ the Project Properties editor, and clicking on the "Analyze Uncategorized
|
||||
Data" checkbox. When enabled, SourceGen will look for ASCII strings and
|
||||
regions of identical bytes, and generate .STR and .FILL directives. When
|
||||
disabled, uncategorized data is presented as one byte per line, which can
|
||||
be handy if you're trying to get at a bit in the middle of a string.</p>
|
||||
<p>As with all other project properties changes, this is an undoable
|
||||
event.</p>
|
||||
be handy if you're trying to get at a byte in the middle of a string.</p>
|
||||
<p>As with all other project property changes, this is an undoable
|
||||
action.</p>
|
||||
|
||||
|
||||
<h3><a name="clipboard">Copying to Clipboard</a></h3>
|
||||
|
Loading…
x
Reference in New Issue
Block a user