1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-12-28 01:29:29 +00:00

Groundwork for animated Visualizations

This adds a new class and a rough GUI for the editor.  Animated
visualizations take a collection of bitmaps and display them in
sequence.  (This will eventually become an animated GIF.)

Fixed the issue where changes to tags in the set currently being
edited weren't visible to the tag uniqueness check when editing other
items in the same set.
This commit is contained in:
Andy McFadden 2019-12-17 16:40:27 -08:00
parent 5d9b9753e8
commit 9f9e518afc
13 changed files with 452 additions and 40 deletions

View File

@ -2173,11 +2173,16 @@ namespace SourceGen {
if (dlg.ShowDialog() != true) {
return;
}
if (curVisSet != dlg.NewVisSet) {
VisualizationSet newSet = dlg.NewVisSet;
if (newSet.Count == 0) {
// empty sets are deleted
newSet = null;
}
if (curVisSet != newSet) {
// New table, edited in place, or deleted.
UndoableChange uc = UndoableChange.CreateVisualizationSetChange(offset,
curVisSet, dlg.NewVisSet);
Debug.WriteLine("Change " + curVisSet + " to " + dlg.NewVisSet);
curVisSet, newSet);
//Debug.WriteLine("Change " + curVisSet + " to " + newSet);
ChangeSet cs = new ChangeSet(uc);
ApplyUndoableChanges(cs);
} else {

View File

@ -279,6 +279,9 @@ namespace RuntimeData.Apple {
int high = ((row & 0x07) << 2) | ((row & 0x30) >> 4);
int rowAddr = baseAddr + ((high << 8) | low);
// Not expecting the data to wrap around, but it's possible.
rowAddr = (baseAddr & 0xff0000) | (rowAddr & 0xffff);
for (int col = 0; col < HR_BYTE_WIDTH; col++) {
int srcOffset = mAddrTrans.AddressToOffset(offset, rowAddr + col);
if (srcOffset < 0) {

View File

@ -177,6 +177,10 @@ invoked is not defined.</p>
<h4>Known Issues and Limitations</h4>
<p>Scripts are currently limited to C# version 5, because the compiler
built into .NET only handles that. C# 6 and later require installing an
additional package (Roslyn).</p>
<p>When a project is opened, any errors encountered by the script compiler
are reported to the user. If the project is already open, and a script
is added to the project through the Project Properties editor, compiler

View File

@ -185,6 +185,10 @@ namespace SourceGen.Sandbox {
out FileLoadReport report) {
report = new FileLoadReport(scriptPathName);
// To get C#6 (and later) features, a NuGet package must be installed, and
// some "black magic" must be invoked.
// See https://stackoverflow.com/a/40311406/294248 and nearby answers.
Microsoft.CSharp.CSharpCodeProvider csProvider =
new Microsoft.CSharp.CSharpCodeProvider();

View File

@ -97,6 +97,7 @@
</Compile>
<Compile Include="LocalVariableTable.cs" />
<Compile Include="Visualization.cs" />
<Compile Include="VisualizationAnimation.cs" />
<Compile Include="VisualizationSet.cs" />
<Compile Include="WpfGui\AboutBox.xaml.cs">
<DependentUpon>AboutBox.xaml</DependentUpon>
@ -104,6 +105,9 @@
<Compile Include="WpfGui\EditAppSettings.xaml.cs">
<DependentUpon>EditAppSettings.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\EditBitmapAnimation.xaml.cs">
<DependentUpon>EditBitmapAnimation.xaml</DependentUpon>
</Compile>
<Compile Include="WpfGui\EditComment.xaml.cs">
<DependentUpon>EditComment.xaml</DependentUpon>
</Compile>
@ -278,6 +282,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\EditBitmapAnimation.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WpfGui\EditComment.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@ -16,6 +16,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Imaging;
@ -29,6 +30,11 @@ namespace SourceGen {
///
/// This is generally immutable, except for the CachedImage field.
/// </summary>
/// <remarks>
/// Immutability is useful here because the undo/redo mechanism operates at VisualizationSet
/// granularity. We want to know that the undo/redo operations are operating on objects
/// that weren't changed while sitting in the undo buffer.
/// </remarks>
public class Visualization {
/// <summary>
/// Unique user-specified tag. This may be any valid string that is at least two
@ -44,15 +50,25 @@ namespace SourceGen {
/// <summary>
/// Parameters to be passed to the visualization generator.
/// </summary>
/// <remarks>
/// We use a read-only dictionary to reinforce the idea that the plugin shouldn't be
/// modifying the parameter dictionary.
/// </remarks>
public ReadOnlyDictionary<string, object> VisGenParams { get; private set; }
/// <summary>
/// Cached reference to 2D image, useful for thumbnails. Not serialized. This always
/// has an image reference; in times of trouble it will point at BROKEN_IMAGE.
/// Cached reference to 2D image, useful for thumbnails that we display in the
/// code listing. Not serialized. This always has an image reference; in times
/// of trouble it will point at BROKEN_IMAGE.
/// </summary>
/// <remarks>
/// Because the underlying data never changes, we only need to regenerate the
/// image if the set of active plugins changes.
///
/// For 2D bitmaps this should be close to a 1:1 representation of the original,
/// subject to the limitations of the visualization generator. For other types of
/// data (vector line art, 3D meshes) this is a "snapshot" to help the user identify
/// the data.
/// </remarks>
public BitmapSource CachedImage { get; set; }
@ -62,19 +78,60 @@ namespace SourceGen {
public static readonly BitmapImage BROKEN_IMAGE =
new BitmapImage(new Uri("pack://application:,,,/Res/RedX.png"));
/// <summary>
/// Serial number, for reference from other Visualization objects. Not serialized.
/// </summary>
/// <remarks>
/// This value is only valid in the current session. It exists because animations
/// need to refer to other Visualization objects, and doing so by Tag gets sticky
/// if a tag gets renamed. We need a way to uniquely identify a reference to a
/// Visualization that persists across Tag renames and other edits. When the objects
/// are serialized to the project file we just output the tags.
/// </remarks>
public int SerialNumber { get; private set; }
/// <summary>
/// Constructor.
/// Serial number source.
/// </summary>
private static int sNextSerial = 1000;
/// <summary>
/// Constructor for a new Visualization.
/// </summary>
/// <param name="tag">Unique identifier.</param>
/// <param name="visGenIdent">Visualization generator identifier.</param>
/// <param name="visGenParams">Parameters for visualization generator.</param>
public Visualization(string tag, string visGenIdent,
ReadOnlyDictionary<string, object> visGenParams) {
ReadOnlyDictionary<string, object> visGenParams)
:this(tag, visGenIdent, visGenParams, null) { }
/// <summary>
/// Constructor for a replacement Visualization.
/// </summary>
/// <param name="tag">Unique identifier.</param>
/// <param name="visGenIdent">Visualization generator identifier.</param>
/// <param name="visGenParams">Parameters for visualization generator.</param>
/// <param name="oldObj">Visualization being replaced, or null if this is new.</param>
public Visualization(string tag, string visGenIdent,
ReadOnlyDictionary<string, object> visGenParams, Visualization oldObj) {
Debug.Assert(!string.IsNullOrEmpty(tag));
Debug.Assert(!string.IsNullOrEmpty(visGenIdent));
Debug.Assert(visGenParams != null);
Tag = tag;
VisGenIdent = visGenIdent;
VisGenParams = visGenParams;
CachedImage = BROKEN_IMAGE;
if (oldObj == null) {
// not worried about multiple threads
SerialNumber = sNextSerial++;
} else {
Debug.Assert(oldObj.SerialNumber >= 0 && oldObj.SerialNumber < sNextSerial);
SerialNumber = oldObj.SerialNumber;
}
Debug.WriteLine("NEW VIS: Serial=" + SerialNumber);
}
/// <summary>

View File

@ -0,0 +1,64 @@
/*
* 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.Collections.ObjectModel;
using System.Diagnostics;
using System.Text;
namespace SourceGen {
/// <summary>
/// A visualization with animated contents.
/// </summary>
/// <remarks>
/// References to Visualization objects (such as a 3D mesh or list of bitmaps) are held
/// here. The VisGenParams property holds animation properties, such as frame rate and
/// view angles.
/// </remarks>
public class VisualizationAnimation : Visualization {
/// <summary>
/// Serial numbers of visualizations, e.g. bitmap frames.
/// </summary>
/// <remarks>
/// We don't reference the Visualization objects directly because they might get
/// edited (e.g. the tag gets renamed), which replaces them with a new object with
/// the same serial number. We don't do things like renames in place because that
/// makes undo/redo harder.
///
/// (We could reference the Visualization objects and then do a serial number lookup
/// before using it. Some opportunities for optimization should the need arise. This
/// might also allow us to avoid exposing the serial number as a public property, though
/// there's not much advantage to that.)
/// </remarks>
private List<int> mSerialNumbers;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="tag">Unique identifier.</param>
/// <param name="visGenIdent">Visualization generator identifier.</param>
/// <param name="visGenParams">Parameters for visualization generator.</param>
/// <param name="visSerialNumbers">Serial numbers of referenced Visualizations.</param>
public VisualizationAnimation(string tag, string visGenIdent,
ReadOnlyDictionary<string, object> visGenParams, List<int> visSerialNumbers)
: base(tag, visGenIdent, visGenParams) {
Debug.Assert(visSerialNumbers != null);
mSerialNumbers = visSerialNumbers;
}
}
}

View File

@ -132,7 +132,7 @@ namespace SourceGen {
if (vis.CachedImage != Visualization.BROKEN_IMAGE) {
continue;
}
Debug.WriteLine("Vis needs refresh: " + vis.Tag);
//Debug.WriteLine("Vis needs refresh: " + vis.Tag);
if (iapp == null) {
// Prep the plugins on first need.
@ -162,7 +162,7 @@ namespace SourceGen {
vis2d = null;
}
if (vis2d != null) {
Debug.WriteLine(" Rendered thumbnail: " + vis.Tag);
//Debug.WriteLine(" Rendered thumbnail: " + vis.Tag);
vis.SetThumbnail(vis2d);
}
}

View File

@ -0,0 +1,148 @@
<!--
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="SourceGen.WpfGui.EditBitmapAnimation"
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:local="clr-namespace:SourceGen.WpfGui"
mc:Ignorable="d"
Title="Edit Bitmap Animation"
SizeToContent="WidthAndHeight" ResizeMode="NoResize"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner">
<Grid Margin="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- top section: bitmap visualization selection -->
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3"
Text="Select bitmap visualizations to use as animation frames:"/>
<DataGrid Grid.Column="0" Grid.Row="1" Name="visSourceGrid"
IsReadOnly="True"
ItemsSource="{Binding VisSourceItems}"
FontFamily="{StaticResource GeneralMonoFont}"
SnapsToDevicePixels="True"
GridLinesVisibility="Vertical"
VerticalGridLinesBrush="#FF7F7F7F"
AutoGenerateColumns="False"
HeadersVisibility="Column"
CanUserReorderColumns="False"
SelectionMode="Single"
MouseDoubleClick="VisSourceGrid_MouseDoubleClick">
<DataGrid.Resources>
<!-- make the no-focus color the same as the in-focus color -->
<!-- thanks: https://stackoverflow.com/a/13053511/294248 -->
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color="{x:Static SystemColors.HighlightColor}"/>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}"
Color="{x:Static SystemColors.HighlightTextColor}"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Img" Width="56">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border BorderThickness="0" Background="{StaticResource BitmapBackground}">
<Image Source="{Binding CachedImage}" Width="48" Height="48"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Tag" Width="176" Binding="{Binding Tag}"/>
</DataGrid.Columns>
</DataGrid>
<DataGrid Grid.Column="2" Grid.Row="1" Name="visAnimGrid"
IsReadOnly="True"
ItemsSource="{Binding VisAnimItems}"
FontFamily="{StaticResource GeneralMonoFont}"
SnapsToDevicePixels="True"
GridLinesVisibility="Vertical"
VerticalGridLinesBrush="#FF7F7F7F"
AutoGenerateColumns="False"
HeadersVisibility="Column"
CanUserReorderColumns="False"
SelectionMode="Single"
MouseDoubleClick="VisAnimGrid_MouseDoubleClick">
<DataGrid.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color="{x:Static SystemColors.HighlightColor}"/>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}"
Color="{x:Static SystemColors.HighlightTextColor}"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Img" Width="56">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border BorderThickness="0" Background="{StaticResource BitmapBackground}">
<Image Source="{Binding CachedImage}" Width="48" Height="48"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Tag" Width="176" Binding="{Binding Tag}"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Column="1" Grid.Row="1" Height="200">
<Button Content="Add &#x2192;" Width="70" Margin="4,24,4,4"/>
<Button Content="&#x2190; Remove" Width="70" Margin="4,0,4,4"/>
<Button Content="Clear" Width="70" Margin="4,4,4,4"/>
<Button Content="Up &#x2191;" Width="70" Margin="4,20,4,4"/>
<Button Content="Down &#x2193;" Width="70" Margin="4,0,4,4"/>
</StackPanel>
</Grid>
<!-- middle section: parameters -->
<Grid Grid.Row="1" Margin="0,8,0,0">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Frame delay (msec):" Margin="0,1,0,0"/>
<TextBox Width="40" MaxLength="5" Margin="4,0,0,0"
Text="{Binding FrameDelayTimeMsec, FallbackValue=88888}" />
</StackPanel>
</Grid>
<!-- bottom section: preview -->
<Grid Grid.Row="2" Margin="0,8,0,0">
<TextBlock Text="Preview:"/>
</Grid>
<DockPanel Grid.Row="3" Margin="0,8,0,0" LastChildFill="False">
<Button DockPanel.Dock="Right" Content="Cancel" Width="70" Margin="8,0,0,0" IsCancel="True"/>
<Button DockPanel.Dock="Right" Grid.Column="1" Content="OK" Width="70"
IsDefault="True" IsEnabled="{Binding IsValid}" Click="OkButton_Click"/>
</DockPanel>
</Grid>
</Window>

View File

@ -0,0 +1,85 @@
/*
* 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.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace SourceGen.WpfGui {
/// <summary>
/// Bitmap animation visualization editor.
/// </summary>
public partial class EditBitmapAnimation : Window, INotifyPropertyChanged {
/// <summary>
/// True if current contents represent a valid visualization animation. Determines
/// whether the OK button is enabled.
/// </summary>
public bool IsValid {
get { return mIsValid; }
set { mIsValid = value; OnPropertyChanged(); }
}
private bool mIsValid;
public ObservableCollection<Visualization> VisSourceItems { get; private set; } =
new ObservableCollection<Visualization>();
public ObservableCollection<Visualization> VisAnimItems { get; private set; } =
new ObservableCollection<Visualization>();
/// <summary>
/// Time between frames, in milliseconds.
/// </summary>
public int FrameDelayTimeMsec {
get { return mFrameDelayTimeMsec; }
set { mFrameDelayTimeMsec = value; OnPropertyChanged(); }
}
private int mFrameDelayTimeMsec;
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="owner"></param>
public EditBitmapAnimation(Window owner) {
InitializeComponent();
Owner = owner;
DataContext = this;
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
}
private void VisSourceGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
}
private void VisAnimGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
}
}
}

View File

@ -40,8 +40,8 @@ namespace SourceGen.WpfGui {
private DisasmProject mProject;
private Formatter mFormatter;
private int mSetOffset;
private SortedList<int, VisualizationSet> mEditedList;
private Visualization mOrigVis;
private string mOrigTag;
/// <summary>
/// Identifier for last visualizer we used, for the benefit of "new".
@ -173,7 +173,7 @@ namespace SourceGen.WpfGui {
/// <param name="formatter">Text formatter.</param>
/// <param name="vis">Visualization to edit, or null if this is new.</param>
public EditVisualization(Window owner, DisasmProject proj, Formatter formatter,
int setOffset, Visualization vis) {
int setOffset, SortedList<int, VisualizationSet> editedList, Visualization vis) {
InitializeComponent();
Owner = owner;
DataContext = this;
@ -181,8 +181,8 @@ namespace SourceGen.WpfGui {
mProject = proj;
mFormatter = formatter;
mSetOffset = setOffset;
mEditedList = editedList;
mOrigVis = vis;
mOrigTag = (vis == null) ? string.Empty : vis.Tag;
mScriptSupport = new ScriptSupport(this);
mProject.PrepareScripts(mScriptSupport);
@ -302,7 +302,7 @@ namespace SourceGen.WpfGui {
ReadOnlyDictionary<string, object> valueDict = CreateVisGenParams();
string trimTag = Visualization.TrimAndValidateTag(TagString, out bool isTagValid);
Debug.Assert(isTagValid);
NewVis = new Visualization(trimTag, item.VisDescriptor.Ident, valueDict);
NewVis = new Visualization(trimTag, item.VisDescriptor.Ident, valueDict, mOrigVis);
NewVis.CachedImage = (BitmapSource)previewImage.Source;
sLastVisIdent = NewVis.VisGenIdent;
@ -465,15 +465,9 @@ namespace SourceGen.WpfGui {
string trimTag = Visualization.TrimAndValidateTag(TagString, out bool tagOk);
Visualization match = FindVisualizationByTag(trimTag);
if (match != null && trimTag != mOrigTag) {
// Another vis already has this tag.
//
// TODO: this is wrong. If I edit the set, edit a Vis, change it's tag, then
// immediately edit it again, I can't change the tag back to what it originally
// was, because the original version of the Vis is in the VisSet and I no longer
// have a way to know that that Vis and this Vis are the same. To make this work
// correctly we need to track renames, which I think we may want to do later on
// for animations, so not dealing with this yet.
if (match != null && (mOrigVis == null || trimTag != mOrigVis.Tag)) {
// Another vis already has this tag. We're checking the edited list, so we'll
// be current with edits to this or other Visualizations in the same set.
tagOk = false;
}
if (!tagOk) {
@ -485,12 +479,13 @@ namespace SourceGen.WpfGui {
}
/// <summary>
/// Finds a Visualization with a matching tag, searching across all sets.
/// Finds a Visualization with a matching tag, searching across all sets in the
/// edited list.
/// </summary>
/// <param name="tag">Tag to search for.</param>
/// <returns>Matching Visualization, or null if not found.</returns>
private Visualization FindVisualizationByTag(string tag) {
foreach (KeyValuePair<int, VisualizationSet> kvp in mProject.VisualizationSets) {
foreach (KeyValuePair<int, VisualizationSet> kvp in mEditedList) {
foreach (Visualization vis in kvp.Value) {
if (vis.Tag == tag) {
return vis;

View File

@ -88,7 +88,9 @@ limitations under the License.
<StackPanel Grid.Column="1" Grid.Row="1">
<Button Width="110" Margin="4" Content="_New Bitmap..."
IsEnabled="{Binding HasVisPlugins}" Click="NewButton_Click"/>
IsEnabled="{Binding HasVisPlugins}" Click="NewBitmapButton_Click"/>
<Button Width="110" Margin="4" Content="_New Bitmap&#x0a;Animation..."
Click="NewBitmapAnimationButton_Click"/>
<Button Width="110" Margin="4,20,4,4" Content="_Edit..."
IsEnabled="{Binding IsEditEnabled}" Click="EditButton_Click"/>

View File

@ -31,6 +31,9 @@ namespace SourceGen.WpfGui {
/// Visualization set editor.
/// </summary>
public partial class EditVisualizationSet : Window, INotifyPropertyChanged {
/// <summary>
/// Modified visualization set. Only valid after OK is hit.
/// </summary>
public VisualizationSet NewVisSet { get; private set; }
private DisasmProject mProject;
@ -139,17 +142,6 @@ namespace SourceGen.WpfGui {
}
}
private VisualizationSet MakeVisSet() {
if (VisualizationList.Count == 0) {
return null;
}
VisualizationSet newSet = new VisualizationSet(VisualizationList.Count);
foreach (Visualization vis in VisualizationList) {
newSet.Add(vis);
}
return newSet;
}
private void VisualizationList_SelectionChanged(object sender,
SelectionChangedEventArgs e) {
bool isItemSelected = (visualizationGrid.SelectedItem != null);
@ -164,9 +156,9 @@ namespace SourceGen.WpfGui {
EditSelectedItem();
}
private void NewButton_Click(object sender, RoutedEventArgs e) {
private void NewBitmapButton_Click(object sender, RoutedEventArgs e) {
EditVisualization dlg = new EditVisualization(this, mProject, mFormatter, mOffset,
null);
CreateEditedSetList(), null);
if (dlg.ShowDialog() != true) {
return;
}
@ -174,19 +166,27 @@ namespace SourceGen.WpfGui {
visualizationGrid.SelectedIndex = VisualizationList.Count - 1;
}
private void NewBitmapAnimationButton_Click(object sender, RoutedEventArgs e) {
EditBitmapAnimation dlg = new EditBitmapAnimation(this);
if (dlg.ShowDialog() != true) {
return;
}
// TODO(xyzzy)
}
private void EditButton_Click(object sender, RoutedEventArgs e) {
EditSelectedItem();
}
private void EditSelectedItem() {
if (!IsEditEnabled) {
// can happen on a double-click
// can get called here by a double-click
return;
}
Visualization item = (Visualization)visualizationGrid.SelectedItem;
EditVisualization dlg = new EditVisualization(this, mProject, mFormatter, mOffset,
item);
CreateEditedSetList(), item);
if (dlg.ShowDialog() != true) {
return;
}
@ -228,5 +228,42 @@ namespace SourceGen.WpfGui {
VisualizationList.Insert(index + 1, item);
visualizationGrid.SelectedIndex = index + 1;
}
/// <summary>
/// Creates a VisualizationSet from the current list of Visualizations.
/// </summary>
/// <returns>New VisualizationSet.</returns>
private VisualizationSet MakeVisSet() {
VisualizationSet newSet = new VisualizationSet(VisualizationList.Count);
foreach (Visualization vis in VisualizationList) {
newSet.Add(vis);
}
return newSet;
}
/// <summary>
/// Generates a list of VisualizationSet references. This is the list from the
/// DisasmProject, but with the set we're editing added or substituted.
/// </summary>
/// <remarks>
/// The editors sometimes need access to the full collection of Visualization objects,
/// such as when testing a tag for uniqueness or getting a list of all bitmap
/// frames for an animation. The editor needs access to recent edits that have not
/// been pushed to the project yet.
/// </remarks>
/// <returns>List of VisualizationSet.</returns>
private SortedList<int, VisualizationSet> CreateEditedSetList() {
SortedList<int, VisualizationSet> mixList =
new SortedList<int, VisualizationSet>(mProject.VisualizationSets.Count);
mixList[mOffset] = MakeVisSet();
foreach (KeyValuePair<int, VisualizationSet> kvp in mProject.VisualizationSets) {
// Skip the entry for mOffset (if it exists).
if (kvp.Key != mOffset) {
mixList[kvp.Key] = kvp.Value;
}
}
return mixList;
}
}
}