provide support for playing, creating, and modifying sprite animations in PictureCollectionObjectModel

This commit is contained in:
Michael Becker 2020-05-28 18:13:27 -04:00
parent f0bf09b709
commit 98a9a347bc
No known key found for this signature in database
GPG Key ID: 506F54899E2BFED7
9 changed files with 1083 additions and 3 deletions

View File

@ -0,0 +1,251 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkTreeStore" id="tmAnimationFrames">
<columns>
<!-- column-name colAnimationFrameIndex -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkDialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Animation Properties</property>
<property name="type_hint">dialog</property>
<child type="titlebar">
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cmdOK">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cmdCancel">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Name</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="txtAnimationName">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToolbar" id="tbAnimationFrames">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToolButton" id="tsbAnimationFrameAdd">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Add</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-add</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="tsbAnimationFrameRemove">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Remove</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-remove</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="tvAnimationFrames">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">tmAnimationFrames</property>
<property name="search_column">0</property>
<child internal-child="selection">
<object class="GtkTreeSelection">
<property name="mode">multiple</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcAnimationFrameIndex">
<property name="resizable">True</property>
<property name="title" translatable="yes">Index</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">0</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSpinButton" id="txtFrameIndex">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage" id="pic">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">16</property>
<property name="stock">gtk-missing-image</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -2,6 +2,14 @@
<!-- Generated with glade 3.22.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkTreeStore" id="tmAnimations">
<columns>
<!-- column-name colAnimationName -->
<column type="gchararray"/>
<!-- column-name colAnimationFrameCount -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow">
<property name="can_focus">False</property>
<child type="titlebar">
@ -63,10 +71,351 @@
</packing>
</child>
<child>
<object class="GtkDrawingArea" id="picFrame">
<property name="name">MBS.Framework.UserInterface.Controls.PictureFrame</property>
<object class="GtkPaned">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can_focus">True</property>
<property name="orientation">vertical</property>
<property name="position">200</property>
<property name="position_set">True</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkDrawingArea" id="picFrame">
<property name="name">MBS.Framework.UserInterface.Controls.PictureFrame</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToolbar" id="tbAnimations">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToolButton" id="tsbAnimationAdd">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Add</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-add</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="tsbAnimationEdit">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Edit</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-edit</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="tsbAnimationRemove">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Remove</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-remove</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="tsbAnimationLoad">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Load</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-open</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="tsbAnimationSave">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Save</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-save</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="tvAnimations">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">tmAnimations</property>
<property name="search_column">0</property>
<child internal-child="selection">
<object class="GtkTreeSelection">
<property name="mode">multiple</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcAnimationName">
<property name="resizable">True</property>
<property name="title" translatable="yes">Name</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">0</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="tvcAnimationFrameCount">
<property name="resizable">True</property>
<property name="title" translatable="yes">Frames</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">1</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Animations</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Start frame</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_End frame</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Frame _duration (ms)</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cmdQuickAnimateSave">
<property name="label" translatable="yes">Save Ani_mation</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="txtQuickAnimateStartFrame">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="txtQuickAnimateEndFrame">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="txtQuickAnimateFrameDuration">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cmdQuickAnimatePlay">
<property name="label" translatable="yes">_Play</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
<property name="width">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Quick Animate</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>

View File

@ -741,6 +741,7 @@
<Content Include="Editors\Multimedia\Audio\Waveform\Controls\WaveformAudioEditorTrack.glade" />
<Content Include="Editors\Multimedia\Audio\Synthesized\Views\MIDIEvents\MIDIEventsView.glade" />
<Content Include="Editors\Multimedia\PictureCollection\PictureCollectionEditor.glade" />
<Content Include="Editors\Multimedia\PictureCollection\Dialogs\AnimationPropertiesDialog.glade" />
</ItemGroup>
<ItemGroup>
<Content Include="Configuration\Application.upl" />

View File

