Wired up the double-click handlers for References, Notes, and
Symbols. These jump to the item at the offset that was double-
clicked. Also hooked up the navigate forward/backward buttons
in the toolbar.
Except for the usual WPF gymnastics required to figure out what you
actually double-clicked on, this went smoothly.
The filtering uses the DataGrid View filtering mechanism. The
built-in sorting only operates on a single column, and we really
want a secondary sort on label when the type is used as the key,
so we provide a custom sort method.
Also, fixed some crashiness in the can-execute tests for hints.
If you crash an a can-execute method you get a really unhelpful
failure message. Asserts don't work there either. Yay WPF.
Extract some XAML icons from the VS2017 Image Library. There's no
particular reason to prefer XAML over PNG, but somehow it feels
more forward-compatible. (OTOH, defining images as ControlTemplate
instances is just weird. Yay WPF.)
Restoring the selection works pretty much like it used to, though
I'm capping the total size of the selection because it goes into
stupid-slow mode if you have too many elements.
Getting the item that is at the top of the ListView is astoundingly
obscure, due to the ListView's extreme generality. I make a
simplifying assumption -- that we're using a VSP -- which allows us
to use a simple vertical offset once we've dug the appropriate
object out of the visual tree. (The alternative is to walk through
the list of items and see what's on screen, or perform a hit test
calculation in the upper left corner.) Yay WPF.
The various items in the Actions menu are enabled or disabled based
on the current selection. There's no SelectedIndices property in
WPF ListViews, so we have to do things slightly differently.
The SelectedItems list isn't kept sorted to match the list contents,
so finding first/last item requires a bit of scanning.
Also, rearranged some stuff. I'm trying to keep the old and new
code somewhat parallel, to make it easier to walk through at the end
and see if I've missed something.
Renamed VirtualListViewSelection to DisplayListSelection, because
it's now tied to the DisplayList implementation. Hooked it up to
handle SelectionChanged events.
Also, tweaked the code list item style to remove the one-pixel gap
between items. Somehow I manage to click on the dead zone with
surprising regularity.
Create context menu as a clone of the Actions menu. This is a bit
easier than it was in WinForms because the ICommand stuff provides
common routing and enable/disable logic for all instances. (It's
one of the few places where WPF has made my life easier. Yay WPF.)
Added CanExecute tests to existing items. Currently they just
check to see if the project is open.
Wired up File > Close.
Doesn't work 100% correctly -- in some cases, using two different
combos in quick succession will fail -- but it's close.
Added stub methods for the four hint operations.
There was a bigger change here, but the approach turned out to
have some problems with large sets. The current app saves and
restores the selected rows when you make an edit, retaining the set
of selected bytes even if the number of lines changes (maybe you
reformatted bytes into a string). There's no way to do that quickly
with WPF when the number of selected items gets large (say 10K+).
I will probably just cap the selection, and refuse to restore it if
it exceeds a certain size.
The ListView SelectedItems management seems to use an O(n^2) (or
worse) algorithm. It might be trying to verify that items being
added to SelectedItems actually exist in Items -- I can see it
calling Contains(). Whatever the case, it's a big step backward
performance-wise from WinForms. Yay WPF.
See the DisasmUiTest project's Selection Test to see what I tried.
The disassembled lines are now shown in the custom-styled list view.
The DisplayList isn't being kept up to date on edits, but since we
can't edit anything yet that's not too limiting.
Pulled more code over, including the mostly-GUI-agnostic bits of the
source generation and assembler execution code.
I'm trying to make the ListView look like the old owner-drawn
WinForms UI. The tricky bit is getting long comments and notes to
start in column 5 (label) and extend across multiple columns.
This approach sort of works, though it's currently incomplete, e.g.
the selection highlight style apparently gets dropped.
In WinForms, if you want a virtual ListView, you set the "virtual"
property and define a couple of callbacks. In WPF, there are
separate notions of "UI virtualization" and "data virtualization".
The former is done automatically (usually) by the ListView. The
latter requires creating an implementation of IList, and relies on
behavior that I'm having trouble finding in official documentation.
Yay WPF.
This splits the source-generation stuff out into DisplayListGen,
leaving DisplayList as a list of stuff to display that can be bound
to WPF as a ListView ItemsSource. The DisplayList instance will have
a hook back into DisplayListGen to perform the on-demand string
rendering. (For now it's just generating test patterns.)
Set up a notifiable property to control whether the "launch panel"
(i.e. the thing you see when the app launches) or the code ListView
is visible. Unearthed the magic required to left-justify the column
headers.
Fixed some stuff that crashed. The project is loaded but nothing
visually interesting happens yet.
I'm still not entirely sure what the deal with declaring resources
is, but it seems you can either declare a ResourceDictionary and put
everything in it, or you can declare a bunch of items, which are then
implicitly placed in a ResourceDictionary. This matters if you want
to have your string definitions merged in with everything else. All
of the examples I found did one thing or the other, not both at once,
so it took some fiddling. Yay WPF.
Done with full WPF fanciness, including XAML string formatting and
property extraction, with a fallback value so I can see what it looks
like in the designer.
It took about half an hour to figure this out. Yay WPF.
Mostly a straight copy & paste of the files. The only significant
change was to move the localizable strings from Properties/Resources
(RESX) to Res/Strings.xaml (Resource Dictionary). I expect a
number of strings will no longer be needed, since WPF lets you put
more of the UI/UX logic into the design side.
I also renamed the namespace to SourceGenWPF, and put the app icon
into the Res directory so it can be a resource rather than a loose
file. I'm merging the "Setup" directory contents into the main app
since there wasn't a whole lot going on there.
The WPF Color class lacks conversions to/from a 32-bit integer, so
I added those.
None of the stuff is wired up yet.
SourceGen creates "auto" labels when it finds a reference to an
address that doesn't have a label associated with it. The label for
address $1234 would be "L1234". This change allows the project to
specify alternative label naming conventions, annotating them with
information from the cross-reference data. For example, a subroutine
entry point (i.e. the target of a JSR) would be "S_1234". (The
underscore was added to avoid confusion when an annotation letter
is the same as a hex digit.)
Also, tweaked the way the preferred clipboard line format is stored
in the settings file (was an integer, now an enumeration string).
In the cross-reference table we now indicate whether the reference
source is doing a read, write, read-modify-write, branch, subroutine
call, is just referencing the address, or is part of the data.
This worked, sort of. The problem is that SourceGen will revert to
hex output in certain situations, such as a broken symbolic
reference. There happens to be one in the ZIPPY example, and it's
on a relative branch.
The goal with the segment stuff is to allow cc65 to treat the
source as relocatable code. In that context, a relative branch to
an absolute address doesn't make any sense, so the assembler reports
a range error.
We don't currently have a mechanism that guarantees no references
are broken (and no affordance for finding them), so we can't make
this mode the default yet.
Instead, we continue to use the generic config, but generate the
correct set of lines as comments.
(issue #39)
The system configuration you get with "-t none" works for smaller
files but fails for larger ones. This updates the generator to
produce a source file and linker script pair. (I kinda saw this
one coming -- it's why the gen/asm dialog has a combo box for the
file preview -- so it didn't require that much work.)
This currently generates a fixed script for a generic system with
64KiB of RAM, using .ORGs to set the addresses as before.
With this change, assembling a file with 65536 NOPs succeeds.
(issue #39)
In the data operand edit section, walk through selecting a single
byte vs. multiple bytes when you want to set a multi-byte format.
(inspired by issue #41)
If you double-click on the opcode of "JSR label", the code view
selection jumps to the label. This now works for partial operands,
e.g. "LDA #<label".
Some changes to the find-label-offset code affected the cc65 "is it
a forward reference to a direct-page label" logic. The regression
test now correctly identifies an instruction that refers to itself
as not being a forward reference.
The cc65 assembler runs in a single pass, which means forward
address references default to 16 bits. For zero-page references
we have to add an explicit width disambiguator. (This is an
unusual situation that only occurs if you have a zero-page .ORG
in the file after code that references it.)
With this change, 2014-label-dp passes, and no other regression
tests were affected.
(issue #40)