/* * 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; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; namespace SourceGen { /// /// A visualization with animated contents. /// /// /// This has a list of references to Visualization objects. The cached images are /// displayed in sequence, at a rate determined by animation parameters also held here. /// /// As with the base class, instances are generally immutable for the benefit of undo/redo. /// public class VisBitmapAnimation : Visualization { /// /// Frame delay parameter. /// public const string P_FRAME_DELAY_MSEC_PARAM = "_frameDelayMsec"; public const string P_FRAME_DELAY_MSEC_PARAM_OLD = "frame-delay-msec"; /// /// Fake visualization generation identifier. /// public const string ANIM_VIS_GEN = "(animation)"; /// /// Serial numbers of visualizations, e.g. bitmap frames. /// /// /// 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.) /// private List mSerialNumbers; /// /// Constructor. /// /// Unique identifier. /// Visualization generator identifier. /// Parameters for visualization generator. /// Serial numbers of referenced Visualizations. public VisBitmapAnimation(string tag, string visGenIdent, ReadOnlyDictionary visGenParams, VisBitmapAnimation oldObj, List visSerialNumbers) : base(tag, visGenIdent, visGenParams, oldObj) { Debug.Assert(visSerialNumbers != null); // Make a copy of the list. mSerialNumbers = new List(visSerialNumbers.Count); foreach (int serial in visSerialNumbers) { mSerialNumbers.Add(serial); } CachedImage = BLANK_IMAGE; OverlayImage = ANIM_OVERLAY_IMAGE; } /// /// Generates a cached image for the animation. /// /// /// Currently just using the first frame. We could do fancy things, like make a /// poster with the first N images. /// /// List of visualization sets. public void GenerateImage(SortedList visSets) { CachedImage = BLANK_IMAGE; if (mSerialNumbers.Count == 0) { return; } Visualization vis = VisualizationSet.FindVisualizationBySerial(visSets, mSerialNumbers[0]); if (vis != null) { CachedImage = vis.CachedImage; } } /// /// The number of Visualizations linked from this animation. /// /// /// 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]; } } /// /// Returns true if this visualization holds a reference to the specified serial number. /// public bool ContainsSerial(int serial) { // Linear search. We don't do this a lot and our lists our short, so okay for now. foreach (int ser in mSerialNumbers) { if (ser == serial) { return true; } } return false; } /// /// Strips serial numbers out of the list. /// /// Object to strip serial numbers from. /// List of serial numbers to remove. /// Object with changes, or null if nothing changed. /// True if something was actually removed. public static bool StripEntries(VisBitmapAnimation visAnim, List removedSerials, out VisBitmapAnimation newAnim) { bool somethingRemoved = false; // Both sets should be small, so not worried about O(m*n). List newSerials = new List(visAnim.mSerialNumbers.Count); foreach (int serial in visAnim.mSerialNumbers) { if (removedSerials.Contains(serial)) { Debug.WriteLine("Removing serial #" + serial + " from " + visAnim.Tag); somethingRemoved = true; continue; } newSerials.Add(serial); } if (somethingRemoved) { newAnim = new VisBitmapAnimation(visAnim.Tag, visAnim.VisGenIdent, visAnim.VisGenParams, visAnim, newSerials); } else { newAnim = null; } return somethingRemoved; } public static bool operator ==(VisBitmapAnimation a, VisBitmapAnimation b) { if (ReferenceEquals(a, b)) { return true; // same object, or both null } if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) { return false; // one is null } return a.Equals(b); } public static bool operator !=(VisBitmapAnimation a, VisBitmapAnimation b) { return !(a == b); } public override bool Equals(object obj) { if (!(obj is VisBitmapAnimation)) { return false; } // Do base-class equality comparison and the ReferenceEquals check. if (!base.Equals(obj)) { return false; } VisBitmapAnimation other = (VisBitmapAnimation)obj; if (other.mSerialNumbers.Count != mSerialNumbers.Count) { return false; } for (int i = 0; i < mSerialNumbers.Count; i++) { if (other.mSerialNumbers[i] != mSerialNumbers[i]) { return false; } } return true; } public override int GetHashCode() { return base.GetHashCode() ^ mSerialNumbers.Count; // weak } } }