@ -0,0 +1,149 @@
//
// AnimationPropertiesDialog.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// 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 <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using MBS.Framework.UserInterface;
using MBS.Framework.UserInterface.Controls;
using MBS.Framework.UserInterface.Dialogs;
using UniversalEditor.ObjectModels.Multimedia.Picture.Collection;
namespace UniversalEditor.Plugins.Multimedia.UserInterface.Editors.Multimedia.PictureCollection.Dialogs
{
[ContainerLayout("~/Editors/Multimedia/PictureCollection/Dialogs/AnimationPropertiesDialog.glade", "GtkDialog")]
public class AnimationPropertiesDialog : CustomDialog
{
private TextBox txtAnimationName;
private Toolbar tbAnimationFrames;
private ListView tvAnimationFrames;
private DefaultTreeModel tmAnimationFrames;
private Button cmdOK;
private Button cmdCancel;
public string AnimationName { get; set; } = String.Empty;
public List<byte> AnimationFrames { get; } = new List<byte>();
private NumericTextBox txtFrameIndex;
private PictureFrame pic;
public PictureCollectionObjectModel PictureCollection { get; set; } = null;
protected override void OnCreated(EventArgs e)
{
base.OnCreated(e);
DefaultButton = cmdOK;
txtAnimationName.Text = AnimationName;
for (int i = 0; i < AnimationFrames.Count; i++)
{
TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmAnimationFrames.Columns[0], AnimationFrames[i].ToString())
});
row.SetExtraData<byte>("FrameIndex", AnimationFrames[i]);
row.SetExtraData<int>("EditingIndex", i);
tmAnimationFrames.Rows.Add(row);
}
UpdateConstraints();
(tbAnimationFrames.Items["tsbAnimationFrameAdd"] as ToolbarItemButton).Click += tsbAnimationFrameAdd_Click;
(tbAnimationFrames.Items["tsbAnimationFrameRemove"] as ToolbarItemButton).Click += tsbAnimationFrameRemove_Click;
}
private void UpdateConstraints()
{
if (!IsCreated) return;
if (PictureCollection == null) return;
txtFrameIndex.Maximum = PictureCollection.Pictures.Count - 1;
txtFrameIndex.Minimum = 0;
}
private byte _OriginalFrameIndex = 0;
[EventHandler(nameof(tvAnimationFrames), "SelectionChanging")]
private void tvAnimationFrames_SelectionChanging(object sender, ListViewSelectionChangingEventArgs e)
{
if ((byte)txtFrameIndex.Value != _OriginalFrameIndex)
{
if (MessageDialog.ShowDialog("You have changed the image index associated with this frame. Do you want to save your change before selecting another frame?", "Save Change", MessageDialogButtons.YesNo, MessageDialogIcon.Warning) == DialogResult.No)
{
e.Cancel = true;
return;
}
if (e.OldSelection != null)
{
for (int i = 0; i < e.OldSelection.Length; i++)
{
e.OldSelection[i].SetExtraData<byte>("FrameIndex", (byte)txtFrameIndex.Value);
AnimationFrames[e.OldSelection[i].GetExtraData<int>("EditingIndex")] = (byte)txtFrameIndex.Value;
e.OldSelection[i].RowColumns[0].Value = txtFrameIndex.Value.ToString();
}
}
}
}
[EventHandler(nameof(tvAnimationFrames), "SelectionChanged")]
private void tvAnimationFrames_SelectionChanged(object sender, EventArgs e)
{
TreeModelRow row = tvAnimationFrames.SelectedRows[0];
int editingIndex = row.GetExtraData<int>("EditingIndex");
txtFrameIndex.Value = AnimationFrames[editingIndex];
_OriginalFrameIndex = (byte)txtFrameIndex.Value;
}
[EventHandler(nameof(txtFrameIndex), "Changed")]
private void txtFrameIndex_Changed(object sender, EventArgs e)
{
if (PictureCollection == null) return;
pic.Image = PictureCollection.Pictures[(int)txtFrameIndex.Value].ToImage();
}
[EventHandler(nameof(cmdOK), "Click")]
private void cmdOK_Click(object sender, EventArgs e)
{
AnimationName = txtAnimationName.Text;
DialogResult = DialogResult.OK;
}
private void tsbAnimationFrameAdd_Click(object sender, EventArgs e)
{
TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmAnimationFrames.Columns[0], txtFrameIndex.Value.ToString())
});
row.SetExtraData<byte>("FrameIndex", (byte)txtFrameIndex.Value);
row.SetExtraData<int>("EditingIndex", tmAnimationFrames.Rows.Count);
tmAnimationFrames.Rows.Add(row);
AnimationFrames.Add((byte)txtFrameIndex.Value);
}
private void tsbAnimationFrameRemove_Click(object sender, EventArgs e)
{
}
}
}

