Commits

Anonymous committed 871ffd6

added missing files
minor bug fix

Comments (0)

Files changed (6)

DarkMotion/Forms/LayerEdit.Designer.cs

+namespace DarkMotion
+{
+    partial class LayerEdit
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.kryptonLabel1 = new System.Windows.Forms.Label();
+            this.txtName = new System.Windows.Forms.TextBox();
+            this.lstMask = new System.Windows.Forms.ListBox();
+            this.kryptonLabel2 = new System.Windows.Forms.Label();
+            this.lstBones = new System.Windows.Forms.ListBox();
+            this.btnRemoveMask = new System.Windows.Forms.Button();
+            this.btnAddMask = new System.Windows.Forms.Button();
+            this.label1 = new System.Windows.Forms.Label();
+            this.cmbType = new System.Windows.Forms.ComboBox();
+            this.SuspendLayout();
+            // 
+            // kryptonLabel1
+            // 
+            this.kryptonLabel1.AutoSize = true;
+            this.kryptonLabel1.Location = new System.Drawing.Point(6, 15);
+            this.kryptonLabel1.Name = "kryptonLabel1";
+            this.kryptonLabel1.Size = new System.Drawing.Size(41, 13);
+            this.kryptonLabel1.TabIndex = 1;
+            this.kryptonLabel1.Text = "Name :";
+            // 
+            // txtName
+            // 
+            this.txtName.Location = new System.Drawing.Point(65, 12);
+            this.txtName.Name = "txtName";
+            this.txtName.Size = new System.Drawing.Size(121, 20);
+            this.txtName.TabIndex = 4;
+            // 
+            // lstMask
+            // 
+            this.lstMask.Location = new System.Drawing.Point(224, 99);
+            this.lstMask.Name = "lstMask";
+            this.lstMask.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
+            this.lstMask.Size = new System.Drawing.Size(177, 251);
+            this.lstMask.TabIndex = 5;
+            // 
+            // kryptonLabel2
+            // 
+            this.kryptonLabel2.AutoSize = true;
+            this.kryptonLabel2.Location = new System.Drawing.Point(6, 84);
+            this.kryptonLabel2.Name = "kryptonLabel2";
+            this.kryptonLabel2.Size = new System.Drawing.Size(72, 13);
+            this.kryptonLabel2.TabIndex = 6;
+            this.kryptonLabel2.Text = "Mask Bones :";
+            // 
+            // lstBones
+            // 
+            this.lstBones.Location = new System.Drawing.Point(9, 100);
+            this.lstBones.Name = "lstBones";
+            this.lstBones.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
+            this.lstBones.Size = new System.Drawing.Size(177, 251);
+            this.lstBones.TabIndex = 9;
+            // 
+            // btnRemoveMask
+            // 
+            this.btnRemoveMask.FlatAppearance.BorderSize = 0;
+            this.btnRemoveMask.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.btnRemoveMask.Image = global::DarkMotion.Properties.Resources.MoveLeft;
+            this.btnRemoveMask.Location = new System.Drawing.Point(189, 221);
+            this.btnRemoveMask.Name = "btnRemoveMask";
+            this.btnRemoveMask.Size = new System.Drawing.Size(32, 32);
+            this.btnRemoveMask.TabIndex = 10;
+            // 
+            // btnAddMask
+            // 
+            this.btnAddMask.FlatAppearance.BorderSize = 0;
+            this.btnAddMask.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.btnAddMask.Image = global::DarkMotion.Properties.Resources.MoveRight;
+            this.btnAddMask.Location = new System.Drawing.Point(189, 183);
+            this.btnAddMask.Name = "btnAddMask";
+            this.btnAddMask.Size = new System.Drawing.Size(32, 32);
+            this.btnAddMask.TabIndex = 7;
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(10, 41);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(37, 13);
+            this.label1.TabIndex = 11;
+            this.label1.Text = "Type :";
+            // 
+            // cmbType
+            // 
+            this.cmbType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cmbType.FormattingEnabled = true;
+            this.cmbType.Items.AddRange(new object[] {
+            "override",
+            "additive"});
+            this.cmbType.Location = new System.Drawing.Point(65, 38);
+            this.cmbType.Name = "cmbType";
+            this.cmbType.Size = new System.Drawing.Size(121, 21);
+            this.cmbType.TabIndex = 13;
+            // 
+            // StateMachineEdit
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(75)))), ((int)(((byte)(95)))), ((int)(((byte)(130)))));
+            this.ClientSize = new System.Drawing.Size(408, 362);
+            this.Controls.Add(this.cmbType);
+            this.Controls.Add(this.label1);
+            this.Controls.Add(this.btnRemoveMask);
+            this.Controls.Add(this.lstBones);
+            this.Controls.Add(this.btnAddMask);
+            this.Controls.Add(this.kryptonLabel2);
+            this.Controls.Add(this.lstMask);
+            this.Controls.Add(this.txtName);
+            this.Controls.Add(this.kryptonLabel1);
+            this.ForeColor = System.Drawing.Color.White;
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
+            this.MaximizeBox = false;
+            this.MinimizeBox = false;
+            this.Name = "StateMachineEdit";
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+            this.Text = "Layer Edit";
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+		private System.Windows.Forms.Label kryptonLabel1;
+		private System.Windows.Forms.TextBox txtName;
+		private System.Windows.Forms.ListBox lstMask;
+		private System.Windows.Forms.Label kryptonLabel2;
+		private System.Windows.Forms.Button btnAddMask;
+		private System.Windows.Forms.ListBox lstBones;
+		private System.Windows.Forms.Button btnRemoveMask;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.ComboBox cmbType;
+    }
+}

