Пример #1
0
 public void AddChange(UndoEntry entry)
 {
     if (m_UndoPos < m_UndoBuffer.Count)
     {
         for (int i = 0, e = m_UndoBuffer.Count; i < e; ++i)
         {
             m_CurrentCost -= GetEntryCost(m_UndoBuffer[i]);
         }
         m_UndoBuffer.RemoveRange(m_UndoPos, m_UndoBuffer.Count - m_UndoPos);
     }
     m_UndoBuffer.Add(entry);
     ++m_UndoPos;
     m_CurrentCost += GetEntryCost(entry);
     if (m_CurrentCost > MAX_UNDO_BUFFER_COST)
     {
         int entries_to_remove;
         for (entries_to_remove = 0; entries_to_remove < m_UndoPos - 1; ++entries_to_remove)
         {
             m_CurrentCost -= GetEntryCost(m_UndoBuffer[entries_to_remove]);
             if (m_CurrentCost <= MAX_UNDO_BUFFER_COST)
             {
                 entries_to_remove++;
                 break;
             }
         }
         m_UndoBuffer.RemoveRange(0, entries_to_remove);
         m_UndoPos -= entries_to_remove;
     }
 }
Пример #2
0
        public UndoEntryInfo(UndoEntry entry)
        {
            InitializeComponent();

            _entry = entry;

            this.Get <TextBlock>("Description").Text = _entry.Description;
        }
Пример #3
0
    // Undo the last move
    void UndoMove()
    {
        if (this.canUndo)
        {
            AudioController.MoveCard();
            UndoEntry entry = _undoManager.Pop();
            Card      card  = RemoveCardAtLocation(entry.toLocation, entry.toIndex);
            MoveCardToLocation(card, entry.fromLocation, entry.fromIndex, true);

            UpdateScore();
        }
    }
Пример #4
0
        public void Contents_Insert(int index, UndoEntry entry)
        {
            UndoEntryInfo viewer = new UndoEntryInfo(entry);

            viewer.Selected += UndoEntry_Select;

            Contents.Children.Insert(index, viewer);

            if (index <= current)
            {
                current++;
            }
            if (index <= saved)
            {
                saved++;
            }

            Dispatcher.UIThread.Post(() => ScrollViewer.Offset = ScrollViewer.Offset.WithY(Contents.Bounds.Height), DispatcherPriority.Background);
        }
