diff --git a/CommonWPF/FrameAnimationControl.xaml.cs b/CommonWPF/FrameAnimationControl.xaml.cs index c01be07..a156bc6 100644 --- a/CommonWPF/FrameAnimationControl.xaml.cs +++ b/CommonWPF/FrameAnimationControl.xaml.cs @@ -90,6 +90,10 @@ namespace CommonWPF { } public void Start() { + if (mBitmaps == null) { + throw new InvalidOperationException("Must set bitmaps before starting"); + } + Tick(null, null); // show something immediately mTimer.Start(); } @@ -98,9 +102,6 @@ namespace CommonWPF { } private void Tick(object sender, EventArgs e) { - if (mBitmaps == null) { - throw new InvalidOperationException("Must set bitmaps before starting"); - } if (mNext >= mBitmaps.Count) { mNext = 0; } diff --git a/SourceGen/ProjectFile.cs b/SourceGen/ProjectFile.cs index 4d76ce9..6ce86c8 100644 --- a/SourceGen/ProjectFile.cs +++ b/SourceGen/ProjectFile.cs @@ -372,14 +372,29 @@ namespace SourceGen { VisGenParams = new Dictionary(vis.VisGenParams); } } + public class SerVisualizationAnimation : SerVisualization { + public List Tags { get; set; } + + public SerVisualizationAnimation() { } + public SerVisualizationAnimation(VisualizationAnimation visAnim, + SortedList visSets) + : base(visAnim) { + Tags = new List(visAnim.Count); + for (int i = 0; i < visAnim.Count; i++) { + Visualization vis = + VisualizationSet.FindVisualizationBySerial(visSets, visAnim[i]); + Tags.Add(vis.Tag); + } + } + } public class SerVisualizationSet { - public List Items { get; set; } + public List Tags { get; set; } public SerVisualizationSet() { } public SerVisualizationSet(VisualizationSet visSet) { - Items = new List(visSet.Count); + Tags = new List(visSet.Count); foreach (Visualization vis in visSet) { - Items.Add(new SerVisualization(vis)); + Tags.Add(vis.Tag); } } } @@ -398,6 +413,8 @@ namespace SourceGen { public Dictionary UserLabels { get; set; } public Dictionary OperandFormats { get; set; } public Dictionary LvTables { get; set; } + public List Visualizations { get; set; } + public List VisualizationAnimations { get; set; } public Dictionary VisualizationSets { get; set; } /// @@ -488,8 +505,20 @@ namespace SourceGen { spf.LvTables.Add(kvp.Key.ToString(), new SerLocalVariableTable(kvp.Value)); } + // Output Visualizations, VisualizationAnimations, and VisualizationSets + spf.Visualizations = new List(); + spf.VisualizationAnimations = new List(); spf.VisualizationSets = new Dictionary(); foreach (KeyValuePair kvp in proj.VisualizationSets) { + foreach (Visualization vis in kvp.Value) { + if (vis is VisualizationAnimation) { + VisualizationAnimation visAnim = (VisualizationAnimation)vis; + spf.VisualizationAnimations.Add(new SerVisualizationAnimation(visAnim, + proj.VisualizationSets)); + } else { + spf.Visualizations.Add(new SerVisualization(vis)); + } + } spf.VisualizationSets.Add(kvp.Key.ToString(), new SerVisualizationSet(kvp.Value)); } @@ -745,21 +774,60 @@ namespace SourceGen { } // Deserialize visualization sets. These were added in v1.5. - if (spf.VisualizationSets != null) { + if (spf.VisualizationSets != null && spf.Visualizations != null) { + Dictionary visDict = + new Dictionary(spf.Visualizations.Count); + + // Extract the Visualizations. + foreach (SerVisualization serVis in spf.Visualizations) { + if (CreateVisualization(serVis, report, out Visualization vis)) { + try { + visDict.Add(vis.Tag, vis); + } catch (ArgumentException) { + string str = string.Format(Res.Strings.ERR_BAD_VISUALIZATION_FMT, + "duplicate tag " + vis.Tag); + report.Add(FileLoadItem.Type.Warning, str); + continue; + } + } + } + + // Extract the VisualizationAnimations, which link to Visualizations by tag. + foreach (SerVisualizationAnimation serVisAnim in spf.VisualizationAnimations) { + if (CreateVisualizationAnimation(serVisAnim, visDict, report, + out VisualizationAnimation visAnim)) { + try { + visDict.Add(visAnim.Tag, visAnim); + } catch (ArgumentException) { + string str = string.Format(Res.Strings.ERR_BAD_VISUALIZATION_FMT, + "duplicate tag " + visAnim.Tag); + report.Add(FileLoadItem.Type.Warning, str); + continue; + } + } + } + + // Extract the VisualizationSets, which link to Visualizations of all types by tag. foreach (KeyValuePair kvp in spf.VisualizationSets) { if (!ParseValidateKey(kvp.Key, spf.FileDataLength, Res.Strings.PROJECT_FIELD_LV_TABLE, report, out int intKey)) { continue; } - if (!CreateVisualizationSet(kvp.Value, report, out VisualizationSet visSet)) { + if (!CreateVisualizationSet(kvp.Value, visDict, report, + out VisualizationSet visSet)) { report.Add(FileLoadItem.Type.Warning, string.Format(Res.Strings.ERR_BAD_VISUALIZATION_SET_FMT, intKey)); continue; } proj.VisualizationSets[intKey] = visSet; + } + if (visDict.Count != 0) { + // We remove visualizations as we add them to sets, so this indicates a + // problem. + Debug.WriteLine("WARNING: visDict still has " + visDict.Count + " entries"); } } @@ -973,39 +1041,115 @@ namespace SourceGen { return true; } - private static bool CreateVisualizationSet(SerVisualizationSet serVisSet, - FileLoadReport report, out VisualizationSet outVisSet) { - outVisSet = new VisualizationSet(); - foreach (SerVisualization serVis in serVisSet.Items) { - string trimTag = Visualization.TrimAndValidateTag(serVis.Tag, out bool isTagValid); - if (!isTagValid) { - Debug.WriteLine("Visualization with invalid tag: " + serVis.Tag); - string str = string.Format(Res.Strings.ERR_BAD_VISUALIZATION_FMT, trimTag); - report.Add(FileLoadItem.Type.Warning, str); - continue; - } - if (string.IsNullOrEmpty(serVis.VisGenIdent) || serVis.VisGenParams == null) { + /// + /// Creates a Visualization from its serialized form. + /// + private static bool CreateVisualization(SerVisualization serVis, FileLoadReport report, + out Visualization vis) { + if (!CheckVis(serVis, report, out Dictionary parms)) { + vis = null; + return false; + } + vis = new Visualization(serVis.Tag, serVis.VisGenIdent, + new ReadOnlyDictionary(parms)); + return true; + } + + /// + /// Creates a VisualizationAnimation from its serialized form. + /// + private static bool CreateVisualizationAnimation(SerVisualizationAnimation serVisAnim, + Dictionary visList, FileLoadReport report, + out VisualizationAnimation visAnim) { + if (!CheckVis(serVisAnim, report, out Dictionary parms)) { + visAnim = null; + return false; + } + List serialNumbers = new List(serVisAnim.Tags.Count); + foreach (string tag in serVisAnim.Tags) { + if (!visList.TryGetValue(tag, out Visualization vis)) { string str = string.Format(Res.Strings.ERR_BAD_VISUALIZATION_FMT, - "ident/params"); + "unknown tag in animation: " + tag); + report.Add(FileLoadItem.Type.Warning, str); + continue; + } + if (vis is VisualizationAnimation) { + string str = string.Format(Res.Strings.ERR_BAD_VISUALIZATION_FMT, + "animation in animation: " + tag); + report.Add(FileLoadItem.Type.Warning, str); + continue; + } + serialNumbers.Add(vis.SerialNumber); + } + visAnim = new VisualizationAnimation(serVisAnim.Tag, serVisAnim.VisGenIdent, + new ReadOnlyDictionary(parms), serialNumbers, null); + return true; + } + + /// + /// Checks for errors common to Visualization objects. Generates a replacement + /// parameter object to work around JavaScript type conversion. + /// + private static bool CheckVis(SerVisualization serVis, FileLoadReport report, + out Dictionary parms) { + parms = null; + + string unused = Visualization.TrimAndValidateTag(serVis.Tag, out bool isTagValid); + if (!isTagValid) { + Debug.WriteLine("Visualization with invalid tag: " + serVis.Tag); + string str = string.Format(Res.Strings.ERR_BAD_VISUALIZATION_FMT, serVis.Tag); + report.Add(FileLoadItem.Type.Warning, str); + return false; + } + if (string.IsNullOrEmpty(serVis.VisGenIdent) || serVis.VisGenParams == null) { + string str = string.Format(Res.Strings.ERR_BAD_VISUALIZATION_FMT, + "ident/params"); + report.Add(FileLoadItem.Type.Warning, str); + return false; + } + + // The JavaScript deserialization turns floats into Decimal. Change it back + // so we don't have to deal with it later. + parms = new Dictionary(serVis.VisGenParams.Count); + foreach (KeyValuePair kvp in serVis.VisGenParams) { + object val = kvp.Value; + if (val is decimal) { + val = (double)((decimal)val); + } + parms.Add(kvp.Key, val); + } + return true; + } + + /// + /// Creates a VisualizationSet from its serialized form. + /// + private static bool CreateVisualizationSet(SerVisualizationSet serVisSet, + Dictionary visList, FileLoadReport report, + out VisualizationSet outVisSet) { + outVisSet = new VisualizationSet(); + foreach (string rawTag in serVisSet.Tags) { + string trimTag = Visualization.TrimAndValidateTag(rawTag, out bool isTagValid); + if (!isTagValid) { + Debug.WriteLine("VisualizationSet with invalid tag: " + rawTag); + string str = string.Format(Res.Strings.ERR_BAD_VISUALIZATION_FMT, rawTag); + report.Add(FileLoadItem.Type.Warning, str); + continue; + } + if (!visList.TryGetValue(trimTag, out Visualization vis)) { + Debug.WriteLine("VisSet ref to unknown tag: " + trimTag); + string str = string.Format(Res.Strings.ERR_BAD_VISUALIZATION_FMT, + "unknown tag: " + trimTag); report.Add(FileLoadItem.Type.Warning, str); continue; } - // The JavaScript deserialization turns floats into Decimal. Change it back - // so we don't have to deal with it later. - Dictionary parms = - new Dictionary(serVis.VisGenParams.Count); - foreach (KeyValuePair kvp in serVis.VisGenParams) { - object val = kvp.Value; - if (val is decimal) { - val = (double)((decimal)val); - } - parms.Add(kvp.Key, val); - } - - Visualization vis = new Visualization(serVis.Tag, serVis.VisGenIdent, - new ReadOnlyDictionary(parms)); outVisSet.Add(vis); + + // Each Visualization should only appear in one VisualizationSet. Things + // might get weird when we remove one if this isn't true. So we remove + // it from the dictionary. + visList.Remove(trimTag); } return true; } diff --git a/SourceGen/SGTestData/Visualization/apple2-bitmap-test#061000.dis65 b/SourceGen/SGTestData/Visualization/apple2-bitmap-test#061000.dis65 index 2db7f7d..d324f5e 100644 --- a/SourceGen/SGTestData/Visualization/apple2-bitmap-test#061000.dis65 +++ b/SourceGen/SGTestData/Visualization/apple2-bitmap-test#061000.dis65 @@ -20,9 +20,7 @@ }, "LongComments":{ "222":{ -"Text":"\r\nPurple/green diagonal\r\n\r\n","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}, -"0":{ -"Text":"Some images:","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}}, +"Text":"\r\nPurple/green diagonal\r\n\r\n","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}}, "Notes":{ "222":{ "Text":"Bitmaps here","BoxMode":false,"MaxWidth":80,"BackgroundColor":-256}}, @@ -45,9 +43,7 @@ "Length":64,"Format":"Dense","SubFormat":"None","SymbolRef":null}}, "LvTables":{ }, -"VisualizationSets":{ -"0":{ -"Items":[{ +"Visualizations":[{ "Tag":"multi1","VisGenIdent":"apple2-hi-res-bitmap","VisGenParams":{ "offset":222,"byteWidth":1,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}, { @@ -55,31 +51,38 @@ "offset":230,"byteWidth":1,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}, { "Tag":"multi3","VisGenIdent":"apple2-hi-res-bitmap","VisGenParams":{ -"offset":238,"byteWidth":12,"height":1,"colStride":0,"rowStride":0,"isColor":false,"isFirstOdd":false}}, +"offset":238,"byteWidth":3,"height":2,"colStride":0,"rowStride":0,"isColor":false,"isFirstOdd":false}}, { -"Tag":"multi4","VisGenIdent":"apple2-hi-res-bitmap","VisGenParams":{ -"offset":270,"byteWidth":3,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}]}, -"222":{ -"Items":[{ "Tag":"vis0000de","VisGenIdent":"apple2-hi-res-bitmap","VisGenParams":{ -"offset":222,"byteWidth":1,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}]}, -"230":{ -"Items":[{ +"offset":222,"byteWidth":1,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}, +{ "Tag":"vis0000e6","VisGenIdent":"apple2-hi-res-bitmap","VisGenParams":{ -"offset":230,"byteWidth":1,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":true}}]}, -"238":{ -"Items":[{ +"offset":230,"byteWidth":1,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":true}}, +{ "Tag":"vis0000ee","VisGenIdent":"apple2-hi-res-bitmap","VisGenParams":{ -"offset":238,"byteWidth":2,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}]}, -"254":{ -"Items":[{ +"offset":238,"byteWidth":2,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}, +{ "Tag":"vis0000fe","VisGenIdent":"apple2-hi-res-bitmap","VisGenParams":{ -"offset":254,"byteWidth":2,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}]}, -"270":{ -"Items":[{ +"offset":254,"byteWidth":2,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}, +{ "Tag":"vis00010e","VisGenIdent":"apple2-hi-res-bitmap","VisGenParams":{ -"offset":270,"byteWidth":3,"height":8,"colStride":0,"rowStride":0,"isColor":true,"isFirstOdd":false}}]}, -"294":{ -"Items":[{ +"offset":270,"byteWidth":3,"height":8,"colStride":0,"rowStride":0,"isColor":false,"isFirstOdd":false}}, +{ "Tag":"vis000126","VisGenIdent":"apple2-hi-res-bitmap","VisGenParams":{ -"offset":294,"byteWidth":3,"height":8,"colStride":2,"rowStride":8,"isColor":true,"isFirstOdd":false}}]}}} +"offset":294,"byteWidth":3,"height":8,"colStride":2,"rowStride":8,"isColor":true,"isFirstOdd":false}}],"VisualizationAnimations":[{ +"Tags":["multi2","vis0000e6","vis0000de","vis0000ee","vis0000de"],"Tag":"anim000012","VisGenIdent":"(animation)","VisGenParams":{ +"frame-delay-msec":400}}],"VisualizationSets":{ +"18":{ +"Tags":["anim000012","multi1","multi2","multi3"]}, +"222":{ +"Tags":["vis0000de"]}, +"230":{ +"Tags":["vis0000e6"]}, +"238":{ +"Tags":["vis0000ee"]}, +"254":{ +"Tags":["vis0000fe"]}, +"270":{ +"Tags":["vis00010e"]}, +"294":{ +"Tags":["vis000126"]}}} diff --git a/SourceGen/SGTestData/Visualization/apple2-screen-img#062000.dis65 b/SourceGen/SGTestData/Visualization/apple2-screen-img#062000.dis65 index b04ca08..6b1c8db 100644 --- a/SourceGen/SGTestData/Visualization/apple2-screen-img#062000.dis65 +++ b/SourceGen/SGTestData/Visualization/apple2-screen-img#062000.dis65 @@ -22,8 +22,8 @@ "Length":8184,"Format":"Dense","SubFormat":"None","SymbolRef":null}}, "LvTables":{ }, -"VisualizationSets":{ +"Visualizations":[{ +"Tag":"vis000000","VisGenIdent":"apple2-hi-res-screen","VisGenParams":{ +"offset":0,"isColor":true}}],"VisualizationAnimations":[],"VisualizationSets":{ "0":{ -"Items":[{ -"Tag":"full screen image","VisGenIdent":"apple2-hi-res-screen","VisGenParams":{ -"offset":0,"isColor":true}}]}}} +"Tags":["vis000000"]}}} diff --git a/SourceGen/SGTestData/Visualization/atari2600-sprite-test.dis65 b/SourceGen/SGTestData/Visualization/atari2600-sprite-test.dis65 index c1c925a..c6029ba 100644 --- a/SourceGen/SGTestData/Visualization/atari2600-sprite-test.dis65 +++ b/SourceGen/SGTestData/Visualization/atari2600-sprite-test.dis65 @@ -44,28 +44,35 @@ "Length":21,"Format":"Dense","SubFormat":"None","SymbolRef":null}}, "LvTables":{ }, -"VisualizationSets":{ +"Visualizations":[{ +"Tag":"vis000014","VisGenIdent":"atari2600-sprite","VisGenParams":{ +"offset":20,"height":3}}, +{ +"Tag":"vis000018","VisGenIdent":"atari2600-sprite","VisGenParams":{ +"offset":24,"height":20}}, +{ +"Tag":"vis00002d","VisGenIdent":"atari2600-sprite","VisGenParams":{ +"offset":45,"height":22}}, +{ +"Tag":"vis000044","VisGenIdent":"atari2600-playfield","VisGenParams":{ +"offset":68,"height":7,"rowThickness":4,"reflected":false}}, +{ +"Tag":"vis000059","VisGenIdent":"atari2600-playfield","VisGenParams":{ +"offset":89,"height":7,"rowThickness":4,"reflected":true}}, +{ +"Tag":"vis00006e","VisGenIdent":"atari2600-playfield","VisGenParams":{ +"offset":110,"height":7,"rowThickness":4,"reflected":true}}],"VisualizationAnimations":[{ +"Tags":["vis000018","vis00002d"],"Tag":"anim00002d","VisGenIdent":"(animation)","VisGenParams":{ +"frame-delay-msec":500}}],"VisualizationSets":{ "20":{ -"Items":[{ -"Tag":"Key sprite","VisGenIdent":"atari2600-sprite","VisGenParams":{ -"offset":20,"height":3}}]}, +"Tags":["vis000014"]}, "24":{ -"Items":[{ -"Tag":"Dragon 0","VisGenIdent":"atari2600-sprite","VisGenParams":{ -"offset":24,"height":20}}]}, +"Tags":["vis000018"]}, "45":{ -"Items":[{ -"Tag":"Dragon 1","VisGenIdent":"atari2600-sprite","VisGenParams":{ -"offset":45,"height":22}}]}, +"Tags":["vis00002d","anim00002d"]}, "68":{ -"Items":[{ -"Tag":"Black Maze 3","VisGenIdent":"atari2600-playfield","VisGenParams":{ -"offset":68,"height":7,"rowThickness":4,"reflected":false}}]}, +"Tags":["vis000044"]}, "89":{ -"Items":[{ -"Tag":"Red Maze (bottom)","VisGenIdent":"atari2600-playfield","VisGenParams":{ -"offset":89,"height":7,"rowThickness":4,"reflected":true}}]}, +"Tags":["vis000059"]}, "110":{ -"Items":[{ -"Tag":"Castle Def","VisGenIdent":"atari2600-playfield","VisGenParams":{ -"offset":110,"height":7,"rowThickness":4,"reflected":true}}]}}} +"Tags":["vis00006e"]}}} diff --git a/SourceGen/SGTestData/Visualization/c64-sprite-test.dis65 b/SourceGen/SGTestData/Visualization/c64-sprite-test.dis65 index 262cda2..c9b9e93 100644 --- a/SourceGen/SGTestData/Visualization/c64-sprite-test.dis65 +++ b/SourceGen/SGTestData/Visualization/c64-sprite-test.dis65 @@ -38,20 +38,25 @@ "Length":1792,"Format":"Junk","SubFormat":"None","SymbolRef":null}}, "LvTables":{ }, -"VisualizationSets":{ -"0":{ -"Items":[{ +"Visualizations":[{ "Tag":"vis000000","VisGenIdent":"c64-multi-color-sprite","VisGenParams":{ -"offset":0,"color":3,"color01":6,"color11":10,"doubleWide":false,"doubleHigh":false}}]}, -"64":{ -"Items":[{ +"offset":0,"color":3,"color01":6,"color11":10,"doubleWide":false,"doubleHigh":false}}, +{ "Tag":"vis000040","VisGenIdent":"c64-hi-res-sprite","VisGenParams":{ -"offset":64,"color":14,"doubleWide":false,"doubleHigh":false}}]}, -"128":{ -"Items":[{ +"offset":64,"color":14,"doubleWide":false,"doubleHigh":false}}, +{ "Tag":"vis000080","VisGenIdent":"c64-multi-color-sprite","VisGenParams":{ -"offset":128,"color":4,"color01":6,"color11":10,"doubleWide":true,"doubleHigh":false}}]}, -"192":{ -"Items":[{ +"offset":128,"color":4,"color01":6,"color11":10,"doubleWide":true,"doubleHigh":false}}, +{ "Tag":"vis0000c0","VisGenIdent":"c64-hi-res-sprite","VisGenParams":{ -"offset":192,"color":5,"doubleWide":true,"doubleHigh":true}}]}}} +"offset":192,"color":5,"doubleWide":true,"doubleHigh":true}}],"VisualizationAnimations":[{ +"Tags":["vis000040","vis000000","vis000080","vis0000c0"],"Tag":"anim000000","VisGenIdent":"(animation)","VisGenParams":{ +"frame-delay-msec":800}}],"VisualizationSets":{ +"0":{ +"Tags":["vis000000","anim000000"]}, +"64":{ +"Tags":["vis000040"]}, +"128":{ +"Tags":["vis000080"]}, +"192":{ +"Tags":["vis0000c0"]}}} diff --git a/SourceGen/VisualizationAnimation.cs b/SourceGen/VisualizationAnimation.cs index c0740ea..0b250c5 100644 --- a/SourceGen/VisualizationAnimation.cs +++ b/SourceGen/VisualizationAnimation.cs @@ -83,13 +83,6 @@ namespace SourceGen { CachedImage = ANIM_OVERLAY_IMAGE; // default to this } - /// - /// The number of Visualizations linked from this animation. - /// - public int SerialCount { - get { return mSerialNumbers.Count; } - } - public void GenerateImage(SortedList visSets) { const int IMAGE_SIZE = 64; @@ -126,10 +119,22 @@ namespace SourceGen { } /// - /// Returns a list of serial numbers. The caller must not modify the list. + /// The number of Visualizations linked from this animation. /// - public List GetSerialNumbers() { - return mSerialNumbers; + /// + /// Visualizations may appear more than once in the list. Each instance is counted. + /// + public int Count { + get { return mSerialNumbers.Count; } + } + + /// + /// Indexes the serial number list. + /// + public int this[int index] { + get { + return mSerialNumbers[index]; + } } /// @@ -226,7 +231,6 @@ namespace SourceGen { if (!base.Equals(obj)) { return false; } - Debug.WriteLine("Detailed: this=" + Tag + " other=" + Tag); VisualizationAnimation other = (VisualizationAnimation)obj; if (other.mSerialNumbers.Count != mSerialNumbers.Count) { return false; @@ -236,7 +240,6 @@ namespace SourceGen { return false; } } - Debug.WriteLine(" All serial numbers match"); return true; } public override int GetHashCode() { diff --git a/SourceGen/VisualizationSet.cs b/SourceGen/VisualizationSet.cs index dd21125..51581ea 100644 --- a/SourceGen/VisualizationSet.cs +++ b/SourceGen/VisualizationSet.cs @@ -126,7 +126,7 @@ namespace SourceGen { if (VisualizationAnimation.StripEntries((VisualizationAnimation) vis, removedSerials, out VisualizationAnimation newAnim)) { somethingRemoved = true; - if (newAnim.SerialCount != 0) { + if (newAnim.Count != 0) { newSet.Add(newAnim); } else { Debug.WriteLine("Deleting empty animation " + vis.Tag); diff --git a/SourceGen/WpfGui/EditBitmapAnimation.xaml.cs b/SourceGen/WpfGui/EditBitmapAnimation.xaml.cs index f3432ea..5574bbc 100644 --- a/SourceGen/WpfGui/EditBitmapAnimation.xaml.cs +++ b/SourceGen/WpfGui/EditBitmapAnimation.xaml.cs @@ -148,8 +148,9 @@ namespace SourceGen.WpfGui { FrameDelayTimeMsec = DEFAULT_FRAME_DELAY.ToString(); if (origAnim != null) { TagString = origAnim.Tag; - int frameDelay = PluginCommon.Util.GetFromObjDict(origAnim.VisGenParams, + mFrameDelayIntMsec = PluginCommon.Util.GetFromObjDict(origAnim.VisGenParams, VisualizationAnimation.FRAME_DELAY_MSEC_PARAM, DEFAULT_FRAME_DELAY); + FrameDelayTimeMsec = mFrameDelayIntMsec.ToString(); } else { TagString = "anim" + mSetOffset.ToString("x6"); } @@ -160,13 +161,17 @@ namespace SourceGen.WpfGui { private void PopulateItemLists() { // Add the animation's visualizations, in order. if (mOrigAnim != null) { - foreach (int serial in mOrigAnim.GetSerialNumbers()) { + for (int i = 0; i < mOrigAnim.Count; i++) { + int serial = mOrigAnim[i]; Visualization vis = VisualizationSet.FindVisualizationBySerial(mEditedList, serial); if (vis != null) { VisAnimItems.Add(vis); } else { - Debug.Assert(false); + // Could happen if the Visualization exists but isn't referenced by + // any VisualizationSets. Shouldn't happen unless the project file + // was damaged. Silently ignore it. + Debug.WriteLine("WARNING: unknown vis serial " + serial); } } } diff --git a/SourceGen/WpfGui/EditVisualizationSet.xaml b/SourceGen/WpfGui/EditVisualizationSet.xaml index 3a06f8e..cd21d83 100644 --- a/SourceGen/WpfGui/EditVisualizationSet.xaml +++ b/SourceGen/WpfGui/EditVisualizationSet.xaml @@ -87,7 +87,7 @@ limitations under the License. -