DarkMotion/Forms/LayerEdit.cs

+/*****************************************************************************
+ * The MIT License (MIT)
+ * Copyright (c) 2014 - mohamad amin valinejad.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * **************************************************************************/
+
+using System;
+using System.Windows.Forms;
+using System.Collections.Generic;
+
+namespace DarkMotion
+{
+    public partial class LayerEdit : Form
+    {
+        public LayerEdit(AnimController animator, AnimLayer stateMachine)
+        {
+            InitializeComponent();
+            _animController = animator;
+            _layer = stateMachine;
+
+            // Bind state name
+            txtName.DataBindings.Add("Text", stateMachine, "Name");
+            cmbType.DataBindings.Add("SelectedItem", stateMachine, "Type");
+            cmbType.SelectedIndexChanged += (s, e) => {
+                cmbType.DataBindings[0].WriteValue();
+            };
+
+            // Bind mask list
+            lstMask.DataSource = stateMachine.Mask;
+
+            foreach (var item in AnimController.Bones) {
+                if (!stateMachine.Mask.Contains(item)) {
+                    lstBones.Items.Add(item);
+                }
+            }
+
+
+            btnAddMask.Click += (s, e) => {
+                if (lstBones.SelectedIndex < 0)
+                    return;
+
+                _layer.Mask.Add(lstBones.SelectedItem as string);
+                lstBones.Items.RemoveAt(lstBones.SelectedIndex);
+
+                // for(int i = lstBones.SelectedIndices.Count - 1; i >= 0; i--) {
+                //     _layer.Mask.Add(lstBones.Items[i] as string);
+                //     lstBones.Items.RemoveAt(i);
+                // }
+                // lstBones.SelectedIndex = -1;
+            };
+
+
+            btnRemoveMask.Click += (s, e) => {
+                if (lstMask.SelectedIndex < 0)
+                    return;
+                string str = lstMask.SelectedItem as string;
+                lstBones.Items.Add(str);
+                _layer.Mask.Remove(str);
+                // int idx = lstMask.SelectedIndex;
+                // if(idx < 0)
+                //     return;
+                // var str = lstMask.Items[idx] as string;
+                // lstBones.Items.Add(str);
+                // _layer.Mask.Remove(str);
+            };
+
+            txtName.TextChanged += (s, e) => {
+                if (_animController.LayerExist(txtName.Text))
+                    txtName.DataBindings[0].ReadValue();
+                else
+                    txtName.DataBindings[0].WriteValue();
+            };
+
+        }
+
+        #region Fields
+        private AnimController _animController = null;
+        private AnimLayer      _layer = null;
+        #endregion
+    }
+}