Пример #5
0
        void DetectAndSaveChange(string new_text, int new_sel_start, int new_sel_length)
        {
            if (m_PrevText != null)
            {
                // We are doing brutalforce change detection as we will work with at most a few hundred kilobytes of text in this project.
                int max_len = Math.Min(m_PrevText.Length, new_text.Length);
                // The Math.Min(m_PrevSelStart, max_len) is there to fix a bug that detected wrongly the actual location of
                // multiple pasted lines. If we pasted lines that are equivalent to the lines starting at the actual paste
                // location then this change detector found our newly pasted text as unchanged text and detected the next
                // block as the change. This caused problems especially in case of the optimized syntax highlighter.
                int common_prefix_len = FindCommonPrefixLength(m_PrevText, new_text, Math.Min(m_PrevSelStart, max_len));
                if (m_PrevText.Length == new_text.Length && new_text.Length == common_prefix_len)
                {
                    return;
                }
                int common_postfix_len = common_prefix_len >= max_len ? 0 : FindCommonPostfixLen(m_PrevText, new_text, max_len - common_prefix_len);

                UndoEntry entry = new UndoEntry();
                entry.Id           = m_NextUndoEntryId++;
                entry.PrevCaretPos = m_PrevSelStart + m_PrevSelLength;
                entry.NewCaretPos  = new_sel_start + new_sel_length;
                entry.Pos          = common_prefix_len;
                entry.CutText      = m_PrevText.Substring(common_prefix_len, m_PrevText.Length - common_prefix_len - common_postfix_len);
                entry.PastedText   = new_text.Substring(common_prefix_len, new_text.Length - common_prefix_len - common_postfix_len);

                m_UndoBuffer.AddChange(entry);

                if (UndoEntryAdded != null)
                {
                    UndoEntryAdded(entry);
                }
            }

            m_PrevText      = new_text;
            m_PrevSelStart  = new_sel_start;
            m_PrevSelLength = new_sel_length;
        }
        void DetectAndSaveChange(string new_text, int new_sel_start, int new_sel_length)
        {
            if (m_PrevText != null)
            {
                // We are doing brutalforce change detection as we will work with at most a few hundred kilobytes of text in this project.
                int max_len = Math.Min(m_PrevText.Length, new_text.Length);
                // The Math.Min(m_PrevSelStart, max_len) is there to fix a bug that detected wrongly the actual location of
                // multiple pasted lines. If we pasted lines that are equivalent to the lines starting at the actual paste
                // location then this change detector found our newly pasted text as unchanged text and detected the next
                // block as the change. This caused problems especially in case of the optimized syntax highlighter.
                int common_prefix_len = FindCommonPrefixLength(m_PrevText, new_text, Math.Min(m_PrevSelStart, max_len));
                if (m_PrevText.Length == new_text.Length && new_text.Length == common_prefix_len)
                    return;
                int common_postfix_len = common_prefix_len >= max_len ? 0 : FindCommonPostfixLen(m_PrevText, new_text, max_len - common_prefix_len);

                UndoEntry entry = new UndoEntry();
                entry.Id = m_NextUndoEntryId++;
                entry.PrevCaretPos = m_PrevSelStart + m_PrevSelLength;
                entry.NewCaretPos = new_sel_start + new_sel_length;
                entry.Pos = common_prefix_len;
                entry.CutText = m_PrevText.Substring(common_prefix_len, m_PrevText.Length - common_prefix_len - common_postfix_len);
                entry.PastedText = new_text.Substring(common_prefix_len, new_text.Length - common_prefix_len - common_postfix_len);

                m_UndoBuffer.AddChange(entry);

                if (UndoEntryAdded != null)
                    UndoEntryAdded(entry);
            }

            m_PrevText = new_text;
            m_PrevSelStart = new_sel_start;
            m_PrevSelLength = new_sel_length;
        }
 private static int GetEntryCost(UndoEntry entry)
 {
     return FIX_COST_PER_ENTRY + entry.CutText.Length*2 + entry.PastedText.Length*2;
 }
 public void Undo(out UndoEntry entry)
 {
     Debug.Assert(CanUndo());
     --m_UndoPos;
     entry = m_UndoBuffer[m_UndoPos];
 }
 public void Redo(out UndoEntry entry)
 {
     Debug.Assert(CanRedo());
     entry = m_UndoBuffer[m_UndoPos];
     ++m_UndoPos;
 }
 public void AddChange(UndoEntry entry)
 {
     if (m_UndoPos < m_UndoBuffer.Count)
     {
         for (int i=0,e=m_UndoBuffer.Count; i<e; ++i)
             m_CurrentCost -= GetEntryCost(m_UndoBuffer[i]);
         m_UndoBuffer.RemoveRange(m_UndoPos, m_UndoBuffer.Count - m_UndoPos);
     }
     m_UndoBuffer.Add(entry);
     ++m_UndoPos;
     m_CurrentCost += GetEntryCost(entry);
     if (m_CurrentCost > MAX_UNDO_BUFFER_COST)
     {
         int entries_to_remove;
         for (entries_to_remove=0; entries_to_remove<m_UndoPos-1; ++entries_to_remove)
         {
             m_CurrentCost -= GetEntryCost(m_UndoBuffer[entries_to_remove]);
             if (m_CurrentCost <= MAX_UNDO_BUFFER_COST)
             {
                 entries_to_remove++;
                 break;
             }
         }
         m_UndoBuffer.RemoveRange(0, entries_to_remove);
         m_UndoPos -= entries_to_remove;
     }
 }
Пример #11
0
 private static int GetEntryCost(UndoEntry entry)
 {
     return(FIX_COST_PER_ENTRY + entry.CutText.Length * 2 + entry.PastedText.Length * 2);
 }
Пример #12
0
 public void Redo(out UndoEntry entry)
 {
     Debug.Assert(CanRedo());
     entry = m_UndoBuffer[m_UndoPos];
     ++m_UndoPos;
 }
Пример #13
0
 public void Undo(out UndoEntry entry)
 {
     Debug.Assert(CanUndo());
     --m_UndoPos;
     entry = m_UndoBuffer[m_UndoPos];
 }
Пример #14
0
 void Unloaded(object sender, VisualTreeAttachmentEventArgs e)
 {
     Selected = null;
     _entry   = null;
 }
