diff --git a/Content/UniversalEditor.Content.PlatformIndependent/Editors/RIFF/Commands.uexml b/Content/UniversalEditor.Content.PlatformIndependent/Editors/RIFF/Commands.uexml new file mode 100644 index 00000000..7a33a27e --- /dev/null +++ b/Content/UniversalEditor.Content.PlatformIndependent/Editors/RIFF/Commands.uexml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Content/UniversalEditor.Content.PlatformIndependent/Editors/RIFF/Dialogs/RIFFChunkPropertiesDialog.glade b/Content/UniversalEditor.Content.PlatformIndependent/Editors/RIFF/Dialogs/RIFFChunkPropertiesDialog.glade new file mode 100644 index 00000000..0fd3602b --- /dev/null +++ b/Content/UniversalEditor.Content.PlatformIndependent/Editors/RIFF/Dialogs/RIFFChunkPropertiesDialog.glade @@ -0,0 +1,283 @@ + + + + + + + + + + + + Data + + + Group + + + + + False + RIFF Chunk Properties + dialog + + + + + + False + vertical + 2 + + + False + end + + + gtk-ok + True + True + True + True + + + True + True + 0 + + + + + gtk-cancel + True + True + True + True + + + True + True + 1 + + + + + False + False + 0 + + + + + True + False + True + True + + + True + False + Chunk _type + True + 0 + + + 0 + 0 + + + + + True + False + True + tmChunkType + 0 + 0 + + + + 0 + + + + + 1 + 0 + 2 + + + + + True + False + Chunk _ID + True + 0 + + + 0 + 1 + + + + + True + False + _Type ID + True + 0 + + + 0 + 2 + + + + + True + True + True + True + True + + + True + False + vertical + + + True + False + + + Import... + True + True + True + True + + + False + True + 0 + + + + + Export... + True + True + True + True + + + False + True + 1 + + + + + True + True + 0 + + + + + MBS.Framework.UserInterface.Controls.HexEditor.HexEditorControl + 400 + 200 + True + False + + + True + True + 1 + + + + + + + True + False + Data + + + + + 0 + 3 + 3 + + + + + True + False + tmChunkTypeIDs + True + 0 + + + True + + + + + 1 + 2 + 2 + + + + + True + True + + + 1 + 1 + 2 + + + + + True + True + 1 + + + + + + button1 + + + + + + + + + + RIFF + + + RIFX + + + FORM + + + LIST + + + CAT + + + + diff --git a/Content/UniversalEditor.Content.PlatformIndependent/Editors/RIFF/RIFFEditor.glade b/Content/UniversalEditor.Content.PlatformIndependent/Editors/RIFF/RIFFEditor.glade new file mode 100644 index 00000000..ddada22c --- /dev/null +++ b/Content/UniversalEditor.Content.PlatformIndependent/Editors/RIFF/RIFFEditor.glade @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + False + + + + + + True + True + in + + + True + True + tm + + + + + + True + Chunk ID + True + True + 0 + + + + 0 + + + + + + + True + Type + True + True + 1 + + + + 1 + + + + + + + True + Length + True + True + 2 + + + + 2 + + + + + + + + + + diff --git a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj index 51c8fab0..6a920430 100644 --- a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj +++ b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj @@ -723,6 +723,9 @@ + + + @@ -776,6 +779,7 @@ + diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/ChunkedObjectModel.cs b/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/ChunkedObjectModel.cs index 3cf07324..fe514b47 100644 --- a/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/ChunkedObjectModel.cs +++ b/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/ChunkedObjectModel.cs @@ -24,7 +24,7 @@ namespace UniversalEditor.ObjectModels.Chunked /// /// Provides an for manipulating chunked binary files (such as RIFF). /// - public class ChunkedObjectModel : ObjectModel + public class ChunkedObjectModel : ObjectModel, IChunkContainer { private ObjectModelReference _omr = null; protected override ObjectModelReference MakeReferenceInternal() @@ -44,19 +44,23 @@ namespace UniversalEditor.ObjectModels.Chunked public RIFFMetadataItem.RIFFMetadataItemCollection Information { get { return mvarInformation; } } #endif - - private RIFFChunk.RIFFChunkCollection mvarChunks = new RIFFChunk.RIFFChunkCollection(); - public RIFFChunk.RIFFChunkCollection Chunks { get { return mvarChunks; } } + + public ChunkedObjectModel() + { + Chunks = new RIFFChunk.RIFFChunkCollection(this); + } + + public RIFFChunk.RIFFChunkCollection Chunks { get; private set; } = null; public override void Clear() { - mvarChunks.Clear(); + Chunks.Clear(); } public override void CopyTo(ObjectModel where) { ChunkedObjectModel clone = where as ChunkedObjectModel; - foreach (RIFFChunk chunk in mvarChunks) + foreach (RIFFChunk chunk in Chunks) { clone.Chunks.Add(chunk.Clone() as RIFFChunk); } diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/IChunkContainer.cs b/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/IChunkContainer.cs new file mode 100644 index 00000000..75f95bf9 --- /dev/null +++ b/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/IChunkContainer.cs @@ -0,0 +1,28 @@ +// +// IChunkContainer.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace UniversalEditor.ObjectModels.Chunked +{ + public interface IChunkContainer + { + RIFFChunk.RIFFChunkCollection Chunks { get; } + } +} diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/RIFFChunk.cs b/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/RIFFChunk.cs index 59b2aaff..3139b776 100644 --- a/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/RIFFChunk.cs +++ b/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/RIFFChunk.cs @@ -28,8 +28,16 @@ namespace UniversalEditor.ObjectModels.Chunked /// public abstract class RIFFChunk : ICloneable { + public IChunkContainer Parent { get; private set; } = null; + public class RIFFChunkCollection : System.Collections.ObjectModel.Collection { + private IChunkContainer _parent = null; + public RIFFChunkCollection(IChunkContainer parent) + { + _parent = parent; + } + public RIFFChunk this[string Name] { get @@ -59,6 +67,31 @@ namespace UniversalEditor.ObjectModels.Chunked base.Add(chunk); return chunk; } + + protected override void InsertItem(int index, RIFFChunk item) + { + base.InsertItem(index, item); + item.Parent = _parent; + } + protected override void RemoveItem(int index) + { + this[index].Parent = null; + base.RemoveItem(index); + } + protected override void SetItem(int index, RIFFChunk item) + { + this[index].Parent = null; + base.SetItem(index, item); + item.Parent = _parent; + } + protected override void ClearItems() + { + for (int i = 0; i < Count; i++) + { + this[i].Parent = null; + } + base.ClearItems(); + } } private string mvarID = String.Empty; diff --git a/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/RIFFGroupChunk.cs b/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/RIFFGroupChunk.cs index b6e44198..0732d060 100644 --- a/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/RIFFGroupChunk.cs +++ b/Libraries/UniversalEditor.Essential/ObjectModels/Chunked/RIFFGroupChunk.cs @@ -26,16 +26,19 @@ namespace UniversalEditor.ObjectModels.Chunked /// /// Represents a group chunk (which can contain subchunks) in a Resource Interchange File Format file. /// - public class RIFFGroupChunk : RIFFChunk + public class RIFFGroupChunk : RIFFChunk, IChunkContainer { - private RIFFChunkCollection mvarChunks = new RIFFChunkCollection(); - public RIFFChunkCollection Chunks { get { return mvarChunks; } } + public RIFFChunkCollection Chunks { get; private set; } = null; + public RIFFGroupChunk() + { + Chunks = new RIFFChunkCollection(this); + } public override object Clone() { RIFFGroupChunk clone = new RIFFGroupChunk(); clone.ID = base.ID; - foreach (RIFFChunk chunk in mvarChunks) + foreach (RIFFChunk chunk in Chunks) { clone.Chunks.Add(chunk.Clone() as RIFFChunk); } @@ -47,7 +50,7 @@ namespace UniversalEditor.ObjectModels.Chunked get { int size = base.Size; - foreach (RIFFChunk chunk in mvarChunks) + foreach (RIFFChunk chunk in Chunks) { size += chunk.Size; } diff --git a/Libraries/UniversalEditor.Essential/UniversalEditor.Essential.csproj b/Libraries/UniversalEditor.Essential/UniversalEditor.Essential.csproj index 9c091b6a..9955d642 100644 --- a/Libraries/UniversalEditor.Essential/UniversalEditor.Essential.csproj +++ b/Libraries/UniversalEditor.Essential/UniversalEditor.Essential.csproj @@ -197,6 +197,7 @@ + diff --git a/Libraries/UniversalEditor.UserInterface/Editors/RIFF/Dialogs/RIFFChunkPropertiesDialog.cs b/Libraries/UniversalEditor.UserInterface/Editors/RIFF/Dialogs/RIFFChunkPropertiesDialog.cs new file mode 100644 index 00000000..aab23c97 --- /dev/null +++ b/Libraries/UniversalEditor.UserInterface/Editors/RIFF/Dialogs/RIFFChunkPropertiesDialog.cs @@ -0,0 +1,106 @@ +// +// RIFFChunkPropertiesDialog.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; + +using MBS.Framework.UserInterface; +using MBS.Framework.UserInterface.Controls; +using MBS.Framework.UserInterface.Controls.HexEditor; +using UniversalEditor.ObjectModels.Chunked; + +namespace UniversalEditor.Editors.RIFF.Dialogs +{ + [ContainerLayout("~/Editors/RIFF/Dialogs/RIFFChunkPropertiesDialog.glade")] + public class RIFFChunkPropertiesDialog : CustomDialog + { + private ComboBox cboChunkType; + private Label lblChunkID; + private TextBox txtChunkID; + private Label lblGroupID; + private ComboBox cboTypeID; + private HexEditorControl hexData; + + public RIFFChunk Chunk { get; set; } = null; + + protected override void OnCreated(EventArgs e) + { + base.OnCreated(e); + + cboChunkType.Changed += cboChunkType_Changed; + + Buttons[0].ResponseValue = (int)DialogResult.None; + Buttons[0].Click += cmdOK_Click; + + if (Chunk != null) + { + txtChunkID.Text = Chunk.ID; + if (Chunk is RIFFDataChunk) + { + cboChunkType.SelectedItem = (cboChunkType.Model as DefaultTreeModel).Rows[0]; + hexData.Data = (Chunk as RIFFDataChunk).Data; + } + else if (Chunk is RIFFGroupChunk) + { + cboChunkType.SelectedItem = (cboChunkType.Model as DefaultTreeModel).Rows[1]; + cboTypeID.Text = (Chunk as RIFFGroupChunk).TypeID; + } + } + } + + private void cmdOK_Click(object sender, EventArgs e) + { + if (cboChunkType.SelectedItem == (cboChunkType.Model as DefaultTreeModel).Rows[0]) + { + // Data + Chunk = new RIFFDataChunk(); + (Chunk as RIFFDataChunk).Data = hexData.Data; + (Chunk as RIFFDataChunk).ID = txtChunkID.Text; + } + else if (cboChunkType.SelectedItem == (cboChunkType.Model as DefaultTreeModel).Rows[1]) + { + // Group + Chunk = new RIFFGroupChunk(); + (Chunk as RIFFGroupChunk).TypeID = cboTypeID.Text; + (Chunk as RIFFGroupChunk).ID = txtChunkID.Text; + } + + this.DialogResult = DialogResult.OK; + this.Close(); + } + + void cboChunkType_Changed(object sender, EventArgs e) + { + if (cboChunkType.SelectedItem == (cboChunkType.Model as DefaultTreeModel).Rows[0]) + { + // Data + cboTypeID.Visible = false; + lblGroupID.Visible = false; + } + else if (cboChunkType.SelectedItem == (cboChunkType.Model as DefaultTreeModel).Rows[1]) + { + // Group + cboTypeID.Visible = true; + lblGroupID.Visible = true; + } + } + + } +} diff --git a/Libraries/UniversalEditor.UserInterface/Editors/RIFF/RIFFEditor.cs b/Libraries/UniversalEditor.UserInterface/Editors/RIFF/RIFFEditor.cs new file mode 100644 index 00000000..37479253 --- /dev/null +++ b/Libraries/UniversalEditor.UserInterface/Editors/RIFF/RIFFEditor.cs @@ -0,0 +1,259 @@ +// +// RIFFEditor.cs +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; + +using MBS.Framework.UserInterface; +using MBS.Framework.UserInterface.Controls; +using MBS.Framework.UserInterface.Dialogs; +using UniversalEditor.ObjectModels.Chunked; +using UniversalEditor.UserInterface; +using UniversalEditor.Editors.RIFF.Dialogs; + +namespace UniversalEditor.Editors.RIFF +{ + [ContainerLayout("~/Editors/RIFF/RIFFEditor.glade")] + public class RIFFEditor : Editor + { + private ListView tv; + private DefaultTreeModel tm; + + public override void UpdateSelections() + { + } + + protected override EditorSelection CreateSelectionInternal(object content) + { + return null; + } + + private static EditorReference _er = null; + public override EditorReference MakeReference() + { + if (_er == null) + { + _er = base.MakeReference(); + _er.SupportedObjectModels.Add(typeof(ChunkedObjectModel)); + } + return _er; + } + + protected override void OnObjectModelChanged(EventArgs e) + { + base.OnObjectModelChanged(e); + + if (!IsCreated) return; + + tm.Rows.Clear(); + + ChunkedObjectModel riff = (ObjectModel as ChunkedObjectModel); + if (riff == null) return; + + if (riff.Chunks.Count == 0) + { + riff.Chunks.Add(new RIFFGroupChunk { TypeID = "RIFF" }); + } + + for (int i = 0; i < riff.Chunks.Count; i++) + { + AddChunkRecursive(riff.Chunks[i], null); + } + } + + private void AddChunkRecursive(RIFFChunk chunk, TreeModelRow parent = null) + { + TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[] + { + new TreeModelRowColumn(tm.Columns[0], chunk.ID), + new TreeModelRowColumn(tm.Columns[1], String.Empty), + new TreeModelRowColumn(tm.Columns[2], chunk.Size) + }); + row.SetExtraData("chunk", chunk); + + if (chunk is RIFFGroupChunk) + { + RIFFGroupChunk g = (RIFFGroupChunk)chunk; + row.RowColumns[1].Value = g.TypeID; + for (int i = 0; i < g.Chunks.Count; i++) + { + AddChunkRecursive(g.Chunks[i], row); + } + } + + if (parent == null) + { + tm.Rows.Add(row); + } + else + { + parent.Rows.Add(row); + } + } + + protected override bool ShowDocumentPropertiesDialogInternal() + { + if (tv.Focused) + { + if (tv.SelectedRows.Count == 0) + return true; + + RIFFChunkPropertiesDialog dlg = new RIFFChunkPropertiesDialog(); + RIFFChunk originalChunk = tv.SelectedRows[0].GetExtraData("chunk"); + dlg.Chunk = originalChunk; + + if (dlg.ShowDialog() == DialogResult.OK) + { + BeginEdit(); + + int originalIndex = originalChunk.Parent.Chunks.IndexOf(originalChunk); + originalChunk.Parent.Chunks[originalIndex] = dlg.Chunk; + + tv.SelectedRows[0].RowColumns[0].Value = dlg.Chunk.ID; + tv.SelectedRows[0].RowColumns[1].Value = (dlg.Chunk as RIFFGroupChunk)?.TypeID ?? String.Empty; + tv.SelectedRows[0].RowColumns[2].Value = dlg.Chunk.Size; + tv.SelectedRows[0].SetExtraData("chunk", dlg.Chunk); + + EndEdit(); + } + return true; + } + return base.ShowDocumentPropertiesDialogInternal(); + } + + private void RIFFEditorContextMenu_Add_NewGroupChunk(object sender, EventArgs e) + { + if (tv.SelectedRows.Count == 0) return; + TreeModelRow rowParent = tv.SelectedRows[0]; + + RIFFGroupChunk group = (rowParent.GetExtraData("chunk") as RIFFGroupChunk); + if (group == null) return; + + RIFFChunkPropertiesDialog dlg2 = new RIFFChunkPropertiesDialog(); + + dlg2.Chunk = new RIFFGroupChunk(); + if (dlg2.ShowDialog() == DialogResult.OK) + { + BeginEdit(); + group.Chunks.Add(dlg2.Chunk); + EndEdit(); + + TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[] + { + new TreeModelRowColumn(tm.Columns[0], dlg2.Chunk.ID), + new TreeModelRowColumn(tm.Columns[1], (dlg2.Chunk as RIFFGroupChunk)?.TypeID), + new TreeModelRowColumn(tm.Columns[2], dlg2.Chunk.Size) + }); + row.SetExtraData("chunk", dlg2.Chunk); + rowParent.Rows.Add(row); + } + } + + private void RIFFEditorContextMenu_Add_NewDataChunk(object sender, EventArgs e) + { + if (tv.SelectedRows.Count == 0) return; + TreeModelRow rowParent = tv.SelectedRows[0]; + + RIFFGroupChunk group = (rowParent.GetExtraData("chunk") as RIFFGroupChunk); + if (group == null) return; + + RIFFChunkPropertiesDialog dlg2 = new RIFFChunkPropertiesDialog(); + + dlg2.Chunk = new RIFFDataChunk { Data = new byte[0] }; + if (dlg2.ShowDialog() == DialogResult.OK) + { + BeginEdit(); + group.Chunks.Add(dlg2.Chunk); + EndEdit(); + + TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[] + { + new TreeModelRowColumn(tm.Columns[0], dlg2.Chunk.ID), + new TreeModelRowColumn(tm.Columns[1], (dlg2.Chunk as RIFFGroupChunk)?.TypeID), + new TreeModelRowColumn(tm.Columns[2], dlg2.Chunk.Size) + }); + row.SetExtraData("chunk", dlg2.Chunk); + rowParent.Rows.Add(row); + } + } + + private void RIFFEditorContextMenu_Add_ExistingFile(object sender, EventArgs e) + { + if (tv.SelectedRows.Count == 0) return; + TreeModelRow rowParent = tv.SelectedRows[0]; + + RIFFGroupChunk group = (rowParent.GetExtraData("chunk") as RIFFGroupChunk); + if (group == null) return; + + FileDialog dlg = new FileDialog(); + dlg.Mode = FileDialogMode.Open; + if (dlg.ShowDialog() == DialogResult.OK) + { + RIFFChunkPropertiesDialog dlg2 = new RIFFChunkPropertiesDialog(); + + dlg2.Chunk = new RIFFDataChunk { Data = System.IO.File.ReadAllBytes(dlg.SelectedFileName) }; + if (dlg2.ShowDialog() == DialogResult.OK) + { + BeginEdit(); + group.Chunks.Add(dlg2.Chunk); + EndEdit(); + + TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[] + { + new TreeModelRowColumn(tm.Columns[0], dlg2.Chunk.ID), + new TreeModelRowColumn(tm.Columns[1], (dlg2.Chunk as RIFFGroupChunk)?.TypeID), + new TreeModelRowColumn(tm.Columns[2], dlg2.Chunk.Size) + }); + row.SetExtraData("chunk", dlg2.Chunk); + rowParent.Rows.Add(row); + } + } + } + private void RIFFEditorContextMenu_Export(object sender, EventArgs e) + { + if (tv.SelectedRows.Count < 1) return; + + RIFFChunk chunk = tv.SelectedRows[0].GetExtraData("chunk"); + if (chunk is RIFFDataChunk) + { + FileDialog dlg = new FileDialog(); + dlg.Mode = FileDialogMode.Save; + if (dlg.ShowDialog() == DialogResult.OK) + { + System.IO.File.WriteAllBytes(dlg.SelectedFileName, (chunk as RIFFDataChunk).Data); + } + } + } + + protected override void OnCreated(EventArgs e) + { + base.OnCreated(e); + + Context.AttachCommandEventHandler("RIFFEditorContextMenu_Add_NewGroupChunk", RIFFEditorContextMenu_Add_NewGroupChunk); + Context.AttachCommandEventHandler("RIFFEditorContextMenu_Add_NewDataChunk", RIFFEditorContextMenu_Add_NewDataChunk); + Context.AttachCommandEventHandler("RIFFEditorContextMenu_Add_ExistingFile", RIFFEditorContextMenu_Add_ExistingFile); + Context.AttachCommandEventHandler("RIFFEditorContextMenu_Export", RIFFEditorContextMenu_Export); + + tv.ContextMenuCommandID = "RIFFEditorContextMenu"; + + OnObjectModelChanged(EventArgs.Empty); + } + } +} diff --git a/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj b/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj index 3621f39e..d0a62be4 100644 --- a/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj +++ b/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj @@ -130,6 +130,8 @@ + + @@ -182,6 +184,8 @@ + +