The new `WaitForRenderingAsync` method allows a ViewModel to check with the work dispatcher to make sure the render thread is caught up. We don't want to do this in all cases, but this gives us the ability to wait or skip events if rendering is taking too long, so that we don't starve the render thread.
For example, when using the `MoveSelectionStart` command, the ViewModel now checks if the rendering is caught up. If we're behind, the command request is simply ignored. If we're nearly caught up, it waits for rendering and then does the move work on a background task. If we're completely caught up, the work is still pushed to a background task, but is able to start running immediately.
If this becomes a performance issue and makes the app run too slowly, it'll be easy to just remove the await from the command.
* don't store the delta object used for initial setup
* avoid making lambdas in `ScriptLine.Matches`, which is called very often.
* use use List<int> instead of SortedSpan<int> for building the initial DestinationToSource cache, since we're already guaranteed that they'll be added in order and without duplicates. This greatly reduces the number of int[] arrays created during startup.
* allow `ArrayRunPointerSegment` to cache the table content results from parsing its InnerFormat, so it doesn't have to re-parse each time. This greatly reduces the number of string allocations.
* Use `ThreadSafeDictionary` for `TryGetValueCaseInsensitive` so we don't need to create a new collection of keys each time we call the method. Also add key caching to `ThreadSafeDictionary` so we don't need to make a new collection each time it's requested.
* Make `GetOptions` return a readonly list. We already know it's unique, this means we don't have to make a new collection every time we parse segments.
* limit the number of undo tokens we store (default 100) to save memory
* Use `byte[]` and `Array.Copy` instead of `List<byte>` and `AddRange` to reduce byte array allocations when loading a file.
* Freeze geometries in the `Icons` collection.
* add option for running garbage collection from the developer menu
* use a custom `AutomationPeer` to prevent WPF from holding memory after controls have been closed.
.gba files will continue to use <name>.toml for <name>.gba files. All other files will use <name>.<extension>.toml. This is to allow you to store metadata for both your .gba file and your .sav file if you want to. And maybe even an .ips or .ups if you get fancy.
Don't CascadeScripts right away. Instead, wait until the model is done loading, and _then_ cascade scripts. RefreshBackingData at the same time so as to refresh the cells on the screen.
Tasks already do what I was wanting to do (manage work timing), and do it better with more features, and do it in a way that other developers will more easily understand. Stop being weird, just use a Task.
UseShellExecute defaults to false in .Net Core. Give it an explicit value of 'true' to allow windows to run non-executable files. In this case, we want to look for whatever program is registered to run the *.gba file, which will very much not be an executable.
Add the ability to open the new scripts folder from within the app. Add sub-menus to organize the pokedex vs expansion utilities, since I'll be adding more expansion utilities soon.
Instead of initializing the model right away, launch a background task to do that. This allows the metadata to load while the tab draws itself. When initialization is complete, Refresh the ViewPort.
For the tests, use InstantDispatcher
Battle Backgrounds use palettes 2,3, and 4. But only palettes 2 and 3 flash when you let out a pokemon. Palette 4 is used for the obfuscation image that covers the screen as you scroll in, like grass or rocks or waves.
When importing an image that shares a palette with another image / tileset, the user may be curious to know what all images use the palette. The input window now has the ability to display "additional details", which right now is only used for sprites. But this would allow me to add other information to the options dialog in the future.
Files reload whenever they detect that the data changes. But this included if HMA changed the file itself o_O so I fixed that.
Re-initializing should not cause a duplicate dictionary addition for pointer offsets. Fixed.
* Pull some important info / links down from the help menu to the start page.
* Remove the Help -> About option, because it's now redundant.
* Add support for opening recent files from the start screen
* Remove concept of palettes from open/save images, since the actual code doesn't use this anymore.
* Refactor the bulk of short[]-and-width conversion into helper methods so they can be used by the new property.
* Add a new property, CopyImage, that can access an image in the clipboard.
The ability to Dispatch work to another thread is a scheduler concern, not a filesystem concern. These sets of operations should not be tied to the same object.