Пример #15
0
        static dynamic Decode(BinaryReader reader, int version, Type ensure = null)
        {
            Type t = DecodeID(reader);

            if (ensure != null && ensure != t)
            {
                throw new InvalidDataException();
            }

            if (t == typeof(Copyable))
            {
                return new Copyable()
                       {
                           Contents = Enumerable.Range(0, reader.ReadInt32()).Select(i => Decode <ISelect>(reader, version)).ToList()
                       }
            }
            ;

            else if (t == typeof(Project))
            {
                int bpm = reader.ReadInt32();

                int[] macros = (version >= 25)? Enumerable.Range(0, 4).Select(i => reader.ReadInt32()).ToArray() : new int[4] {
                    reader.ReadInt32(), 1, 1, 1
                };
                List <Track> tracks = Enumerable.Range(0, reader.ReadInt32()).Select(i => Decode <Track>(reader, version)).ToList();

                string author  = "";
                long   time    = 0;
                long   started = 0;

                if (version >= 17)
                {
                    author  = reader.ReadString();
                    time    = reader.ReadInt64();
                    started = reader.ReadInt64();
                }

                UndoManager undo = null;
                if (version >= 30)
                {
                    undo = Decode <UndoManager>(reader, version);
                }

                return(new Project(bpm, macros, tracks, author, time, started, undo));
            }
            else if (t == typeof(Track))
            {
                Chain     chain = Decode <Chain>(reader, version);
                Launchpad lp    = Decode <Launchpad>(reader, version);
                string    name  = reader.ReadString();

                bool enabled = true;
                if (version >= 8)
                {
                    enabled = reader.ReadBoolean();
                }

                return(new Track(chain, lp, name)
                {
                    Enabled = enabled
                });
            }
            else if (t == typeof(Chain))
            {
                List <Device> devices = Enumerable.Range(0, reader.ReadInt32()).Select(i => Decode <Device>(reader, version)).ToList();
                string        name    = reader.ReadString();

                bool enabled = true;
                if (version >= 6)
                {
                    enabled = reader.ReadBoolean();
                }

                bool[] filter = null;
                if (version >= 29)
                {
                    filter = Enumerable.Range(0, 101).Select(i => reader.ReadBoolean()).ToArray();
                }

                return(new Chain(devices, name, filter)
                {
                    Enabled = enabled
                });
            }
            else if (t == typeof(Device))
            {
                bool collapsed = false;
                if (version >= 5)
                {
                    collapsed = reader.ReadBoolean();
                }

                bool enabled = true;
                if (version >= 5)
                {
                    enabled = reader.ReadBoolean();
                }

                Device ret = (Device)Decode(reader, version); // This needs to be a cast!
                ret.Collapsed = collapsed;
                ret.Enabled   = enabled;

                return(ret);
            }
            else if (t == typeof(Launchpad))
            {
                string name = reader.ReadString();
                if (name == "")
                {
                    return(MIDI.NoOutput);
                }

                InputType format = InputType.DrumRack;
                if (version >= 2)
                {
                    format = (InputType)reader.ReadInt32();
                }

                RotationType rotation = RotationType.D0;
                if (version >= 9)
                {
                    rotation = (RotationType)reader.ReadInt32();
                }

                foreach (Launchpad lp in MIDI.Devices)
                {
                    if (lp.Name == name)
                    {
                        if (lp.GetType() == typeof(Launchpad))
                        {
                            lp.InputFormat = format;
                            lp.Rotation    = rotation;
                        }
                        return(lp);
                    }
                }

                Launchpad ret;
                if (name.Contains("Virtual Launchpad "))
                {
                    ret = new VirtualLaunchpad(name, Convert.ToInt32(name.Substring(18)));
                }
                else if (name.Contains("Ableton Connector "))
                {
                    ret = new AbletonLaunchpad(name);
                }
                else
                {
                    ret = new Launchpad(name, format, rotation);
                }

                MIDI.Devices.Add(ret);

                return(ret);
            }
            else if (t == typeof(Group))
            {
                return(new Group(
                           Enumerable.Range(0, reader.ReadInt32()).Select(i => Decode <Chain>(reader, version)).ToList(),
                           reader.ReadBoolean()? (int?)reader.ReadInt32() : null
                           ));
            }

            else if (t == typeof(Choke))
            {
                return(new Choke(
                           reader.ReadInt32(),
                           Decode <Chain>(reader, version)
                           ));
            }

            else if (t == typeof(Clear))
            {
                return(new Clear(
                           (ClearType)reader.ReadInt32()
                           ));
            }

            else if (t == typeof(ColorFilter))
            {
                return(new ColorFilter(
                           reader.ReadDouble(),
                           reader.ReadDouble(),
                           reader.ReadDouble(),
                           reader.ReadDouble(),
                           reader.ReadDouble(),
                           reader.ReadDouble()
                           ));
            }

            else if (t == typeof(Copy))
            {
                Time time;
                if (version <= 2)
                {
                    time = new Time(
                        reader.ReadBoolean(),
                        Decode(reader, version),
                        reader.ReadInt32()
                        );
                }
                else
                {
                    time = Decode(reader, version);
                }

                double gate;
                if (version <= 13)
                {
                    gate = (double)reader.ReadDecimal();
                }
                else
                {
                    gate = reader.ReadDouble();
                }

                double pinch = 0;
                if (version >= 26)
                {
                    pinch = reader.ReadDouble();
                }

                bool bilateral = false;
                if (version >= 28)
                {
                    bilateral = reader.ReadBoolean();
                }

                bool reverse = false;
                if (version >= 26)
                {
                    reverse = reader.ReadBoolean();
                }

                bool infinite = false;
                if (version >= 27)
                {
                    infinite = reader.ReadBoolean();
                }

                CopyType copyType = (CopyType)reader.ReadInt32();
                GridType gridType = (GridType)reader.ReadInt32();
                bool     wrap     = reader.ReadBoolean();

                int           count;
                List <Offset> offsets = Enumerable.Range(0, count = reader.ReadInt32()).Select(i => Decode <Offset>(reader, version)).ToList();
                List <int>    angles  = Enumerable.Range(0, count).Select(i => (version >= 25)? reader.ReadInt32() : 0).ToList();

                return(new Copy(time, gate, pinch, bilateral, reverse, infinite, copyType, gridType, wrap, offsets, angles));
            }
            else if (t == typeof(Delay))
            {
                Time time;
                if (version <= 2)
                {
                    time = new Time(
                        reader.ReadBoolean(),
                        Decode(reader, version),
                        reader.ReadInt32()
                        );
                }
                else
                {
                    time = Decode(reader, version);
                }

                double gate;
                if (version <= 13)
                {
                    gate = (double)reader.ReadDecimal();
                }
                else
                {
                    gate = reader.ReadDouble();
                }

                return(new Delay(time, gate));
            }
            else if (t == typeof(Fade))
            {
                Time time;
                if (version <= 2)
                {
                    time = new Time(
                        reader.ReadBoolean(),
                        Decode(reader, version),
                        reader.ReadInt32()
                        );
                }
                else
                {
                    time = Decode(reader, version);
                }

                double gate;
                if (version <= 13)
                {
                    gate = (double)reader.ReadDecimal();
                }
                else
                {
                    gate = reader.ReadDouble();
                }

                FadePlaybackType playmode = (FadePlaybackType)reader.ReadInt32();

                int             count;
                List <Color>    colors    = Enumerable.Range(0, count = reader.ReadInt32()).Select(i => Decode <Color>(reader, version)).ToList();
                List <double>   positions = Enumerable.Range(0, count).Select(i => (version <= 13)? (double)reader.ReadDecimal() : reader.ReadDouble()).ToList();
                List <FadeType> types     = Enumerable.Range(0, count - 1).Select(i => (version <= 24) ? FadeType.Linear : (FadeType)reader.ReadInt32()).ToList();

                int?expanded = null;
                if (version >= 23)
                {
                    expanded = reader.ReadBoolean()? (int?)reader.ReadInt32() : null;
                }

                return(new Fade(time, gate, playmode, colors, positions, types, expanded));
            }
            else if (t == typeof(Flip))
            {
                return(new Flip(
                           (FlipType)reader.ReadInt32(),
                           reader.ReadBoolean()
                           ));
            }

            else if (t == typeof(Hold))
            {
                Time time;
                if (version <= 2)
                {
                    time = new Time(
                        reader.ReadBoolean(),
                        Decode(reader, version),
                        reader.ReadInt32()
                        );
                }
                else
                {
                    time = Decode(reader, version);
                }

                double gate;
                if (version <= 13)
                {
                    gate = (double)reader.ReadDecimal();
                }
                else
                {
                    gate = reader.ReadDouble();
                }

                HoldType holdmode;
                if (version <= 31)
                {
                    holdmode = reader.ReadBoolean()? HoldType.Infinite : HoldType.Trigger;
                }
                else
                {
                    holdmode = (HoldType)reader.ReadInt32();
                }

                return(new Hold(
                           time,
                           gate,
                           holdmode,
                           reader.ReadBoolean()
                           ));
            }
            else if (t == typeof(KeyFilter))
            {
                bool[] filter;
                if (version <= 18)
                {
                    List <bool> oldFilter = Enumerable.Range(0, 100).Select(i => reader.ReadBoolean()).ToList();
                    oldFilter.Insert(99, false);
                    filter = oldFilter.ToArray();
                }
                else
                {
                    filter = Enumerable.Range(0, 101).Select(i => reader.ReadBoolean()).ToArray();
                }

                return(new KeyFilter(filter));
            }
            else if (t == typeof(Layer))
            {
                int target = reader.ReadInt32();

                BlendingType blending = BlendingType.Normal;
                if (version >= 5)
                {
                    if (version == 5)
                    {
                        blending = (BlendingType)reader.ReadInt32();
                        if ((int)blending == 2)
                        {
                            blending = BlendingType.Mask;
                        }
                    }
                    else
                    {
                        blending = (BlendingType)reader.ReadInt32();
                    }
                }

                int range = 200;
                if (version >= 21)
                {
                    range = reader.ReadInt32();
                }

                return(new Layer(target, blending, range));
            }
            else if (t == typeof(LayerFilter))
            {
                return(new LayerFilter(
                           reader.ReadInt32(),
                           reader.ReadInt32()
                           ));
            }

            else if (t == typeof(Loop))
            {
                return(new Loop(
                           Decode(reader, version),
                           reader.ReadDouble(),
                           reader.ReadInt32(),
                           reader.ReadBoolean()
                           ));
            }

            else if (t == typeof(Move))
            {
                return(new Move(
                           Decode(reader, version),
                           (GridType)reader.ReadInt32(),
                           reader.ReadBoolean()
                           ));
            }

            else if (t == typeof(Multi))
            {
                Chain preprocess = Decode(reader, version);

                int          count = reader.ReadInt32();
                List <Chain> init  = Enumerable.Range(0, count).Select(i => Decode <Chain>(reader, version)).ToList();

                if (version == 28)
                {
                    List <bool[]> filters = Enumerable.Range(0, count).Select(i =>
                                                                              Enumerable.Range(0, 101).Select(i => reader.ReadBoolean()).ToArray()
                                                                              ).ToList();

                    for (int i = 0; i < count; i++)
                    {
                        init[i].SecretMultiFilter = filters[i];
                    }
                }

                int?      expanded = reader.ReadBoolean()? (int?)reader.ReadInt32() : null;
                MultiType mode     = (MultiType)reader.ReadInt32();

                return(new Multi(preprocess, init, expanded, mode));
            }
            else if (t == typeof(Output))
            {
                return(new Output(
                           reader.ReadInt32()
                           ));
            }

            else if (t == typeof(MacroFilter))
            {
                return(new MacroFilter(
                           (version >= 25)? reader.ReadInt32() : 1,
                           Enumerable.Range(0, 100).Select(i => reader.ReadBoolean()).ToArray()
                           ));
            }

            else if (t == typeof(Paint))
            {
                return(new Paint(
                           Decode(reader, version)
                           ));
            }

            else if (t == typeof(Pattern))
            {
                int repeats = 1;
                if (version >= 11)
                {
                    repeats = reader.ReadInt32();
                }

                double gate;
                if (version <= 13)
                {
                    gate = (double)reader.ReadDecimal();
                }
                else
                {
                    gate = reader.ReadDouble();
                }

                double pinch = 0;
                if (version >= 24)
                {
                    pinch = reader.ReadDouble();
                }

                bool bilateral = false;
                if (version >= 28)
                {
                    bilateral = reader.ReadBoolean();
                }

                List <Frame> frames = Enumerable.Range(0, reader.ReadInt32()).Select(i => Decode <Frame>(reader, version)).ToList();
                PlaybackType mode   = (PlaybackType)reader.ReadInt32();

                bool chokeenabled = false;
                int  choke        = 8;

                if (version <= 10)
                {
                    chokeenabled = reader.ReadBoolean();

                    if (version <= 0)
                    {
                        if (chokeenabled)
                        {
                            choke = reader.ReadInt32();
                        }
                    }
                    else
                    {
                        choke = reader.ReadInt32();
                    }
                }

                bool infinite = false;
                if (version >= 4)
                {
                    infinite = reader.ReadBoolean();
                }

                int?rootkey = null;
                if (version >= 12)
                {
                    rootkey = reader.ReadBoolean()? (int?)reader.ReadInt32() : null;
                }

                bool wrap = false;
                if (version >= 13)
                {
                    wrap = reader.ReadBoolean();
                }

                int expanded = reader.ReadInt32();

                Pattern ret = new Pattern(repeats, gate, pinch, bilateral, frames, mode, infinite, rootkey, wrap, expanded);

                if (chokeenabled)
                {
                    return(new Choke(choke, new Chain(new List <Device>()
                    {
                        ret
                    })));
                }

                return(ret);
            }
            else if (t == typeof(Preview))
            {
                return(new Preview());
            }

            else if (t == typeof(Rotate))
            {
                return(new Rotate(
                           (RotateType)reader.ReadInt32(),
                           reader.ReadBoolean()
                           ));
            }

            else if (t == typeof(Refresh))
            {
                return(new Refresh(
                           Enumerable.Range(0, 4).Select(i => reader.ReadBoolean()).ToArray()
                           ));
            }

            else if (t == typeof(Switch))
            {
                int target = (version >= 25)? reader.ReadInt32() : 1;
                int value  = reader.ReadInt32();

                if (18 <= version && version <= 21 && reader.ReadBoolean())
                {
                    return(new Group(new List <Chain>()
                    {
                        new Chain(new List <Device>()
                        {
                            new Switch(1, value), new Clear(ClearType.Multi)
                        }, "Switch Reset")
                    }));
                }

                return(new Switch(target, value));
            }
            else if (t == typeof(Tone))
            {
                return(new Tone(
                           reader.ReadDouble(),
                           reader.ReadDouble(),
                           reader.ReadDouble(),
                           reader.ReadDouble(),
                           reader.ReadDouble()
                           ));
            }

            else if (t == typeof(Color))
            {
                byte red   = reader.ReadByte();
                byte green = reader.ReadByte();
                byte blue  = reader.ReadByte();

                if (version == 24)
                {
                    if (red > 0)
                    {
                        red = (byte)((red - 1) * 62.0 / 126 + 1);
                    }
                    if (green > 0)
                    {
                        green = (byte)((green - 1) * 62.0 / 126 + 1);
                    }
                    if (blue > 0)
                    {
                        blue = (byte)((blue - 1) * 62.0 / 126 + 1);
                    }
                }

                return(new Color(red, green, blue));
            }
            else if (t == typeof(Frame))
            {
                Time time;
                if (version <= 2)
                {
                    time = new Time(
                        reader.ReadBoolean(),
                        Decode(reader, version),
                        reader.ReadInt32()
                        );
                }
                else
                {
                    time = Decode(reader, version);
                }

                Color[] screen;
                if (version <= 19)
                {
                    List <Color> oldScreen = Enumerable.Range(0, 100).Select(i => Decode <Color>(reader, version)).ToList();
                    oldScreen.Insert(99, new Color(0));
                    screen = oldScreen.ToArray();
                }
                else
                {
                    screen = Enumerable.Range(0, 101).Select(i => Decode <Color>(reader, version)).ToArray();
                }

                return(new Frame(time, screen));
            }
            else if (t == typeof(Length))
            {
                return(new Length(
                           reader.ReadInt32()
                           ));
            }

            else if (t == typeof(Offset))
            {
                int x = reader.ReadInt32();
                int y = reader.ReadInt32();

                bool absolute = false;
                int  ax       = 5;
                int  ay       = 5;
                if (version >= 25)
                {
                    absolute = reader.ReadBoolean();
                    ax       = reader.ReadInt32();
                    ay       = reader.ReadInt32();
                }

                return(new Offset(x, y, absolute, ax, ay));
            }
            else if (t == typeof(Time))
            {
                return(new Time(
                           reader.ReadBoolean(),
                           Decode(reader, version),
                           reader.ReadInt32()
                           ));
            }

            else if (t == typeof(UndoManager))
            {
                int undoVersion = reader.ReadInt32();
                int size        = reader.ReadInt32();

                if (undoVersion == UndoBinary.Version)
                {
                    return(new UndoManager(
                               Enumerable.Range(0, reader.ReadInt32()).Select(i => UndoEntry.DecodeEntry(reader, version)).ToList(),
                               reader.ReadInt32()
                               ));
                }

                reader.ReadBytes(size);
                return(new UndoManager());
            }

            throw new InvalidDataException();
        }