DarkMotion/JsonFormat.cs

         #endregion
 
         #region Fields
-        [JsonProperty]
+        [JsonProperty("reel")]
         private string               _reel = "";
         [JsonProperty("params")]
         private List<JsonParam>      _params = new List<JsonParam>();
-        [JsonProperty]
+        [JsonProperty("layers")]
         private List<JsonLayer>      _layers = new List<JsonLayer>();
-        [JsonProperty]
+        [JsonProperty("states")]
         private List<JsonState>      _states = new List<JsonState>();
-        [JsonProperty]
+        [JsonProperty("blendtrees")]
         private List<JsonBlendTree>  _blendTrees = new List<JsonBlendTree>();
-        [JsonProperty]
+        [JsonProperty("clips")]
         private List<JsonClip>       _clips = new List<JsonClip>();
-        [JsonProperty]
+        [JsonProperty("transitions")]
         private List<JsonTransition> _transitions = new List<JsonTransition>();
         #endregion
     }

DarkMotion/UserControls/AnimLayerView.Designer.cs

+namespace DarkMotion
+{
+    partial class AnimLayerView
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null)) {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.components = new System.ComponentModel.Container();
+            this.cnxLayer = new System.Windows.Forms.ContextMenuStrip(this.components);
+            this.cnxNewState = new System.Windows.Forms.ToolStripMenuItem();
+            this.cnxNewAnimClip = new System.Windows.Forms.ToolStripMenuItem();
+            this.cnxNewBlendTree = new System.Windows.Forms.ToolStripMenuItem();
+            this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+            this.cnxMove = new System.Windows.Forms.ToolStripMenuItem();
+            this.cnxAddTransition = new System.Windows.Forms.ToolStripMenuItem();
+            this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+            this.cnxSetDefault = new System.Windows.Forms.ToolStripMenuItem();
+            this.cnxLayer.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // cnxStateMachine
+            // 
+            this.cnxLayer.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.cnxNewState,
+            this.toolStripSeparator1,
+            this.cnxMove,
+            this.cnxAddTransition,
+            this.toolStripSeparator2,
+            this.cnxSetDefault});
+            this.cnxLayer.Name = "cnxStateMachine";
+            this.cnxLayer.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
+            this.cnxLayer.Size = new System.Drawing.Size(144, 104);
+            // 
+            // cnxNewState
+            // 
+            this.cnxNewState.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.cnxNewAnimClip,
+            this.cnxNewBlendTree});
+            this.cnxNewState.Name = "cnxNewState";
+            this.cnxNewState.Size = new System.Drawing.Size(143, 22);
+            this.cnxNewState.Text = "NewState";
+            // 
+            // cnxNewAnimClip
+            // 
+            this.cnxNewAnimClip.Name = "cnxNewAnimClip";
+            this.cnxNewAnimClip.Size = new System.Drawing.Size(138, 22);
+            this.cnxNewAnimClip.Text = "AnimationClip";
+            this.cnxNewAnimClip.Click += new System.EventHandler(this.cnxNewAnimClip_Click);
+            // 
+            // cnxNewBlendTree
+            // 
+            this.cnxNewBlendTree.Name = "cnxNewBlendTree";
+            this.cnxNewBlendTree.Size = new System.Drawing.Size(138, 22);
+            this.cnxNewBlendTree.Text = "BlendTree";
+            this.cnxNewBlendTree.Click += new System.EventHandler(this.cnxNewBlendTree_Click);
+            // 
+            // toolStripSeparator1
+            // 
+            this.toolStripSeparator1.Name = "toolStripSeparator1";
+            this.toolStripSeparator1.Size = new System.Drawing.Size(140, 6);
+            // 
+            // cnxMove
+            // 
+            this.cnxMove.Name = "cnxMove";
+            this.cnxMove.Size = new System.Drawing.Size(143, 22);
+            this.cnxMove.Text = "Move";
+            this.cnxMove.Click += new System.EventHandler(this.cnxMove_Click);
+            // 
+            // cnxAddTransition
+            // 
+            this.cnxAddTransition.Name = "cnxAddTransition";
+            this.cnxAddTransition.Size = new System.Drawing.Size(143, 22);
+            this.cnxAddTransition.Text = "Add Transition";
+            this.cnxAddTransition.Click += new System.EventHandler(this.cnxAddTransition_Click);
+            // 
+            // toolStripSeparator2
+            // 
+            this.toolStripSeparator2.Name = "toolStripSeparator2";
+            this.toolStripSeparator2.Size = new System.Drawing.Size(140, 6);
+            // 
+            // cnxSetDefault
+            // 
+            this.cnxSetDefault.Name = "cnxSetDefault";
+            this.cnxSetDefault.Size = new System.Drawing.Size(143, 22);
+            this.cnxSetDefault.Text = "Set As Default";
+            this.cnxSetDefault.Click += new System.EventHandler(this.cnxSetDefault_Click);
+            // 
+            // StateMachineView
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.BackColor = System.Drawing.SystemColors.ControlDarkDark;
+            this.Name = "StateMachineView";
+            this.Size = new System.Drawing.Size(423, 281);
+            this.cnxLayer.ResumeLayout(false);
+            this.ResumeLayout(false);
+
+        }
+
+        private System.Windows.Forms.ContextMenuStrip cnxLayer;
+        private System.Windows.Forms.ToolStripMenuItem cnxNewState;
+        private System.Windows.Forms.ToolStripMenuItem cnxNewAnimClip;
+        private System.Windows.Forms.ToolStripMenuItem cnxNewBlendTree;
+        private System.Windows.Forms.ToolStripMenuItem cnxMove;
+
+        private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
+        private System.Windows.Forms.ToolStripMenuItem cnxAddTransition;
+        private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
+        private System.Windows.Forms.ToolStripMenuItem cnxSetDefault;
+    }
+}