View File

@ -28,6 +28,7 @@ using UniversalEditor.Accessors;
using UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap;
using UniversalEditor.ObjectModels.Multimedia.Picture;
using UniversalEditor.ObjectModels.Multimedia.Picture.Collection;
using UniversalEditor.ObjectModels.Multimedia.SpriteAnimationCollection;
using UniversalEditor.UserInterface;
namespace UniversalEditor.Plugins.Multimedia.UserInterface.Editors.Multimedia.PictureCollection
@ -42,6 +43,18 @@ namespace UniversalEditor.Plugins.Multimedia.UserInterface.Editors.Multimedia.Pi
private Button cmdSaveAll;
private NumericTextBox txtFrameIndex;
private NumericTextBox txtQuickAnimateStartFrame;
private NumericTextBox txtQuickAnimateEndFrame;
private NumericTextBox txtQuickAnimateFrameDuration;
private Button cmdQuickAnimatePlay;
private Button cmdQuickAnimateSave;
private Toolbar tbAnimations;
private ListView tvAnimations;
private DefaultTreeModel tmAnimations;
private static EditorReference _er = null;
public override EditorReference MakeReference()
{
@ -69,9 +82,154 @@ namespace UniversalEditor.Plugins.Multimedia.UserInterface.Editors.Multimedia.Pi
{
base.OnCreated(e);
(tbAnimations.Items["tsbAnimationAdd"] as ToolbarItemButton).Click += tsbAnimationAdd_Click;
(tbAnimations.Items["tsbAnimationEdit"] as ToolbarItemButton).Click += tsbAnimationEdit_Click;
(tbAnimations.Items["tsbAnimationRemove"] as ToolbarItemButton).Click += tsbAnimationRemove_Click;
(tbAnimations.Items["tsbAnimationLoad"] as ToolbarItemButton).Click += tsbAnimationOpen_Click;
(tbAnimations.Items["tsbAnimationSave"] as ToolbarItemButton).Click += tsbAnimationSave_Click;
OnObjectModelChanged(e);
}
private void tsbAnimationAdd_Click(object sender, EventArgs e)
{
Dialogs.AnimationPropertiesDialog dlg = new Dialogs.AnimationPropertiesDialog();
dlg.PictureCollection = (ObjectModel as PictureCollectionObjectModel);
if (dlg.ShowDialog() == DialogResult.OK)
{
SpriteAnimation anim = new SpriteAnimation();
anim.Name = dlg.AnimationName;
for (int i = 0; i < dlg.AnimationFrames.Count; i++)
{
anim.Frames.Add(dlg.AnimationFrames[i]);
}
TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmAnimations.Columns[0], anim.Name),
new TreeModelRowColumn(tmAnimations.Columns[1], anim.Frames.Count)
});
row.SetExtraData<SpriteAnimation>("anim", anim);
tmAnimations.Rows.Add(row);
}
}
private void tsbAnimationEdit_Click(object sender, EventArgs e)
{
if (tvAnimations.SelectedRows.Count != 1)
{
MessageDialog.ShowDialog("Please select EXACTLY ONE animation to edit.", "Error", MessageDialogButtons.OK, MessageDialogIcon.Error);
return;
}
TreeModelRow row = tvAnimations.SelectedRows[0];
SpriteAnimation anim = row.GetExtraData<SpriteAnimation>("anim");
Dialogs.AnimationPropertiesDialog dlg = new Dialogs.AnimationPropertiesDialog();
dlg.AnimationName = anim.Name;
dlg.PictureCollection = (ObjectModel as PictureCollectionObjectModel);
for (int i = 0; i < anim.Frames.Count; i++)
{
dlg.AnimationFrames.Add(anim.Frames[i]);
}
if (dlg.ShowDialog() == DialogResult.OK)
{
anim.Name = dlg.AnimationName;
anim.Frames.Clear();
for (int i = 0; i < dlg.AnimationFrames.Count; i++)
{
anim.Frames.Add(dlg.AnimationFrames[i]);
}
row.RowColumns[0].Value = anim.Name;
row.RowColumns[1].Value = anim.Frames.Count.ToString();
}
}
private void tsbAnimationRemove_Click(object sender, EventArgs e)
{
if (tvAnimations.SelectedRows.Count < 1)
{
MessageDialog.ShowDialog("Please select AT LEAST ONE animation to remove.", "Error", MessageDialogButtons.OK, MessageDialogIcon.Error);
return;
}
if (MessageDialog.ShowDialog(String.Format("Are you sure you want to remove the {0}?", tvAnimations.SelectedRows.Count == 1 ? "selected animation" : String.Format("{0} selected animations", tvAnimations.SelectedRows.Count)), "Remove Animations", MessageDialogButtons.YesNo, MessageDialogIcon.Warning) == DialogResult.Yes)
{
// FIXME: GTK doesn't remove the same row from the SelectedRows even when the row gets removed from the model...
// probably because the GtkTreeView automatically selects the other row. this is convenient for the user but not for the developer!
for (int i = 0; i < tvAnimations.SelectedRows.Count; i++)
{
tmAnimations.Rows.Remove(tvAnimations.SelectedRows[i]);
}
}
}
private void tsbAnimationOpen_Click(object sender, EventArgs e)
{
FileDialog fd = new FileDialog();
fd.Mode = FileDialogMode.Open;
SpriteAnimationCollectionObjectModel wow = new SpriteAnimationCollectionObjectModel();
if (fd.ShowDialog() == DialogResult.OK)
{
FileAccessor fa = new FileAccessor(fd.SelectedFileName);
DataFormatReference[] dfrs = Common.Reflection.GetAvailableDataFormats(fa);
for (int i = 0; i < dfrs.Length; i++)
{
DataFormat wdf = dfrs[i].Create();
try
{
Document.Load(wow, wdf, fa);
foreach (SpriteAnimation anim in wow.Animations)
{
TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmAnimations.Columns[0], anim.Name),
new TreeModelRowColumn(tmAnimations.Columns[1], anim.Frames.Count.ToString())
});
row.SetExtraData<SpriteAnimation>("anim", anim);
tmAnimations.Rows.Add(row);
}
break;
}
catch (ObjectModelNotSupportedException ex)
{
continue;
}
catch (InvalidDataFormatException ex)
{
continue;
}
}
}
}
private void tsbAnimationSave_Click(object sender, EventArgs e)
{
}
[EventHandler(nameof(tvAnimations), "RowActivated")]
private void tvAnimations_RowActivated(object sender, ListViewRowActivatedEventArgs e)
{
if (e.Row == null) return;
SpriteAnimation anim = e.Row.GetExtraData<SpriteAnimation>("anim");
if (anim == null) return;
if (anim.Frames.Count == 0) return;
_QuickAnimateAnimation = anim;
PlayAnimation();
}
private SpriteAnimation _QuickAnimateAnimation = null;
protected override void OnObjectModelChanged(EventArgs e)
{
base.OnObjectModelChanged(e);
@ -169,6 +327,95 @@ namespace UniversalEditor.Plugins.Multimedia.UserInterface.Editors.Multimedia.Pi
}
}
private Timer tmr = new Timer();
public PictureCollectionEditor()
{
tmr.Tick += Timer_Tick;
}
private void PlayAnimation()
{
if (tmr.Enabled) return;
cmdQuickAnimatePlay.Text = "_Pause";
if (_QuickAnimateAnimation != null)
{
txtQuickAnimateStartFrame.Enabled = false;
txtQuickAnimateEndFrame.Enabled = false;
}
if ((int)txtQuickAnimateFrameDuration.Value == 0)
{
txtQuickAnimateFrameDuration.Value = 150; // anim.FrameDuration;
}
tmr.Duration = (int)txtQuickAnimateFrameDuration.Value;
tmr.Enabled = true;
}
private void StopAnimation()
{
if (!tmr.Enabled) return;
tmr.Enabled = false;
txtQuickAnimateStartFrame.Enabled = true;
txtQuickAnimateEndFrame.Enabled = true;
cmdQuickAnimatePlay.Text = "_Play";
}
[EventHandler(nameof(cmdQuickAnimatePlay), "Click")]
private void cmdQuickAnimatePlay_Click(object sender, EventArgs e)
{
if (!tmr.Enabled)
{
if ((int)(txtQuickAnimateEndFrame.Value - txtQuickAnimateStartFrame.Value) <= 0)
{
MessageDialog.ShowDialog("Please select a range of frames to animate.", "Error", MessageDialogButtons.OK, MessageDialogIcon.Error);
return;
}
PlayAnimation();
}
else
{
StopAnimation();
_QuickAnimateAnimation = null;
}
}
private int _c_frame = 0, _c_frameIndex = 0;
private void Timer_Tick(object sender, EventArgs e)
{
txtFrameIndex.Value = _c_frame;
_c_frame++;
_c_frameIndex++;
if (_QuickAnimateAnimation != null)
{
if (_c_frameIndex >= _QuickAnimateAnimation.Frames.Count)
{
_c_frameIndex = 0;
}
_c_frame = _QuickAnimateAnimation.Frames[_c_frameIndex];
}
else
{
if (_c_frame > (int)txtQuickAnimateEndFrame.Value)
{
_c_frame = (int)txtQuickAnimateStartFrame.Value;
}
}
}
[EventHandler(nameof(cmdQuickAnimateSave), "Click")]
private void cmdQuickAnimateSave_Click(object sender, EventArgs e)
{
}
public override void UpdateSelections()
{

View File

@ -56,6 +56,7 @@
<Compile Include="Editors\Multimedia\Audio\Waveform\Controls\WaveformAudioEditorTrackWaveform.cs" />
<Compile Include="Editors\Multimedia\Audio\Synthesized\Views\MIDIEvents\MIDIEventsView.cs" />
<Compile Include="Editors\Multimedia\Audio\Waveform\WaveformAudioEditorSelection.cs" />
<Compile Include="Editors\Multimedia\PictureCollection\Dialogs\AnimationPropertiesDialog.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Editors\" />
@ -76,6 +77,7 @@
<Folder Include="Editors\Multimedia\Audio\Waveform\" />
<Folder Include="Editors\Multimedia\Audio\Waveform\Controls\" />
<Folder Include="Editors\Multimedia\Audio\Synthesized\Views\MIDIEvents\" />
<Folder Include="Editors\Multimedia\PictureCollection\Dialogs\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Core\UniversalEditor.Core.csproj">

View File

@ -0,0 +1,38 @@
//
// SpriteAnimation.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// 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 <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
namespace UniversalEditor.ObjectModels.Multimedia.SpriteAnimationCollection
{
public class SpriteAnimation
{
public class SpriteAnimationCollection
: System.Collections.ObjectModel.Collection<SpriteAnimation>
{
}
public string Name { get; set; } = String.Empty;
public List<byte> Frames { get; } = new List<byte>();
}
}

View File

@ -0,0 +1,40 @@
//
// SpriteAnimationCollectionObjectModel.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// 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 <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.Multimedia.SpriteAnimationCollection
{
public class SpriteAnimationCollectionObjectModel : ObjectModel
{
public SpriteAnimationCollectionObjectModel()
{
}
public SpriteAnimation.SpriteAnimationCollection Animations { get; } = new SpriteAnimation.SpriteAnimationCollection();
public override void Clear()
{
}
public override void CopyTo(ObjectModel where)
{
}
}
}

View File

@ -321,6 +321,8 @@
<Compile Include="DataFormats\Multimedia\Audio\Synthesized\MIDI\MIDIFileFormatType.cs" />
<Compile Include="DataFormats\Multimedia\Audio\Synthesized\MIDI\MIDIEventType.cs" />
<Compile Include="DataFormats\Multimedia\Audio\Synthesized\MIDI\MIDIMetaEventType.cs" />
<Compile Include="ObjectModels\Multimedia\SpriteAnimationCollection\SpriteAnimationCollectionObjectModel.cs" />
<Compile Include="ObjectModels\Multimedia\SpriteAnimationCollection\SpriteAnimation.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Compression\UniversalEditor.Compression.csproj">
@ -371,6 +373,7 @@
<Folder Include="DataFormats\Multimedia\Audio\Waveform\CRI\" />
<Folder Include="DataFormats\Multimedia\Audio\Waveform\CRI\ADX\" />
<Folder Include="DataFormats\Multimedia\Audio\Synthesized\EdLib\" />
<Folder Include="ObjectModels\Multimedia\SpriteAnimationCollection\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>