DarkMotion/UserControls/AnimLayerView.cs

+/*****************************************************************************
+ * The MIT License (MIT)
+ * Copyright (c) 2014 - mohamad amin valinejad.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * **************************************************************************/
+
+using SharpHammer;
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace DarkMotion
+{
+    public partial class AnimLayerView : EditorBase.Canvas
+    {
+        public AnimLayerView()
+            : base()
+        {
+            InitializeComponent();
+
+            _centerAlign.Alignment = StringAlignment.Center;
+            _centerAlign.LineAlignment = StringAlignment.Center;
+            _selectedPen.DashStyle = DashStyle.Custom;
+            _selectedPen.DashPattern = new float[] { 6, 2 };
+            _transitionPen.CustomEndCap = new AdjustableArrowCap(5, 8);
+            _selectedTransPen.CustomEndCap = new AdjustableArrowCap(4, 6);
+            _selectedTransPen.DashStyle = DashStyle.Dash;
+        }
+
+        #region Enums
+        public enum Tools
+        {
+            Move,
+            AddTransition
+        }
+        #endregion
+
+        #region Events
+        public event Action RebindTrigger;
+        #endregion
+
+        #region Methods
+        public object GetObjectAtPoint(PointF pnt)
+        {
+            var wPos = ScreenToCanvas(pnt);
+            object selObj = null;
+            _editStateMachine.ForEachState(s => {
+                foreach (var item in s.Transitions) {
+                    PointF from, to;
+                    findClosestPoints(s, item.Target, out from, out to);
+                    if (linePointdist(from, to, wPos) < 5)
+                        selObj = item;
+                }
+            });
+            _editStateMachine.ForEachState(s => {
+                if (getStateRect(s).Contains(wPos))
+                    selObj = s;
+            });
+            return selObj;
+        }
+
+        protected override void OnDrawCanvas(Graphics g)
+        {
+            if (_editStateMachine != null) {
+                // Draw Transition
+                g.SmoothingMode = SmoothingMode.AntiAlias;
+                _editStateMachine.ForEachState(s => {
+                    foreach (var item in s.Transitions) {
+                        PointF from, to;
+                        findClosestPoints(s, item.Target, out from, out to);
+                        Pen tpen = _selected == item ? _selectedTransPen : _transitionPen;
+                        Brush tbr = _selected == item ? Brushes.Red : Brushes.LightGray;
+                        g.FillEllipse(tbr, from.X - 5, from.Y - 5, 10, 10);
+                        g.DrawLine(tpen, from, to);
+                    }
+                });
+                g.SmoothingMode = SmoothingMode.Default;
+
+                // Draw States
+                _editStateMachine.ForEachState(s => {
+                    var rect = getStateRect(s);
+
+                    g.FillRectangle((s == _editStateMachine.DefaultState) ?
+										_defaultStateBrush : _stateBrush, rect);
+                    var overlayBrush = new LinearGradientBrush(rect, Color.FromArgb(100, 0, 0, 0),
+                                             Color.FromArgb(0, 255, 255, 255), 270f);
+                    g.FillRectangle(overlayBrush, rect);
+                    g.DrawRectangle(Pens.Black, rect.X, rect.Y, rect.Width, rect.Height);
+                    g.DrawString(s.Name, Font, Brushes.Black, s.Position.X, s.Position.Y, _centerAlign);
+
+                    if (s.Sequence is BlendTree)
+                        g.DrawImage(_treeIcon, rect.Right - _treeIcon.Width, rect.Bottom - _treeIcon.Height, _treeIcon.Width, _treeIcon.Height);
+                    if (_selected == s) {
+                        rect.X -= 3;
+                        rect.Y -= 3;
+                        rect.Width += 6;
+                        rect.Height += 6;
+                        g.FillRectangle(_selectedFillBrush, rect);
+                        g.DrawRectangle(_selectedPen, rect.X, rect.Y, rect.Width, rect.Height);
+                    }
+
+                    overlayBrush.Dispose();
+                });
+
+                g.SmoothingMode = SmoothingMode.AntiAlias;
+                if (_dragging && _currentTool == Tools.AddTransition) {
+                    var srcState = _selected as State;
+                    if (srcState != null) {
+                        PointF to = ScreenToCanvas(lastMousePos);
+                        g.DrawLine(_transitionPen, srcState.Position.ToPointF(), to);
+                    }
+                }
+                g.SmoothingMode = SmoothingMode.Default;
+            }
+        }
+
+        protected override void OnDrawScreen(Graphics g)
+        {
+            // Draw layer string
+            if (_editStateMachine != null)
+                g.DrawString("Layer : " + _editStateMachine.Name, Font, Brushes.White,
+                                        new PointF(10, Height - Font.Height - 10));
+        }
+
+        protected override void OnKeyDown(KeyEventArgs e)
+        {
+            base.OnKeyDown(e);
+            if (e.KeyCode == Keys.Delete) {
+                var selState = _selected as State;
+                var selTrans = _selected as Transition;
+                if (selState != null)
+                    _editStateMachine.RemoveState(selState);
+                else if (selTrans != null)
+                    _editStateMachine.RemoveTransition(selTrans);
+                Invalidate();
+            }
+        }
+
+        protected override void OnMouseDoubleClick(MouseEventArgs e)
+        {
+            base.OnMouseDoubleClick(e);
+
+            var target = GetObjectAtPoint(e.Location);
+
+            var s = target as State;
+            var t = target as Transition;
+            if (s != null && s.Sequence is BlendTree) {
+                var blendEdit = new BlendTreeEdit(s.Sequence as BlendTree, _editStateMachine, s);
+                blendEdit.ShowDialog();
+            } else if (t != null) {
+
+            }
+        }
+
+        protected override void OnMouseDown(MouseEventArgs e)
+        {
+            base.OnMouseDown(e);
+            lastMousePos = e.Location;
+
+            if (e.Button == MouseButtons.Left) {
+                _selected = null;
+                _selected = GetObjectAtPoint(e.Location);
+                if (RebindTrigger != null)
+                    RebindTrigger();
+                _dragging = true;
+            } else if (e.Button == MouseButtons.Right)
+                cnxLayer.Show(this, e.Location);
+
+            Invalidate();
+        }
+
+        protected override void OnMouseMove(MouseEventArgs e)
+        {
+            var delta = new Vec2(e.X - lastMousePos.X,
+                         e.Y - lastMousePos.Y);
+
+            if (e.Button == MouseButtons.Left && _currentTool == Tools.Move) {
+                var s = _selected as State;
+                if (s != null) {
+                    s.Position += delta;
+                }
+            }
+
+            if (_dragging)
+                Invalidate();
+
+            base.OnMouseMove(e);
+        }
+
+        protected override void OnMouseUp(MouseEventArgs e)
+        {
+            base.OnMouseUp(e);
+
+            var s = _selected as State;
+            if (e.Button == MouseButtons.Left) {
+                _dragging = false;
+                if (_currentTool == Tools.AddTransition && s != null) {
+                    var target = GetObjectAtPoint(e.Location) as State;
+                    if (target != null && target != s) {
+                        if (!s.Transitions.Any(t => t.Target == target))
+                            s.Transitions.Add(new Transition(target));
+                    }
+                }
+            }
+
+            Invalidate();
+
+            if (RebindTrigger != null)
+                RebindTrigger();
+        }
+
+        private void cnxAddTransition_Click(object sender, EventArgs e)
+        {
+            _currentTool = Tools.AddTransition;
+        }
+
+        private void cnxMove_Click(object sender, EventArgs e)
+        {
+            _currentTool = Tools.Move;
+        }
+
+        private void cnxNewAnimClip_Click(object sender, EventArgs e)
+        {
+            var newOne = _editStateMachine.AddState(new AnimClip(null));
+            newOne.Position = Vec2.FromPointF(ScreenToCanvas(lastMousePos));
+            Invalidate();
+        }
+
+        private void cnxNewBlendTree_Click(object sender, EventArgs e)
+        {
+            var newOne = _editStateMachine.AddState(BlendTree.CreateNew(null));
+            newOne.Position = Vec2.FromPointF(ScreenToCanvas(lastMousePos));
+            Invalidate();
+        }
+
+        private void cnxSetDefault_Click(object sender, EventArgs e)
+        {
+            var s = GetObjectAtPoint(lastMousePos) as State;
+            if (s != null) {
+                _editStateMachine.DefaultState = s;
+                Invalidate();
+            }
+        }
+
+        private void findClosestPoints(State s1, State s2, out PointF a, out PointF b)
+        {
+            RectangleF rect1 = new RectangleF(s1.X - _stateSize.Width / 2f,
+                              s1.Y - _stateSize.Height / 2f,
+                              _stateSize.Width, _stateSize.Height);
+            RectangleF rect2 = new RectangleF(s2.X - _stateSize.Width / 2f,
+                              s2.Y - _stateSize.Height / 2f,
+                              _stateSize.Width, _stateSize.Height);
+            Vec2 rect1_center = new Vec2(rect1.X + rect1.Width / 2, rect1.Y + rect1.Height / 2);
+            Vec2 rect2_center = new Vec2(rect2.X + rect2.Width / 2, rect2.Y + rect2.Height / 2);
+            Vec2 midPoint = (rect1_center + rect2_center) / 2;
+
+            Vec2 v1 = new Vec2(
+                  MathUtil.Clamp(midPoint.X, rect1.Left, rect1.Right),
+                  MathUtil.Clamp(midPoint.Y, rect1.Top, rect1.Bottom));
+            Vec2 v2 = new Vec2(
+                  MathUtil.Clamp(midPoint.X, rect2.Left, rect2.Right),
+                  MathUtil.Clamp(midPoint.Y, rect2.Top, rect2.Bottom));
+
+            var dir = v2 - v1;
+            dir.Normalize();
+            Vec2 offcet = new Vec2(dir.Y, -dir.X) * 5;
+            a = (v1 + offcet).ToPointF();
+            b = (v2 + offcet).ToPointF();
+        }
+
+        private RectangleF getStateRect(State s)
+        {
+            return new RectangleF(s.Position.X - (_stateSize.Width / 2),
+                          s.Position.Y - (_stateSize.Height / 2),
+                          _stateSize.Width, _stateSize.Height);
+        }
+
+        private float linePointdist(PointF ln1, PointF ln2, PointF pnt)
+        {
+            return MathUtil.LinePointDistance(Vec2.FromPointF(ln1), Vec2.FromPointF(ln2), Vec2.FromPointF(pnt));
+        }
+        #endregion
+
+        #region Properties
+        public AnimLayer AnimLayer
+        {
+            get
+            {
+                return _editStateMachine;
+            }
+            set
+            {
+                _editStateMachine = value;
+                _selected = null;
+                Invalidate();
+            }
+        }
+
+        public Color DefaultStateColor
+        {
+            get
+            {
+                return _defaultStateBrush.Color;
+            }
+            set
+            {
+                _defaultStateBrush.Color = value;
+                Invalidate();
+            }
+        }
+
+        public State SelectedState
+        {
+            get
+            {
+                return _selected as State;
+            }
+        }
+
+        public Transition SelectedTransition
+        {
+            get
+            {
+                return _selected as Transition;
+            }
+        }
+
+        public Color StateColor
+        {
+            get
+            {
+                return _stateBrush.Color;
+            }
+            set
+            {
+                _stateBrush.Color = value;
+                Invalidate();
+            }
+        }
+
+        public Size StateSize
+        {
+            get
+            {
+                return _stateSize;
+            }
+            set
+            {
+                _stateSize = value;
+                Invalidate();
+            }
+        }
+        #endregion
+
+        #region Fields
+        private AnimLayer    _editStateMachine;
+        private Size         _stateSize;
+        private StringFormat _centerAlign       = new StringFormat();
+        private Tools        _currentTool       = Tools.Move;
+        private SolidBrush   _defaultStateBrush = new SolidBrush(Color.White);
+        private SolidBrush   _selectedFillBrush = new SolidBrush(Color.FromArgb(64, 255, 50, 100));
+        private Pen          _selectedPen       = new Pen(Color.OrangeRed, 1.5f);
+        private Pen          _selectedTransPen  = new Pen(Color.Red, 2);
+        private SolidBrush   _stateBrush        = new SolidBrush(Color.White);
+        private Pen          _transitionPen     = new Pen(Color.LightGray, 2);
+        private Image        _treeIcon          = Properties.Resources.tree;
+        private bool         _dragging          = false;
+        private object       _selected          = null;
+        #endregion
+    }
+}

DarkMotion/UserControls/AnimLayerView.resx

+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="cnxStateMachine.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>22, 12</value>
+  </metadata>
+</root>